rename web/ to admin/, along with the web-named build and cli identifiers
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import type { LiveQueryEvent, QueryRow } from "@/lib/types";
|
||||
|
||||
/** A live stream row; `key` is a client-side monotonic counter (SSE frames carry no id). */
|
||||
export interface LiveRow extends LiveQueryEvent {
|
||||
key: number;
|
||||
}
|
||||
|
||||
export const RING_CAPACITY = 500;
|
||||
|
||||
/** Prepend `row` (rows are newest-first) and drop the oldest beyond `capacity`. */
|
||||
export function pushRow(rows: LiveRow[], row: LiveRow, capacity: number = RING_CAPACITY): LiveRow[] {
|
||||
const next = [row, ...rows];
|
||||
return next.length > capacity ? next.slice(0, capacity) : next;
|
||||
}
|
||||
|
||||
// `since` on GET /api/queries is inclusive, so the re-sync fetch returns the
|
||||
// last-seen row(s) again; live rows have no id, so identity is this tuple.
|
||||
function signature(row: LiveQueryEvent): string {
|
||||
return `${row.ts}|${row.domain}|${row.client_ip}|${row.qtype ?? -1}|${row.blocked}|${row.upstream}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge rows fetched for a reconnect gap (newest-first, from GET /api/queries)
|
||||
* into the buffer. Rows already present are skipped; `missed` counts what was
|
||||
* actually added. The result stays newest-first (stable sort by ts) and capped.
|
||||
*/
|
||||
export function mergeGap(
|
||||
rows: LiveRow[],
|
||||
fetched: QueryRow[],
|
||||
nextKey: () => number,
|
||||
capacity: number = RING_CAPACITY,
|
||||
): { rows: LiveRow[]; missed: number } {
|
||||
const seen = new Set(rows.map(signature));
|
||||
const added: LiveRow[] = [];
|
||||
for (const row of fetched) {
|
||||
const event: LiveQueryEvent = {
|
||||
ts: row.ts,
|
||||
domain: row.domain,
|
||||
client_ip: row.client_ip,
|
||||
qtype: row.qtype,
|
||||
blocked: row.blocked,
|
||||
block_reason: row.block_reason,
|
||||
response_time_us: row.response_time_us,
|
||||
cache_hit: row.cache_hit,
|
||||
upstream: row.upstream,
|
||||
};
|
||||
if (seen.has(signature(event))) continue;
|
||||
added.push({ ...event, key: nextKey() });
|
||||
}
|
||||
if (added.length === 0) return { rows, missed: 0 };
|
||||
const merged = [...added, ...rows].sort((a, b) => b.ts - a.ts).slice(0, capacity);
|
||||
return { rows: merged, missed: added.length };
|
||||
}
|
||||
Reference in New Issue
Block a user