event-cache.actor.ts raw
1 import { Func, Inbox, Lifecycle, spawn, loop, STOP } from 'anneal'
2 import { Event as NEvent } from 'nostr-tools'
3 import { compareEvents, getReplaceableCoordinateFromEvent, isReplaceableEvent } from '@/lib/event'
4
5 export type EventCacheActor = {
6 cache: Inbox<NEvent>
7 lookup: Func<string, NEvent | undefined>
8 lookupMany: Func<string[], (NEvent | undefined)[]>
9 lookupReplaceable: Func<string, NEvent | undefined>
10 lc: Lifecycle
11 }
12
13 export function createEventCacheActor(): EventCacheActor {
14 const events = new Map<string, NEvent>()
15 const replaceables = new Map<string, NEvent>()
16
17 const cache = new Inbox<NEvent>(0)
18 const lookup = new Func<string, NEvent | undefined>()
19 const lookupMany = new Func<string[], (NEvent | undefined)[]>()
20 const lookupReplaceable = new Func<string, NEvent | undefined>()
21 const lc = new Lifecycle()
22
23 spawn(lc, async () => {
24 await loop(
25 lc.on(() => STOP),
26 cache.on((event) => {
27 events.set(event.id, event)
28 if (isReplaceableEvent(event.kind)) {
29 const coord = getReplaceableCoordinateFromEvent(event)
30 const existing = replaceables.get(coord)
31 if (!existing || compareEvents(event, existing) > 0) {
32 replaceables.set(coord, event)
33 }
34 }
35 }),
36 lookup.on(({ req: id, reply }) => {
37 reply(events.get(id))
38 }),
39 lookupMany.on(({ req: ids, reply }) => {
40 reply(ids.map((id) => events.get(id)))
41 }),
42 lookupReplaceable.on(({ req: coord, reply }) => {
43 reply(replaceables.get(coord))
44 })
45 )
46 })
47
48 return { cache, lookup, lookupMany, lookupReplaceable, lc }
49 }
50