59 lines
1.4 KiB
TypeScript
59 lines
1.4 KiB
TypeScript
import type { LoaderFunction } from "@remix-run/node";
|
|
|
|
import { events } from "~/utils/events.server";
|
|
import type { NotificationPayload } from "~/utils/web-push.server";
|
|
|
|
export let loader: LoaderFunction = ({ request }) => {
|
|
if (!request.signal) {
|
|
return new Response(null, { status: 500 });
|
|
}
|
|
|
|
return new Response(
|
|
new ReadableStream({
|
|
start(controller) {
|
|
const encoder = new TextEncoder();
|
|
let keepAliveTimeout = setTimeout(keepAlive, 30 * 1000);
|
|
let closed = false;
|
|
|
|
events.addListener("notification", onNotification);
|
|
request.signal.addEventListener("abort", close);
|
|
if (request.signal.aborted) {
|
|
close();
|
|
return;
|
|
}
|
|
|
|
function onNotification(notification: NotificationPayload) {
|
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(notification)}\n\n`));
|
|
}
|
|
|
|
function keepAlive() {
|
|
if (closed) {
|
|
return;
|
|
}
|
|
|
|
controller.enqueue(encoder.encode(":\n\n"));
|
|
keepAliveTimeout = setTimeout(keepAlive, 30 * 1000);
|
|
}
|
|
|
|
function close() {
|
|
if (closed) {
|
|
return;
|
|
}
|
|
|
|
closed = true;
|
|
clearTimeout(keepAliveTimeout);
|
|
events.removeListener("notification", onNotification);
|
|
request.signal.removeEventListener("abort", close);
|
|
controller.close();
|
|
}
|
|
},
|
|
}),
|
|
{
|
|
headers: {
|
|
"Content-Type": "text/event-stream",
|
|
"Cache-Control": "no-cache",
|
|
},
|
|
},
|
|
);
|
|
};
|