cal_core/device/
device.rs

1// Filename cal-core/src/device/device.rs
2
3use crate::{AsrVendor, ConnectState, FlowState, Region, VoiceServer};
4use std::fmt::{Debug, Formatter};
5use std::sync::Arc;
6
7use cal_jambonz::dial::TranscribeDial;
8use cal_jambonz::listen::Listen;
9
10pub use crate::device::ani_router::ANIRouter;
11pub use crate::device::app_flow::AppFlow;
12pub use crate::device::client::Client;
13pub use crate::device::date_range_router::DateRangeRouter;
14pub use crate::device::day_of_week_router::DayOfWeekRouter;
15pub use crate::device::digit_router::DigitRouter;
16pub use crate::device::dnis_router::DNISRouter;
17pub use crate::device::email::Email;
18pub use crate::device::event::Event;
19pub use crate::device::hunt_group::HuntGroup;
20pub use crate::device::inbound_flow::InboundFlow;
21pub use crate::device::message_ani_router::MessageAniRouter;
22pub use crate::device::message_buttons::MessageButtons;
23pub use crate::device::message_dnis_router::MessageDnisRouter;
24pub use crate::device::message_plugin::MessagePlugin;
25pub use crate::device::message_template::MessageTemplate;
26pub use crate::device::message_text::MessageText;
27pub use crate::device::outbound_flow::OutboundFlow;
28pub use crate::device::play::Play;
29pub use crate::device::plugin::Plugin;
30pub use crate::device::queue::Queue;
31pub use crate::device::remote::Remote;
32pub use crate::device::say::Say;
33pub use crate::device::service::Service;
34pub use crate::device::shared::{RecordOptions, TranscribeOptions};
35pub use crate::device::sip_extension::SipExtension;
36pub use crate::device::sip_gateway::SipGateway;
37pub use crate::device::sms::Sms;
38pub use crate::device::tag_router::TagRouter;
39pub use crate::device::teams::Teams;
40pub use crate::device::time_range_router::TimeRangeRouter;
41pub use crate::device::voicemail::VoiceMail;
42pub use crate::device::whatsapp_flow::WhatsAppFlow;
43pub use crate::zone_router::ZoneRouter;
44use serde::{Deserialize, Deserializer, Serialize};
45use serde_json::Value;
46#[cfg(feature = "openapi")]
47use utoipa::{ToSchema, IntoParams};
48
49use crate::script::Script;
50use crate::tag::Tag;
51
52pub trait Connector {
53    fn get_connect_to(&mut self, state: &mut FlowState) -> ConnectState;
54
55    // Default implementation indicates this is not an endpoint
56    fn is_endpoint(&self) -> bool {
57        false
58    }
59
60    // Whether this device can route to other devices when in connector mode
61    fn supports_routing(&self) -> bool {
62        true
63    }
64}
65
66pub trait BaseDevice {
67    fn get_id(&mut self) -> String;
68    fn get_name(&mut self) -> String;
69    fn get_extension(&mut self) -> u16;
70}
71
72/// Type of device in the telephony system
73#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
74#[cfg_attr(feature = "openapi", derive(ToSchema))]
75#[cfg_attr(feature = "openapi", schema(
76    title ="Enumeration of all available device types in the system",
77    example = "CLIENT"
78))]
79pub enum DeviceType {
80    /// Inbound call flow starting point
81    #[serde(rename = "ROUTE_START")]
82    InboundFlow,
83
84    /// Outbound call flow with pattern matching
85    #[serde(rename = "MATCH_START")]
86    OutboundFlow,
87
88    /// WhatsApp messaging flow
89    #[serde(rename = "WHATSAPP_START")]
90    WhatsAppFlow,
91
92    /// Application flow entry point
93    #[serde(rename = "APP_START")]
94    AppFlow,
95
96    /// Routes based on caller ID (ANI)
97    #[serde(rename = "ANI_ROUTER")]
98    AniRouter,
99
100    /// Routes based on called number (DNIS)
101    #[serde(rename = "DNIS_ROUTER")]
102    DnisRouter,
103
104    /// Routes based on geographic zone
105    #[serde(rename = "ZONE_ROUTER")]
106    ZoneRouter,
107
108    /// Routes based on digit input
109    #[serde(rename = "NUMBER_PLAN")]
110    DigitRouter,
111
112    /// Routes based on time ranges
113    #[serde(rename = "TIME_RANGE_ROUTER")]
114    TimeRangeRouter,
115
116    /// Routes based on day of week
117    #[serde(rename = "DAY_OF_WEEK_ROUTER")]
118    DayOfWeekRouter,
119
120    /// Routes based on date ranges
121    #[serde(rename = "DATE_RANGE_ROUTER")]
122    DateRangeRouter,
123
124    /// Hunt group for distributing calls
125    #[serde(rename = "HUNT_GROUP")]
126    HuntGroup,
127
128    /// Client endpoint device
129    #[serde(rename = "CLIENT")]
130    Client,
131
132    /// Microsoft Teams integration
133    #[serde(rename = "TEAMS")]
134    Teams,
135
136    /// SIP extension endpoint
137    #[serde(rename = "SIP")]
138    SipExtension,
139
140    /// SIP gateway for external connectivity
141    #[serde(rename = "SIP_GATEWAY")]
142    SipGateway,
143
144    /// Remote endpoint
145    #[serde(rename = "REMOTE")]
146    Remote,
147
148    /// Plugin for custom functionality
149    #[serde(rename = "PLUGIN")]
150    Plugin,
151
152    /// Play audio file
153    #[serde(rename = "PLAY")]
154    Play,
155
156    /// Text-to-speech
157    #[serde(rename = "SAY")]
158    Say,
159
160    /// Voicemail system
161    #[serde(rename = "VOICEMAIL")]
162    Voicemail,
163
164    /// Custom script execution
165    #[serde(rename = "SCRIPT")]
166    Script,
167
168    /// Call queue
169    #[serde(rename = "QUEUE")]
170    Queue,
171
172    /// SMS messaging
173    #[serde(rename = "SMS")]
174    Sms,
175
176    /// Email integration
177    #[serde(rename = "EMAIL")]
178    Email,
179
180    /// Tag assignment
181    #[serde(rename = "TAG")]
182    Tag,
183
184    /// Routes based on tags
185    #[serde(rename = "TAG_ROUTER")]
186    TagRouter,
187
188    /// Message plugin for custom messaging
189    #[serde(rename = "MESSAGE_PLUGIN")]
190    MessagePlugin,
191
192    /// Simple text message
193    #[serde(rename = "MESSAGE_TEXT")]
194    MessageText,
195
196    /// Interactive message buttons
197    #[serde(rename = "MESSAGE_BUTTONS")]
198    MessageButtons,
199
200    /// Message template
201    #[serde(rename = "MESSAGE_TEMPLATE")]
202    MessageTemplate,
203
204    /// Message routing based on ANI
205    #[serde(rename = "MESSAGE_ANI_ROUTER")]
206    MessageAniRouter,
207
208    /// Service endpoint
209    #[serde(rename = "SERVICE")]
210    Service,
211}
212
213/// Polymorphic device representation
214#[derive(Serialize, Deserialize, Clone)]
215#[serde(untagged)]
216pub enum Device {
217    InboundFlow(InboundFlow),
218    OutboundFlow(OutboundFlow),
219    WhatsAppFlow(WhatsAppFlow),
220    AppFlow(AppFlow),
221    AniRouter(ANIRouter),
222    DnisRouter(DNISRouter),
223    DigitRouter(DigitRouter),
224    TimeRangeRouter(TimeRangeRouter),
225    DayOfWeekRouter(DayOfWeekRouter),
226    DateRangeRouter(DateRangeRouter),
227    ZoneRouter(ZoneRouter),
228    HuntGroup(HuntGroup),
229    Client(Client),
230    Teams(Teams),
231    SipExtension(SipExtension),
232    SipGateway(SipGateway),
233    Remote(Remote),
234    Plugin(Plugin),
235    Play(Play),
236    Say(Say),
237    Voicemail(VoiceMail),
238    Script(Script),
239    Queue(Queue),
240    Sms(Sms),
241    Email(Email),
242    Tag(Tag),
243    TagRouter(TagRouter),
244    MessagePlugin(MessagePlugin),
245    MessageButtons(MessageButtons),
246    MessageText(MessageText),
247    MessageTemplate(MessageTemplate),
248    MessageAniRouter(MessageAniRouter),
249    Service(Service),
250}
251
252/// Complete device configuration structure
253#[derive(Serialize, Deserialize, Clone)]
254#[cfg_attr(feature = "openapi", derive(ToSchema))]
255#[cfg_attr(feature = "openapi", schema(
256    title ="Device configuration containing all possible device types and their settings",
257    example = json!({
258        "_id": "dev_507f1f77bcf86cd799439011",
259        "type": "CLIENT",
260        "name": "John's Desk Phone",
261        "extension": 1001,
262        "tags": [
263            {
264                "type": "session",
265                "name": "department",
266                "value": "sales"
267            }
268        ],
269        "client": {
270            "username": "john.doe",
271            "password": "encrypted_password",
272            "realm": "sip.example.com"
273        }
274    })
275))]
276#[serde(rename_all = "camelCase")]
277pub struct DeviceStruct {
278    /// Unique device identifier
279    #[serde(rename = "_id")]
280    #[cfg_attr(feature = "openapi", schema(example = "dev_507f1f77bcf86cd799439011"))]
281    pub id: String,
282
283    /// Type of device
284    #[serde(rename = "type")]
285    pub device_type: DeviceType,
286
287    /// Display name for the device
288    #[cfg_attr(feature = "openapi", schema(example = "Reception Phone", min_length = 1))]
289    pub name: String,
290
291    /// Extension number
292    #[serde(deserialize_with = "from_str")]
293    #[cfg_attr(feature = "openapi", schema(example = 1001, minimum = 1, maximum = 9999))]
294    pub extension: u16,
295
296    /// Tags associated with the device
297    #[serde(default)]
298    pub tags: Vec<DeviceTag>,
299
300    /// Inbound flow configuration
301    #[serde(rename = "startRoute")]
302    #[serde(skip_serializing_if = "Option::is_none")]
303    pub start_route: Option<InboundFlow>,
304
305    /// Outbound flow configuration
306    #[serde(rename = "regexRoute")]
307    #[serde(skip_serializing_if = "Option::is_none")]
308    pub regex_route: Option<OutboundFlow>,
309
310    /// Application flow configuration
311    #[serde(rename = "appRoute")]
312    #[serde(skip_serializing_if = "Option::is_none")]
313    pub app_route: Option<AppFlow>,
314
315    /// Digit router configuration
316    #[serde(rename = "numberPlan")]
317    #[serde(skip_serializing_if = "Option::is_none")]
318    pub number_plan: Option<DigitRouter>,
319
320    /// ANI router configuration
321    #[serde(rename = "aniRouter")]
322    #[serde(skip_serializing_if = "Option::is_none")]
323    pub ani_router: Option<ANIRouter>,
324
325    /// DNIS router configuration
326    #[serde(rename = "dnisRouter")]
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub dnis_router: Option<DNISRouter>,
329
330    /// Zone router configuration
331    #[serde(rename = "zoneRouter")]
332    #[serde(skip_serializing_if = "Option::is_none")]
333    pub zone_router: Option<ZoneRouter>,
334
335    /// Tag router configuration
336    #[serde(rename = "tagRouter")]
337    #[serde(skip_serializing_if = "Option::is_none")]
338    pub tag_router: Option<TagRouter>,
339
340    /// Time range router configuration
341    #[serde(rename = "timeRangeRoute")]
342    #[serde(skip_serializing_if = "Option::is_none")]
343    pub time_range_router: Option<TimeRangeRouter>,
344
345    /// Day of week router configuration
346    #[serde(rename = "dayOfWeekRoute")]
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub day_of_week_router: Option<DayOfWeekRouter>,
349
350    /// Date range router configuration
351    #[serde(rename = "dateRangeRoute")]
352    #[serde(skip_serializing_if = "Option::is_none")]
353    pub date_range_router: Option<DateRangeRouter>,
354
355    /// Hunt group configuration
356    #[serde(rename = "huntGroup")]
357    #[serde(skip_serializing_if = "Option::is_none")]
358    pub hunt_group: Option<HuntGroup>,
359
360    /// Client device configuration
361    #[serde(rename = "client")]
362    #[serde(skip_serializing_if = "Option::is_none")]
363    pub client: Option<Client>,
364
365    /// Teams integration configuration
366    #[serde(rename = "teams")]
367    #[serde(skip_serializing_if = "Option::is_none")]
368    pub teams: Option<Teams>,
369
370    /// SIP extension configuration
371    #[serde(rename = "sipExtension")]
372    #[serde(skip_serializing_if = "Option::is_none")]
373    pub sip_extension: Option<SipExtension>,
374
375    /// SIP gateway configuration
376    #[serde(rename = "sipGateway")]
377    #[serde(skip_serializing_if = "Option::is_none")]
378    pub sip_gateway: Option<SipGateway>,
379
380    /// Remote endpoint configuration
381    #[serde(rename = "remote")]
382    #[serde(skip_serializing_if = "Option::is_none")]
383    pub remote: Option<Remote>,
384
385    /// Voicemail configuration
386    #[serde(rename = "voicemail")]
387    #[serde(skip_serializing_if = "Option::is_none")]
388    pub voice_mail: Option<VoiceMail>,
389
390    /// Queue configuration
391    #[serde(rename = "queue")]
392    #[serde(skip_serializing_if = "Option::is_none")]
393    pub queue: Option<Queue>,
394
395    /// Plugin configuration
396    #[serde(rename = "plugin")]
397    #[serde(skip_serializing_if = "Option::is_none")]
398    pub plugin: Option<Plugin>,
399
400    /// Service configuration
401    #[serde(rename = "service")]
402    #[serde(skip_serializing_if = "Option::is_none")]
403    pub service: Option<Service>,
404
405    /// Play audio configuration
406    #[serde(rename = "play")]
407    #[serde(skip_serializing_if = "Option::is_none")]
408    pub play: Option<Play>,
409
410    /// Text-to-speech configuration
411    #[serde(rename = "say")]
412    #[serde(skip_serializing_if = "Option::is_none")]
413    pub say: Option<Say>,
414
415    /// Script configuration
416    #[serde(rename = "script")]
417    #[serde(skip_serializing_if = "Option::is_none")]
418    pub script: Option<Script>,
419
420    /// Email configuration
421    #[serde(rename = "email")]
422    #[serde(skip_serializing_if = "Option::is_none")]
423    pub email: Option<Email>,
424
425    /// SMS configuration
426    #[serde(rename = "sms")]
427    #[serde(skip_serializing_if = "Option::is_none")]
428    pub sms: Option<Sms>,
429
430    /// Tag configuration
431    #[serde(rename = "tag")]
432    #[serde(skip_serializing_if = "Option::is_none")]
433    pub tag: Option<Tag>,
434
435    /// Event configuration
436    #[serde(rename = "event")]
437    #[serde(skip_serializing_if = "Option::is_none")]
438    pub event: Option<Event>,
439
440    /// WhatsApp flow configuration
441    #[serde(rename = "whatsAppRoute")]
442    #[serde(skip_serializing_if = "Option::is_none")]
443    pub whats_app_flow: Option<WhatsAppFlow>,
444
445    /// Message plugin configuration
446    #[serde(rename = "messagePlugin")]
447    #[serde(skip_serializing_if = "Option::is_none")]
448    pub message_plugin: Option<MessagePlugin>,
449
450    /// Message text configuration
451    #[serde(rename = "messageText")]
452    #[serde(skip_serializing_if = "Option::is_none")]
453    pub message_text: Option<MessageText>,
454
455    /// Message buttons configuration
456    #[serde(rename = "messageButtons")]
457    #[serde(skip_serializing_if = "Option::is_none")]
458    pub message_buttons: Option<MessageButtons>,
459
460    /// Message template configuration
461    #[serde(rename = "messageTemplate")]
462    #[serde(skip_serializing_if = "Option::is_none")]
463    pub message_template: Option<MessageTemplate>,
464
465    /// Message ANI router configuration
466    #[serde(rename = "messageANIRouter")]
467    #[serde(skip_serializing_if = "Option::is_none")]
468    pub message_ani_router: Option<MessageAniRouter>,
469
470    /// Message DNIS router configuration
471    #[serde(rename = "messageDNISRouter")]
472    #[serde(skip_serializing_if = "Option::is_none")]
473    pub message_dnis_router: Option<MessageDnisRouter>,
474}
475
476/// Custom deserializer for extension field
477fn from_str<'de, D>(deserializer: D) -> Result<u16, D::Error>
478where
479    D: Deserializer<'de>,
480{
481    let value = Value::deserialize(deserializer)?;
482    if value.is_string() {
483        Ok(value.as_str().unwrap().parse().unwrap())
484    } else if value.is_u64() {
485        Ok(value.as_u64().unwrap() as u16)
486    } else if value.is_i64() {
487        Ok(value.as_i64().unwrap() as u16)
488    } else {
489        Err(serde::de::Error::custom("Cannot map extension to u16"))
490    }
491}
492
493impl DeviceStruct {
494    /// Get recording options based on device type
495    pub fn record_options(&self) -> Option<RecordOptions> {
496        match &self.device_type {
497            DeviceType::HuntGroup => self.hunt_group.as_ref().map(|h| h.record_options.clone()),
498            DeviceType::Client => self.client.as_ref().map(|c| c.record_options.clone()),
499            DeviceType::Teams => self.teams.as_ref().map(|t| t.record_options.clone()),
500            DeviceType::SipExtension => self.sip_extension.as_ref().map(|s| s.record_options.clone()),
501            DeviceType::SipGateway => self.sip_gateway.as_ref().map(|s| s.record_options.clone()),
502            DeviceType::Remote => self.remote.as_ref().map(|r| r.record_options.clone()),
503            DeviceType::Plugin => self.plugin.as_ref().map(|p| p.record_options.clone()),
504            DeviceType::Voicemail => self.voice_mail.as_ref().map(|v| v.record_options.clone()),
505            _ => None,
506        }
507    }
508
509    /// Get transcription options based on device type
510    pub fn transcribe_options(&self) -> Option<TranscribeOptions> {
511        match &self.device_type {
512            DeviceType::HuntGroup => self.hunt_group.as_ref().map(|h| h.transcribe_options.clone()),
513            DeviceType::Client => self.client.as_ref().map(|c| c.transcribe_options.clone()),
514            DeviceType::Teams => self.teams.as_ref().map(|t| t.transcribe_options.clone()),
515            DeviceType::SipExtension => self.sip_extension.as_ref().map(|s| s.transcribe_options.clone()),
516            DeviceType::SipGateway => self.sip_gateway.as_ref().map(|s| s.transcribe_options.clone()),
517            DeviceType::Remote => self.remote.as_ref().map(|r| r.transcribe_options.clone()),
518            DeviceType::Plugin => self.plugin.as_ref().map(|p| p.transcribe_options.clone()),
519            DeviceType::Voicemail => self.voice_mail.as_ref().map(|v| v.transcribe_options.clone()),
520            _ => None,
521        }
522    }
523
524    /// Check if device has the given ID
525    pub fn is_id(&self, _id: &str) -> bool {
526        self.id == _id
527    }
528
529    /// Check if device is of the given type
530    pub fn is_device_type(&self, device_type: DeviceType) -> bool {
531        self.device_type == device_type
532    }
533
534    /// Match device by various identifiers
535    pub fn match_device(&self, str: &str) -> bool {
536        let matched = match &self.device_type {
537            DeviceType::InboundFlow => {
538                self.start_route
539                    .as_ref()
540                    .map_or(false, |v| v.ddis.contains(&str.to_string()))
541            }
542            DeviceType::Client => {
543                self.client
544                    .as_ref()
545                    .map_or(false, |v| v.username.eq(str))
546            }
547            DeviceType::SipGateway => {
548                self.sip_gateway
549                    .as_ref()
550                    .map_or(false, |v| v.trunks.contains(&str.to_string()))
551            }
552            _ => false,
553        };
554
555        matched || self.id.eq(str) || self.extension.to_string().eq(str)
556    }
557
558    /// Check if this is an outbound flow device
559    pub fn match_outbound_flow(&self) -> bool {
560        match &self.device_type {
561            DeviceType::OutboundFlow => true,
562            _ => false,
563        }
564    }
565
566    /// Check if device acts as a connector
567    pub fn is_connector(&self) -> bool {
568        vec![
569            DeviceType::InboundFlow,
570            DeviceType::OutboundFlow,
571            DeviceType::AppFlow,
572            DeviceType::WhatsAppFlow,
573            DeviceType::AniRouter,
574            DeviceType::DnisRouter,
575            DeviceType::DigitRouter,
576            DeviceType::TimeRangeRouter,
577            DeviceType::DayOfWeekRouter,
578            DeviceType::DateRangeRouter,
579            DeviceType::Play,
580            DeviceType::Say,
581            DeviceType::Voicemail,
582            DeviceType::Script,
583            DeviceType::Queue,
584            DeviceType::Sms,
585            DeviceType::Email,
586            DeviceType::Tag,
587            DeviceType::TagRouter,
588            DeviceType::Service,
589        ]
590            .contains(&self.device_type)
591    }
592
593    /// Check if device handles calls
594    pub fn is_call_handler(&self) -> bool {
595        vec![
596            DeviceType::HuntGroup,
597            DeviceType::Client,
598            DeviceType::Teams,
599            DeviceType::SipExtension,
600            DeviceType::SipGateway,
601            DeviceType::Remote,
602            DeviceType::Plugin,
603        ]
604            .contains(&self.device_type)
605    }
606}
607
608/// Tag associated with a device
609#[derive(Serialize, Deserialize, Clone)]
610#[cfg_attr(feature = "openapi", derive(ToSchema))]
611#[cfg_attr(feature = "openapi", schema(
612    title ="Tag for categorizing and routing devices",
613    example = json!({
614        "type": "session",
615        "name": "department",
616        "value": "sales"
617    })
618))]
619#[serde(rename_all = "camelCase")]
620pub struct DeviceTag {
621    /// Type of tag (session or global)
622    #[serde(rename = "type")]
623    pub tag_type: TagType,
624
625    /// Tag name/key
626    #[cfg_attr(feature = "openapi", schema(example = "department"))]
627    pub name: String,
628
629    /// Tag value
630    #[cfg_attr(feature = "openapi", schema(example = "sales"))]
631    pub value: String,
632}
633
634/// Tag scope type
635#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
636#[cfg_attr(feature = "openapi", derive(ToSchema))]
637#[cfg_attr(feature = "openapi", schema(
638    title ="Scope of the tag - session-specific or globally available"
639))]
640#[serde(rename_all = "camelCase")]
641pub enum TagType {
642    /// Tag persists for the session only
643    Session,
644    /// Tag is globally available
645    Global,
646}
647
648pub trait Endpoint {
649    fn get_caller_id(&self, state: &FlowState) -> String {
650        state.initial_request.from.clone()
651    }
652    fn get_called_id(&self, state: &FlowState) -> String {
653        state.initial_request.to.clone()
654    }
655    fn get_listen(&self, state: &FlowState) -> Option<Listen>;
656    fn get_proxy(&self, _state: &FlowState, _regions:Vec<Arc<Region>>) -> Option<VoiceServer> {
657        None
658    }
659    fn get_transcribe(&self, _state: &FlowState) -> Option<TranscribeDial> {
660        None
661    }
662}
663
664// New trait for endpoint devices that can terminate calls
665pub trait EndpointDevice: Connector {
666    fn is_endpoint(&self) -> bool {
667        true
668    }
669
670    // This method returns the device type name for logging
671    fn device_type_name(&self) -> &'static str;
672
673    // Whether this endpoint can also act as a connector (for post-dial routing)
674    fn supports_routing(&self) -> bool {
675        false
676    }
677}
678
679//DEBUG
680
681// DeviceType Debug Implementation
682impl Debug for DeviceType {
683    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
684        match self {
685            DeviceType::InboundFlow => write!(f, "InboundFlow"),
686            DeviceType::OutboundFlow => write!(f, "OutboundFlow"),
687            DeviceType::WhatsAppFlow => write!(f, "WhatsAppFlow"),
688            DeviceType::AppFlow => write!(f, "AppFlow"),
689            DeviceType::AniRouter => write!(f, "AniRouter"),
690            DeviceType::DnisRouter => write!(f, "DnisRouter"),
691            DeviceType::DigitRouter => write!(f, "DigitRouter"),
692            DeviceType::TimeRangeRouter => write!(f, "TimeRangeRouter"),
693            DeviceType::DayOfWeekRouter => write!(f, "DayOfWeekRouter"),
694            DeviceType::DateRangeRouter => write!(f, "DateRangeRouter"),
695            DeviceType::ZoneRouter => write!(f, "ZoneRouter"),
696            DeviceType::HuntGroup => write!(f, "HuntGroup"),
697            DeviceType::Client => write!(f, "Client"),
698            DeviceType::Teams => write!(f, "Teams"),
699            DeviceType::SipExtension => write!(f, "SipExtension"),
700            DeviceType::SipGateway => write!(f, "SipGateway"),
701            DeviceType::Remote => write!(f, "Remote"),
702            DeviceType::Plugin => write!(f, "Plugin"),
703            DeviceType::Play => write!(f, "Play"),
704            DeviceType::Say => write!(f, "Say"),
705            DeviceType::Voicemail => write!(f, "Voicemail"),
706            DeviceType::Script => write!(f, "Script"),
707            DeviceType::Queue => write!(f, "Queue"),
708            DeviceType::Sms => write!(f, "Sms"),
709            DeviceType::Email => write!(f, "Email"),
710            DeviceType::Tag => write!(f, "Tag"),
711            DeviceType::TagRouter => write!(f, "TagRouter"),
712            DeviceType::MessagePlugin => write!(f, "MessagePlugin"),
713            DeviceType::MessageText => write!(f, "MessageText"),
714            DeviceType::MessageButtons => write!(f, "MessageButtons"),
715            DeviceType::MessageTemplate => write!(f, "MessageTemplate"),
716            DeviceType::MessageAniRouter => write!(f, "MessageAniRouter"),
717            DeviceType::Service => write!(f, "Service"),
718        }
719    }
720}
721
722// Device Enum Debug Implementation
723impl Debug for Device {
724    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
725        match self {
726            Device::InboundFlow(_) => write!(f, "Device::InboundFlow"),
727            Device::OutboundFlow(_) => write!(f, "Device::OutboundFlow"),
728            Device::WhatsAppFlow(_) => write!(f, "Device::WhatsAppFlow"),
729            Device::AppFlow(_) => write!(f, "Device::AppFlow"),
730            Device::AniRouter(_) => write!(f, "Device::AniRouter"),
731            Device::DnisRouter(_) => write!(f, "Device::DnisRouter"),
732            Device::DigitRouter(_) => write!(f, "Device::DigitRouter"),
733            Device::TimeRangeRouter(_) => write!(f, "Device::TimeRangeRouter"),
734            Device::DayOfWeekRouter(_) => write!(f, "Device::DayOfWeekRouter"),
735            Device::DateRangeRouter(_) => write!(f, "Device::DateRangeRouter"),
736            Device::ZoneRouter(_) => write!(f, "Device::ZoneRouter"),
737            Device::HuntGroup(_) => write!(f, "Device::HuntGroup"),
738            Device::Client(_) => write!(f, "Device::Client"),
739            Device::Teams(_) => write!(f, "Device::Teams"),
740            Device::SipExtension(_) => write!(f, "Device::SipExtension"),
741            Device::SipGateway(_) => write!(f, "Device::SipGateway"),
742            Device::Remote(_) => write!(f, "Device::Remote"),
743            Device::Plugin(_) => write!(f, "Device::Plugin"),
744            Device::Play(_) => write!(f, "Device::Play"),
745            Device::Say(_) => write!(f, "Device::Say"),
746            Device::Voicemail(_) => write!(f, "Device::Voicemail"),
747            Device::Script(_) => write!(f, "Device::Script"),
748            Device::Queue(_) => write!(f, "Device::Queue"),
749            Device::Sms(_) => write!(f, "Device::Sms"),
750            Device::Email(_) => write!(f, "Device::Email"),
751            Device::Tag(_) => write!(f, "Device::Tag"),
752            Device::TagRouter(_) => write!(f, "Device::TagRouter"),
753            Device::MessagePlugin(_) => write!(f, "Device::MessagePlugin"),
754            Device::MessageButtons(_) => write!(f, "Device::MessageButtons"),
755            Device::MessageText(_) => write!(f, "Device::MessageText"),
756            Device::MessageTemplate(_) => write!(f, "Device::MessageTemplate"),
757            Device::MessageAniRouter(_) => write!(f, "Device::MessageAniRouter"),
758            Device::Service(_) => write!(f, "Device::Service"),
759        }
760    }
761}
762
763// DeviceStruct Debug Implementation
764impl Debug for DeviceStruct {
765    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
766        f.debug_struct("DeviceStruct")
767            .field("id", &self.id)
768            .field("device_type", &self.device_type)
769            .field("name", &self.name)
770            .field("extension", &self.extension)
771            .finish_non_exhaustive()
772    }
773}
774
775// TagType Debug Implementation
776impl Debug for TagType {
777    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
778        match self {
779            TagType::Session => write!(f, "Session"),
780            TagType::Global => write!(f, "Global"),
781        }
782    }
783}
784
785// DeviceTag Debug Implementation
786impl Debug for DeviceTag {
787    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
788        f.debug_struct("DeviceTag")
789            .field("tag_type", &self.tag_type)
790            .field("name", &self.name)
791            .field("value", &self.value)
792            .finish()
793    }
794}
795
796// RecordOptions Debug Implementation
797impl Debug for RecordOptions {
798    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
799        f.debug_struct("RecordOptions")
800            .field("enabled", &self.enabled)
801            .field("retention", &self.retention)
802            .field("mix_type", &self.mix_type)
803            .field("sample_rate", &self.sample_rate)
804            .finish()
805    }
806}
807
808// TranscribeOptions Debug Implementation
809impl Debug for TranscribeOptions {
810    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
811        f.debug_struct("TranscribeOptions")
812            .field("enabled", &self.enabled)
813            .field("language", &self.language)
814            .finish()
815    }
816}
817
818// AsrVendor Debug Implementation
819impl Debug for AsrVendor {
820    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
821        match self {
822            AsrVendor::Google => write!(f, "Google"),
823            AsrVendor::Deepgram => write!(f, "DeepGram"),
824            AsrVendor::Microsoft => write!(f, "Microsoft"),
825            AsrVendor::Aws => write!(f, "Aws"),
826            AsrVendor::Ibm => write!(f, "Ibm"),
827            AsrVendor::Nuance => write!(f, "Nuance"),
828            AsrVendor::Nvidia =>write!(f, "Nvidia"),
829            AsrVendor::Soniox => write!(f, "Soniox"),
830        }
831    }
832}