MCPcopy
hub / github.com/cpaczek/skylight / WsUpstream

Class WsUpstream

tracker/src/upstream.ts:33–122  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

31}
32
33export class WsUpstream implements Upstream {
34 private ws: WebSocket | null = null;
35 private connected = false;
36 private closed = false;
37 private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
38 private config: Config = DEFAULT_CONFIG;
39 private aircraft = new Map<string, Aircraft>();
40
41 constructor(
42 private url: string,
43 private events: UpstreamEvents = {},
44 ) {}
45
46 start(): void {
47 this.closed = false;
48 this.open();
49 }
50
51 stop(): void {
52 this.closed = true;
53 if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
54 this.ws?.close();
55 }
56
57 isConnected(): boolean {
58 return this.connected;
59 }
60 getConfig(): Config {
61 return this.config;
62 }
63 getAircraft(): Aircraft[] {
64 return [...this.aircraft.values()];
65 }
66 find(hex: string): Aircraft | undefined {
67 return this.aircraft.get(hex);
68 }
69
70 patchConfig(patch: Partial<Config>): void {
71 const msg: ClientMessage = { type: "patchConfig", patch };
72 if (this.ws?.readyState === WebSocket.OPEN) {
73 this.ws.send(JSON.stringify(msg));
74 }
75 // Optimistic local merge so the tracker reacts immediately.
76 this.config = mergeConfig(this.config, patch);
77 this.events.onConfig?.(this.config);
78 }
79
80 private open(): void {
81 const ws = new WebSocket(this.url);
82 this.ws = ws;
83 ws.on("open", () => {
84 this.connected = true;
85 ws.send(JSON.stringify({ type: "hello", role: "control" } satisfies ClientMessage));
86 });
87 ws.on("close", () => {
88 this.connected = false;
89 this.scheduleReconnect();
90 });

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected