Files
whatshooked/pkg/events/events.go
Hein a7a5831911
Some checks failed
CI / Test (1.23) (push) Failing after -24m15s
CI / Test (1.22) (push) Failing after -24m12s
CI / Build (push) Successful in -26m47s
CI / Lint (push) Successful in -26m36s
feat(whatsapp): 🎉 Add extended sending and template management
* Implemented new endpoints for sending various message types:
  - Audio
  - Sticker
  - Location
  - Contacts
  - Interactive messages
  - Template messages
  - Flow messages
  - Reactions
  - Marking messages as read

* Added template management endpoints:
  - List templates
  - Upload templates
  - Delete templates

* Introduced flow management endpoints:
  - List flows
  - Create flows
  - Get flow details
  - Upload flow assets
  - Publish flows
  - Delete flows

* Added phone number management endpoints:
  - List phone numbers
  - Request verification code
  - Verify code

* Enhanced media management with delete media endpoint.

* Updated dependencies.
2026-02-03 18:07:42 +02:00

170 lines
4.3 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"
// Template events
EventTemplateStatusUpdate EventType = "template.status_update"
// 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,
EventTemplateStatusUpdate,
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,
}
}