166 lines
4.2 KiB
Go
166 lines
4.2 KiB
Go
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,
|
|
}
|
|
}
|