/// import { ServerWebSocket } from "bun"; import { useServerRouter } from "../server/server-route"; import { sessionRouter } from "./router/session-router"; import { newSessionStore } from "./store/session-store"; import { ServerContext, SessionAuth, SessionStore, SingleSession, } from "./type"; import { createId } from "@paralleldrive/cuid2"; import { ConsoleLogWriter } from "drizzle-orm"; type WS = ServerWebSocket<{ url: string }>; type SessionServerHandler = { cleanup: () => Promise; handle: (arg: ServerContext) => Promise; ws: { sids: Record; index: Record; conns: Map; init: () => PrasiServer["ws"]; }; }; export const initSessionServer = ( server: PrasiServer, arg: { encrypt?: boolean; router?: ReturnType; login: ( session: SessionStore, arg: SessionAuth ) => Promise | false>; } ) => { try { const session_store = newSessionStore(server.site_id); const session_router = useServerRouter(sessionRouter); const server_handler: SessionServerHandler = { async cleanup() {}, ws: { sids: {}, index: {}, conns: new Map(), init() { return { async message(ws, message) { const sids = server_handler.ws.sids; const conns = server_handler.ws.conns; const index = server_handler.ws.index; const conn = conns.get(ws); if (conn) { try { if (typeof message === "string") { const parsed = JSON.parse(message) as { action: "logout" }; if (parsed.action === "logout") { const sid = `${conn.uid}-${conn.sid}`; if (!sids[sid]) { sids[sid] = []; } sids[sid].forEach((e) => { conns.delete(e); e.close(); }); session_store.update( { sid: conn.sid, uid: conn.uid }, { active: false, wsid: [], } ); } } } catch (e) {} } else { try { if (typeof message === "string") { const activateSession = (result: SingleSession) => { try { const wsid = createId(); conns.set(ws, { wsid, uid: result.uid, sid: result.sid, }); index[wsid] = ws; const sid = `${result.uid}-${result.sid}`; if (!sids[sid]) { sids[sid] = []; } sids[sid].push(ws); const wsids = Object.values(sids[sid]).map( (e) => server_handler.ws.conns.get(e)?.sid || "" ); session_store.update( { sid: result.sid, uid: result.uid }, { wsid: wsids, } ); ws.send( JSON.stringify({ status: "ok", wsid, session: result, }) ); } catch (e) { console.error(e); } }; const parsed = JSON.parse(message) as | { method: undefined; uid: string; sid: string; } | SessionAuth; if (parsed) { if (parsed.method) { if (parsed.method === "user-pass") { const result = await arg.login(session_store, parsed); if (result) { activateSession(result); } else { ws.send(JSON.stringify({ status: "failed" })); } } } else { const result = session_store.findFirst({ uid: parsed.uid, sid: parsed.sid, }); if (result) { if ( result.active && (!result.expired_at || (result.expired_at && result.expired_at > Date.now())) ) { activateSession(result); } else { session_store.update( { uid: parsed.uid, sid: parsed.sid, }, { active: false } ); ws.send(JSON.stringify({ status: "expired" })); } } } } } } catch (e) { console.error(e); } } }, close(ws, code, reason) { const result = server_handler.ws.conns.get(ws); if (result) { const sid = `${result.uid}-${result.sid}`; if (server_handler.ws.sids[sid]) { server_handler.ws.sids[sid] = server_handler.ws.sids[ sid ].filter((e) => e !== ws); session_store.update( { sid: result.sid }, { wsid: Object.values(server_handler.ws.sids[sid]).map( (e) => server_handler.ws.conns.get(e)?.sid || "" ), } ); } delete server_handler.ws.index[result.wsid]; server_handler.ws.conns.delete(ws); } }, }; }, }, async handle(server_arg) { const { req, handle, url } = server_arg; const route_arg = { ...server_arg, session: { ...session_store, current: undefined, }, }; if (url.pathname.startsWith("/_session/")) { const res = await session_router.handle(route_arg); if (res) return res; } if (arg.router) { const res = await arg.router.handle(route_arg); if (res) return res; } return handle(req); }, }; server.ws = server_handler.ws.init(); server.session = server_handler; } catch (e) { console.log(e); } };