diff options
| author | netop://ウィビ <paul@webb.page> | 2026-10-21 16:47:38 -0700 |
|---|---|---|
| committer | netop://ウィビ <paul@webb.page> | 2026-10-21 16:47:38 -0700 |
| commit | 389ad1349c4ff245a3466a2e361c1cd1dd11d2ba (patch) | |
| tree | 0ad0638f60ab0a77c7a095e96b472312ab39f83b /source/utility/pubsub.ts | |
| parent | bbcbb02ef64d094f0f13de22ae135eeba1ff4c5d (diff) | |
| download | gq-primary.tar.gz gq-primary.zip | |
- inlined vendored dependencies from npm
- makes this module work in Ende
Diffstat (limited to '')
| -rw-r--r-- | source/utility/pubsub.ts | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/source/utility/pubsub.ts b/source/utility/pubsub.ts new file mode 100644 index 0000000..bb8679a --- /dev/null +++ b/source/utility/pubsub.ts @@ -0,0 +1,64 @@ +export class PubSub { + #target = new EventTarget(); + + publish(trigger: string, payload: unknown): Promise<void> { + this.#target.dispatchEvent(new CustomEvent(trigger, { detail: payload })); + return Promise.resolve(); + } + + asyncIterator<T>(triggers: string | string[]): AsyncIterableIterator<T> { + const names = Array.isArray(triggers) ? triggers : [triggers]; + const pulls: Array<(result: IteratorResult<T>) => void> = []; + const pushes: T[] = []; + let done = false; + + const listener = (event: Event) => { + const value = (event as CustomEvent<T>).detail; + const pull = pulls.shift(); + + if (pull) + pull({ done: false, value }); + else + pushes.push(value); + }; + + for (const name of names) + this.#target.addEventListener(name, listener); + + const close = (): Promise<IteratorResult<T>> => { + if (!done) { + done = true; + + for (const name of names) + this.#target.removeEventListener(name, listener); + + for (const pull of pulls.splice(0)) + pull({ done: true, value: undefined }); + + pushes.length = 0; + } + + return Promise.resolve({ done: true, value: undefined }); + }; + + return { + next: () => { + if (done) + return Promise.resolve({ done: true, value: undefined }); + + if (pushes.length > 0) + return Promise.resolve({ done: false, value: pushes.shift() as T }); + + return new Promise((resolve) => pulls.push(resolve)); + }, + return: close, + throw: (error: unknown) => { + close(); + return Promise.reject(error); + }, + [Symbol.asyncIterator]() { + return this; + } + }; + } +} |