chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { eventStream } from "remix-utils/sse/server";
|
||||
import { env } from "~/env.server";
|
||||
import { getRequestAbortSignal } from "~/services/httpAsyncStorage.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
|
||||
type SseProps = {
|
||||
request: Request;
|
||||
pingInterval?: number;
|
||||
updateInterval?: number;
|
||||
run: (send: (event: Event) => void, stop: () => void) => void;
|
||||
};
|
||||
|
||||
type Event = {
|
||||
/**
|
||||
* @default "update"
|
||||
*/
|
||||
event?: string;
|
||||
data: string;
|
||||
};
|
||||
|
||||
export function sse({ request, pingInterval = 1000, updateInterval = 348, run }: SseProps) {
|
||||
if (env.DISABLE_SSE === "1" || env.DISABLE_SSE === "true") {
|
||||
return new Response("SSE disabled", { status: 200 });
|
||||
}
|
||||
|
||||
const signal = getRequestAbortSignal();
|
||||
|
||||
let pinger: NodeJS.Timeout | undefined = undefined;
|
||||
let updater: NodeJS.Timeout | undefined = undefined;
|
||||
let timeout: NodeJS.Timeout | undefined = undefined;
|
||||
|
||||
const abort = () => {
|
||||
clearInterval(pinger);
|
||||
clearInterval(updater);
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
|
||||
return eventStream(signal, (send, close) => {
|
||||
const safeSend = (args: { event?: string; data: string }) => {
|
||||
try {
|
||||
send(args);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
if (error.name !== "TypeError") {
|
||||
logger.debug("Error sending SSE, aborting", {
|
||||
error: {
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
},
|
||||
args,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
logger.debug("Unknown error sending SSE, aborting", {
|
||||
error,
|
||||
args,
|
||||
});
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
};
|
||||
|
||||
pinger = setInterval(() => {
|
||||
if (signal.aborted) {
|
||||
return abort();
|
||||
}
|
||||
|
||||
safeSend({ event: "ping", data: new Date().toISOString() });
|
||||
}, pingInterval);
|
||||
|
||||
updater = setInterval(() => {
|
||||
if (signal.aborted) {
|
||||
return abort();
|
||||
}
|
||||
|
||||
run(safeSend, abort);
|
||||
}, updateInterval);
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
close(); // close the connection after 1 minute of inactivity, which will refresh the connection (that's why we aren't using abort)
|
||||
}, 60 * 1000); // 1 minute
|
||||
|
||||
return abort;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user