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