diff --git a/src/app/api/run/route.ts b/src/app/api/run/route.ts index 4f7b19f..ac92e5a 100644 --- a/src/app/api/run/route.ts +++ b/src/app/api/run/route.ts @@ -1,190 +1,204 @@ import { WebSocketServer, WebSocket } from "ws"; import { randomUUID } from "crypto"; -import { createClient } from "@/lib/supabase/server"; +import { createClientCookie } from "@/lib/supabase/server"; import { getSession } from "@/modules/account/core"; import * as Core from "@/modules/live-run/core"; import { ClientMessage } from "./types"; +import { NextRequest } from "next/server"; + +export function GET(req: NextRequest) { + const headers = new Headers(); + headers.set("Connection", "Upgrade"); + headers.set("Upgrade", "websocket"); + return new Response("Upgrade Required", { status: 426, headers }); +} export function UPGRADE(client: WebSocket, server: WebSocketServer) { - client.on("message", async (raw) => { - try { - const msg: ClientMessage = JSON.parse(raw.toString()); + client.once("message", async (raw) => { + const { cookies }: { cookies: Record } = JSON.parse( + raw.toString(), + ); - const supabase = await createClient(); - const session = await getSession(supabase); - - if (!session) { - client.send(JSON.stringify({ ok: false, error: "Invalid session" })); - return; - } - - switch (msg.type) { - /* ---------------- CREATE ---------------- */ - case "create": { - const { problem, category } = msg; - - if (!problem || !category) { - client.send( - JSON.stringify({ - ok: false, - error: "problem and category required", - }), - ); - return; - } - - const runId = randomUUID(); - - await Core.addLiveRun({ - id: runId, - problem, - category, - username: session[1].username, - views: 0, - start: Date.now(), - runsCount: 0, - }); - - client.send( - JSON.stringify({ - ok: true, - type: "create", - data: { runId }, - }), - ); - break; - } - - /* ---------------- DELETE ---------------- */ - case "move": { - const { runId, moves, file, language } = msg; - - if ( - !runId || - !moves || - file === undefined || - language === undefined - ) { - client.send( - JSON.stringify({ - ok: false, - error: "body requires runId, moves, file and language", - }), - ); - return; - } - - const supabase = await createClient(); - const session = await getSession(supabase); - - if (!session) { - client.send( - JSON.stringify({ ok: false, error: "Invalid session" }), - ); - return; - } - - const liveRun = await Core.getLiveRun(runId); - - if (!liveRun) { - client.send( - JSON.stringify({ - ok: false, - error: "Run is not live or does not exist", - }), - ); - return; - } - - const run = await Core.addLiveRunEvent( - liveRun.id, - file, - language, - moves, - ); - - client.send( - JSON.stringify({ - ok: true, - type: "move", - data: run, - }), - ); - - break; - } - - /* ---------------- SUBMIT ---------------- */ - case "submit": { - const { runId } = msg; - - if (!runId) { - client.send(JSON.stringify({ ok: false, error: "runId required" })); - return; - } - - const liveRun = await Core.getLiveRun(runId); - - if (!liveRun) { - client.send( - JSON.stringify({ - ok: false, - error: "Run is not live or does not exist", - }), - ); - return; - } - - const run = await Core.submitRun(supabase, liveRun, session[0].id); - - client.send( - JSON.stringify({ - ok: true, - type: "submit", - data: run, - }), - ); - break; - } - - /* ---------------- DELETE ---------------- */ - case "delete": { - const { runId } = msg; - - if (!runId) { - client.send(JSON.stringify({ ok: false, error: "runId required" })); - return; - } - - const run = await Core.removeLiveRun(runId); - - client.send( - JSON.stringify({ - ok: true, - type: "delete", - data: run, - }), - ); - break; - } - - default: - client.send( - JSON.stringify({ - ok: false, - error: "Unknown message type", - }), - ); - } - } catch (err) { - console.error(err); - client.send( - JSON.stringify({ - ok: false, - error: "Malformed message", - }), - ); + if (!cookies) { + client.send(JSON.stringify({ ok: false, error: "Missing cookies" })); + client.close(); + return; } + + const supabase = await createClientCookie(new Map(Object.entries(cookies))); + const session = await getSession(supabase); + + if (!session) { + client.send(JSON.stringify({ ok: false, error: "Invalid session" })); + return; + } + + client.on("message", async (raw) => { + try { + const msg: ClientMessage = JSON.parse(raw.toString()); + + switch (msg.type) { + /* ---------------- CREATE ---------------- */ + case "create": { + const { problem, category } = msg; + + if (!problem || !category) { + client.send( + JSON.stringify({ + ok: false, + error: "problem and category required", + }), + ); + return; + } + + const runId = randomUUID(); + + await Core.addLiveRun({ + id: runId, + problem, + category, + username: session[1].username, + views: 0, + start: Date.now(), + runsCount: 0, + }); + + client.send( + JSON.stringify({ + ok: true, + type: "create", + data: { runId }, + }), + ); + break; + } + + /* ---------------- DELETE ---------------- */ + case "move": { + const { runId, moves, file, language } = msg; + + if ( + !runId || + !moves || + file === undefined || + language === undefined + ) { + client.send( + JSON.stringify({ + ok: false, + error: "body requires runId, moves, file and language", + }), + ); + return; + } + + const liveRun = await Core.getLiveRun(runId); + + if (!liveRun) { + client.send( + JSON.stringify({ + ok: false, + error: "Run is not live or does not exist", + }), + ); + return; + } + + const run = await Core.addLiveRunEvent( + liveRun.id, + file, + language, + moves, + ); + + client.send( + JSON.stringify({ + ok: true, + type: "move", + data: run, + }), + ); + + break; + } + + /* ---------------- SUBMIT ---------------- */ + case "submit": { + const { runId } = msg; + + if (!runId) { + client.send( + JSON.stringify({ ok: false, error: "runId required" }), + ); + return; + } + + const liveRun = await Core.getLiveRun(runId); + + if (!liveRun) { + client.send( + JSON.stringify({ + ok: false, + error: "Run is not live or does not exist", + }), + ); + return; + } + + const run = await Core.submitRun(supabase, liveRun, session[0].id); + + client.send( + JSON.stringify({ + ok: true, + type: "submit", + data: run, + }), + ); + break; + } + + /* ---------------- DELETE ---------------- */ + case "delete": { + const { runId } = msg; + + if (!runId) { + client.send( + JSON.stringify({ ok: false, error: "runId required" }), + ); + return; + } + + const run = await Core.removeLiveRun(runId); + + client.send( + JSON.stringify({ + ok: true, + type: "delete", + data: run, + }), + ); + break; + } + + default: + client.send( + JSON.stringify({ + ok: false, + error: "Unknown message type", + }), + ); + } + } catch (err) { + console.error(err); + client.send( + JSON.stringify({ + ok: false, + error: "Malformed message", + }), + ); + } + }); }); client.on("close", () => { diff --git a/src/lib/supabase/server.ts b/src/lib/supabase/server.ts index 30a93dc..c8fed94 100644 --- a/src/lib/supabase/server.ts +++ b/src/lib/supabase/server.ts @@ -27,22 +27,20 @@ export async function createClient() { ); } -export async function createClientApi() { - const cookieStore = await cookies(); - +export async function createClientCookie(cookies: Map) { return createServerClient( process.env.SUPABASE_URL!, process.env.SUPABASE_SECRET_KEY!, { cookies: { get(name: string) { - return cookieStore.get(name)?.value; + return cookies.get(name) || null; }, - set(name: string, value: string, options: CookieOptions) { - cookieStore.set(name, value, options); + set(name: string, value: string) { + cookies.set(name, value); }, remove(name: string, options: CookieOptions) { - cookieStore.set(name, "", options); + cookies.delete(name); }, }, },