refactor: Replace EventEmitter with custom SSE event emitter implementation
- Create a type-safe CustomEventEmitter class for SSE events - Implement custom event handling with type-specific data - Add listener management with max listener tracking - Preserve existing logging and initialization behavior - Improve type safety and control over event emissions
- commit
- 5367de1ec0b6fff42fcab70d5e0299bb4c600f55
- author
- Kit · · 2025-02-14 08:05 UTC
- parent
- 1f4430f
- signature
- SSH Unverified
SHA256:H91DFuEG4jpk5edzLA4aUKkpv4zv9Q339ipRmkph6TkThe key is unknown
1 file · +48 -4
M src/lib/sseEmitter.ts +48 -4
| @@ -1,5 +1,49 @@ | |||
| 1 | - | import { EventEmitter } from 'events'; | |
| 1 | + | type SSEEventData = { | |
| 2 | + | type: string; | |
| 3 | + | data: unknown; | |
| 4 | + | }; | |
| 2 | 5 | ||
| 3 | - | console.debug('Initializing shared SSE emitter'); | |
| 4 | - | export const sseEmitter = new EventEmitter(); | |
| 5 | - | sseEmitter.setMaxListeners(100); ⏎̸ | |
| 6 | + | class CustomEventEmitter { | |
| 7 | + | private listeners: Map<string, Array<(data: SSEEventData) => void>> = new Map(); | |
| 8 | + | private maxListeners: number = 100; | |
| 9 | + | ||
| 10 | + | constructor() { | |
| 11 | + | console.debug('Initializing custom SSE emitter'); | |
| 12 | + | } | |
| 13 | + | ||
| 14 | + | emit(event: string, data: SSEEventData) { | |
| 15 | + | const eventListeners = this.listeners.get(event); | |
| 16 | + | if (eventListeners) { | |
| 17 | + | eventListeners.forEach(listener => listener(data)); | |
| 18 | + | } | |
| 19 | + | } | |
| 20 | + | ||
| 21 | + | addListener(event: string, listener: (data: SSEEventData) => void) { | |
| 22 | + | if (!this.listeners.has(event)) { | |
| 23 | + | this.listeners.set(event, []); | |
| 24 | + | } | |
| 25 | + | const eventListeners = this.listeners.get(event)!; | |
| 26 | + | ||
| 27 | + | if (eventListeners.length >= this.maxListeners) { | |
| 28 | + | console.warn(`Warning: Event '${event}' has exceeded the maximum number of listeners (${this.maxListeners})`); | |
| 29 | + | } | |
| 30 | + | ||
| 31 | + | eventListeners.push(listener); | |
| 32 | + | } | |
| 33 | + | ||
| 34 | + | removeListener(event: string, listenerToRemove: (data: SSEEventData) => void) { | |
| 35 | + | const eventListeners = this.listeners.get(event); | |
| 36 | + | if (eventListeners) { | |
| 37 | + | this.listeners.set( | |
| 38 | + | event, | |
| 39 | + | eventListeners.filter(listener => listener !== listenerToRemove) | |
| 40 | + | ); | |
| 41 | + | } | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | setMaxListeners(n: number) { | |
| 45 | + | this.maxListeners = n; | |
| 46 | + | } | |
| 47 | + | } | |
| 48 | + | ||
| 49 | + | export const sseEmitter = new CustomEventEmitter(); ⏎̸ | |
| @@ -1,5 +1,49 @@ | |||||
| 1 | - | import { EventEmitter } from 'events'; | 1 | + | type SSEEventData = { |
| 2 | + | type: string; | |||
| 3 | + | data: unknown; | |||
| 4 | + | }; | |||
| 2 | 5 | ||||
| 3 | - | console.debug('Initializing shared SSE emitter'); | 6 | + | class CustomEventEmitter { |
| 4 | - | export const sseEmitter = new EventEmitter(); | 7 | + | private listeners: Map<string, Array<(data: SSEEventData) => void>> = new Map(); |
| 5 | - | sseEmitter.setMaxListeners(100); ⏎̸ | 8 | + | private maxListeners: number = 100; |
| 9 | + | ||||
| 10 | + | constructor() { | |||
| 11 | + | console.debug('Initializing custom SSE emitter'); | |||
| 12 | + | } | |||
| 13 | + | ||||
| 14 | + | emit(event: string, data: SSEEventData) { | |||
| 15 | + | const eventListeners = this.listeners.get(event); | |||
| 16 | + | if (eventListeners) { | |||
| 17 | + | eventListeners.forEach(listener => listener(data)); | |||
| 18 | + | } | |||
| 19 | + | } | |||
| 20 | + | ||||
| 21 | + | addListener(event: string, listener: (data: SSEEventData) => void) { | |||
| 22 | + | if (!this.listeners.has(event)) { | |||
| 23 | + | this.listeners.set(event, []); | |||
| 24 | + | } | |||
| 25 | + | const eventListeners = this.listeners.get(event)!; | |||
| 26 | + | ||||
| 27 | + | if (eventListeners.length >= this.maxListeners) { | |||
| 28 | + | console.warn(`Warning: Event '${event}' has exceeded the maximum number of listeners (${this.maxListeners})`); | |||
| 29 | + | } | |||
| 30 | + | ||||
| 31 | + | eventListeners.push(listener); | |||
| 32 | + | } | |||
| 33 | + | ||||
| 34 | + | removeListener(event: string, listenerToRemove: (data: SSEEventData) => void) { | |||
| 35 | + | const eventListeners = this.listeners.get(event); | |||
| 36 | + | if (eventListeners) { | |||
| 37 | + | this.listeners.set( | |||
| 38 | + | event, | |||
| 39 | + | eventListeners.filter(listener => listener !== listenerToRemove) | |||
| 40 | + | ); | |||
| 41 | + | } | |||
| 42 | + | } | |||
| 43 | + | ||||
| 44 | + | setMaxListeners(n: number) { | |||
| 45 | + | this.maxListeners = n; | |||
| 46 | + | } | |||
| 47 | + | } | |||
| 48 | + | ||||
| 49 | + | export const sseEmitter = new CustomEventEmitter(); ⏎̸ | |||