import { Schedule } from "@/app/schedule/types"; function sendMessage( stream: WritableStream, message: string, ) { const writer = stream.getWriter(); writer.ready .then(() => writer.write(message)) .catch(console.error) .finally(() => writer.releaseLock()) ; } let streams = new Set>(); let lastBroadcastData: string | null = null; let lastBroadcastId = 0; export function broadcastUpdate(schedule: Schedule) { const id = Date.now(); const data = JSON.stringify(schedule); lastBroadcastId = id; lastBroadcastData = data; const message = `id: ${id}\nevent: update\ndata: ${data}\n\n` for (const stream of streams) { sendMessage(stream, message); } } setInterval(() => { for (const stream of streams) { sendMessage(stream, "data: keepalive\n\n"); } }, 10e3) export async function GET(request: Request) { const encoder = new TextEncoder(); const source = request.headers.get("x-forwarded-for"); console.log(`starting event stream for ${source}`) const stream = new TransformStream({ transform(chunk, controller) { controller.enqueue(encoder.encode(chunk)); }, flush(controller) { console.log(`finished event stream for ${source}`); streams.delete(stream.writable); }, // @ts-expect-error experimental API cancel(reason) { console.log(`cancelled event stream for ${source}`); streams.delete(stream.writable); } }) streams.add(stream.writable); if (lastBroadcastId) { sendMessage( stream.writable, `id: ${lastBroadcastData}\nevent: update\ndata: ${lastBroadcastData}\n\n` ); } return new Response( stream.readable, { headers: { "Access-Control-Allow-Origin": "*", "Content-Type": "text/event-stream", } } ); }