feat: 添加推送通知功能,支持Web Push订阅和发送

This commit is contained in:
2025-11-28 22:35:45 +08:00
parent a4bb8e984f
commit 35a948c515
13 changed files with 338 additions and 2 deletions
+4
View File
@@ -1,4 +1,5 @@
import { sendMsg } from "./push/qq";
import { sendWebPush } from "./webpush";
export function push(message: string) {
console.log(`[NOTIFICATION] ${new Date().toISOString()}: ${message}`)
@@ -8,5 +9,8 @@ export function push(message: string) {
if (process.env.QQ_BOT_URL && process.env.QQ_BOT_TARGET_ID) {
sendMsg(msg, process.env.QQ_BOT_TARGET_ID, process.env.QQ_BOT_URL);
}
// Send Web Push
sendWebPush(message).catch(err => console.error("Web Push Error:", err));
}
+49
View File
@@ -0,0 +1,49 @@
import webpush from 'web-push';
import { prisma } from '@/lib/prisma';
if (process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY && process.env.VAPID_PRIVATE_KEY) {
webpush.setVapidDetails(
process.env.VAPID_SUBJECT || 'mailto:example@yourdomain.org',
process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY
);
}
export async function sendWebPush(message: string) {
if (!process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
console.warn('VAPID keys not configured, skipping web push');
return;
}
const subscriptions = await prisma.pushSubscription.findMany();
const notificationPayload = JSON.stringify({
title: 'WinUpdate Notification',
body: message,
icon: '/icons/icon-192x192.png', // Assuming you have icons
});
const promises = subscriptions.map((sub) => {
const pushSubscription = {
endpoint: sub.endpoint,
keys: {
p256dh: sub.p256dh,
auth: sub.auth,
},
};
return webpush.sendNotification(pushSubscription, notificationPayload)
.catch((err) => {
if (err.statusCode === 410 || err.statusCode === 404) {
// Subscription has expired or is no longer valid
console.log(`Subscription expired, deleting: ${sub.endpoint}`);
return prisma.pushSubscription.delete({
where: { endpoint: sub.endpoint },
});
}
console.error('Error sending web push:', err);
});
});
await Promise.all(promises);
}