2023-08-24 20:28:13 +00:00
|
|
|
import { type Event } from '@/deps.ts';
|
2023-08-25 18:35:20 +00:00
|
|
|
import { Subscription } from '@/subscription.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
|
|
|
|
|
|
|
/**
|
|
|
|
* Manages Ditto event subscriptions.
|
|
|
|
* Subscriptions can be added, removed, and matched against events.
|
|
|
|
*/
|
|
|
|
class SubscriptionStore {
|
|
|
|
#store = new Map<WebSocket, Map<string, Subscription>>();
|
|
|
|
|
2023-08-25 18:35:20 +00:00
|
|
|
/**
|
|
|
|
* Add a subscription to the store, and then iterate over it.
|
|
|
|
*
|
|
|
|
* ```ts
|
|
|
|
* for (const event of Sub.sub(socket, subId, filters)) {
|
|
|
|
* console.log(event);
|
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*/
|
|
|
|
sub(socket: WebSocket, id: string, filters: DittoFilter[]): Subscription {
|
|
|
|
let subs = this.#store.get(socket);
|
2023-08-24 04:25:38 +00:00
|
|
|
|
|
|
|
if (!subs) {
|
|
|
|
subs = new Map();
|
2023-08-25 18:35:20 +00:00
|
|
|
this.#store.set(socket, subs);
|
2023-08-24 04:25:38 +00:00
|
|
|
}
|
|
|
|
|
2023-08-25 18:35:20 +00:00
|
|
|
const sub = new Subscription(filters);
|
|
|
|
|
|
|
|
this.unsub(socket, id);
|
|
|
|
subs.set(id, sub);
|
|
|
|
|
|
|
|
return sub;
|
2023-08-24 04:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Remove a subscription from the store. */
|
2023-08-25 18:35:20 +00:00
|
|
|
unsub(socket: WebSocket, id: string): void {
|
|
|
|
this.#store.get(socket)?.get(id)?.close();
|
|
|
|
this.#store.get(socket)?.delete(id);
|
2023-08-24 04:25:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Remove an entire socket. */
|
|
|
|
close(socket: WebSocket): void {
|
2023-08-25 18:35:20 +00:00
|
|
|
const subs = this.#store.get(socket);
|
|
|
|
|
|
|
|
if (subs) {
|
|
|
|
for (const sub of subs.values()) {
|
|
|
|
sub.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-24 04:25:38 +00:00
|
|
|
this.#store.delete(socket);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loop through matching subscriptions to stream out.
|
|
|
|
*
|
|
|
|
* ```ts
|
2023-08-25 18:35:20 +00:00
|
|
|
* for (const sub of Sub.matches(event, data)) {
|
|
|
|
* sub.stream(event);
|
2023-08-24 04:25:38 +00:00
|
|
|
* }
|
|
|
|
* ```
|
|
|
|
*/
|
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-25 18:35:20 +00:00
|
|
|
if (sub.matches(event, data)) {
|
2023-08-24 04:25:38 +00:00
|
|
|
yield sub;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const Sub = new SubscriptionStore();
|
|
|
|
|
|
|
|
export { Sub };
|