diff --git a/server/client.test.ts b/server/client.test.ts index 28d172a..cfbf96a 100644 --- a/server/client.test.ts +++ b/server/client.test.ts @@ -1,12 +1,13 @@ import { assertEquals } from "jsr:@std/assert"; +import { createSession } from "#/server/handler.ts"; import handler from "./handler.ts"; import { close, connect, flush, href, setup } from "./testSetup.ts"; Deno.test( "test", setup(async () => { - const t1 = "123-abc"; - const [s1, m1] = await connect(`${href}?ticket=${t1}`); + const sessionId = createSession(); + const [s1, m1] = await connect(`${href}?sessionId=${sessionId}`); await flush(); assertEquals(m1, []); await close(s1); diff --git a/server/handler.ts b/server/handler.ts index 2c7ab98..8c5dfaa 100644 --- a/server/handler.ts +++ b/server/handler.ts @@ -2,14 +2,12 @@ import { STATUS_CODE, STATUS_TEXT, type StatusCode } from "jsr:@std/http"; const ALLOWED_ORIGIN = "http://0.0.0.0:8042"; -const sessions = new Map(); - -function createSession(socket: WebSocket): string { - const session = crypto.randomUUID(); - sessions.set(session, socket); - - return session; -} +type Session = { + id: string; + connId: number; + createdAt: number; + lastSeenAt: number; +}; function createResponse( status: StatusCode, @@ -18,32 +16,66 @@ function createResponse( return new Response(body, { status, statusText: STATUS_TEXT[status] }); } +const sessions = new Map(); +const connections = new Map(); + +export function createSession(): string { + const id = crypto.randomUUID(); + const now = Date.now(); + sessions.set(id, { + id, + connId: 0, + createdAt: now, + lastSeenAt: 0, + }); + + return id; +} + +let currentId = 1; +const nextId = (): number => { + return currentId++; +}; + +const connectSession = (session: Session, request: Request): Response => { + const { response, socket } = Deno.upgradeWebSocket(request); + const connId = nextId(); + + socket.onopen = () => { + session.lastSeenAt = Date.now(); + session.connId = connId; + connections.set(connId, socket); + }; + socket.onclose = () => { + session.lastSeenAt = Date.now(); + connections.delete(connId); + }; + socket.onmessage = () => { + session.lastSeenAt = Date.now(); + }; + socket.onerror = (e) => { + session.lastSeenAt = Date.now(); + console.error(e); + }; + + return response; +}; + export default function (request: Request): Response { if (request.headers.get("upgrade")?.toLowerCase() !== "websocket") { return createResponse(STATUS_CODE.UpgradeRequired); } const url = new URL(request.url); - if (url.origin !== ALLOWED_ORIGIN) { + const sessionId = url.searchParams.get("sessionId"); + if (url.origin !== ALLOWED_ORIGIN || sessionId === null) { return createResponse(STATUS_CODE.BadRequest); } - const sessionId = url.searchParams.get("sessionId"); - - if (sessionId === null) { - const upgrade = Deno.upgradeWebSocket(request); - createSession(upgrade.socket); - - return upgrade.response; - } else { - const session = sessions.get(sessionId); - if (session === null) { - return createResponse(STATUS_CODE.Unauthorized); - } - - // TODO - // I need a new socket every time + const session = sessions.get(sessionId); + if (session === undefined) { + return createResponse(STATUS_CODE.Unauthorized); } - return createResponse(STATUS_CODE.InternalServerError); + return connectSession(session, request); }