cal_core/agent/
status.rs

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