From 9e087a8b13cf67efbc395d85d6b94dcd8f5a6f9e Mon Sep 17 00:00:00 2001 From: socram03 Date: Mon, 12 Jun 2023 15:20:50 +0000 Subject: [PATCH] feat(helpers): events collector --- packages/helpers/src/Collector.ts | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 packages/helpers/src/Collector.ts diff --git a/packages/helpers/src/Collector.ts b/packages/helpers/src/Collector.ts new file mode 100644 index 0000000..3315627 --- /dev/null +++ b/packages/helpers/src/Collector.ts @@ -0,0 +1,79 @@ +import { MakeRequired, Options } from '@biscuitland/common'; +import { type Session, Handler } from '@biscuitland/core'; +import { GatewayEvents } from '@biscuitland/ws'; +import { EventEmitter } from 'node:events'; + +interface CollectorOptions { + event: `${E}`; + filter?: (...args: Parameters) => unknown; + max?: number; + time?: number; + idle?: number; +} + +export const DEFAULT_OPTIONS = { + filter: () => true, + max: -1 +}; + +export enum CollectorStatus { + Idle = 0, + Started = 1, + Ended = 2 +} + +export class EventCollector extends EventEmitter { + collected = new Set[0]>(); + status: CollectorStatus = CollectorStatus.Idle; + options: MakeRequired, 'filter' | 'max'>; + private timeout: NodeJS.Timeout | null = null; + + constructor(readonly session: Session, rawOptions: CollectorOptions) { + super(); + this.options = Options(DEFAULT_OPTIONS, rawOptions); + } + + start() { + this.session.setMaxListeners(this.session.getMaxListeners() + 1); + this.session.on(this.options.event, (...args: unknown[]) => this.collect(...(args as Parameters))); + this.timeout = setTimeout(() => this.stop('time'), this.options.idle ?? this.options.time); + } + + private collect(...args: Parameters) { + if (this.options.filter?.(...args)) { + this.collected.add(args[0]); + this.emit('collect', ...args); + } + + if (this.options.idle) { + if (this.timeout) clearTimeout(this.timeout); + this.timeout = setTimeout(() => this.stop('time'), this.options.idle); + } + + if (this.collected.size >= this.options.max!) this.stop('max'); + } + + stop(reason = 'User stopped') { + if (this.status === CollectorStatus.Ended) return; + + if (this.timeout) clearTimeout(this.timeout); + + this.session.removeListener(this.options.event, (...args: unknown[]) => this.collect(...(args as Parameters))); + this.session.setMaxListeners(this.session.getMaxListeners() - 1); + + this.status = CollectorStatus.Ended; + this.emit('end', reason, this.collected); + } + + on(event: 'collect', listener: (...args: Parameters) => unknown): this; + on(event: 'end', listener: (reason: string | null | undefined, collected: Set[0]>) => void): this; + on(event: string, listener: unknown): this { + return super.on(event, listener as () => unknown); + } + + once(event: 'collect', listener: (...args: Parameters) => unknown): this; + once(event: 'end', listener: (reason: string | null | undefined, collected: Set[0]>) => void): this; + once(event: string, listener: unknown): this { + return super.once(event, listener as () => unknown); + } +}