UNPKG

nodejs-event-driven

Version:

NodeJS agnostic event driven with EventEmitter support

82 lines 3.42 kB
import { EventEmitter } from 'node:events'; import { writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { basename, dirname, join } from 'node:path'; import { BaseEventBusService } from '../../../base-event-bus.service.js'; import { createDirIfNeeded, createDirSyncIfNeeded, watchFiles, } from '../../../util/fs.helper.js'; export default class FsEventBusService extends BaseEventBusService { static defaultDataRootDir = join(tmpdir(), 'fs-event-bus'); #abortController = null; #dataRootDir; #eventEmitter; #logger; #pollingDelayMs; constructor(config) { super(); this.#logger = config.logger; this.#pollingDelayMs = config.eventBusFsPollingDelayMs; this.#eventEmitter = new EventEmitter(); this.#dataRootDir = config.eventBusFsBaseDataDir ?? FsEventBusService.defaultDataRootDir; } on(eventName, listener) { this.#logger?.debug(`register listener for event: ${eventName}`); this.#eventEmitter.on(eventName, listener); } once(eventName, listener) { this.#logger?.debug(`register once listener for event: ${eventName}`); this.#eventEmitter.once(eventName, listener); } off(eventName, listener) { this.#logger?.debug(`unregister listener for event: ${eventName}`); this.#eventEmitter.off(eventName, listener); } send(eventName, data) { this.#logger?.debug(`sending event: ${eventName} with ${String(data)}`); const dataRootDir = this.#dataRootDir; const eventFileBaseDir = join(dataRootDir, eventName); createDirSyncIfNeeded(eventFileBaseDir); const timestamp = process.hrtime.bigint(); const eventFilePath = join(eventFileBaseDir, `event-${timestamp}.data`); void writeFile(eventFilePath, JSON.stringify(data), 'utf-8'); } sendAndWait(sendEventName, successEventName, errorEventName, data) { this.#logger?.debug(`sending event ${sendEventName} and waiting for event ${successEventName}…`); return super.sendAndWait(sendEventName, successEventName, errorEventName, data); } async start() { const abortController = new AbortController(); this.#abortController = abortController; await this.#watch(abortController); } stop() { const abortController = this.#abortController; if (!abortController) { return Promise.resolve(); } abortController.abort(); this.#abortController = null; return Promise.resolve(); } async #watch(abortController) { const dataRootDir = this.#dataRootDir; await createDirIfNeeded(dataRootDir); const { signal } = abortController; const watchPattern = /event-(\d+)\.data$/; const watchConfig = { signal, baseDir: dataRootDir, logger: this.#logger, fileType: 'json', filenamePattern: watchPattern, pollingDelayMs: this.#pollingDelayMs, }; const watcher = await watchFiles(watchConfig); watcher.onFile((filePath, data) => { const eventName = basename(dirname(filePath)); this.#logger?.debug(`sending event: ${eventName} with ${String(data)}`); this.#eventEmitter.emit(eventName, data); }); } } //# sourceMappingURL=fs-event-bus.service.js.map