UNPKG

bowling-analysis-system

Version:

A comprehensive system for analyzing bowling techniques using video processing and metrics calculation

182 lines (157 loc) 4.89 kB
/** * Event Bus * * Centralized event system for the application * @module events/EventBus */ /** * @class EventBus * @description Provides a centralized event system with subscription management */ class EventBus { /** * Create a new event bus */ constructor() { this.subscribers = new Map(); this.onceSubscribers = new Map(); this.middlewares = []; } /** * Subscribe to an event * @param {string} event - Event name * @param {Function} handler - Event handler * @param {Object} options - Subscription options * @returns {Function} Unsubscribe function */ subscribe(event, handler, options = {}) { if (!this.subscribers.has(event)) { this.subscribers.set(event, new Set()); } const subscribers = this.subscribers.get(event); subscribers.add(handler); return () => { subscribers.delete(handler); if (subscribers.size === 0) { this.subscribers.delete(event); } }; } /** * Subscribe to an event and unsubscribe after the first occurrence * @param {string} event - Event name * @param {Function} handler - Event handler * @returns {Function} Unsubscribe function */ once(event, handler) { if (!this.onceSubscribers.has(event)) { this.onceSubscribers.set(event, new Set()); } const subscribers = this.onceSubscribers.get(event); subscribers.add(handler); return () => { subscribers.delete(handler); if (subscribers.size === 0) { this.onceSubscribers.delete(event); } }; } /** * Unsubscribe from all events * @param {Function} handler - Event handler */ unsubscribeAll(handler) { // Remove from regular subscribers for (const [event, subscribers] of this.subscribers.entries()) { subscribers.delete(handler); if (subscribers.size === 0) { this.subscribers.delete(event); } } // Remove from once subscribers for (const [event, subscribers] of this.onceSubscribers.entries()) { subscribers.delete(handler); if (subscribers.size === 0) { this.onceSubscribers.delete(event); } } } /** * Add middleware for processing events * @param {Function} middleware - Middleware function * @returns {Function} Remove middleware function */ use(middleware) { this.middlewares.push(middleware); return () => { const index = this.middlewares.indexOf(middleware); if (index !== -1) { this.middlewares.splice(index, 1); } }; } /** * Emit an event * @param {string} event - Event name * @param {*} payload - Event payload * @returns {Promise<void>} */ async emit(event, payload) { // Create event object const eventObj = { name: event, payload, timestamp: Date.now(), cancelled: false }; // Apply middlewares for (const middleware of this.middlewares) { await middleware(eventObj); if (eventObj.cancelled) { return; } } // Notify regular subscribers const subscribers = this.subscribers.get(event) || new Set(); const promises = Array.from(subscribers).map(handler => Promise.resolve().then(() => handler(eventObj.payload, eventObj)) ); // Notify once subscribers const onceSubscribers = this.onceSubscribers.get(event) || new Set(); if (onceSubscribers.size > 0) { const oncePromises = Array.from(onceSubscribers).map(handler => Promise.resolve().then(() => handler(eventObj.payload, eventObj)) ); // Clear once subscribers after calling them this.onceSubscribers.delete(event); promises.push(...oncePromises); } await Promise.all(promises); } /** * Check if an event has subscribers * @param {string} event - Event name * @returns {boolean} True if event has subscribers */ hasSubscribers(event) { const regularSubscribers = this.subscribers.get(event) || new Set(); const onceSubscribers = this.onceSubscribers.get(event) || new Set(); return regularSubscribers.size > 0 || onceSubscribers.size > 0; } /** * Get subscriber count for an event * @param {string} event - Event name * @returns {number} Subscriber count */ subscriberCount(event) { const regularSubscribers = this.subscribers.get(event) || new Set(); const onceSubscribers = this.onceSubscribers.get(event) || new Set(); return regularSubscribers.size + onceSubscribers.size; } } // Create default event bus instance const defaultEventBus = new EventBus(); module.exports = { EventBus, defaultEventBus };