blob: 6c178f0e8fb08635ea545de4421ddf6943341260 [file] [log] [blame]
gioa1efbad2025-05-21 07:16:45 +00001import { z } from "zod";
2
3export const WorkerSchema = z.object({
4 id: z.string(),
5 service: z.string(),
6 address: z.string().url(),
7 status: z.optional(
8 z.object({
9 repoOK: z.boolean(),
10 commit: z.string(),
11 commands: z.optional(
12 z.array(
13 z.object({
14 command: z.string(),
15 state: z.string(),
16 }),
17 ),
18 ),
19 }),
20 ),
21 logs: z.optional(z.string()),
22});
23
24export type Worker = z.infer<typeof WorkerSchema>;
25
26class ServiceMonitor {
27 private workers: Map<string, string> = new Map();
28 private logs: Map<string, string> = new Map();
29 private statuses: Map<string, Worker["status"]> = new Map();
30
31 constructor(public readonly serviceName: string) {}
32
33 registerWorker(workerId: string, workerAddress: string, workerLog?: string, workerStatus?: Worker["status"]): void {
34 this.workers.set(workerId, workerAddress);
35 if (workerLog) {
36 this.logs.set(workerId, workerLog);
37 }
38 if (workerStatus) {
39 this.statuses.set(workerId, workerStatus);
40 }
41 }
42
43 getWorkerAddress(workerId: string): string | undefined {
44 return this.workers.get(workerId);
45 }
46
47 getWorkerLog(workerId: string): string | undefined {
48 return this.logs.get(workerId);
49 }
50
51 getWorkerStatus(workerId: string): Worker["status"] | undefined {
52 return this.statuses.get(workerId);
53 }
54
55 getAllLogs(): Map<string, string> {
56 return new Map(this.logs);
57 }
58
59 getAllStatuses(): Map<string, Worker["status"]> {
60 return new Map(this.statuses);
61 }
62
63 getWorkerAddresses(): string[] {
64 return Array.from(this.workers.values());
65 }
66
67 getWorkerIds(): string[] {
68 return Array.from(this.workers.keys());
69 }
70
71 hasLogs(): boolean {
72 return this.logs.size > 0;
73 }
74}
75
76export class ProjectMonitor {
77 private serviceMonitors: Map<string, ServiceMonitor> = new Map();
78
79 constructor() {}
80
81 registerWorker(workerData: Worker): void {
82 let serviceMonitor = this.serviceMonitors.get(workerData.service);
83 if (!serviceMonitor) {
84 serviceMonitor = new ServiceMonitor(workerData.service);
85 this.serviceMonitors.set(workerData.service, serviceMonitor);
86 }
87 serviceMonitor.registerWorker(workerData.id, workerData.address, workerData.logs, workerData.status);
88 }
89
90 getWorkerAddresses(): string[] {
91 let allAddresses: string[] = [];
92 for (const serviceMonitor of this.serviceMonitors.values()) {
93 allAddresses = allAddresses.concat(serviceMonitor.getWorkerAddresses());
94 }
95 return Array.from(new Set(allAddresses));
96 }
97
98 getWorkerLog(serviceName: string, workerId: string): string | undefined {
99 const serviceMonitor = this.serviceMonitors.get(serviceName);
100 if (serviceMonitor) {
101 return serviceMonitor.getWorkerLog(workerId);
102 }
103 return undefined;
104 }
105
106 getAllServiceNames(): string[] {
107 return Array.from(this.serviceMonitors.keys());
108 }
109
110 hasLogs(): boolean {
111 for (const serviceMonitor of this.serviceMonitors.values()) {
112 if (serviceMonitor.hasLogs()) {
113 return true;
114 }
115 }
116 return false;
117 }
118
119 getServiceMonitor(serviceName: string): ServiceMonitor | undefined {
120 return this.serviceMonitors.get(serviceName);
121 }
122
123 getWorkerStatusesForService(serviceName: string): Map<string, Worker["status"]> {
124 const serviceMonitor = this.serviceMonitors.get(serviceName);
125 if (serviceMonitor) {
126 return serviceMonitor.getAllStatuses();
127 }
128 return new Map();
129 }
130}