66 lines
2.0 KiB
TypeScript
66 lines
2.0 KiB
TypeScript
export interface PocketBaseSseFrame {
|
|
event: string;
|
|
id?: string;
|
|
data: string;
|
|
}
|
|
|
|
export const createRealtimeMetricsTopic = (systemId: string) =>
|
|
`rt_metrics?options=${encodeURIComponent(JSON.stringify({ query: { system: systemId } }))}`;
|
|
|
|
export class PocketBaseSseParser {
|
|
private buffer = "";
|
|
private event = "message";
|
|
private id: string | undefined;
|
|
private dataLines: string[] = [];
|
|
|
|
public push(chunk: string): PocketBaseSseFrame[] {
|
|
this.buffer += chunk;
|
|
const frames: PocketBaseSseFrame[] = [];
|
|
const lines = this.buffer.split(/\r?\n/);
|
|
this.buffer = lines.pop() ?? "";
|
|
|
|
for (const line of lines) {
|
|
const frame = this.processLine(line);
|
|
if (frame) frames.push(frame);
|
|
}
|
|
|
|
return frames;
|
|
}
|
|
|
|
public finish(): PocketBaseSseFrame[] {
|
|
const frames: PocketBaseSseFrame[] = [];
|
|
if (this.buffer !== "") {
|
|
const frame = this.processLine(this.buffer);
|
|
if (frame) frames.push(frame);
|
|
this.buffer = "";
|
|
}
|
|
const trailingFrame = this.dispatch();
|
|
if (trailingFrame) frames.push(trailingFrame);
|
|
return frames;
|
|
}
|
|
|
|
private processLine(line: string): PocketBaseSseFrame | null {
|
|
if (line === "") return this.dispatch();
|
|
if (line.startsWith(":")) return null;
|
|
|
|
const colonIndex = line.indexOf(":");
|
|
const field = colonIndex === -1 ? line : line.slice(0, colonIndex);
|
|
let value = colonIndex === -1 ? "" : line.slice(colonIndex + 1);
|
|
if (value.startsWith(" ")) value = value.slice(1);
|
|
|
|
if (field === "event") this.event = value;
|
|
else if (field === "id") this.id = value;
|
|
else if (field === "data") this.dataLines.push(value);
|
|
return null;
|
|
}
|
|
|
|
private dispatch(): PocketBaseSseFrame | null {
|
|
if (this.dataLines.length === 0 && this.event === "message" && this.id === undefined) return null;
|
|
const frame = { event: this.event, id: this.id, data: this.dataLines.join("\n") };
|
|
this.event = "message";
|
|
this.id = undefined;
|
|
this.dataLines = [];
|
|
return frame;
|
|
}
|
|
}
|