diff --git a/src/server.tsx b/src/server.tsx index 4b99dab..116e86e 100644 --- a/src/server.tsx +++ b/src/server.tsx @@ -25,9 +25,11 @@ type Success = { export const GIT_SHA = process.env.RENDER_GIT_COMMIT ?? (await Bun.$`git rev-parse HEAD`.text()).trim() +const REQUEST_TIMEOUT = 30_000 + type Connection = { app: string, ws: any } let connections: Record = {} -const pending = new Map void> +const pending = new Map void, subdomain: string }> const app = new Hono @@ -65,15 +67,21 @@ app.get("/tunnel", c => { console.log(`connection opened: ${name} -> ${app}`) send(ws, { subdomain: name }) }, - onClose: (_event, ws) => { + onClose: (_event, _ws) => { console.log("connection closed:", name) delete connections[name] + for (const [id, entry] of pending) { + if (entry.subdomain === name) { + entry.resolve({ id, status: 502, headers: {}, body: "Tunnel disconnected" }) + pending.delete(id) + } + } }, async onMessage(event, _ws) { const msg = JSON.parse(event.data.toString()) - const resolve = pending.get(msg.id) - if (resolve) { - resolve(msg) + const entry = pending.get(msg.id) + if (entry) { + entry.resolve(msg) pending.delete(msg.id) } }, @@ -95,11 +103,24 @@ app.all("*", async c => { const id = randomID() const headers = Object.fromEntries(c.req.raw.headers) + delete headers['host'] + delete headers['connection'] + delete headers['keep-alive'] + delete headers['transfer-encoding'] + delete headers['content-length'] const body = await c.req.text() const app = connection.app - const result = await new Promise(resolve => { - pending.set(id, resolve) + const result = await new Promise((resolve, reject) => { + const timer = setTimeout(() => { + pending.delete(id) + reject(new Error("Tunnel request timed out")) + }, REQUEST_TIMEOUT) + + pending.set(id, { + resolve: (res) => { clearTimeout(timer); resolve(res) }, + subdomain, + }) send(connection.ws, { id, app, @@ -108,7 +129,7 @@ app.all("*", async c => { headers, body }) - }) + }).catch((): Response => ({ id, status: 504, headers: {}, body: "Gateway Timeout" })) if (result.isBinary) { const buffer = Buffer.from(result.body, 'base64') @@ -125,7 +146,7 @@ app.all("*", async c => { }) function send(connection: any, msg: Request | Success) { - console.log("sending", msg) + console.log("sending", 'id' in msg ? `${msg.id} ${msg.method} ${msg.path}` : `connected: ${msg.subdomain}`) connection.send(JSON.stringify(msg)) }