59 lines
2.3 KiB
TypeScript
59 lines
2.3 KiB
TypeScript
import { storage } from '../storage';
|
||
import { webPushService } from '../services/web-push.service';
|
||
import { eventBus } from '../routes/shared';
|
||
|
||
const SYNC_PUSH_COOLDOWN_MS = 5 * 60 * 1000; // 5 minutes
|
||
const lastPushByOrganization = new Map<number, number>();
|
||
|
||
/**
|
||
* Sends a silent web-push to subscribed devices in the organization
|
||
* telling them to run an offline sync (delta sync) because task data changed.
|
||
*
|
||
* The push has no visible notification; the Service Worker catches the
|
||
* `SYNC_NEEDED` payload and registers a background sync.
|
||
*
|
||
* Throttled to one push per organization per cooldown window, and skipped
|
||
* for users that currently have an active SSE connection (their open app
|
||
* will sync via SSE immediately).
|
||
*/
|
||
export async function pushSyncNeeded(organizationId: number): Promise<void> {
|
||
try {
|
||
const now = Date.now();
|
||
const lastPush = lastPushByOrganization.get(organizationId);
|
||
if (lastPush != null && now - lastPush < SYNC_PUSH_COOLDOWN_MS) {
|
||
console.log(`[WebPush] pushSyncNeeded skipped for org ${organizationId}: cooldown active`);
|
||
return;
|
||
}
|
||
|
||
const subscriptions = await storage.getWebPushSubscriptionsByOrganization(organizationId);
|
||
if (subscriptions.length === 0) return;
|
||
|
||
let sent = 0;
|
||
let skipped = 0;
|
||
for (const sub of subscriptions) {
|
||
try {
|
||
// Если у пользователя открыто приложение с активным SSE, пуш не нужен —
|
||
// он и так получит task_updated и запустит синхронизацию.
|
||
if (eventBus.isUserConnected(sub.userId, organizationId)) {
|
||
skipped++;
|
||
continue;
|
||
}
|
||
|
||
const subscription = JSON.parse(sub.subscription);
|
||
const success = await webPushService.sendNotification(subscription, {
|
||
type: 'SYNC_NEEDED',
|
||
data: { organizationId },
|
||
});
|
||
if (success) sent++;
|
||
} catch (err) {
|
||
console.error('[WebPush] pushSyncNeeded single subscription error:', err);
|
||
}
|
||
}
|
||
|
||
lastPushByOrganization.set(organizationId, now);
|
||
console.log(`[WebPush] pushSyncNeeded org=${organizationId} sent=${sent} skipped_sse=${skipped}/${subscriptions.length}`);
|
||
} catch (err) {
|
||
console.error('[WebPush] pushSyncNeeded error:', err);
|
||
}
|
||
}
|