155 lines
4.9 KiB
Go
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)
|
|
}
|
|
} |