cal_core/agent/
status.rs

1// File: cal-core/src/agent/status.rs
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct AgentStatus {
7    pub user_id: String,
8    pub account_id: String,
9    pub agent_name: String,
10    pub agent_status: String,
11    pub registration: Option<UserRegistration>,
12    pub user_call_status: Option<UserCallStatus>,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct UserRegistration {
17    pub registered: bool,
18    pub registration_time: Option<i64>,
19    pub sip_uri: Option<String>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct UserCallStatus {
24    pub status: String,
25    pub state: Option<SipSessionState>,
26    pub start_time: Option<i64>,
27    pub answer_time: Option<i64>,
28    pub remote_party: Option<String>,
29    pub call_sid: Option<String>,
30    pub direction: Option<String>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct SipSessionState {
35    pub state: String,
36    pub end_state: Option<EndState>,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct EndState {
41    pub status: String,
42    pub cause: Option<String>,
43}
44
45impl AgentStatus {
46
47    pub fn is_registered(&self) -> bool {
48        self.registration
49            .as_ref()
50            .map(|r| r.registered)
51            .unwrap_or(false)
52    }
53
54    pub fn get_agent_name(&self) -> &str {
55        self.agent_name.as_str()
56    }
57
58    pub fn get_user_presence(&self) -> &str {
59        &self.agent_status.as_str()
60    }
61
62    pub fn is_available(&self) -> bool {
63        self.get_user_presence() == "available"
64    }
65
66    pub fn get_call_presence(&self) -> String {
67        self.user_call_status
68            .as_ref()
69            .and_then(|status| {
70                if status.status != "ended" {
71                    Some(status.status.clone())
72                } else {
73                    None
74                }
75            })
76            .unwrap_or_else(|| self.get_user_presence().to_string())
77    }
78
79    pub fn get_user_presence_title(&self) -> String {
80        let presence = self.get_user_presence();
81        if let Some(first_char) = presence.chars().next() {
82            first_char.to_uppercase().collect::<String>() + &presence[1..]
83        } else {
84            presence.to_string()
85        }
86    }
87
88    pub fn is_active(&self) -> bool {
89        self.user_call_status
90            .as_ref()
91            .map(|status| status.is_active())
92            .unwrap_or(false)
93    }
94
95    pub fn is_not_active(&self) -> bool {
96        !self.is_active()
97    }
98
99    pub fn get_start_time(&self) -> i64 {
100        self.user_call_status
101            .as_ref()
102            .and_then(|status| status.start_time)
103            .unwrap_or_else(|| chrono::Utc::now().timestamp_millis())
104    }
105
106    pub fn get_answer_time(&self) -> i64 {
107        self.user_call_status
108            .as_ref()
109            .and_then(|status| status.answer_time)
110            .unwrap_or_else(|| chrono::Utc::now().timestamp_millis())
111    }
112
113    pub fn get_remote_party(&self) -> Option<&str> {
114        self.user_call_status
115            .as_ref()
116            .and_then(|status| status.remote_party.as_deref())
117    }
118
119    pub fn get_failed_reason(&self) -> Option<String> {
120        self.user_call_status
121            .as_ref()
122            .and_then(|status| status.state.as_ref())
123            .and_then(|state| state.end_state.as_ref())
124            .and_then(|end_state| end_state.cause.clone())
125    }
126
127    pub fn get_failed(&self) -> bool {
128        self.user_call_status
129            .as_ref()
130            .and_then(|status| status.state.as_ref())
131            .and_then(|state| state.end_state.as_ref())
132            .map(|end_state| end_state.status == "failed")
133            .unwrap_or(false)
134    }
135}
136
137impl UserRegistration {
138    pub fn is_registered(&self) -> bool {
139        self.registered
140    }
141}
142
143impl UserCallStatus {
144    pub fn is_active(&self) -> bool {
145        matches!(self.status.as_str(), "active" | "ringing" | "in-progress" | "connected")
146    }
147}
148
149// Keep the simple update structures
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct AgentStatusUpdate {
152    pub agent_id: String,
153    pub new_status: AgentStatusType,
154    pub reason: Option<String>,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub enum AgentStatusType {
159    Available,
160    Busy,
161    Away,
162    Offline,
163    Break,
164    Lunch,
165    Training,
166    Meeting,
167}