import {Emitter, remove, omit} from "@welshman/lib" import {HashedEvent, SignedEvent} from "@welshman/util" import {Tracker} from "./tracker.js" import {Repository} from "./repository.js" export type WrapItem = Omit & { rumorId: string recipient: string } export type WrapReference = string[] export type WrapManagerOptions = { repository: Repository tracker: Tracker } export class WrapManager extends Emitter { _wrapIndex = new Map() _rumorIndex = new Map() _recipientIndex = new Map() constructor(readonly options: WrapManagerOptions) { super() } // Reading/exporting dump = () => Array.from(this._wrapIndex.values()) getWraps = (rumorId: string) => (this._rumorIndex.get(rumorId) || []).map(wrapId => this._wrapIndex.get(wrapId)!) getRumor = (wrapId: string) => { const wrapItem = this._wrapIndex.get(wrapId) if (wrapItem) { return this.options.repository.getEvent(wrapItem.rumorId) } } // Adding/importing clear = () => { this._wrapIndex.clear() this._rumorIndex.clear() this._recipientIndex.clear() this.emit("load") } load = (wrapItems: WrapItem[]) => { this.clear() for (const wrapItem of wrapItems) { this._add(wrapItem) } this.emit("load") } add = ({recipient, rumor, wrap}: {recipient: string; rumor: HashedEvent; wrap: SignedEvent}) => { const wrapItem = { ...omit(["content"], wrap), rumorId: rumor.id, recipient, } this._add(wrapItem) // Save to our repository this.options.repository.publish(rumor) // Mark the rumor as having come from the wrap's urls this.options.tracker.copy(wrap.id, rumor.id) this.emit("add", wrapItem) } // Removing remove = (id: string) => { const wrapItem = this._wrapIndex.get(id) if (wrapItem) { this._remove(wrapItem) this.options.repository.removeEvent(wrapItem.rumorId) this.emit("remove", wrapItem) } } removeByRumorId = (rumorId: string) => { for (const id of this._rumorIndex.get(rumorId) || []) { this.remove(id) } } // Utils _add = (wrapItem: WrapItem) => { this._wrapIndex.set(wrapItem.id, wrapItem) this._addReference(this._rumorIndex, wrapItem.rumorId, wrapItem.id) this._addReference(this._recipientIndex, wrapItem.recipient, wrapItem.id) } _addReference = (index: Map, key: string, wrapId: string) => { const reference = index.get(key) if (reference) { reference.push(wrapId) } else { index.set(key, [wrapId]) } } _remove = (wrapItem: WrapItem) => { this._wrapIndex.delete(wrapItem.id) this._removeReference(this._rumorIndex, wrapItem.rumorId, wrapItem.id) this._removeReference(this._recipientIndex, wrapItem.recipient, wrapItem.id) } _removeReference = (index: Map, key: string, wrapId: string) => { const reference = index.get(key) if (reference) { const wraps = remove(wrapId, reference) if (wraps.length > 0) { index.set(key, wraps) } else { index.delete(key) } } } }