package events import ( "context" "sync" "time" ) // EventType represents the type of event type EventType string const ( // WhatsApp connection events EventWhatsAppConnected EventType = "whatsapp.connected" EventWhatsAppDisconnected EventType = "whatsapp.disconnected" EventWhatsAppPairSuccess EventType = "whatsapp.pair.success" EventWhatsAppPairFailed EventType = "whatsapp.pair.failed" EventWhatsAppQRCode EventType = "whatsapp.qr.code" EventWhatsAppQRTimeout EventType = "whatsapp.qr.timeout" EventWhatsAppQRError EventType = "whatsapp.qr.error" EventWhatsAppPairEvent EventType = "whatsapp.pair.event" // WhatsApp message events EventMessageReceived EventType = "message.received" EventMessageSent EventType = "message.sent" EventMessageFailed EventType = "message.failed" EventMessageDelivered EventType = "message.delivered" EventMessageRead EventType = "message.read" // Hook events EventHookTriggered EventType = "hook.triggered" EventHookSuccess EventType = "hook.success" EventHookFailed EventType = "hook.failed" ) // Event represents an event in the system type Event struct { Type EventType `json:"type"` Timestamp time.Time `json:"timestamp"` Data map[string]any `json:"data"` Context context.Context `json:"-"` } // Subscriber is a function that handles events type Subscriber func(event Event) // EventBus manages event publishing and subscription type EventBus struct { subscribers map[EventType][]Subscriber mu sync.RWMutex } // NewEventBus creates a new event bus func NewEventBus() *EventBus { return &EventBus{ subscribers: make(map[EventType][]Subscriber), } } // Subscribe registers a subscriber for a specific event type func (eb *EventBus) Subscribe(eventType EventType, subscriber Subscriber) { eb.mu.Lock() defer eb.mu.Unlock() if eb.subscribers[eventType] == nil { eb.subscribers[eventType] = make([]Subscriber, 0) } eb.subscribers[eventType] = append(eb.subscribers[eventType], subscriber) } // SubscribeAll registers a subscriber for all event types func (eb *EventBus) SubscribeAll(subscriber Subscriber) { eb.mu.Lock() defer eb.mu.Unlock() allTypes := []EventType{ EventWhatsAppConnected, EventWhatsAppDisconnected, EventWhatsAppPairSuccess, EventWhatsAppPairFailed, EventWhatsAppQRCode, EventWhatsAppQRTimeout, EventWhatsAppQRError, EventWhatsAppPairEvent, EventMessageReceived, EventMessageSent, EventMessageFailed, EventMessageDelivered, EventMessageRead, EventHookTriggered, EventHookSuccess, EventHookFailed, } for _, eventType := range allTypes { if eb.subscribers[eventType] == nil { eb.subscribers[eventType] = make([]Subscriber, 0) } eb.subscribers[eventType] = append(eb.subscribers[eventType], subscriber) } } // Publish publishes an event to all subscribers asynchronously func (eb *EventBus) Publish(event Event) { eb.mu.RLock() subscribers := make([]Subscriber, len(eb.subscribers[event.Type])) copy(subscribers, eb.subscribers[event.Type]) eb.mu.RUnlock() // Use event context if available, otherwise background ctx := event.Context if ctx == nil { ctx = context.Background() } for _, subscriber := range subscribers { go func(sub Subscriber, evt Event) { // Check if context is already cancelled select { case <-ctx.Done(): return default: sub(evt) } }(subscriber, event) } } // PublishSync publishes an event to all subscribers synchronously func (eb *EventBus) PublishSync(event Event) { eb.mu.RLock() subscribers := make([]Subscriber, len(eb.subscribers[event.Type])) copy(subscribers, eb.subscribers[event.Type]) eb.mu.RUnlock() // Use event context if available, otherwise background ctx := event.Context if ctx == nil { ctx = context.Background() } for _, subscriber := range subscribers { // Check if context is already cancelled select { case <-ctx.Done(): return default: subscriber(event) } } } // NewEvent creates a new event with the current timestamp and context func NewEvent(ctx context.Context, eventType EventType, data map[string]any) Event { if ctx == nil { ctx = context.Background() } return Event{ Type: eventType, Timestamp: time.Now(), Data: data, Context: ctx, } }