feat: add monitor event send notification
This commit is contained in:
parent
af49417899
commit
0346dc21d9
@ -14,7 +14,7 @@ import { useCurrentWorkspaceId } from '../../store/user';
|
|||||||
export const NotificationList: React.FC = React.memo(() => {
|
export const NotificationList: React.FC = React.memo(() => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const currentWorkspaceId = useCurrentWorkspaceId();
|
const currentWorkspaceId = useCurrentWorkspaceId();
|
||||||
const { data: list = [], refetch } = trpc.notification.getAll.useQuery({
|
const { data: list = [], refetch } = trpc.notification.all.useQuery({
|
||||||
workspaceId: currentWorkspaceId!,
|
workspaceId: currentWorkspaceId!,
|
||||||
});
|
});
|
||||||
const [editingFormData, setEditingFormData] = useState<
|
const [editingFormData, setEditingFormData] = useState<
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import { Monitor } from '@prisma/client';
|
import { Monitor, Notification } from '@prisma/client';
|
||||||
import { createSubscribeInitializer, subscribeEventBus } from '../../ws/shared';
|
import { subscribeEventBus } from '../../ws/shared';
|
||||||
import { prisma } from '../_client';
|
import { prisma } from '../_client';
|
||||||
import { monitorProviders } from './provider';
|
import { monitorProviders } from './provider';
|
||||||
|
import { sendNotification } from '../notification';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
export type MonitorUpsertData = Pick<
|
export type MonitorUpsertData = Pick<
|
||||||
Monitor,
|
Monitor,
|
||||||
'workspaceId' | 'name' | 'type' | 'interval'
|
'workspaceId' | 'name' | 'type' | 'interval'
|
||||||
> & { id?: string; active?: boolean; payload: Record<string, any> };
|
> & { id?: string; active?: boolean; payload: Record<string, any> };
|
||||||
|
|
||||||
|
type MonitorWithNotification = Monitor & { notifications: Notification[] };
|
||||||
|
|
||||||
class MonitorManager {
|
class MonitorManager {
|
||||||
private monitorRunner: Record<string, MonitorRunner> = {};
|
private monitorRunner: Record<string, MonitorRunner> = {};
|
||||||
private isStarted = false;
|
private isStarted = false;
|
||||||
@ -15,8 +19,8 @@ class MonitorManager {
|
|||||||
/**
|
/**
|
||||||
* create or update
|
* create or update
|
||||||
*/
|
*/
|
||||||
async upsert(data: MonitorUpsertData): Promise<Monitor> {
|
async upsert(data: MonitorUpsertData): Promise<MonitorWithNotification> {
|
||||||
let monitor: Monitor;
|
let monitor: MonitorWithNotification;
|
||||||
if (data.id) {
|
if (data.id) {
|
||||||
// update
|
// update
|
||||||
monitor = await prisma.monitor.update({
|
monitor = await prisma.monitor.update({
|
||||||
@ -24,6 +28,9 @@ class MonitorManager {
|
|||||||
id: data.id,
|
id: data.id,
|
||||||
},
|
},
|
||||||
data: { ...data },
|
data: { ...data },
|
||||||
|
include: {
|
||||||
|
notifications: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return monitor;
|
return monitor;
|
||||||
@ -31,6 +38,9 @@ class MonitorManager {
|
|||||||
// create
|
// create
|
||||||
monitor = await prisma.monitor.create({
|
monitor = await prisma.monitor.create({
|
||||||
data: { ...data },
|
data: { ...data },
|
||||||
|
include: {
|
||||||
|
notifications: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +73,9 @@ class MonitorManager {
|
|||||||
where: {
|
where: {
|
||||||
active: true,
|
active: true,
|
||||||
},
|
},
|
||||||
|
include: {
|
||||||
|
notifications: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all(
|
Promise.all(
|
||||||
@ -88,7 +101,7 @@ class MonitorRunner {
|
|||||||
isStopped = false;
|
isStopped = false;
|
||||||
timer: NodeJS.Timeout | null = null;
|
timer: NodeJS.Timeout | null = null;
|
||||||
|
|
||||||
constructor(public monitor: Monitor) {}
|
constructor(public monitor: Monitor & { notifications: Notification[] }) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start single monitor
|
* Start single monitor
|
||||||
@ -114,7 +127,7 @@ class MonitorRunner {
|
|||||||
}, interval * 1000);
|
}, interval * 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function run() {
|
const run = async () => {
|
||||||
let value = 0;
|
let value = 0;
|
||||||
try {
|
try {
|
||||||
value = await provider.run(monitor);
|
value = await provider.run(monitor);
|
||||||
@ -132,6 +145,12 @@ class MonitorRunner {
|
|||||||
type: 'DOWN',
|
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') {
|
} else if (value > 0 && currentStatus === 'DOWN') {
|
||||||
await prisma.monitorEvent.create({
|
await prisma.monitorEvent.create({
|
||||||
data: {
|
data: {
|
||||||
@ -140,6 +159,12 @@ class MonitorRunner {
|
|||||||
type: 'UP',
|
type: 'UP',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
await this.notify(
|
||||||
|
`[${monitor.name}] ✅ Up`,
|
||||||
|
`[${monitor.name}] ✅ Up\nTime: ${dayjs().format(
|
||||||
|
'YYYY-MM-DD HH:mm:ss'
|
||||||
|
)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert into data
|
// insert into data
|
||||||
@ -154,7 +179,7 @@ class MonitorRunner {
|
|||||||
|
|
||||||
// Run next loop
|
// Run next loop
|
||||||
nextAction();
|
nextAction();
|
||||||
}
|
};
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
|
||||||
@ -177,6 +202,17 @@ class MonitorRunner {
|
|||||||
this.stopMonitor();
|
this.stopMonitor();
|
||||||
this.startMonitor();
|
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();
|
export const monitorManager = new MonitorManager();
|
||||||
|
@ -3,6 +3,7 @@ import { notificationProviders } from './provider';
|
|||||||
|
|
||||||
export async function sendNotification(
|
export async function sendNotification(
|
||||||
notification: Pick<Notification, 'name' | 'type' | 'payload'>,
|
notification: Pick<Notification, 'name' | 'type' | 'payload'>,
|
||||||
|
title: string,
|
||||||
message: string
|
message: string
|
||||||
) {
|
) {
|
||||||
const type = notification.type;
|
const type = notification.type;
|
||||||
@ -11,5 +12,5 @@ export async function sendNotification(
|
|||||||
throw new Error('Not match type:' + type);
|
throw new Error('Not match type:' + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
await notificationProviders[type].send(notification, message);
|
await notificationProviders[type].send(notification, title, message);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ interface SMTPPayload {
|
|||||||
|
|
||||||
// Fork from https://github.com/louislam/uptime-kuma/blob/HEAD/server/notification-providers/smtp.js
|
// Fork from https://github.com/louislam/uptime-kuma/blob/HEAD/server/notification-providers/smtp.js
|
||||||
export const smtp: NotificationProvider = {
|
export const smtp: NotificationProvider = {
|
||||||
send: async (notification, message) => {
|
send: async (notification, title, message) => {
|
||||||
const payload = notification.payload as unknown as SMTPPayload;
|
const payload = notification.payload as unknown as SMTPPayload;
|
||||||
|
|
||||||
const config: SMTPTransport.Options = {
|
const config: SMTPTransport.Options = {
|
||||||
@ -34,7 +34,7 @@ export const smtp: NotificationProvider = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const subject = message;
|
const subject = title;
|
||||||
const bodyTextContent = message;
|
const bodyTextContent = message;
|
||||||
|
|
||||||
const transporter = nodemailer.createTransport(config);
|
const transporter = nodemailer.createTransport(config);
|
||||||
|
@ -3,6 +3,7 @@ import { Notification } from '@prisma/client';
|
|||||||
export interface NotificationProvider {
|
export interface NotificationProvider {
|
||||||
send: (
|
send: (
|
||||||
notification: Pick<Notification, 'name' | 'type' | 'payload'>,
|
notification: Pick<Notification, 'name' | 'type' | 'payload'>,
|
||||||
|
title: string,
|
||||||
message: string
|
message: string
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { prisma } from '../../model/_client';
|
|||||||
import { sendNotification } from '../../model/notification';
|
import { sendNotification } from '../../model/notification';
|
||||||
|
|
||||||
export const notificationRouter = router({
|
export const notificationRouter = router({
|
||||||
getAll: workspaceProcedure.query(({ input }) => {
|
all: workspaceProcedure.query(({ input }) => {
|
||||||
const workspaceId = input.workspaceId;
|
const workspaceId = input.workspaceId;
|
||||||
|
|
||||||
return prisma.notification.findMany({
|
return prisma.notification.findMany({
|
||||||
@ -23,7 +23,11 @@ export const notificationRouter = router({
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
.mutation(async ({ input }) => {
|
.mutation(async ({ input }) => {
|
||||||
await sendNotification(input, `${input.name} + Notification Testing`);
|
await sendNotification(
|
||||||
|
input,
|
||||||
|
`${input.name} Notification Testing`,
|
||||||
|
`This is Notification Testing`
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
upsert: workspaceOwnerProcedure
|
upsert: workspaceOwnerProcedure
|
||||||
.input(
|
.input(
|
||||||
|
Loading…
Reference in New Issue
Block a user