68 lines
1.7 KiB
TypeScript
68 lines
1.7 KiB
TypeScript
import type { LoaderFunctionArgs } from "@remix-run/server-runtime";
|
|
import { z } from "zod";
|
|
import { logger } from "~/services/logger.server";
|
|
import { sse } from "~/utils/sse.server";
|
|
|
|
export async function loader({ request }: LoaderFunctionArgs) {
|
|
const url = new URL(request.url);
|
|
const searchParams = Object.fromEntries(url.searchParams.entries());
|
|
|
|
const options = z
|
|
.object({
|
|
minDelay: z.coerce.number().int(),
|
|
maxDelay: z.coerce.number().int(),
|
|
undefinedProbability: z.coerce.number().min(0).max(1).default(0.1),
|
|
})
|
|
.parse(searchParams);
|
|
|
|
logger.debug("Test SSE stream", { options });
|
|
|
|
let lastSignals = calculateChangeSignals(Date.now());
|
|
|
|
return sse({
|
|
request,
|
|
run: async (send, stop) => {
|
|
const result = await dateForUpdates(options);
|
|
|
|
if (!result) {
|
|
return stop();
|
|
}
|
|
|
|
const newSignals = calculateChangeSignals(result);
|
|
|
|
if (lastSignals.ts !== newSignals.ts) {
|
|
send({ data: JSON.stringify(newSignals) });
|
|
}
|
|
|
|
lastSignals = newSignals;
|
|
},
|
|
});
|
|
}
|
|
|
|
async function dateForUpdates(opts: {
|
|
minDelay: number;
|
|
maxDelay: number;
|
|
undefinedProbability: number;
|
|
}): Promise<number | undefined> {
|
|
// Randomly await between minDelay and maxDelay
|
|
await new Promise((resolve) => {
|
|
setTimeout(resolve, Math.random() * (opts.maxDelay - opts.minDelay) + opts.minDelay);
|
|
});
|
|
|
|
// There should be about a x% chance that this returns undefined
|
|
if (Math.random() < opts.undefinedProbability) {
|
|
logger.debug("Test SSE dataForUpdates returning undefined");
|
|
|
|
return undefined;
|
|
}
|
|
|
|
// Randomly return true or false
|
|
return Date.now();
|
|
}
|
|
|
|
function calculateChangeSignals(ts: number) {
|
|
return {
|
|
ts,
|
|
};
|
|
}
|