bowling-analysis-system
Version:
A comprehensive system for analyzing bowling techniques using video processing and metrics calculation
182 lines (157 loc) • 4.89 kB
JavaScript
/**
* 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
};