cal_core/device/
client.rs

1// Filename cal-core/src/device/client.rs
2
3use crate::device::device::{Connector, Endpoint, RecordOptions, TranscribeOptions};
4use crate::device::shared::{AiOptions, CallControl};
5use crate::device::utils::{get_caller_id, get_listen, get_transcribe};
6use crate::{format_number, ConnectState, FlowState, NumberFormat, RecordReference};
7use cal_jambonz::dial::TranscribeDial;
8use cal_jambonz::listen::Listen;
9use cal_jambonz::shared::shared::SIPStatus;
10use serde::{Deserialize, Serialize};
11use std::fmt::{Debug, Formatter};
12
13#[derive(Serialize, Deserialize, Clone)]
14#[serde(rename_all = "camelCase")]
15pub struct Client {
16    pub username: String,
17    pub password: String,
18    #[serde(default = "crate::device::shared::build_client_profile")]
19    pub profile: ClientProfile,
20    pub user: Option<RecordReference>,
21    #[serde(default = "crate::device::shared::build_format")]
22    pub format: NumberFormat,
23    #[serde(default = "crate::device::shared::build_present")]
24    pub present: String,
25    #[serde(default = "crate::device::shared::build_country_code")]
26    pub country_code: String,
27    #[serde(default = "crate::device::shared::build_connect_to")]
28    pub on_complete: String,
29    #[serde(default = "crate::device::shared::build_connect_to")]
30    pub on_busy: String,
31    #[serde(default = "crate::device::shared::build_connect_to")]
32    pub on_fail: String,
33    #[serde(default = "crate::device::shared::build_connect_to")]
34    pub on_no_answer: String,
35    #[serde(default = "crate::device::shared::build_ring_time")]
36    pub ring_time: u8,
37    #[serde(default = "crate::device::shared::build_call_time")]
38    pub max_call_time: u16,
39    #[serde(default)]
40    pub transcribe_options: TranscribeOptions,
41    #[serde(default)]
42    pub record_options: RecordOptions,
43    #[serde(default)]
44    pub ai_options: AiOptions,
45    #[serde(default)]
46    pub call_control: CallControl,
47}
48
49impl Endpoint for Client {
50    fn get_caller_id(&self, state: &FlowState) -> String {
51        get_caller_id(&self.format, state)
52    }
53
54    fn get_called_id(&self, state: &FlowState) -> String {
55        let country_code = state.account.country_code();
56        let mut called_id = match state.data.get("to") {
57            Some(dt) => dt.value.clone(),
58            None => state.initial_request.to.clone(),
59        };
60        called_id = format_number(
61            called_id.as_str(),
62            state.account.country_code(),
63            &self.format,
64        );
65        match self.profile {
66            ClientProfile::GenericSoftphone
67            | ClientProfile::CallablePhone
68            | ClientProfile::Avaya
69            | ClientProfile::Generic => called_id,
70            ClientProfile::GenericE164Plus => {
71                format_number(called_id.as_str(), country_code, &NumberFormat::E164Plus)
72            }
73            ClientProfile::AvayaE164 => {
74                format_number(called_id.as_str(), country_code, &NumberFormat::E164)
75            }
76        }
77    }
78
79    fn get_listen(&self, state: &FlowState) -> Option<Listen> {
80        get_listen(&self.record_options, self.ai_options.clone(), state)
81    }
82
83    fn get_transcribe(&self, _state: &FlowState) -> Option<TranscribeDial> {
84        get_transcribe(self.transcribe_options.clone())
85    }
86}
87
88impl Connector for Client {
89    fn get_connect_to(&mut self, state: &mut FlowState) -> ConnectState {
90        match &state.get_dial_status() {
91            Some(status) => match status {
92                SIPStatus::Ok => ConnectState::complete(self.on_complete.as_str()),
93                SIPStatus::RequestTerminated => ConnectState::no_answer(self.on_no_answer.as_str()),
94                SIPStatus::BusyHere | SIPStatus::BusyEverywhere => {
95                    ConnectState::busy(self.on_busy.as_str())
96                }
97                _ => ConnectState::fail(self.on_fail.as_str()),
98            },
99            None => ConnectState::dialling(),
100        }
101    }
102}
103
104#[derive(Serialize, Deserialize, Clone)]
105#[serde(rename_all = "snake_case")]
106pub enum ClientProfile {
107    Generic,
108    GenericE164Plus,
109    GenericSoftphone,
110    CallablePhone,
111    Avaya,
112    AvayaE164,
113}
114
115// Client Debug Implementation
116impl Debug for Client {
117    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
118        f.debug_struct("Client")
119            .field("username", &self.username)
120            .field("password", &"REDACTED")
121            .field("profile", &self.profile)
122            .field("user", &self.user)
123            .field("format", &self.format)
124            .field("present", &self.present)
125            .field("country_code", &self.country_code)
126            .field("on_complete", &self.on_complete)
127            .field("on_busy", &self.on_busy)
128            .field("on_fail", &self.on_fail)
129            .field("on_no_answer", &self.on_no_answer)
130            .field("ring_time", &self.ring_time)
131            .field("max_call_time", &self.max_call_time)
132            .field("transcribe_options", &self.transcribe_options)
133            .field("record_options", &self.record_options)
134            .field("ai_options", &self.ai_options)
135            .field("call_control", &self.call_control)
136            .finish()
137    }
138}
139
140impl Debug for ClientProfile {
141    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
142        match self {
143            ClientProfile::GenericE164Plus => write!(f, "GenericE164Plus"),
144            ClientProfile::CallablePhone => write!(f, "CallablePhone"),
145            ClientProfile::Avaya => write!(f, "Avaya"),
146            ClientProfile::Generic => write!(f, "Generic"),
147            ClientProfile::GenericSoftphone =>  write!(f, "GenericSoftphone"),
148            ClientProfile::AvayaE164 =>  write!(f, "AvayaE164"),
149        }
150    }
151}
152
153impl Debug for NumberFormat {
154    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
155        match self {
156            NumberFormat::National => write!(f, "National"),
157            NumberFormat::E164Plus => write!(f, "E164+"),
158            NumberFormat::E164 => write!(f, "E164"),
159        }
160    }
161}
162