Major refactor to library
This commit is contained in:
161
pkg/events/builders.go
Normal file
161
pkg/events/builders.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// WhatsAppConnectedEvent creates a WhatsApp connected event
|
||||
func WhatsAppConnectedEvent(ctx context.Context, accountID string, phoneNumber string) Event {
|
||||
return NewEvent(ctx, EventWhatsAppConnected, map[string]any{
|
||||
"account_id": accountID,
|
||||
"phone_number": phoneNumber,
|
||||
})
|
||||
}
|
||||
|
||||
// WhatsAppDisconnectedEvent creates a WhatsApp disconnected event
|
||||
func WhatsAppDisconnectedEvent(ctx context.Context, accountID string, reason string) Event {
|
||||
return NewEvent(ctx, EventWhatsAppDisconnected, map[string]any{
|
||||
"account_id": accountID,
|
||||
"reason": reason,
|
||||
})
|
||||
}
|
||||
|
||||
// WhatsAppPairSuccessEvent creates a WhatsApp pair success event
|
||||
func WhatsAppPairSuccessEvent(ctx context.Context, accountID string) Event {
|
||||
return NewEvent(ctx, EventWhatsAppPairSuccess, map[string]any{
|
||||
"account_id": accountID,
|
||||
})
|
||||
}
|
||||
|
||||
// WhatsAppPairFailedEvent creates a WhatsApp pair failed event
|
||||
func WhatsAppPairFailedEvent(ctx context.Context, accountID string, err error) Event {
|
||||
return NewEvent(ctx, EventWhatsAppPairFailed, map[string]any{
|
||||
"account_id": accountID,
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// WhatsAppQRCodeEvent creates a WhatsApp QR code event
|
||||
func WhatsAppQRCodeEvent(ctx context.Context, accountID string, qrCode string) Event {
|
||||
return NewEvent(ctx, EventWhatsAppQRCode, map[string]any{
|
||||
"account_id": accountID,
|
||||
"qr_code": qrCode,
|
||||
})
|
||||
}
|
||||
|
||||
// WhatsAppQRTimeoutEvent creates a WhatsApp QR timeout event
|
||||
func WhatsAppQRTimeoutEvent(ctx context.Context, accountID string) Event {
|
||||
return NewEvent(ctx, EventWhatsAppQRTimeout, map[string]any{
|
||||
"account_id": accountID,
|
||||
})
|
||||
}
|
||||
|
||||
// WhatsAppQRErrorEvent creates a WhatsApp QR error event
|
||||
func WhatsAppQRErrorEvent(ctx context.Context, accountID string, err error) Event {
|
||||
return NewEvent(ctx, EventWhatsAppQRError, map[string]any{
|
||||
"account_id": accountID,
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// WhatsAppPairEventGeneric creates a generic WhatsApp pairing event
|
||||
func WhatsAppPairEventGeneric(ctx context.Context, accountID string, eventName string, data map[string]any) Event {
|
||||
eventData := map[string]any{
|
||||
"account_id": accountID,
|
||||
"event": eventName,
|
||||
}
|
||||
for k, v := range data {
|
||||
eventData[k] = v
|
||||
}
|
||||
return NewEvent(ctx, EventWhatsAppPairEvent, eventData)
|
||||
}
|
||||
|
||||
// MessageReceivedEvent creates a message received event
|
||||
func MessageReceivedEvent(ctx context.Context, accountID, messageID, from, to, text string, timestamp time.Time, isGroup bool, groupName, senderName, messageType, mimeType, filename, mediaBase64, mediaURL string) Event {
|
||||
return NewEvent(ctx, EventMessageReceived, map[string]any{
|
||||
"account_id": accountID,
|
||||
"message_id": messageID,
|
||||
"from": from,
|
||||
"to": to,
|
||||
"text": text,
|
||||
"timestamp": timestamp,
|
||||
"is_group": isGroup,
|
||||
"group_name": groupName,
|
||||
"sender_name": senderName,
|
||||
"message_type": messageType,
|
||||
"mime_type": mimeType,
|
||||
"filename": filename,
|
||||
"media_base64": mediaBase64,
|
||||
"media_url": mediaURL,
|
||||
})
|
||||
}
|
||||
|
||||
// MessageSentEvent creates a message sent event
|
||||
func MessageSentEvent(ctx context.Context, accountID, messageID, to, text string) Event {
|
||||
return NewEvent(ctx, EventMessageSent, map[string]any{
|
||||
"account_id": accountID,
|
||||
"message_id": messageID,
|
||||
"to": to,
|
||||
"text": text,
|
||||
})
|
||||
}
|
||||
|
||||
// MessageFailedEvent creates a message failed event
|
||||
func MessageFailedEvent(ctx context.Context, accountID, to, text string, err error) Event {
|
||||
return NewEvent(ctx, EventMessageFailed, map[string]any{
|
||||
"account_id": accountID,
|
||||
"to": to,
|
||||
"text": text,
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
// MessageDeliveredEvent creates a message delivered event
|
||||
func MessageDeliveredEvent(ctx context.Context, accountID, messageID, from string, timestamp time.Time) Event {
|
||||
return NewEvent(ctx, EventMessageDelivered, map[string]any{
|
||||
"account_id": accountID,
|
||||
"message_id": messageID,
|
||||
"from": from,
|
||||
"timestamp": timestamp,
|
||||
})
|
||||
}
|
||||
|
||||
// MessageReadEvent creates a message read event
|
||||
func MessageReadEvent(ctx context.Context, accountID, messageID, from string, timestamp time.Time) Event {
|
||||
return NewEvent(ctx, EventMessageRead, map[string]any{
|
||||
"account_id": accountID,
|
||||
"message_id": messageID,
|
||||
"from": from,
|
||||
"timestamp": timestamp,
|
||||
})
|
||||
}
|
||||
|
||||
// HookTriggeredEvent creates a hook triggered event
|
||||
func HookTriggeredEvent(ctx context.Context, hookID, hookName, url string, payload any) Event {
|
||||
return NewEvent(ctx, EventHookTriggered, map[string]any{
|
||||
"hook_id": hookID,
|
||||
"hook_name": hookName,
|
||||
"url": url,
|
||||
"payload": payload,
|
||||
})
|
||||
}
|
||||
|
||||
// HookSuccessEvent creates a hook success event
|
||||
func HookSuccessEvent(ctx context.Context, hookID, hookName string, statusCode int, response any) Event {
|
||||
return NewEvent(ctx, EventHookSuccess, map[string]any{
|
||||
"hook_id": hookID,
|
||||
"hook_name": hookName,
|
||||
"status_code": statusCode,
|
||||
"response": response,
|
||||
})
|
||||
}
|
||||
|
||||
// HookFailedEvent creates a hook failed event
|
||||
func HookFailedEvent(ctx context.Context, hookID, hookName string, err error) Event {
|
||||
return NewEvent(ctx, EventHookFailed, map[string]any{
|
||||
"hook_id": hookID,
|
||||
"hook_name": hookName,
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
161
pkg/events/events.go
Normal file
161
pkg/events/events.go
Normal file
@@ -0,0 +1,161 @@
|
||||
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,
|
||||
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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user