133 lines
3.7 KiB
TypeScript
133 lines
3.7 KiB
TypeScript
/**
|
|
* Helper for syncing payment notes
|
|
* Handles the special case of payment notes which require multiple subscriptions
|
|
*/
|
|
|
|
import type { Event, Filter } from 'nostr-tools'
|
|
import type { SimplePoolWithSub } from '@/types/nostr-tools-extended'
|
|
import { PLATFORM_SERVICE } from '../platformConfig'
|
|
import { getPrimaryRelaySync } from '../config'
|
|
import { createSubscription } from '@/types/nostr-tools-extended'
|
|
import { tryWithRelayRotation } from '../relayRotation'
|
|
import { extractTagsFromEvent } from '../nostrTagSystem'
|
|
import { cachePaymentNotes } from './syncCacheHelpers'
|
|
|
|
export function buildPaymentNoteFilters(userPubkey: string, lastSyncDate: number): Filter[] {
|
|
return [
|
|
{
|
|
kinds: [1],
|
|
authors: [userPubkey],
|
|
'#payment': [''],
|
|
'#service': [PLATFORM_SERVICE],
|
|
since: lastSyncDate,
|
|
limit: 1000,
|
|
},
|
|
{
|
|
kinds: [1],
|
|
'#recipient': [userPubkey],
|
|
'#payment': [''],
|
|
'#service': [PLATFORM_SERVICE],
|
|
since: lastSyncDate,
|
|
limit: 1000,
|
|
},
|
|
]
|
|
}
|
|
|
|
export async function createPaymentNoteSubscriptions(
|
|
pool: SimplePoolWithSub,
|
|
filters: Filter[]
|
|
): Promise<Array<ReturnType<typeof createSubscription>>> {
|
|
let subscriptions: Array<ReturnType<typeof createSubscription>> = []
|
|
|
|
try {
|
|
const result = await tryWithRelayRotation(
|
|
pool as unknown as import('nostr-tools').SimplePool,
|
|
async (relayUrl, poolWithSub) => {
|
|
await updateProgressForRelay(relayUrl)
|
|
return filters.map((filter) => createSubscription(poolWithSub, [relayUrl], [filter]))
|
|
},
|
|
5000
|
|
)
|
|
subscriptions = result.flat()
|
|
} catch {
|
|
const usedRelayUrl = getPrimaryRelaySync()
|
|
subscriptions = filters.map((filter) => createSubscription(pool, [usedRelayUrl], [filter]))
|
|
}
|
|
|
|
if (subscriptions.length === 0) {
|
|
throw new Error('Failed to create subscriptions')
|
|
}
|
|
|
|
return subscriptions
|
|
}
|
|
|
|
async function updateProgressForRelay(relayUrl: string): Promise<void> {
|
|
const { syncProgressManager } = await import('../syncProgressManager')
|
|
const currentProgress = syncProgressManager.getProgress()
|
|
if (currentProgress) {
|
|
syncProgressManager.setProgress({
|
|
...currentProgress,
|
|
currentStep: 0,
|
|
currentRelay: relayUrl,
|
|
})
|
|
}
|
|
}
|
|
|
|
export async function processPaymentNoteEvents(
|
|
subscriptions: Array<ReturnType<typeof createSubscription>>
|
|
): Promise<void> {
|
|
const events: Event[] = []
|
|
|
|
return new Promise<void>((resolve) => {
|
|
let finished = false
|
|
let eoseCount = 0
|
|
|
|
const done = async (): Promise<void> => {
|
|
if (finished) {
|
|
return
|
|
}
|
|
finished = true
|
|
subscriptions.forEach((sub) => sub.unsub())
|
|
await cachePaymentNotes(events)
|
|
resolve()
|
|
}
|
|
|
|
const handleEose = (): void => {
|
|
eoseCount++
|
|
if (eoseCount >= subscriptions.length) {
|
|
console.warn(`[Sync] EOSE for payment notes, received ${events.length} events`)
|
|
void done()
|
|
}
|
|
}
|
|
|
|
setupPaymentNoteSubscriptions(subscriptions, events, handleEose)
|
|
|
|
setTimeout((): void => {
|
|
if (!finished) {
|
|
console.warn(`[Sync] Timeout for payment notes, received ${events.length} events`)
|
|
}
|
|
void done()
|
|
}, 10000).unref?.()
|
|
})
|
|
}
|
|
|
|
function setupPaymentNoteSubscriptions(
|
|
subscriptions: Array<ReturnType<typeof createSubscription>>,
|
|
events: Event[],
|
|
onEose: () => void
|
|
): void {
|
|
subscriptions.forEach((sub) => {
|
|
sub.on('event', (event: Event): void => {
|
|
const tags = extractTagsFromEvent(event)
|
|
if (tags.type === 'payment' && tags.payment) {
|
|
console.warn('[Sync] Received payment note event:', event.id)
|
|
if (!events.some((e) => e.id === event.id)) {
|
|
events.push(event)
|
|
}
|
|
}
|
|
})
|
|
|
|
sub.on('eose', onEose)
|
|
})
|
|
}
|