Files
electric-cherry/src/lib/server/pipeline/bus.ts
T

90 lines
2.8 KiB
TypeScript

import type { StatusPlayer, GameObservation } from '../../server-observation.js';
import { EventEmitter } from 'node:events';
import type { GameTelemetry } from '../../telemetry.js';
import type { RconEndpoint, RconFailure } from '../integrations/rcon.js';
import type { Health } from '../fleet/health.js';
// One in-process event bus, multiplexed by the SSE endpoints. Kept separate
// from any specific subscriber so push/beta/sweep can emit without pulling
// the whole worker module in.
export interface ServerStatusEntry {
server: string;
containerState?: string | null;
containerCheckedAt?: string | null;
telemetryAfter?: string | null;
rconStatus?: GameObservation;
telemetry?: GameTelemetry;
players: number | null;
map: string | null;
gametype: string | null;
roster: StatusPlayer[] | null;
health: Health;
lastSeenAt: string | null;
lastError: string | null;
endpoint: RconEndpoint | null;
reason: RconFailure | null;
replySnippet: string | null;
activeSince: string | null;
inactiveSince: string | null;
gameStartedAt: string | null;
gameEndedAt: string | null;
}
export type BetaStage =
| 'queued'
| 'observing'
| 'inconclusive'
| 'deploying'
| 'awaiting-empty'
| 'restarting'
| 'awaiting-health'
| 'awaiting-match'
| 'ready'
| 'failed';
export type BetaState = 'running' | 'ready-promote' | 'promoted' | 'rolled-back';
export type PipelineEvent =
| { type: 'server-telemetry'; entries: GameTelemetry[] }
| { type: 'deployment-opened'; deploymentId: string; action: string; servers: string[] }
| { type: 'server-changed'; deploymentId: string; server: string; files: number }
| {
type: 'server-state';
deploymentId: string;
server: string;
state: 'pending' | 'done' | 'failed' | 'held' | 'manual';
players: number | null;
error: string | null;
}
| { type: 'sweep-tick'; frozen: boolean; reason?: string }
| { type: 'server-status'; entries: ServerStatusEntry[] }
| { type: 'beta-opened'; betaId: number; scriptIds: number[]; servers: string[] }
| {
type: 'beta-server-stage';
betaId: number;
server: string;
stage: BetaStage;
error: string | null;
}
| { type: 'beta-state'; betaId: number; state: BetaState };
class Bus extends EventEmitter {
constructor() {
super();
// Deployments and sweep can produce a lot of events during a big push.
this.setMaxListeners(64);
}
}
const bus = new Bus();
export function emit(event: PipelineEvent): void {
bus.emit('event', event);
}
export function subscribe(listener: (event: PipelineEvent) => void): () => void {
bus.on('event', listener);
return () => bus.off('event', listener);
}