Initial commit

This commit is contained in:
2025-12-07 14:32:46 +00:00
commit 0a0969b8af
4726 changed files with 536089 additions and 0 deletions

75
utils/pushService.js Normal file
View File

@@ -0,0 +1,75 @@
// utils/pushService.js
const webpush = require('web-push');
const db = require('../db');
const hasVapid =
!!process.env.VAPID_PUBLIC_KEY && !!process.env.VAPID_PRIVATE_KEY;
if (!hasVapid) {
console.warn('[Push] VAPID keys não definidas. Push desativado.');
} else {
webpush.setVapidDetails(
process.env.VAPID_SUBJECT || 'mailto:admin@evstation.local',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY
);
}
// retry simples p/ 429 e 5xx
async function sendWithRetry(subscription, message, tries = 2) {
try {
return await webpush.sendNotification(subscription, message);
} catch (err) {
const code = err?.statusCode;
if ((code === 429 || code >= 500) && tries > 1) {
await new Promise((r) => setTimeout(r, 1000));
return sendWithRetry(subscription, message, tries - 1);
}
throw err;
}
}
async function sendPushToUser(userId, payload) {
if (!hasVapid) return;
const subs = await db('push_subscriptions')
.where({ user_id: userId })
.select('id', 'endpoint', 'p256dh', 'auth');
if (!subs.length) return;
const message = JSON.stringify(payload);
await Promise.allSettled(
subs.map(async (s) => {
const subscription = {
endpoint: s.endpoint,
keys: {
p256dh: s.p256dh,
auth: s.auth,
},
};
try {
await sendWithRetry(subscription, message);
// TTL opcional (default 15min)
// se quiseres usar TTL do payload, descomenta e passa options no sendWithRetry
// await webpush.sendNotification(subscription, message, {
// TTL: payload.ttl ?? 60 * 15,
// });
} catch (err) {
const code = err?.statusCode;
// remove subscriptions mortas
if (code === 404 || code === 410) {
await db('push_subscriptions').where({ id: s.id }).del();
} else {
console.error('[Push] erro ao enviar:', err.message);
}
}
})
);
}
module.exports = { sendPushToUser };