Files
directus/api/src/emitter.ts
Rijk van Zanten 2b9056cc80 Refactor default import logger with useLogger (#20872)
* useLogger

* Rework to useLogger and no globals

* Only export useLogger / createLogger

* Temp remove logger tests

* Refactor logger

* Refactor logger

* Refactor logger

* Refactor logger use

* Fix tests

* Fix logger usage in bootstrap

* Run formatter

* Remove logger tests

Feels drastic, but I'm about to rewrite them into @directus/logger :)

* Fix log operation test
2023-12-26 11:38:38 -05:00

121 lines
3.2 KiB
TypeScript

import type { ActionHandler, EventContext, FilterHandler, InitHandler } from '@directus/types';
import ee2 from 'eventemitter2';
import getDatabase from './database/index.js';
import { useLogger } from './logger.js';
export class Emitter {
private filterEmitter;
private actionEmitter;
private initEmitter;
constructor() {
const emitterOptions = {
wildcard: true,
verboseMemoryLeak: true,
delimiter: '.',
// This will ignore the "unspecified event" error
ignoreErrors: true,
};
this.filterEmitter = new ee2.EventEmitter2(emitterOptions);
this.actionEmitter = new ee2.EventEmitter2(emitterOptions);
this.initEmitter = new ee2.EventEmitter2(emitterOptions);
}
private getDefaultContext(): EventContext {
return {
database: getDatabase(),
accountability: null,
schema: null,
};
}
public async emitFilter<T>(
event: string | string[],
payload: T,
meta: Record<string, any>,
context: EventContext | null = null,
): Promise<T> {
const events = Array.isArray(event) ? event : [event];
const eventListeners = events.map((event) => ({
event,
listeners: this.filterEmitter.listeners(event) as FilterHandler<T>[],
}));
let updatedPayload = payload;
for (const { event, listeners } of eventListeners) {
for (const listener of listeners) {
const result = await listener(updatedPayload, { event, ...meta }, context ?? this.getDefaultContext());
if (result !== undefined) {
updatedPayload = result;
}
}
}
return updatedPayload;
}
public emitAction(event: string | string[], meta: Record<string, any>, context: EventContext | null = null): void {
const logger = useLogger();
const events = Array.isArray(event) ? event : [event];
for (const event of events) {
this.actionEmitter.emitAsync(event, { event, ...meta }, context ?? this.getDefaultContext()).catch((err) => {
logger.warn(`An error was thrown while executing action "${event}"`);
logger.warn(err);
});
}
}
public async emitInit(event: string, meta: Record<string, any>): Promise<void> {
const logger = useLogger();
try {
await this.initEmitter.emitAsync(event, { event, ...meta });
} catch (err: any) {
logger.warn(`An error was thrown while executing init "${event}"`);
logger.warn(err);
}
}
public onFilter<T = unknown>(event: string, handler: FilterHandler<T>): void {
this.filterEmitter.on(event, handler);
}
public onAction(event: string, handler: ActionHandler): void {
this.actionEmitter.on(event, handler);
}
public onInit(event: string, handler: InitHandler): void {
this.initEmitter.on(event, handler);
}
public offFilter<T = unknown>(event: string, handler: FilterHandler<T>): void {
this.filterEmitter.off(event, handler);
}
public offAction(event: string, handler: ActionHandler): void {
this.actionEmitter.off(event, handler);
}
public offInit(event: string, handler: InitHandler): void {
this.initEmitter.off(event, handler);
}
public offAll(): void {
this.filterEmitter.removeAllListeners();
this.actionEmitter.removeAllListeners();
this.initEmitter.removeAllListeners();
}
}
const emitter = new Emitter();
export const useEmitter = () => emitter;
export default emitter;