Add replay mode for tapes
This commit is contained in:
parent
fd175260c9
commit
a21d513f32
4 changed files with 314 additions and 51 deletions
|
|
@ -14,7 +14,9 @@ import {
|
|||
createClickHouseClient,
|
||||
ensureEquityPrintsTable,
|
||||
ensureOptionPrintsTable,
|
||||
fetchEquityPrintsAfter,
|
||||
fetchRecentEquityPrints,
|
||||
fetchOptionPrintsAfter,
|
||||
fetchRecentOptionPrints
|
||||
} from "@islandflow/storage";
|
||||
import { EquityPrintSchema, OptionPrintSchema } from "@islandflow/types";
|
||||
|
|
@ -34,6 +36,11 @@ const envSchema = z.object({
|
|||
const env = readEnv(envSchema);
|
||||
|
||||
const limitSchema = z.coerce.number().int().positive().max(1000);
|
||||
const replayParamsSchema = z.object({
|
||||
after_ts: z.coerce.number().int().nonnegative().default(0),
|
||||
after_seq: z.coerce.number().int().nonnegative().default(0),
|
||||
limit: z.coerce.number().int().positive().max(1000).default(200)
|
||||
});
|
||||
|
||||
type Channel = "options" | "equities";
|
||||
|
||||
|
|
@ -61,6 +68,20 @@ const parseLimit = (value: string | null): number => {
|
|||
return limitSchema.parse(value);
|
||||
};
|
||||
|
||||
const parseReplayParams = (url: URL): { afterTs: number; afterSeq: number; limit: number } => {
|
||||
const params = replayParamsSchema.parse({
|
||||
after_ts: url.searchParams.get("after_ts") ?? undefined,
|
||||
after_seq: url.searchParams.get("after_seq") ?? undefined,
|
||||
limit: url.searchParams.get("limit") ?? undefined
|
||||
});
|
||||
|
||||
return {
|
||||
afterTs: params.after_ts,
|
||||
afterSeq: params.after_seq,
|
||||
limit: params.limit
|
||||
};
|
||||
};
|
||||
|
||||
const broadcast = (sockets: Set<WebSocket<WsData>>, payload: unknown): void => {
|
||||
const message = JSON.stringify(payload);
|
||||
|
||||
|
|
@ -187,6 +208,22 @@ const run = async () => {
|
|||
return jsonResponse({ data });
|
||||
}
|
||||
|
||||
if (req.method === "GET" && url.pathname === "/replay/options") {
|
||||
const { afterTs, afterSeq, limit } = parseReplayParams(url);
|
||||
const data = await fetchOptionPrintsAfter(clickhouse, afterTs, afterSeq, limit);
|
||||
const last = data.at(-1);
|
||||
const next = last ? { ts: last.ts, seq: last.seq } : null;
|
||||
return jsonResponse({ data, next });
|
||||
}
|
||||
|
||||
if (req.method === "GET" && url.pathname === "/replay/equities") {
|
||||
const { afterTs, afterSeq, limit } = parseReplayParams(url);
|
||||
const data = await fetchEquityPrintsAfter(clickhouse, afterTs, afterSeq, limit);
|
||||
const last = data.at(-1);
|
||||
const next = last ? { ts: last.ts, seq: last.seq } : null;
|
||||
return jsonResponse({ data, next });
|
||||
}
|
||||
|
||||
if (req.method === "GET" && url.pathname === "/ws/options") {
|
||||
if (serverRef.upgrade(req, { data: { channel: "options" } })) {
|
||||
return new Response(null, { status: 101 });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue