ditto/src/subs.ts

77 lines
1.8 KiB
TypeScript
Raw Normal View History

2023-08-24 20:28:13 +00:00
import { type Event } from '@/deps.ts';
import { matchDittoFilters } from './filter.ts';
2023-08-24 04:25:38 +00:00
2023-08-24 22:00:08 +00:00
import type { DittoFilter, EventData } from '@/types.ts';
2023-08-24 04:25:38 +00:00
/** Nostr subscription to receive realtime events. */
interface Subscription {
/** User-defined NIP-01 subscription ID. */
id: string;
/** Event filters for the subscription. */
filters: DittoFilter[];
/** WebSocket to deliver results to. */
socket: WebSocket;
}
/**
* Manages Ditto event subscriptions.
*
* Subscriptions can be added, removed, and matched against events.
*
* ```ts
2023-08-24 22:00:08 +00:00
* for (const sub of Sub.matches(event)) {
2023-08-24 04:25:38 +00:00
* // Send event to sub.socket
* sub.socket.send(JSON.stringify(event));
* }
* ```
*/
class SubscriptionStore {
#store = new Map<WebSocket, Map<string, Subscription>>();
/** Add a subscription to the store. */
sub(data: Subscription): void {
let subs = this.#store.get(data.socket);
if (!subs) {
subs = new Map();
this.#store.set(data.socket, subs);
}
subs.set(data.id, data);
}
/** Remove a subscription from the store. */
unsub(sub: Pick<Subscription, 'socket' | 'id'>): void {
this.#store.get(sub.socket)?.delete(sub.id);
}
/** Remove an entire socket. */
close(socket: WebSocket): void {
this.#store.delete(socket);
}
/**
* Loop through matching subscriptions to stream out.
*
* ```ts
2023-08-24 22:00:08 +00:00
* for (const sub of Sub.matches(event)) {
2023-08-24 04:25:38 +00:00
* // Send event to sub.socket
* sub.socket.send(JSON.stringify(event));
* }
* ```
*/
2023-08-24 22:00:08 +00:00
*matches(event: Event, data: EventData): Iterable<Subscription> {
2023-08-24 04:25:38 +00:00
for (const subs of this.#store.values()) {
for (const sub of subs.values()) {
2023-08-24 22:00:08 +00:00
if (matchDittoFilters(sub.filters, event, data)) {
2023-08-24 04:25:38 +00:00
yield sub;
}
}
}
}
}
const Sub = new SubscriptionStore();
export { Sub };