145 lines
4.5 KiB
TypeScript
145 lines
4.5 KiB
TypeScript
/**
|
|
* Write orchestrator service - manages writes/updates to WebSockets/API and to write Web Worker
|
|
* Orchestrates communication between interface, network (Nostr/WebSockets) and write Web Worker
|
|
*/
|
|
|
|
import { websocketService } from './websocketService'
|
|
import { writeService } from './writeService'
|
|
import type { EventTemplate } from 'nostr-tools'
|
|
import { finalizeEvent } from 'nostr-tools'
|
|
import { hexToBytes } from 'nostr-tools/utils'
|
|
import type { ObjectType } from './objectCache'
|
|
import type { NostrEvent } from 'nostr-tools'
|
|
|
|
interface WriteObjectParams {
|
|
objectType: ObjectType
|
|
hash: string
|
|
event: NostrEvent
|
|
parsed: unknown
|
|
version: number
|
|
hidden: boolean
|
|
index?: number
|
|
published?: false | string[]
|
|
}
|
|
|
|
class WriteOrchestrator {
|
|
private privateKey: string | null = null
|
|
|
|
/**
|
|
* Set private key for signing events
|
|
*/
|
|
setPrivateKey(privateKey: string): void {
|
|
this.privateKey = privateKey
|
|
}
|
|
|
|
/**
|
|
* Write object to IndexedDB and publish to network
|
|
* Orchestrates: WebSockets → Web Worker → IndexedDB
|
|
* Écriture en parallèle réseau et local indépendamment
|
|
* Si réseau échoue mais écriture locale réussit, rien (un autre service worker réessaiera)
|
|
*/
|
|
async writeAndPublish(
|
|
params: WriteObjectParams,
|
|
relays: string[]
|
|
): Promise<{ success: boolean; eventId: string; published: false | string[] }> {
|
|
const { objectType, hash, event, parsed, version, hidden, index } = params
|
|
|
|
// Écriture en parallèle : réseau et local indépendamment
|
|
const [networkResult, localResult] = await Promise.allSettled([
|
|
// 1. Publish to network via WebSocket service (en parallèle)
|
|
websocketService.publishEvent(event, relays).then((statuses) => {
|
|
return statuses
|
|
.map((status, statusIndex) => (status.success ? relays[statusIndex] : null))
|
|
.filter((relay): relay is string => relay !== null)
|
|
}),
|
|
// 2. Write to IndexedDB via Web Worker (en parallèle, avec published: false initialement)
|
|
writeService.writeObject(objectType, hash, event, parsed, version, hidden, index, false),
|
|
])
|
|
|
|
// Traiter le résultat réseau
|
|
let publishedRelays: string[] = []
|
|
if (networkResult.status === 'fulfilled') {
|
|
publishedRelays = networkResult.value
|
|
} else {
|
|
// Si réseau échoue, rien : un autre service worker réessaiera
|
|
console.warn('[WriteOrchestrator] Network publish failed, will retry later:', networkResult.reason)
|
|
}
|
|
|
|
// Traiter le résultat local
|
|
if (localResult.status === 'rejected') {
|
|
console.error('[WriteOrchestrator] Local write failed:', localResult.reason)
|
|
throw new Error(`Failed to write to IndexedDB: ${localResult.reason}`)
|
|
}
|
|
|
|
// 3. Update published status in IndexedDB via Web Worker (même si réseau a échoué)
|
|
const publishedStatus: false | string[] = publishedRelays.length > 0 ? publishedRelays : false
|
|
await writeService.updatePublished(objectType, hash, publishedStatus)
|
|
|
|
return {
|
|
success: publishedRelays.length > 0,
|
|
eventId: event.id,
|
|
published: publishedStatus,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create and publish event from template
|
|
*/
|
|
async createAndPublishEvent(
|
|
eventTemplate: EventTemplate,
|
|
relays: string[],
|
|
objectType: ObjectType,
|
|
hash: string,
|
|
parsed: unknown,
|
|
version: number,
|
|
hidden: boolean,
|
|
index?: number
|
|
): Promise<{ success: boolean; event: NostrEvent; published: false | string[] }> {
|
|
if (!this.privateKey) {
|
|
throw new Error('Private key not set')
|
|
}
|
|
|
|
// Create event
|
|
const unsignedEvent: EventTemplate = {
|
|
...eventTemplate,
|
|
created_at: eventTemplate.created_at ?? Math.floor(Date.now() / 1000),
|
|
}
|
|
|
|
const secretKey = hexToBytes(this.privateKey)
|
|
const finalizedEvent = finalizeEvent(unsignedEvent, secretKey)
|
|
|
|
// Write and publish
|
|
const result = await this.writeAndPublish(
|
|
{
|
|
objectType,
|
|
hash,
|
|
event: finalizedEvent,
|
|
parsed,
|
|
version,
|
|
hidden,
|
|
...(index !== undefined ? { index } : {}),
|
|
},
|
|
relays
|
|
)
|
|
|
|
return {
|
|
success: result.success,
|
|
event: finalizedEvent,
|
|
published: result.published,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update published status (for republishing)
|
|
*/
|
|
async updatePublishedStatus(
|
|
objectType: ObjectType,
|
|
id: string,
|
|
published: false | string[]
|
|
): Promise<void> {
|
|
await writeService.updatePublished(objectType, id, published)
|
|
}
|
|
}
|
|
|
|
export const writeOrchestrator = new WriteOrchestrator()
|