// Package realtime implements the WebSocket hub: real-time delivery of // conversation events (messages, typing, presence, read receipts). package realtime import ( "encoding/json" "time" ) // Event type constants sent over the wire. const ( EventMessageCreated = "message.created" EventTyping = "typing" EventPresence = "presence" EventRead = "read" EventConversationAdded = "conversation.added" EventConversationRemoved = "conversation.removed" EventMemberAdded = "member.added" EventMemberRemoved = "member.removed" EventReactionAdded = "reaction.added" EventReactionRemoved = "reaction.removed" ) // Presence status values. const ( StatusOnline = "online" StatusOffline = "offline" ) // MessageCreated is published when a message is stored. type MessageCreated struct { TempID string `json:"temp_id,omitempty"` ConversationID int64 `json:"conversation_id"` MessageID int64 `json:"message_id"` SenderID int64 `json:"sender_id"` Body string `json:"body"` MediaID *int64 `json:"media_id,omitempty"` Media *MediaInfo `json:"media,omitempty"` CreatedAt time.Time `json:"created_at"` } // MediaInfo mirrors attachment metadata delivered with a message event. type MediaInfo struct { ID int64 `json:"id"` Filename string `json:"filename"` ContentType string `json:"content_type"` Size int64 `json:"size"` URL string `json:"url"` ThumbURL string `json:"thumb_url,omitempty"` } // Typing is published when a user starts or stops typing in a conversation. type Typing struct { ConversationID int64 `json:"conversation_id"` UserID int64 `json:"user_id"` IsTyping bool `json:"is_typing"` } // Presence is published when a user comes online or goes offline. type Presence struct { UserID int64 `json:"user_id"` Status string `json:"status"` } // Read is published when a user marks messages in a conversation as read. type Read struct { ConversationID int64 `json:"conversation_id"` UserID int64 `json:"user_id"` MessageID int64 `json:"message_id"` } // ConversationChanged is sent to a user when they gain or lose a conversation. type ConversationChanged struct { ConversationID int64 `json:"conversation_id"` } // MemberChanged is published when a user joins or leaves a conversation. type MemberChanged struct { ConversationID int64 `json:"conversation_id"` UserID int64 `json:"user_id"` } // ReactionChanged is published when a reaction is added to or removed from a message. type ReactionChanged struct { ConversationID int64 `json:"conversation_id"` MessageID int64 `json:"message_id"` UserID int64 `json:"user_id"` Emoji string `json:"emoji"` } // envelope is the wire format for every message, both inbound and outbound. type envelope struct { Type string `json:"type"` Data json.RawMessage `json:"data"` } // clientTyping is sent by the client to signal typing state. type clientTyping struct { ConversationID int64 `json:"conversation_id"` IsTyping bool `json:"is_typing"` } // clientRead is sent by the client to mark messages as read. type clientRead struct { ConversationID int64 `json:"conversation_id"` MessageID int64 `json:"message_id"` }