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