use crate::device::device::{DeviceStruct, DeviceTag};
use crate::{clean_str_parse_country, AccountLite, CodeCache, Region, VoiceServer};
use bson::oid::ObjectId;
use cal_jambonz::rest::{InitialRequest, Request};
use cal_jambonz::shared::shared::SIPStatus;
use cal_jambonz::TenantType;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
pub const HANG_UP_CONNECT: &'static str = "HANGUP";
pub const DEFAULT_TTS_VOICE: &'static str = "en-GB-Standard-B";
pub const DEFAULT_TTS_LANGUAGE: &'static str = "en-GB";
pub const DEFAULT_TTS_VENDOR: &'static str = "google";
pub const DEFAULT_ASR_LANGUAGE: &'static str = "en-GB";
pub const DEFAULT_ASR_VENDOR: &'static str = "google";
pub const DEFAULT_RECORDING_RETENTION: &'static str = "P30D";
pub const DEFAULT_CLIENT_PROFILE: &'static str = "generic_e164_plus";
pub const DEFAULT_COUNTRY_CODE: &'static str = "gb";
pub const DEFAULT_DIGITS_FINISH_KEY: &'static str = "#";
pub const DEFAULT_ENDPOINT_PRESENT: &'static str = "pass-through";
pub const DEFAULT_REMOTE_DESTINATION: &'static str = "[request.tp]";
pub const DEFAULT_VM_FINISH_KEY: &'static str = "#";
pub const DEFAULT_ENDPOINT_FORMAT: &'static str = "e164p";
pub const DEFAULT_TIMEZONE: &'static str = "Europe/London";
pub const DEFAULT_TRUNK_DESCRIPTION: &'static str = "SIP Trunk";
pub const DEFAULT_TRUNK_PORT: u16 = 5060;
pub const DEFAULT_RING_TIME: u8 = 180;
pub const DEFAULT_DIGIT_TIMEOUT: u8 = 10;
pub const DEFAULT_MAX_DIGITS: u8 = 1;
pub const DEFAULT_VM_TIMEOUT: u8 = 30;
pub const DEFAULT_VM_MAX_LENGTH: u8 = 30;
pub const DEFAULT_CALL_TIME: u16 = 14400;
#[derive(Clone)]
pub struct FlowState {
pub base_url: String,
pub initial_request: InitialRequest,
pub current_request: Option<Request>,
pub account: Arc<AccountLite>,
pub region: Arc<Region>,
pub voice_server: VoiceServer,
pub device: Option<Arc<DeviceStruct>>,
pub connect: Option<ConnectState>,
pub tenant_type: TenantType,
pub code: CodeCache,
pub data: HashMap<String, DeviceTag>,
pub connect_states: Vec<ConnectState>,
pub devices: Vec<String>, }
impl FlowState {
const MAX_CONNECT_HISTORY: usize = 20;
const MAX_DEVICE_HISTORY: usize = 20;
pub fn get_country_code(&self) -> &str {
&self.account.environment.country_code
}
pub fn get_from(&self) -> String {
clean_str_parse_country(
self.get_country_code(),
self.initial_request.from.as_str(),
)
}
pub fn get_to(&self) -> String {
clean_str_parse_country(
self.get_country_code(),
self.initial_request.to.as_str(),
)
}
pub fn get_paid_or_from(&self) -> String {
match &self.initial_request.sip.headers.p_asserted_identity {
Some(str) => clean_str_parse_country(self.get_country_code(), str.as_str()),
None => self.get_from(),
}
}
pub fn get_timezone(&self) -> &str {
&self.account.environment.time_zone
}
pub fn get_dial_status(&self) -> Option<SIPStatus> {
match &self.current_request {
Some(request) => match request {
Request::Dial(value) => Some(value.sip_status.clone()),
_ => None,
},
_ => None,
}
}
pub fn get_digits(&self) -> Option<String> {
match &self.current_request {
Some(request) => match request {
Request::Subsequent(value) => value.digits.clone(),
_ => None,
},
_ => None,
}
}
pub fn with_connect_state(mut self, connect: Option<ConnectState>) -> Self {
self.connect = connect.clone();
if let Some(connect_val) = connect {
if self.connect_states.len() < Self::MAX_CONNECT_HISTORY {
self.connect_states.push(connect_val);
}
}
self
}
pub fn with_device(mut self, device: Option<Arc<DeviceStruct>>) -> Self {
if let Some(dev) = &device {
if self.devices.len() < Self::MAX_DEVICE_HISTORY {
self.devices.push(dev.id.clone());
for dt in dev.tags.clone() {
self.data.insert(dt.name.clone(), dt);
}
}
}
self.device = device;
self
}
pub fn find_region(&self, region_id: &str, regions: Vec<Arc<Region>>) -> Option<Arc<Region>> {
regions
.iter()
.find(|r| r.id.to_string() == region_id)
.map(|r| r.clone())
}
pub fn with_request(mut self, request: Request) -> Self {
self.current_request = Some(request);
self
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct SerializableFlowState {
pub base_url: String,
pub initial_request: InitialRequest,
pub current_request: Option<Request>,
pub account_id: String,
pub region_id: ObjectId,
pub voice_server: VoiceServer,
pub device_id: Option<String>,
pub connect: Option<ConnectState>,
pub tenant_type: TenantType,
pub code: CodeCache,
pub data: HashMap<String, DeviceTag>,
pub connect_states: Vec<ConnectState>,
pub device_ids: Vec<String>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct ConnectState {
pub status: ConnectStatus,
pub value: Option<String>,
pub match_value: Option<String>,
pub connect_to: String,
}
impl Debug for ConnectState {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
f.debug_struct("ConnectState")
.field("status", &self.status)
.field("connect_to", &self.connect_to)
.field("value", &self.value)
.field("match_value", &self.match_value)
.finish()
}
}
impl ConnectState {
pub fn complete(connect_to: &str) -> ConnectState {
ConnectState {
connect_to: connect_to.to_string(),
status: ConnectStatus::OnCompleted,
match_value: None,
value: Some("Call Completed".to_string()),
}
}
pub fn fail(connect_to: &str) -> ConnectState {
ConnectState {
connect_to: connect_to.to_string(),
status: ConnectStatus::OnFail,
match_value: None,
value: Some("Call Failed".to_string()),
}
}
pub fn device_error(connect_to: &str) -> ConnectState {
ConnectState {
connect_to: connect_to.to_string(),
status: ConnectStatus::OnFail,
match_value: None,
value: Some("Unknown Device".to_string()),
}
}
pub fn no_answer(connect_to: &str) -> ConnectState {
ConnectState {
connect_to: connect_to.to_string(),
status: ConnectStatus::OnNoAnswer,
match_value: None,
value: Some("No Answer".to_string()),
}
}
pub fn busy(connect_to: &str) -> ConnectState {
ConnectState {
connect_to: connect_to.to_string(),
status: ConnectStatus::OnBusy,
match_value: None,
value: Some("Call Busy".to_string()),
}
}
pub fn waiting() -> ConnectState {
ConnectState {
connect_to: "WAITING".to_string(),
status: ConnectStatus::OnWaiting,
match_value: None,
value: None,
}
}
pub fn dialling() -> ConnectState {
ConnectState {
connect_to: "DIALLING".to_string(),
status: ConnectStatus::OnDialling,
match_value: None,
value: None,
}
}
pub fn matched(
connect_to: &str,
value: Option<String>,
match_value: Option<String>,
) -> ConnectState {
ConnectState {
connect_to: connect_to.to_string(),
status: ConnectStatus::OnMatch,
match_value,
value,
}
}
pub fn default(connect_to: &str, value: Option<String>) -> ConnectState {
ConnectState {
connect_to: connect_to.to_string(),
status: ConnectStatus::OnDefault,
match_value: None,
value,
}
}
}
#[derive(Serialize, Deserialize, Clone)]
pub enum ConnectStatus {
OnDefault,
OnMatch,
OnCompleted,
OnFail,
OnBusy,
OnNoAnswer,
OnTransfer,
OnError,
OnWaiting,
OnDialling,
OnDeviceFailure
}
impl Debug for ConnectStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
ConnectStatus::OnMatch => write!(f, "OnMatch"),
ConnectStatus::OnDefault => write!(f, "OnDefault"),
ConnectStatus::OnCompleted => write!(f, "OnCompleted"),
ConnectStatus::OnFail => write!(f, "OnFail"),
ConnectStatus::OnNoAnswer => write!(f, "OnNoAnswer"),
ConnectStatus::OnBusy => write!(f, "OnBusy"),
ConnectStatus::OnWaiting => write!(f, "OnWaiting"),
ConnectStatus::OnDialling => write!(f, "OnDialling"),
_ => {
write!(f, "Unknown")
}
}
}
}