diff --git a/fresh.gen.ts b/fresh.gen.ts index 1aabb31..a04a29a 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -4,8 +4,7 @@ import * as $0 from "./routes/_404.tsx"; import * as $1 from "./routes/_app.tsx"; -import * as $2 from "./routes/_middleware.ts"; -import * as $3 from "./routes/index.tsx"; +import * as $2 from "./routes/index.tsx"; import * as $$0 from "./islands/CounterCard.tsx"; import * as $$1 from "./islands/MarkdownContent.tsx"; @@ -13,8 +12,7 @@ const manifest = { routes: { "./routes/_404.tsx": $0, "./routes/_app.tsx": $1, - "./routes/_middleware.ts": $2, - "./routes/index.tsx": $3, + "./routes/index.tsx": $2, }, islands: { "./islands/CounterCard.tsx": $$0, diff --git a/islands/CounterCard.tsx b/islands/CounterCard.tsx index c08a7c1..d39709d 100644 --- a/islands/CounterCard.tsx +++ b/islands/CounterCard.tsx @@ -89,7 +89,7 @@ export default function Counter(props: SharedProps) { JSON.stringify({ data: internalCount + 1 }), ); console.info( - `[${new Date()}] Updating global count: ${internalCount + 1}`, + `[${new Date().toISOString()}] Updating global count: ${internalCount + 1}`, ); setInternalCount(0); } @@ -97,27 +97,26 @@ export default function Counter(props: SharedProps) { }; useEffect(() => { - let es = new EventSource(window.location.href); + let ws = new WebSocket(window.location.href.replace("http", "ws")); - es.addEventListener("open", () => { - console.log(`[${new Date()}] Connected to statistics stream`); + ws.addEventListener("open", () => { + console.log(`[${new Date().toISOString()}] Connected to statistics socket`); }); - es.addEventListener("message", (e) => { - console.log(`[${new Date()}] Received global count: ${e.data}`); + ws.addEventListener("message", (e) => { + console.log(`[${new Date().toISOString()}] Received global count: ${e.data}`); const data = JSON.parse(e.data); setGlobalCount(BigInt(parseInt(data.globalCount))); }); - // TODO: Reconnect backoff logic could be improved - es.addEventListener("error", () => { + ws.addEventListener("error", () => { console.warn( - `[${new Date()}] Disconnected from statistics stream, attempting to reconnect...`, + `[${new Date().toISOString()}] Disconnected from statistics socket, attempting to reconnect...`, ); const backoff = 1000 + Math.random() * 5000; new Promise((resolve) => setTimeout(resolve, backoff)); - es = new EventSource(window.location.href); - }); + ws = new WebSocket(window.location.href.replace("http", "ws")); + }) }, []); return ( diff --git a/routes/_middleware.ts b/routes/_middleware.ts deleted file mode 100644 index 96fef95..0000000 --- a/routes/_middleware.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { MiddlewareHandlerContext } from "$fresh/server.ts"; - -export async function handler(req: Request, ctx: MiddlewareHandlerContext) { - const origin = req.headers.get("Origin") || "*"; - const resp = await ctx.next(); - const headers = resp.headers; - - headers.set("Access-Control-Allow-Origin", origin); - headers.set("Access-Control-Allow-Credentials", "true"); - headers.set("X-Content-Type-Options", "nosniff"); - headers.set("Cache-Control", "public, max-age=3600"); - headers.set( - "Access-Control-Allow-Headers", - "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, accept, origin, Cache-Control, X-Requested-With", - ); - headers.set( - "Access-Control-Allow-Methods", - "POST, OPTIONS, GET", - ); - - return resp; -} diff --git a/routes/index.tsx b/routes/index.tsx index 1a64d3c..50ab841 100644 --- a/routes/index.tsx +++ b/routes/index.tsx @@ -1,6 +1,5 @@ import { Handlers } from "$fresh/server.ts"; import Counter from "../islands/CounterCard.tsx"; -import { CSS, render } from "$gfm"; import { getGlobalStatistics, setGlobalStatistics } from "../shared/db.ts"; import MarkdownContent from "../islands/MarkdownContent.tsx"; @@ -19,46 +18,47 @@ for (const f of Deno.readDirSync("static/assets/audio/ja/")) { export const handler: Handlers = { GET: async (req, ctx) => { - const accept = req.headers.get("accept"); + let bc = new BroadcastChannel("global-count"); - if (accept?.includes("text/event-stream")) { - const bc = new BroadcastChannel("global-count"); - const body = new ReadableStream({ - start(controller) { - bc.addEventListener("message", async () => { - try { - const data = await getGlobalStatistics(); - const chunk = `data: ${ - JSON.stringify({ globalCount: data }) - }\n\n`; - controller.enqueue(new TextEncoder().encode(chunk)); - } catch (e) { - console.error( - `[${new Date()}] Error while getting global statistics: ${e}`, - ); - } - }); - console.log( - `[${new Date()}] Opened statistics stream for ${ - JSON.stringify(ctx.remoteAddr) - }`, - ); - }, - cancel() { - bc.close(); - console.log( - `[${new Date()}] Closed statistics stream for ${ - JSON.stringify(ctx.remoteAddr) - }`, - ); - }, - }); - return new Response(body, { - headers: { - "Content-Type": "text/event-stream; charset=utf-8", - }, + // check if we're requesting wss:// or ws://, add the response header accordingly + if (req.headers.get("upgrade") === "websocket") { + const { socket, response } = Deno.upgradeWebSocket(req); + + socket.onopen = () => { + bc = new BroadcastChannel("global-count"); + console.log( + `[${new Date().toISOString()}] Connection opened for ${ + JSON.stringify(ctx.remoteAddr) + }`, + ); + }; + + bc.addEventListener("message", (e) => { + console.log(e); + socket.send(JSON.stringify({ globalCount: e.data })); }); + + socket.onclose = () => { + bc.close(); + console.log( + `[${new Date().toISOString()}] Connection closed for ${ + JSON.stringify(ctx.remoteAddr) + }`, + ); + }; + + socket.onerror = (e) => { + bc.close(); + console.error( + `[${new Date().toISOString()}] Connection errored for ${ + JSON.stringify(ctx.remoteAddr) + }: ${e}`, + ); + }; + + return response; } + const data = await getGlobalStatistics(); const res = await ctx.render({ globalCount: data }); return res; @@ -66,9 +66,11 @@ export const handler: Handlers = { POST: async (req, ctx) => { const body = await req.json(); await setGlobalStatistics(body.data); + + const updatedCount = await getGlobalStatistics(); const bc = new BroadcastChannel("global-count"); - bc.postMessage(new TextEncoder().encode(getGlobalStatistics().toString())); + bc.postMessage(updatedCount.toString()); return new Response("", { status: 200, @@ -84,7 +86,10 @@ export default function Home( return (
-
+

Welcome to herta kuru