From bfeb85b674d3d3eea9d4db28b6066141f6fb1f16 Mon Sep 17 00:00:00 2001 From: Seth Trowbridge Date: Fri, 10 Oct 2025 14:03:06 -0400 Subject: [PATCH] copilot socket fixes --- hmr/hmr-listen.tsx | 45 ++++++++++++++++++++++++++++++++++----------- server.ts | 34 +++++++++++++--------------------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/hmr/hmr-listen.tsx b/hmr/hmr-listen.tsx index 50caf18..6b46056 100644 --- a/hmr/hmr-listen.tsx +++ b/hmr/hmr-listen.tsx @@ -8,14 +8,37 @@ export const FileListen =(inPath:string, inHandler:()=>void)=> FileListeners.set(inPath, members); }; -const Socket:WebSocket = new WebSocket("ws://"+document.location.host); -Socket.addEventListener('message', async(event:{data:string})=> -{ - // When a file changes, dynamically re-import it to get the updated members - // send the updated members to any listeners for that file - const reImport = await import(document.location.origin+event.data+"?reload="+Math.random()); - FileListeners.get(event.data)?.forEach(reExport=>reExport(reImport)); - HMR.update(); -}); -Socket.addEventListener("error", ()=>{clearInterval(SocketTimer); console.log("HMR socket lost")}) -const SocketTimer = setInterval(()=>{Socket.send("ping")}, 5000); \ No newline at end of file +let socket: WebSocket; +let socketTimer: number | undefined; +let reconnectAttempts = 0; + +function connect() { + socket = new WebSocket("ws://" + location.host); + socket.addEventListener("open", () => { + reconnectAttempts = 0; + socketTimer = window.setInterval(() => { + if (socket.readyState === WebSocket.OPEN) socket.send("ping"); + }, 5000); + }); + socket.addEventListener("message", async (ev) => { + try { + const reImport = await import(location.origin + ev.data + "?reload=" + Math.random()); + FileListeners.get(ev.data)?.forEach(h => h(reImport)); + HMR.update(); + } catch (e) { + console.error("HMR import failed for", ev.data, e); + } + }); + socket.addEventListener("close", () => { + if (socketTimer) { clearInterval(socketTimer); socketTimer = undefined; } + // simple exponential backoff reconnect + reconnectAttempts++; + const delay = Math.min(30000, 500 * (2 ** (reconnectAttempts - 1))); + setTimeout(connect, delay); + }); + socket.addEventListener("error", () => { + if (socketTimer) { clearInterval(socketTimer); socketTimer = undefined; } + }); +} + +connect(); \ No newline at end of file diff --git a/server.ts b/server.ts index 4f141cf..e44ee16 100644 --- a/server.ts +++ b/server.ts @@ -118,6 +118,7 @@ const JSResponse =(body:string)=> return new Response(stream, JSHead); } + Deno.serve(async(req:Request)=> { if(req.headers.get("upgrade") == "websocket") @@ -127,11 +128,11 @@ Deno.serve(async(req:Request)=> const { response, socket } = Deno.upgradeWebSocket(req); socket.onopen = () => SocketsLive.add(socket); socket.onclose = () => SocketsLive.delete(socket); + socket.onerror = (e) => { console.log("socket error", e); SocketsLive.delete(socket); }; socket.onmessage = () => {}; - socket.onerror = (e) => {console.log("Socket errored:", e);SocketsLive.delete(socket);} return response; } - catch(e){ console.log("Socket errored:", e); } + catch(e){ console.log("upgradeWebSocket failed", e); } } const url = new URL(req.url); @@ -172,31 +173,22 @@ Deno.serve(async(req:Request)=> return new Response(); }); -const SocketsLive:Set = new Set(); -const SocketsSend =(inData:string)=> -{ - // iterate over a snapshot so we can remove while iterating - for (const socket of Array.from(SocketsLive)) - { - try - { - if (socket.readyState === WebSocket.OPEN) - { +const SocketsLive = new Set(); + +const SocketsSend = (inData: string) => { + for (const socket of Array.from(SocketsLive)) { + try { + if (socket.readyState === WebSocket.OPEN) { socket.send(inData); - } - else - { - // not open any more — remove it + } else { SocketsLive.delete(socket); } - } - catch (err) - { - console.log("Failed to send to socket:", err); + } catch (e) { + console.log("socket send failed:", e); SocketsLive.delete(socket); } } -} +}; const Watcher =async()=> {