1use 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#[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}