1use crate::device::device::{DeviceStruct, DeviceTag};
2use crate::{clean_str_parse_country, AccountLite, CodeCache, Region, VoiceServer};
3use bson::oid::ObjectId;
4use cal_jambonz::rest::{InitialRequest, Request};
5use cal_jambonz::shared::shared::SIPStatus;
6use cal_jambonz::TenantType;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::fmt::{Debug, Formatter};
10use std::sync::Arc;
11
12pub const HANG_UP_CONNECT: &'static str = "HANGUP";
13pub const DEFAULT_TTS_VOICE: &'static str = "en-GB-Standard-B";
14pub const DEFAULT_TTS_LANGUAGE: &'static str = "en-GB";
15pub const DEFAULT_TTS_VENDOR: &'static str = "google";
16pub const DEFAULT_ASR_LANGUAGE: &'static str = "en-GB";
17pub const DEFAULT_ASR_VENDOR: &'static str = "google";
18pub const DEFAULT_RECORDING_RETENTION: &'static str = "P30D";
19pub const DEFAULT_CLIENT_PROFILE: &'static str = "generic_e164_plus";
20pub const DEFAULT_COUNTRY_CODE: &'static str = "gb";
21pub const DEFAULT_DIGITS_FINISH_KEY: &'static str = "#";
22pub const DEFAULT_ENDPOINT_PRESENT: &'static str = "pass-through";
23pub const DEFAULT_REMOTE_DESTINATION: &'static str = "[request.tp]";
24pub const DEFAULT_VM_FINISH_KEY: &'static str = "#";
25pub const DEFAULT_ENDPOINT_FORMAT: &'static str = "e164p";
26pub const DEFAULT_TIMEZONE: &'static str = "Europe/London";
27pub const DEFAULT_TRUNK_DESCRIPTION: &'static str = "SIP Trunk";
28pub const DEFAULT_TRUNK_PORT: u16 = 5060;
29pub const DEFAULT_RING_TIME: u8 = 180;
30pub const DEFAULT_DIGIT_TIMEOUT: u8 = 10;
31pub const DEFAULT_MAX_DIGITS: u8 = 1;
32pub const DEFAULT_VM_TIMEOUT: u8 = 30;
33pub const DEFAULT_VM_MAX_LENGTH: u8 = 30;
34pub const DEFAULT_CALL_TIME: u16 = 14400;
35
36#[derive(Clone)]
37pub struct FlowState {
38 pub base_url: String,
40 pub initial_request: InitialRequest,
41 pub current_request: Option<Request>,
42
43 pub account: Arc<AccountLite>,
45 pub region: Arc<Region>,
46
47 pub voice_server: VoiceServer,
49
50 pub device: Option<Arc<DeviceStruct>>,
52
53 pub connect: Option<ConnectState>,
55
56 pub tenant_type: TenantType,
58 pub code: CodeCache,
59
60 pub data: HashMap<String, DeviceTag>,
62
63 pub connect_states: Vec<ConnectState>,
65 pub devices: Vec<String>, }
67
68impl FlowState {
69 const MAX_CONNECT_HISTORY: usize = 20;
71 const MAX_DEVICE_HISTORY: usize = 20;
72
73 pub fn get_country_code(&self) -> &str {
75 &self.account.environment.country_code
76 }
77
78 pub fn get_from(&self) -> String {
79 clean_str_parse_country(
80 self.get_country_code(),
81 self.initial_request.from.as_str(),
82 )
83 }
84
85 pub fn get_to(&self) -> String {
86 clean_str_parse_country(
87 self.get_country_code(),
88 self.initial_request.to.as_str(),
89 )
90 }
91
92 pub fn get_paid_or_from(&self) -> String {
93 match &self.initial_request.sip.headers.p_asserted_identity {
94 Some(str) => clean_str_parse_country(self.get_country_code(), str.as_str()),
95 None => self.get_from(),
96 }
97 }
98
99 pub fn get_timezone(&self) -> &str {
100 &self.account.environment.time_zone
101 }
102
103 pub fn get_dial_status(&self) -> Option<SIPStatus> {
104 match &self.current_request {
105 Some(request) => match request {
106 Request::Dial(value) => Some(value.sip_status.clone()),
107 _ => None,
108 },
109 _ => None,
110 }
111 }
112
113 pub fn get_digits(&self) -> Option<String> {
114 match &self.current_request {
115 Some(request) => match request {
116 Request::Subsequent(value) => value.digits.clone(),
117 _ => None,
118 },
119 _ => None,
120 }
121 }
122
123 pub fn with_connect_state(mut self, connect: Option<ConnectState>) -> Self {
125 self.connect = connect.clone();
126 if let Some(connect_val) = connect {
127 if self.connect_states.len() < Self::MAX_CONNECT_HISTORY {
128 self.connect_states.push(connect_val);
129 }
130 }
131 self
132 }
133
134 pub fn with_device(mut self, device: Option<Arc<DeviceStruct>>) -> Self {
136 if let Some(dev) = &device {
137 if self.devices.len() < Self::MAX_DEVICE_HISTORY {
138 self.devices.push(dev.id.clone());
139 for dt in dev.tags.clone() {
140 self.data.insert(dt.name.clone(), dt);
141 }
142 }
143 }
144 self.device = device;
145 self
146 }
147
148 pub fn find_region(&self, region_id: &str, regions: Vec<Arc<Region>>) -> Option<Arc<Region>> {
150 regions
151 .iter()
152 .find(|r| r.id.to_string() == region_id)
153 .map(|r| r.clone())
154 }
155
156 pub fn with_request(mut self, request: Request) -> Self {
158 self.current_request = Some(request);
159 self
160 }
161}
162
163#[derive(Serialize, Deserialize, Clone)]
165pub struct SerializableFlowState {
166 pub base_url: String,
167 pub initial_request: InitialRequest,
168 pub current_request: Option<Request>,
169 pub account_id: String,
170 pub region_id: ObjectId,
171 pub voice_server: VoiceServer,
172 pub device_id: Option<String>,
173 pub connect: Option<ConnectState>,
174 pub tenant_type: TenantType,
175 pub code: CodeCache,
176 pub data: HashMap<String, DeviceTag>,
177 pub connect_states: Vec<ConnectState>,
178 pub device_ids: Vec<String>,
179}
180
181
182#[derive(Serialize, Deserialize, Clone)]
183pub struct ConnectState {
184 pub status: ConnectStatus,
185 pub value: Option<String>,
186 pub match_value: Option<String>,
187 pub connect_to: String,
188}
189
190impl Debug for ConnectState {
191 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
192 f.debug_struct("ConnectState")
193 .field("status", &self.status)
194 .field("connect_to", &self.connect_to)
195 .field("value", &self.value)
196 .field("match_value", &self.match_value)
197 .finish()
198 }
199}
200
201impl ConnectState {
202 pub fn complete(connect_to: &str) -> ConnectState {
203 ConnectState {
204 connect_to: connect_to.to_string(),
205 status: ConnectStatus::OnCompleted,
206 match_value: None,
207 value: Some("Call Completed".to_string()),
208 }
209 }
210 pub fn fail(connect_to: &str) -> ConnectState {
211 ConnectState {
212 connect_to: connect_to.to_string(),
213 status: ConnectStatus::OnFail,
214 match_value: None,
215 value: Some("Call Failed".to_string()),
216 }
217 }
218
219 pub fn device_error(connect_to: &str) -> ConnectState {
220 ConnectState {
221 connect_to: connect_to.to_string(),
222 status: ConnectStatus::OnFail,
223 match_value: None,
224 value: Some("Unknown Device".to_string()),
225 }
226 }
227
228 pub fn no_answer(connect_to: &str) -> ConnectState {
229 ConnectState {
230 connect_to: connect_to.to_string(),
231 status: ConnectStatus::OnNoAnswer,
232 match_value: None,
233 value: Some("No Answer".to_string()),
234 }
235 }
236
237 pub fn busy(connect_to: &str) -> ConnectState {
238 ConnectState {
239 connect_to: connect_to.to_string(),
240 status: ConnectStatus::OnBusy,
241 match_value: None,
242 value: Some("Call Busy".to_string()),
243 }
244 }
245
246 pub fn waiting() -> ConnectState {
247 ConnectState {
248 connect_to: "WAITING".to_string(),
249 status: ConnectStatus::OnWaiting,
250 match_value: None,
251 value: None,
252 }
253 }
254
255 pub fn dialling() -> ConnectState {
256 ConnectState {
257 connect_to: "DIALLING".to_string(),
258 status: ConnectStatus::OnDialling,
259 match_value: None,
260 value: None,
261 }
262 }
263
264 pub fn matched(
265 connect_to: &str,
266 value: Option<String>,
267 match_value: Option<String>,
268 ) -> ConnectState {
269 ConnectState {
270 connect_to: connect_to.to_string(),
271 status: ConnectStatus::OnMatch,
272 match_value,
273 value,
274 }
275 }
276
277 pub fn default(connect_to: &str, value: Option<String>) -> ConnectState {
278 ConnectState {
279 connect_to: connect_to.to_string(),
280 status: ConnectStatus::OnDefault,
281 match_value: None,
282 value,
283 }
284 }
285}
286
287#[derive(Serialize, Deserialize, Clone)]
288pub enum ConnectStatus {
289 OnDefault,
290 OnMatch,
291 OnCompleted,
292 OnFail,
293 OnBusy,
294 OnNoAnswer,
295 OnTransfer,
296 OnError,
297 OnWaiting,
298 OnDialling,
299 OnDeviceFailure
300}
301
302impl Debug for ConnectStatus {
303 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
304 match self {
305 ConnectStatus::OnMatch => write!(f, "OnMatch"),
306 ConnectStatus::OnDefault => write!(f, "OnDefault"),
307 ConnectStatus::OnCompleted => write!(f, "OnCompleted"),
308 ConnectStatus::OnFail => write!(f, "OnFail"),
309 ConnectStatus::OnNoAnswer => write!(f, "OnNoAnswer"),
310 ConnectStatus::OnBusy => write!(f, "OnBusy"),
311 ConnectStatus::OnWaiting => write!(f, "OnWaiting"),
312 ConnectStatus::OnDialling => write!(f, "OnDialling"),
313 _ => {
314 write!(f, "Unknown")
315 }
316 }
317 }
318}