package websocket import ( "encoding/json" "time" "github.com/google/uuid" ) // INT-014: Standardized WebSocket message format // MessageType represents the type of WebSocket message type MessageType string const ( // Connection messages MessageTypePing MessageType = "ping" MessageTypePong MessageType = "pong" MessageTypeError MessageType = "error" // Subscription messages MessageTypeSubscribe MessageType = "subscribe" MessageTypeUnsubscribe MessageType = "unsubscribe" MessageTypeSubscribed MessageType = "subscribed" MessageTypeUnsubscribed MessageType = "unsubscribed" // Chat messages MessageTypeChatMessage MessageType = "chat_message" MessageTypeTyping MessageType = "typing" MessageTypeReadReceipt MessageType = "read_receipt" MessageTypeUserJoined MessageType = "user_joined" MessageTypeUserLeft MessageType = "user_left" MessageTypeConversationUpdated MessageType = "conversation_updated" // Playback messages MessageTypePlaybackState MessageType = "playback_state" MessageTypePlaybackSync MessageType = "playback_sync" MessageTypeAnalyticsUpdate MessageType = "analytics_update" MessageTypeStatsUpdate MessageType = "stats_update" // Notification messages MessageTypeNotification MessageType = "notification" ) // WebSocketMessage represents a standardized WebSocket message format // INT-014: All WebSocket messages follow this structure type WebSocketMessage struct { // Message identification ID string `json:"id,omitempty"` // Unique message ID (UUID) Type string `json:"type"` // Message type (required) Timestamp string `json:"timestamp"` // ISO 8601 timestamp (RFC3339) // Message data Data interface{} `json:"data,omitempty"` // Message payload (optional) // Error information (for error messages) Error *MessageError `json:"error,omitempty"` // Error details (for error type messages) // Context information RequestID string `json:"request_id,omitempty"` // Request ID for correlation UserID string `json:"user_id,omitempty"` // User ID (if applicable) TrackID string `json:"track_id,omitempty"` // Track ID (if applicable) ConversationID string `json:"conversation_id,omitempty"` // Conversation ID (if applicable) } // MessageError represents error information in WebSocket messages type MessageError struct { Code int `json:"code"` // Error code Message string `json:"message"` // Error message Details map[string]interface{} `json:"details,omitempty"` // Additional error details } // NewWebSocketMessage creates a new WebSocket message with standardized format func NewWebSocketMessage(msgType MessageType, data interface{}) *WebSocketMessage { return &WebSocketMessage{ ID: uuid.New().String(), Type: string(msgType), Timestamp: time.Now().UTC().Format(time.RFC3339), Data: data, } } // NewErrorMessage creates a new error WebSocket message func NewErrorMessage(code int, message string, details map[string]interface{}) *WebSocketMessage { return &WebSocketMessage{ ID: uuid.New().String(), Type: string(MessageTypeError), Timestamp: time.Now().UTC().Format(time.RFC3339), Error: &MessageError{ Code: code, Message: message, Details: details, }, } } // WithRequestID sets the request ID for correlation func (m *WebSocketMessage) WithRequestID(requestID string) *WebSocketMessage { m.RequestID = requestID return m } // WithUserID sets the user ID func (m *WebSocketMessage) WithUserID(userID string) *WebSocketMessage { m.UserID = userID return m } // WithTrackID sets the track ID func (m *WebSocketMessage) WithTrackID(trackID string) *WebSocketMessage { m.TrackID = trackID return m } // WithConversationID sets the conversation ID func (m *WebSocketMessage) WithConversationID(conversationID string) *WebSocketMessage { m.ConversationID = conversationID return m } // ToJSON converts the message to JSON bytes func (m *WebSocketMessage) ToJSON() ([]byte, error) { return json.Marshal(m) } // ParseWebSocketMessage parses a JSON message into WebSocketMessage func ParseWebSocketMessage(data []byte) (*WebSocketMessage, error) { var msg WebSocketMessage if err := json.Unmarshal(data, &msg); err != nil { return nil, err } return &msg, nil } // IsValid checks if the message has required fields func (m *WebSocketMessage) IsValid() bool { return m.Type != "" && m.Timestamp != "" }