Files
gochat/internal/dispatch/event.go
T
2026-06-04 15:44:48 +08:00

155 lines
4.9 KiB
Go

package dispatch
// Event types and helper functions for the enhanced dispatch system.
//
// Reference: Chatwoot event naming conventions
// - Chatwoot uses Wisper-style event names like "conversation.created",
// "message.created", "contact.created", etc.
// - In gochat, channel.EventType already defines these constants.
// - This file provides additional event types specific to the dispatch layer
// and helper functions for event construction.
import (
"fmt"
"time"
"github.com/gochat/gochat/internal/channel"
)
// DispatchEvent defines additional event types specific to the dispatch layer.
// These complement the channel.EventType constants already defined in
// channel/event.go.
type DispatchEvent string
const (
// Auto-assignment events (triggered by autoassignment listener)
DispatchEventAutoAssign DispatchEvent = "auto_assignment.assign"
DispatchEventAutoAssignFailed DispatchEvent = "auto_assignment.assign_failed"
DispatchEventAutoAssignSkipped DispatchEvent = "auto_assignment.assign_skipped"
// Reporting events (for analytics and reporting)
DispatchEventReportGenerated DispatchEvent = "report.generated"
DispatchEventReportFailed DispatchEvent = "report.failed"
// CSAT survey events
DispatchEventCsatSurveySent DispatchEvent = "csat_survey.sent"
DispatchEventCsatResponseReceived DispatchEvent = "csat_survey.response_received"
// Campaign events
DispatchEventCampaignStarted DispatchEvent = "campaign.started"
DispatchEventCampaignCompleted DispatchEvent = "campaign.completed"
// Webhook/hook events
DispatchEventHookTriggered DispatchEvent = "hook.triggered"
DispatchEventWebhookSent DispatchEvent = "webhook.sent"
DispatchEventWebhookFailed DispatchEvent = "webhook.failed"
)
// NewChannelEvent creates a ChannelEvent with the given type and data.
// Timestamp is set to the current Unix milliseconds.
func NewChannelEvent(eventType string, data map[string]interface{}) *channel.ChannelEvent {
if data == nil {
data = make(map[string]interface{})
}
return &channel.ChannelEvent{
Type: channel.EventType(eventType),
Data: data,
Timestamp: time.Now().UnixMilli(),
}
}
// NewDispatchEvent creates a ChannelEvent from a DispatchEvent type.
func NewDispatchEvent(eventType DispatchEvent, data map[string]interface{}) *channel.ChannelEvent {
return NewChannelEvent(string(eventType), data)
}
// EventDataWithConversation creates event data containing a conversation ID.
// This is a common pattern where events need to reference a specific conversation.
func EventDataWithConversation(conversationID uint, accountID uint, inboxID uint) map[string]interface{} {
return map[string]interface{}{
"conversation_id": conversationID,
"account_id": accountID,
"inbox_id": inboxID,
}
}
// EventDataWithAssignment creates event data for an assignment event,
// including the agent who was assigned.
func EventDataWithAssignment(conversationID uint, accountID uint, inboxID uint, assigneeID uint) map[string]interface{} {
data := EventDataWithConversation(conversationID, accountID, inboxID)
data["assignee_id"] = assigneeID
return data
}
// ExtractConversationID extracts a conversation ID from event data.
// Returns 0 and an error if not found or not a valid uint.
func ExtractConversationID(data map[string]interface{}) (uint, error) {
raw, ok := data["conversation_id"]
if !ok {
return 0, fmt.Errorf("conversation_id not found in event data")
}
switch v := raw.(type) {
case uint:
return v, nil
case int:
return uint(v), nil
case float64:
return uint(v), nil
default:
return 0, fmt.Errorf("unexpected type for conversation_id: %T", raw)
}
}
// ExtractAccountID extracts an account ID from event data.
func ExtractAccountID(data map[string]interface{}) (uint, error) {
raw, ok := data["account_id"]
if !ok {
return 0, fmt.Errorf("account_id not found in event data")
}
switch v := raw.(type) {
case uint:
return v, nil
case int:
return uint(v), nil
case float64:
return uint(v), nil
default:
return 0, fmt.Errorf("unexpected type for account_id: %T", raw)
}
}
// ExtractInboxID extracts an inbox ID from event data.
func ExtractInboxID(data map[string]interface{}) (uint, error) {
raw, ok := data["inbox_id"]
if !ok {
return 0, fmt.Errorf("inbox_id not found in event data")
}
switch v := raw.(type) {
case uint:
return v, nil
case int:
return uint(v), nil
case float64:
return uint(v), nil
default:
return 0, fmt.Errorf("unexpected type for inbox_id: %T", raw)
}
}
// ExtractAssigneeID extracts an assignee (agent) ID from event data.
func ExtractAssigneeID(data map[string]interface{}) (uint, error) {
raw, ok := data["assignee_id"]
if !ok {
return 0, fmt.Errorf("assignee_id not found in event data")
}
switch v := raw.(type) {
case uint:
return v, nil
case int:
return uint(v), nil
case float64:
return uint(v), nil
default:
return 0, fmt.Errorf("unexpected type for assignee_id: %T", raw)
}
}