feat: add monitor event send notification

This commit is contained in:
moonrailgun 2023-10-20 00:28:46 +08:00
parent af49417899
commit 0346dc21d9
6 changed files with 55 additions and 13 deletions

View File

@ -14,7 +14,7 @@ import { useCurrentWorkspaceId } from '../../store/user';
export const NotificationList: React.FC = React.memo(() => {
const [open, setOpen] = useState(false);
const currentWorkspaceId = useCurrentWorkspaceId();
const { data: list = [], refetch } = trpc.notification.getAll.useQuery({
const { data: list = [], refetch } = trpc.notification.all.useQuery({
workspaceId: currentWorkspaceId!,
});
const [editingFormData, setEditingFormData] = useState<

View File

@ -1,13 +1,17 @@
import { Monitor } from '@prisma/client';
import { createSubscribeInitializer, subscribeEventBus } from '../../ws/shared';
import { Monitor, Notification } from '@prisma/client';
import { subscribeEventBus } from '../../ws/shared';
import { prisma } from '../_client';
import { monitorProviders } from './provider';
import { sendNotification } from '../notification';
import dayjs from 'dayjs';
export type MonitorUpsertData = Pick<
Monitor,
'workspaceId' | 'name' | 'type' | 'interval'
> & { id?: string; active?: boolean; payload: Record<string, any> };
type MonitorWithNotification = Monitor & { notifications: Notification[] };
class MonitorManager {
private monitorRunner: Record<string, MonitorRunner> = {};
private isStarted = false;
@ -15,8 +19,8 @@ class MonitorManager {
/**
* create or update
*/
async upsert(data: MonitorUpsertData): Promise<Monitor> {
let monitor: Monitor;
async upsert(data: MonitorUpsertData): Promise<MonitorWithNotification> {
let monitor: MonitorWithNotification;
if (data.id) {
// update
monitor = await prisma.monitor.update({
@ -24,6 +28,9 @@ class MonitorManager {
id: data.id,
},
data: { ...data },
include: {
notifications: true,
},
});
return monitor;
@ -31,6 +38,9 @@ class MonitorManager {
// create
monitor = await prisma.monitor.create({
data: { ...data },
include: {
notifications: true,
},
});
}
@ -63,6 +73,9 @@ class MonitorManager {
where: {
active: true,
},
include: {
notifications: true,
},
});
Promise.all(
@ -88,7 +101,7 @@ class MonitorRunner {
isStopped = false;
timer: NodeJS.Timeout | null = null;
constructor(public monitor: Monitor) {}
constructor(public monitor: Monitor & { notifications: Notification[] }) {}
/**
* Start single monitor
@ -114,7 +127,7 @@ class MonitorRunner {
}, interval * 1000);
};
async function run() {
const run = async () => {
let value = 0;
try {
value = await provider.run(monitor);
@ -132,6 +145,12 @@ class MonitorRunner {
type: 'DOWN',
},
});
await this.notify(
`[${monitor.name}] 🔴 Down`,
`[${monitor.name}] 🔴 Down\nTime: ${dayjs().format(
'YYYY-MM-DD HH:mm:ss'
)}`
);
} else if (value > 0 && currentStatus === 'DOWN') {
await prisma.monitorEvent.create({
data: {
@ -140,6 +159,12 @@ class MonitorRunner {
type: 'UP',
},
});
await this.notify(
`[${monitor.name}] ✅ Up`,
`[${monitor.name}] ✅ Up\nTime: ${dayjs().format(
'YYYY-MM-DD HH:mm:ss'
)}`
);
}
// insert into data
@ -154,7 +179,7 @@ class MonitorRunner {
// Run next loop
nextAction();
}
};
run();
@ -177,6 +202,17 @@ class MonitorRunner {
this.stopMonitor();
this.startMonitor();
}
async notify(title: string, message: string) {
const notifications = this.monitor.notifications;
await Promise.all(
notifications.map((n) =>
sendNotification(n, title, message).catch((err) => {
console.error(err);
})
)
);
}
}
export const monitorManager = new MonitorManager();

View File

@ -3,6 +3,7 @@ import { notificationProviders } from './provider';
export async function sendNotification(
notification: Pick<Notification, 'name' | 'type' | 'payload'>,
title: string,
message: string
) {
const type = notification.type;
@ -11,5 +12,5 @@ export async function sendNotification(
throw new Error('Not match type:' + type);
}
await notificationProviders[type].send(notification, message);
await notificationProviders[type].send(notification, title, message);
}

View File

@ -17,7 +17,7 @@ interface SMTPPayload {
// Fork from https://github.com/louislam/uptime-kuma/blob/HEAD/server/notification-providers/smtp.js
export const smtp: NotificationProvider = {
send: async (notification, message) => {
send: async (notification, title, message) => {
const payload = notification.payload as unknown as SMTPPayload;
const config: SMTPTransport.Options = {
@ -34,7 +34,7 @@ export const smtp: NotificationProvider = {
};
}
const subject = message;
const subject = title;
const bodyTextContent = message;
const transporter = nodemailer.createTransport(config);

View File

@ -3,6 +3,7 @@ import { Notification } from '@prisma/client';
export interface NotificationProvider {
send: (
notification: Pick<Notification, 'name' | 'type' | 'payload'>,
title: string,
message: string
) => Promise<void>;
}

View File

@ -4,7 +4,7 @@ import { prisma } from '../../model/_client';
import { sendNotification } from '../../model/notification';
export const notificationRouter = router({
getAll: workspaceProcedure.query(({ input }) => {
all: workspaceProcedure.query(({ input }) => {
const workspaceId = input.workspaceId;
return prisma.notification.findMany({
@ -23,7 +23,11 @@ export const notificationRouter = router({
})
)
.mutation(async ({ input }) => {
await sendNotification(input, `${input.name} + Notification Testing`);
await sendNotification(
input,
`${input.name} Notification Testing`,
`This is Notification Testing`
);
}),
upsert: workspaceOwnerProcedure
.input(