import { Monitor, Notification } from '@prisma/client'; import { prisma } from '../_client.js'; import { MonitorRunner } from './runner.js'; import { logger } from '../../utils/logger.js'; export type MonitorUpsertData = Pick< Monitor, 'workspaceId' | 'name' | 'type' | 'interval' | 'maxRetries' | 'trendingMode' > & { id?: string; active?: boolean; notificationIds?: string[]; payload: Record; }; type MonitorWithNotification = Monitor & { notifications: Notification[] }; export class MonitorManager { private monitorRunner: Record = {}; private isStarted = false; /** * create or update */ async upsert(data: MonitorUpsertData): Promise { let monitor: MonitorWithNotification; const { id, workspaceId, notificationIds = [], ...others } = data; if (id) { // update monitor = await prisma.monitor.update({ where: { id, workspaceId, }, data: { ...others, notifications: { set: notificationIds.map((id) => ({ id })), }, }, include: { notifications: true, }, }); } else { // create monitor = await prisma.monitor.create({ data: { ...others, workspaceId, notifications: { connect: notificationIds.map((id) => ({ id })), }, }, include: { notifications: true, }, }); } if (this.monitorRunner[monitor.id]) { // Stop and remove old this.monitorRunner[monitor.id].stopMonitor(); delete this.monitorRunner[monitor.id]; } const runner = (this.monitorRunner[monitor.id] = new MonitorRunner( monitor )); runner.startMonitor(); return monitor; } async delete(workspaceId: string, monitorId: string) { const runner = this.getRunner(monitorId); if (!runner) { throw new Error('This monitor not found'); } runner.stopMonitor(); delete this.monitorRunner[monitorId]; return prisma.monitor.delete({ where: { workspaceId, id: monitorId, }, }); } /** * Get and start all monitors */ async startAll() { if (this.isStarted === true) { logger.warn('MonitorManager.startAll should only call once, skipped.'); return; } this.isStarted = true; const monitors = await prisma.monitor.findMany({ where: { active: true, }, include: { notifications: true, }, }); Promise.all( monitors.map(async (m) => { try { const runner = new MonitorRunner(m); this.monitorRunner[m.id] = runner; await runner.startMonitor(); } catch (err) { logger.error('Start monitor error:', String(err)); } }) ).then(() => { logger.info('All monitor has been begin.'); }); } getRunner(monitorId: string): MonitorRunner | undefined { return this.monitorRunner[monitorId]; } createRunner(monitor: MonitorWithNotification) { const runner = (this.monitorRunner[monitor.id] = new MonitorRunner( monitor )); return runner; } }