// Package goemitter implements an event emitter pattern similar to Node.js EventEmitter. // It provides a way to register event listeners and emit events with data. // // Basic usage example: // // emitter := goemitter.NewEmitter() // // // Register an event listener // handle := emitter.On("userConnected", func(args ...interface{}) { // user := args[0].(string) // fmt.Printf("User connected: %s\n", user) // }) // // // Emit an event // emitter.Emit("userConnected", "john_doe") // // // Remove the listener when no longer needed // handle.Remove() package goemitter import ( "sync" ) // EventEmitter provides event subscription and publishing functionality. // It is safe for concurrent use thanks to internal synchronization. type EventEmitter struct { callbacks map[string]map[int]func(args ...interface{}) // Persistent event callbacks indexed by ID onceCallbacks map[string][]func(args ...interface{}) // One-time event callbacks lock sync.Mutex // Mutex to ensure thread safety counter int // Counter for generating unique callback IDs } // EventHandle represents a handle to a registered event listener. // It can be used to remove the listener when it's no longer needed. type EventHandle struct { id int // Unique identifier for the callback event string // Event name emitter *EventEmitter // Reference to the parent emitter } // Remove unregisters the event listener associated with this handle. // After removal, the listener will no longer receive events. func (eh *EventHandle) Remove() { eh.emitter.lock.Lock() defer eh.emitter.lock.Unlock() if _, ok := eh.emitter.callbacks[eh.event]; ok { delete(eh.emitter.callbacks[eh.event], eh.id) } } // On registers a new event listener for the specified event. // It returns an EventHandle that can be used to remove the listener later. // The callback function can accept any number of arguments passed during event emission. func (e *EventEmitter) On(event string, callback func(args ...interface{})) *EventHandle { e.lock.Lock() defer e.lock.Unlock() e.counter++ if _, ok := e.callbacks[event]; !ok { e.callbacks[event] = make(map[int]func(args ...interface{})) } e.callbacks[event][e.counter] = callback return &EventHandle{ id: e.counter, event: event, emitter: e, } } // Once registers a one-time event listener for the specified event. // The listener will be automatically removed after being triggered once. // Multiple one-time listeners can be registered for the same event. func (e *EventEmitter) Once(event string, callback func(args ...interface{})) { e.lock.Lock() defer e.lock.Unlock() if _, ok := e.onceCallbacks[event]; !ok { e.onceCallbacks[event] = []func(args ...interface{}){callback} } else { e.onceCallbacks[event] = append(e.onceCallbacks[event], callback) } } // Emit triggers an event asynchronously with the provided arguments. // All registered callbacks for the event will be executed in separate goroutines. // One-time callbacks are cleared after emission. func (e *EventEmitter) Emit(event string, data ...interface{}) { e.lock.Lock() defer e.lock.Unlock() // Execute persistent callbacks asynchronously if callbacks, ok := e.callbacks[event]; ok { for _, callback := range callbacks { go callback(data...) } } // Execute and clear one-time callbacks if onceCallbacks, ok := e.onceCallbacks[event]; ok { for _, callback := range onceCallbacks { go callback(data...) } e.onceCallbacks[event] = []func(args ...interface{}){} } } // EmitSync triggers an event synchronously with the provided arguments. // All registered callbacks for the event will be executed in the current goroutine. // One-time callbacks are cleared after emission. func (e *EventEmitter) EmitSync(event string, data ...interface{}) { e.lock.Lock() defer e.lock.Unlock() // Execute persistent callbacks synchronously if callbacks, ok := e.callbacks[event]; ok { for _, callback := range callbacks { callback(data...) } } // Execute and clear one-time callbacks if onceCallbacks, ok := e.onceCallbacks[event]; ok { for _, callback := range onceCallbacks { callback(data...) } e.onceCallbacks[event] = []func(args ...interface{}){} } } // NewEmitter creates and initializes a new EventEmitter instance. // It initializes the internal maps for storing callbacks and returns // a pointer to the new instance. func NewEmitter() *EventEmitter { ret := &EventEmitter{} ret.callbacks = make(map[string]map[int]func(args ...interface{})) ret.onceCallbacks = make(map[string][]func(args ...interface{})) return ret }