cal_core/device/
client.rs

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