UNPKG

masto

Version:

Mastodon API client for JavaScript, TypeScript, Node.js, browsers

91 lines (90 loc) 3.07 kB
import { MastoUnexpectedError } from "../errors/index.js"; import { toAsyncIterable } from "./async-iterable.js"; export class WebSocketSubscription { connector; counter; serializer; stream; logger; params; connection; constructor(connector, counter, serializer, stream, logger, params) { this.connector = connector; this.counter = counter; this.serializer = serializer; this.stream = stream; this.logger = logger; this.params = params; } async *values() { try { this.logger?.log("info", "Subscribing to stream", this.stream); for await (this.connection of this.connector) { const data = this.serializer.serialize("json", { type: "subscribe", stream: this.stream, ...this.params, }); this.logger?.log("debug", "↑ WEBSOCKET", data); this.connection.send(data); this.counter.increment(this.stream, this.params); const messages = toAsyncIterable(this.connection); for await (const message of messages) { const event = this.parseMessage(message.data); if (!this.test(event)) { continue; } this.logger?.log("debug", "↓ WEBSOCKET", event); yield event; } /* c8 ignore next */ } } finally { this.unsubscribe(); } } unsubscribe() { if (!this.connection) { return; } this.counter.decrement(this.stream, this.params); if (this.counter.count(this.stream, this.params) <= 0) { const data = this.serializer.serialize("json", { type: "unsubscribe", stream: this.stream, ...this.params, }); this.connection.send(data); } this.connection = undefined; } [Symbol.asyncIterator]() { return this.values(); } [Symbol.dispose]() { this.unsubscribe(); } test(event) { // subscribe("hashtag", { tag: "foo" }) -> ["hashtag", "foo"] // subscribe("list", { list: "foo" }) -> ["list", "foo"] const params = this.params ?? {}; const extra = Object.values(params); const stream = [this.stream, ...extra]; return stream.every((s) => event.stream.includes(s)); } parseMessage(rawEvent) { const data = this.serializer.deserialize("json", rawEvent); if ("error" in data) { throw new MastoUnexpectedError(data.error); } const payload = data.event === "delete" || data.payload == undefined ? data.payload : this.serializer.deserialize("json", data.payload); return { stream: data.stream, event: data.event, payload: payload, }; } }