diff --git a/src/storages/memorelay.ts b/src/storages/memorelay.ts new file mode 100644 index 00000000..0ab71938 --- /dev/null +++ b/src/storages/memorelay.ts @@ -0,0 +1,63 @@ +import { Debug, type Event, type Filter, LRUCache } from '@/deps.ts'; +import { getFilterId, getMicroFilters, isMicrofilter } from '@/filter.ts'; +import { type EventStore, type GetEventsOpts } from '@/store.ts'; + +/** In-memory data store for events using microfilters. */ +class Memorelay implements EventStore { + #debug = Debug('ditto:memorelay'); + #events: LRUCache; + + constructor(...args: ConstructorParameters>) { + this.#events = new LRUCache(...args); + } + + /** Get events from memory. */ + getEvents(filters: Filter[], opts: GetEventsOpts = {}): Promise[]> { + if (opts.signal?.aborted) return Promise.resolve([]); + if (!filters.length) return Promise.resolve([]); + this.#debug('REQ', JSON.stringify(filters)); + + const results: Event[] = []; + + for (const filter of filters) { + if (isMicrofilter(filter)) { + const event = this.#events.get(getFilterId(filter)); + if (event) { + results.push(event as Event); + } + } + } + + return Promise.resolve(results); + } + + /** Insert an event into memory. */ + storeEvent(event: Event): Promise { + for (const microfilter of getMicroFilters(event)) { + const filterId = getFilterId(microfilter); + const existing = this.#events.get(filterId); + if (!existing || event.created_at > existing.created_at) { + this.#events.set(filterId, event); + } + } + return Promise.resolve(); + } + + /** Count events in memory for the filters. */ + async countEvents(filters: Filter[]): Promise { + const events = await this.getEvents(filters); + return events.length; + } + + /** Delete events from memory. */ + deleteEvents(filters: Filter[]): Promise { + for (const filter of filters) { + if (isMicrofilter(filter)) { + this.#events.delete(getFilterId(filter)); + } + } + return Promise.resolve(); + } +} + +export { Memorelay }; \ No newline at end of file