summaryrefslogtreecommitdiff
path: root/admin-panel/src/server/ws.ts
blob: c0ffd8e3a21c9b562503fafce117f5207bc0adda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { WebSocketServer, WebSocket } from 'ws';
import type { Server } from 'http';

let wss: WebSocketServer;

interface Subscription {
  ws: WebSocket;
  projects: Set<string>;
}

const subscriptions: Subscription[] = [];

export function setupWebSocket(server: Server): void {
  wss = new WebSocketServer({ server, path: '/ws' });

  wss.on('connection', (ws) => {
    const sub: Subscription = { ws, projects: new Set() };
    subscriptions.push(sub);

    ws.on('message', (data) => {
      try {
        const msg = JSON.parse(data.toString());
        if (msg.type === 'subscribe' && msg.project) {
          sub.projects.add(msg.project);
        } else if (msg.type === 'unsubscribe' && msg.project) {
          sub.projects.delete(msg.project);
        }
      } catch {
        // ignore malformed messages
      }
    });

    ws.on('close', () => {
      const idx = subscriptions.indexOf(sub);
      if (idx !== -1) subscriptions.splice(idx, 1);
    });
  });
}

export function broadcast(project: string, event: Record<string, unknown>): void {
  const payload = JSON.stringify(event);
  for (const sub of subscriptions) {
    if (sub.projects.has(project) && sub.ws.readyState === WebSocket.OPEN) {
      sub.ws.send(payload);
    }
  }
}

export function broadcastAll(event: Record<string, unknown>): void {
  const payload = JSON.stringify(event);
  for (const sub of subscriptions) {
    if (sub.ws.readyState === WebSocket.OPEN) {
      sub.ws.send(payload);
    }
  }
}