nodejs-event-driven
Version:
NodeJS agnostic event driven with EventEmitter support
82 lines • 3.42 kB
JavaScript
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