feat: decode activity SSE events and expose tracker total
This commit is contained in:
@@ -8,6 +8,12 @@ export function decodeEvent(msg: SseMessage): FeedEvent | null {
|
|||||||
if (!outer.data) return null;
|
if (!outer.data) return null;
|
||||||
const inner = JSON.parse(outer.data) as Record<string, unknown>;
|
const inner = JSON.parse(outer.data) as Record<string, unknown>;
|
||||||
|
|
||||||
|
if (outer.type === "activity") {
|
||||||
|
const id = typeof inner.id === "number" ? inner.id : Number.NaN;
|
||||||
|
if (Number.isFinite(id)) return { type: "activity", id };
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (outer.type === "inflight") {
|
if (outer.type === "inflight") {
|
||||||
const operation = inner.operation as string;
|
const operation = inner.operation as string;
|
||||||
if (operation === "remove") {
|
if (operation === "remove") {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export interface ModelState {
|
|||||||
export type FeedEvent =
|
export type FeedEvent =
|
||||||
| { type: "inflight"; operation: "snapshot" | "add"; requests: InflightRequest[] }
|
| { type: "inflight"; operation: "snapshot" | "add"; requests: InflightRequest[] }
|
||||||
| { type: "inflight"; operation: "remove"; id: string }
|
| { type: "inflight"; operation: "remove"; id: string }
|
||||||
|
| { type: "activity"; id: number }
|
||||||
| { type: "modelStatus"; models: ModelState[] };
|
| { type: "modelStatus"; models: ModelState[] };
|
||||||
|
|
||||||
export type ModelRuntimeState = "stopped" | "loading" | "ready";
|
export type ModelRuntimeState = "stopped" | "loading" | "ready";
|
||||||
@@ -44,6 +45,10 @@ export class InflightTracker {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
total(): number {
|
||||||
|
return this.requests.size;
|
||||||
|
}
|
||||||
|
|
||||||
state(modelId: string): ModelRuntimeState | undefined {
|
state(modelId: string): ModelRuntimeState | undefined {
|
||||||
return this.states.get(modelId);
|
return this.states.get(modelId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,3 +117,12 @@ test("decodeEvent handles inflight with a non-array requests field and no reques
|
|||||||
assert.deepEqual(ev.requests, []);
|
assert.deepEqual(ev.requests, []);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("decodeEvent parses an activity event with an id", () => {
|
||||||
|
const msg: SseMessage = {
|
||||||
|
event: "message",
|
||||||
|
data: JSON.stringify({ type: "activity", data: JSON.stringify({ id: 817 }) }),
|
||||||
|
};
|
||||||
|
const ev = decodeEvent(msg);
|
||||||
|
assert.deepEqual(ev, { type: "activity", id: 817 });
|
||||||
|
});
|
||||||
|
|||||||
@@ -63,3 +63,13 @@ test("modelStatus normalizes states", () => {
|
|||||||
assert.equal(tracker.state("D"), "stopped");
|
assert.equal(tracker.state("D"), "stopped");
|
||||||
assert.equal(tracker.state("missing"), undefined);
|
assert.equal(tracker.state("missing"), undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("total sums in-flight requests across all models", () => {
|
||||||
|
const tracker = new InflightTracker();
|
||||||
|
assert.equal(tracker.total(), 0);
|
||||||
|
tracker.apply({ type: "inflight", operation: "add", requests: [{ model: "A", id: "1" }, { model: "B", id: "2" }] });
|
||||||
|
tracker.apply({ type: "inflight", operation: "add", requests: [{ model: "A", id: "3" }] });
|
||||||
|
assert.equal(tracker.total(), 3);
|
||||||
|
tracker.apply({ type: "inflight", operation: "remove", id: "1" });
|
||||||
|
assert.equal(tracker.total(), 2);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user