cal_core/
websocket.rs

1// File: cal-core/src/websocket.rs
2
3use serde::{Deserialize, Serialize};
4use chrono::{DateTime, Utc};
5use crate::{RecordReference, agent::{AgentStatus, AgentStatusUpdate}};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8#[serde(tag = "type", content = "data")]
9pub enum WebSocketMessage {
10    // Authentication (required for WebSocket security)
11    Auth(AuthMessage),
12    AuthResponse(AuthResponse),
13
14    // Agent Status
15    AgentStatus(AgentStatus),
16    AgentStatusUpdate(AgentStatusUpdate),
17
18    // Typing Indicators
19    IsTyping(IsTypingMessage),
20    IsTypingUpdate(IsTypingUpdate),
21
22    // Queue
23    QueueGroup(crate::queue::QueueGroup),
24
25    // Conversation
26    ConversationNotification(crate::conversation::ConversationNotification),
27
28    // System
29    Ping,
30    Pong,
31    Error(ErrorMessage),
32    Reconnect(ReconnectMessage),
33}
34
35// ==================== Authentication Messages ====================
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct AuthMessage {
39    pub token: String,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct AuthResponse {
44    pub success: bool,
45    pub user_id: Option<String>,
46    pub agent_id: Option<String>,
47    pub permissions: Vec<String>,
48    pub error: Option<String>,
49}
50
51// ==================== Typing Messages ====================
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct IsTypingMessage {
55    pub account: RecordReference,
56    pub user: RecordReference,
57    pub agent_name: String,
58    pub from: String,
59    pub action: String, // "typing" or "stopped"
60    pub timestamp: i64,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct IsTypingUpdate {
65    pub conversation_id: String,
66    pub user_id: String,
67    pub is_typing: bool,
68    pub timestamp: i64,
69}
70
71// ==================== System Messages ====================
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct ErrorMessage {
75    pub code: String,
76    pub message: String,
77    pub details: Option<serde_json::Value>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct ReconnectMessage {
82    pub reason: String,
83    pub retry_after: u32, // seconds
84}
85
86// ==================== Helper Implementations ====================
87
88impl WebSocketMessage {
89    pub fn ping() -> Self {
90        WebSocketMessage::Ping
91    }
92
93    pub fn pong() -> Self {
94        WebSocketMessage::Pong
95    }
96
97    pub fn error(code: String, message: String) -> Self {
98        WebSocketMessage::Error(ErrorMessage {
99            code,
100            message,
101            details: None,
102        })
103    }
104
105    pub fn is_ping(&self) -> bool {
106        matches!(self, WebSocketMessage::Ping)
107    }
108
109    pub fn is_pong(&self) -> bool {
110        matches!(self, WebSocketMessage::Pong)
111    }
112}