use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentStatus {
pub user_id: String,
pub account_id: String,
pub agent_name: String,
pub agent_status: String,
pub registration: Option<UserRegistration>,
pub user_call_status: Option<UserCallStatus>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserRegistration {
pub registered: bool,
pub registration_time: Option<i64>,
pub sip_uri: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserCallStatus {
pub status: String,
pub state: Option<SipSessionState>,
pub start_time: Option<i64>,
pub answer_time: Option<i64>,
pub remote_party: Option<String>,
pub call_sid: Option<String>,
pub direction: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SipSessionState {
pub state: String,
pub end_state: Option<EndState>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EndState {
pub status: String,
pub cause: Option<String>,
}
impl AgentStatus {
pub fn is_registered(&self) -> bool {
self.registration
.as_ref()
.map(|r| r.registered)
.unwrap_or(false)
}
pub fn get_agent_name(&self) -> &str {
self.agent_name.as_str()
}
pub fn get_user_presence(&self) -> &str {
&self.agent_status.as_str()
}
pub fn is_available(&self) -> bool {
self.get_user_presence() == "available"
}
pub fn get_call_presence(&self) -> String {
self.user_call_status
.as_ref()
.and_then(|status| {
if status.status != "ended" {
Some(status.status.clone())
} else {
None
}
})
.unwrap_or_else(|| self.get_user_presence().to_string())
}
pub fn get_user_presence_title(&self) -> String {
let presence = self.get_user_presence();
if let Some(first_char) = presence.chars().next() {
first_char.to_uppercase().collect::<String>() + &presence[1..]
} else {
presence.to_string()
}
}
pub fn is_active(&self) -> bool {
self.user_call_status
.as_ref()
.map(|status| status.is_active())
.unwrap_or(false)
}
pub fn is_not_active(&self) -> bool {
!self.is_active()
}
pub fn get_start_time(&self) -> i64 {
self.user_call_status
.as_ref()
.and_then(|status| status.start_time)
.unwrap_or_else(|| chrono::Utc::now().timestamp_millis())
}
pub fn get_answer_time(&self) -> i64 {
self.user_call_status
.as_ref()
.and_then(|status| status.answer_time)
.unwrap_or_else(|| chrono::Utc::now().timestamp_millis())
}
pub fn get_remote_party(&self) -> Option<&str> {
self.user_call_status
.as_ref()
.and_then(|status| status.remote_party.as_deref())
}
pub fn get_failed_reason(&self) -> Option<String> {
self.user_call_status
.as_ref()
.and_then(|status| status.state.as_ref())
.and_then(|state| state.end_state.as_ref())
.and_then(|end_state| end_state.cause.clone())
}
pub fn get_failed(&self) -> bool {
self.user_call_status
.as_ref()
.and_then(|status| status.state.as_ref())
.and_then(|state| state.end_state.as_ref())
.map(|end_state| end_state.status == "failed")
.unwrap_or(false)
}
}
impl UserRegistration {
pub fn is_registered(&self) -> bool {
self.registered
}
}
impl UserCallStatus {
pub fn is_active(&self) -> bool {
matches!(self.status.as_str(), "active" | "ringing" | "in-progress" | "connected")
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentStatusUpdate {
pub agent_id: String,
pub new_status: AgentStatusType,
pub reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AgentStatusType {
Available,
Busy,
Away,
Offline,
Break,
Lunch,
Training,
Meeting,
}