- Added telemetry utility to capture application events and metrics. - Integrated PostHog for event tracking with distinct user identification. - Implemented telemetry initialization, event capturing, and shutdown procedures. feat: add UV environment setup for Python management - Created utilities to manage Python installation and configuration. - Implemented network optimization checks for Python installation mirrors. - Added functions to set up managed Python environments with error handling. feat: enhance host API communication with token management - Introduced host API token retrieval and management for secure requests. - Updated host API fetch functions to include token in headers. - Added support for creating event sources with authentication. test: add comprehensive tests for gateway protocol and startup helpers - Implemented unit tests for gateway protocol helpers, event dispatching, and state management. - Added tests for startup recovery strategies and process policies. - Ensured coverage for connection monitoring and restart governance logic.
65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
import type { ServerResponse } from 'node:http';
|
|
|
|
type EventPayload = unknown;
|
|
|
|
type EventListener = (payload: EventPayload) => void;
|
|
|
|
export class HostEventBus {
|
|
private readonly listeners = new Map<string, Set<EventListener>>();
|
|
private readonly sseClients = new Set<ServerResponse>();
|
|
|
|
on(eventName: string, listener: EventListener): () => void {
|
|
const bucket = this.listeners.get(eventName) ?? new Set<EventListener>();
|
|
bucket.add(listener);
|
|
this.listeners.set(eventName, bucket);
|
|
|
|
return () => {
|
|
bucket.delete(listener);
|
|
if (bucket.size === 0) {
|
|
this.listeners.delete(eventName);
|
|
}
|
|
};
|
|
}
|
|
|
|
addSseClient(res: ServerResponse): void {
|
|
this.sseClients.add(res);
|
|
res.on('close', () => {
|
|
this.sseClients.delete(res);
|
|
});
|
|
}
|
|
|
|
emit(eventName: string, payload: EventPayload): void {
|
|
const bucket = this.listeners.get(eventName);
|
|
if (bucket) {
|
|
for (const listener of bucket) {
|
|
listener(payload);
|
|
}
|
|
}
|
|
|
|
if (this.sseClients.size > 0) {
|
|
const message = `event: ${eventName}\ndata: ${JSON.stringify(payload)}\n\n`;
|
|
for (const client of this.sseClients) {
|
|
try {
|
|
client.write(message);
|
|
} catch {
|
|
this.sseClients.delete(client);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
closeAll(): void {
|
|
this.listeners.clear();
|
|
for (const client of this.sseClients) {
|
|
try {
|
|
client.end();
|
|
} catch {
|
|
// Ignore individual client close failures.
|
|
}
|
|
}
|
|
this.sseClients.clear();
|
|
}
|
|
}
|
|
|
|
export const hostEventBus = new HostEventBus();
|