story-research-zapwall/lib/swSyncHandler.ts
2026-01-07 01:51:26 +01:00

186 lines
6.2 KiB
TypeScript

/**
* Service Worker sync handler - executes sync operations in main thread
* Listens to requests from Service Worker and executes them
*/
import { platformSyncService } from './platformSync'
import { syncUserContentToCache } from './userContentSync'
import { publishWorker } from './publishWorker'
import { nostrService } from './nostr'
import { swClient } from './swClient'
import type { Event } from 'nostr-tools'
class ServiceWorkerSyncHandler {
private initialized = false
/**
* Initialize the sync handler
* Sets up message listeners from Service Worker
*/
async initialize(): Promise<void> {
if (this.initialized) {
return
}
if (typeof window === 'undefined') {
return
}
try {
await swClient.register()
// Listen for sync requests from Service Worker
swClient.onMessage('SYNC_REQUEST', (data: unknown) => {
void (async (): Promise<void> => {
const syncData = data as { syncType: string; userPubkey?: string }
if (syncData.syncType === 'platform') {
await this.handlePlatformSyncRequest()
} else if (syncData.syncType === 'user' && syncData.userPubkey) {
await this.handleUserSyncRequest(syncData.userPubkey)
}
})()
})
// Listen for publish worker requests
swClient.onMessage('PUBLISH_WORKER_REQUEST', () => {
void (async (): Promise<void> => {
await this.handlePublishWorkerRequest()
})()
})
// Listen for publish requests
swClient.onMessage('PUBLISH_REQUEST', (data: unknown) => {
void (async (): Promise<void> => {
const publishData = data as { event: Event; relays: string[] }
await this.handlePublishRequest(publishData.event, publishData.relays)
})()
})
// Listen for notification detection requests
swClient.onMessage('NOTIFICATION_DETECT_REQUEST', (data: unknown) => {
void (async (): Promise<void> => {
const detectData = data as { userPubkey: string }
await this.handleNotificationDetectRequest(detectData.userPubkey)
})()
})
this.initialized = true
console.warn('[SWSyncHandler] Initialized')
} catch (error) {
console.error('[SWSyncHandler] Initialization failed:', error)
}
}
/**
* Handle platform sync request from Service Worker
*/
private async handlePlatformSyncRequest(): Promise<void> {
try {
console.warn('[SWSyncHandler] Executing platform sync request')
await platformSyncService.startSync()
} catch (error) {
console.error('[SWSyncHandler] Error in platform sync:', error)
}
}
/**
* Handle user sync request from Service Worker
*/
private async handleUserSyncRequest(userPubkey: string): Promise<void> {
try {
console.warn('[SWSyncHandler] Executing user sync request for:', userPubkey)
await syncUserContentToCache(userPubkey)
} catch (error) {
console.error('[SWSyncHandler] Error in user sync:', error)
}
}
/**
* Handle publish worker request from Service Worker
*/
private async handlePublishWorkerRequest(): Promise<void> {
try {
console.warn('[SWSyncHandler] Executing publish worker request')
// Trigger publish worker processing
// The publishWorker will process unpublished objects
await publishWorker['processUnpublished']()
} catch (error) {
console.error('[SWSyncHandler] Error in publish worker:', error)
}
}
/**
* Handle notification detection request from Service Worker
* Le Service Worker détecte les changements indépendamment
* Ce handler exécute la détection dans le thread principal et crée les notifications via writeService
*/
private async handleNotificationDetectRequest(userPubkey: string): Promise<void> {
try {
console.warn('[SWSyncHandler] Executing notification detection request for:', userPubkey)
const { notificationDetector } = await import('./notificationDetector')
const { writeService } = await import('./writeService')
// Scanner IndexedDB pour détecter les nouveaux événements
await notificationDetector.scan()
// Les notifications sont créées via notificationDetector qui utilise notificationService
// qui utilise maintenant writeService pour écrire via Web Worker
} catch (error) {
console.error('[SWSyncHandler] Error in notification detection:', error)
}
}
/**
* Handle publish request from Service Worker
*/
private async handlePublishRequest(event: Event, relays: string[]): Promise<void> {
try {
console.warn('[SWSyncHandler] Executing publish request for event:', event.id)
const pool = nostrService.getPool()
if (!pool) {
throw new Error('Pool not initialized')
}
// Publish to specified relays
const pubs = pool.publish(relays, event)
const results = await Promise.allSettled(pubs)
const { publishLog } = await import('./publishLog')
const successfulRelays: string[] = []
results.forEach((result, index) => {
const relayUrl = relays[index]
if (!relayUrl) {
return
}
if (result.status === 'fulfilled') {
successfulRelays.push(relayUrl)
// Log successful publication
void publishLog.logPublication(event.id, relayUrl, true, undefined)
} else {
const error = result.reason
const errorMessage = error instanceof Error ? error.message : String(error)
console.error(`[SWSyncHandler] Relay ${relayUrl} failed:`, error)
// Log failed publication
void publishLog.logPublication(event.id, relayUrl, false, errorMessage)
}
})
// Update published status in IndexedDB
// Access private method via type assertion
const nostrServiceAny = nostrService as unknown as {
updatePublishedStatus: (eventId: string, published: false | string[]) => Promise<void>
}
await nostrServiceAny.updatePublishedStatus(
event.id,
successfulRelays.length > 0 ? successfulRelays : false
)
} catch (error) {
console.error('[SWSyncHandler] Error in publish request:', error)
}
}
}
export const swSyncHandler = new ServiceWorkerSyncHandler()