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