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
49#[derive(Debug, Deserialize)]
50#[cfg_attr(feature = "openapi", derive(ToSchema, IntoParams))]
51pub struct AccountIdQuery {
52    /// Account ID for the operation
53    pub account_id: String,
54}
55use crate::script::Script;
56use crate::tag::Tag;
57
58pub trait Connector {
59
60    fn get_connect_to(&mut self, state: &mut FlowState) -> ConnectState;
61
62    // Default implementation indicates this is not an endpoint
63    fn is_endpoint(&self) -> bool {
64        false
65    }
66
67    // Whether this device can route to other devices when in connector mode
68    fn supports_routing(&self) -> bool {
69        true
70    }
71}
72
73pub trait BaseDevice {
74    fn get_id(&mut self) -> String;
75    fn get_name(&mut self) -> String;
76    fn get_extension(&mut self) -> u16;
77}
78
79#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
80pub enum DeviceType {
81    #[serde(rename = "ROUTE_START")]
82    InboundFlow,
83    #[serde(rename = "MATCH_START")]
84    OutboundFlow,
85    #[serde(rename = "WHATSAPP_START")]
86    WhatsAppFlow,
87    #[serde(rename = "APP_START")]
88    AppFlow,
89    #[serde(rename = "ANI_ROUTER")]
90    AniRouter,
91    #[serde(rename = "DNIS_ROUTER")]
92    DnisRouter,
93    #[serde(rename = "ZONE_ROUTER")]
94    ZoneRouter,
95    #[serde(rename = "NUMBER_PLAN")]
96    DigitRouter,
97    #[serde(rename = "TIME_RANGE_ROUTER")]
98    TimeRangeRouter,
99    #[serde(rename = "DAY_OF_WEEK_ROUTER")]
100    DayOfWeekRouter,
101    #[serde(rename = "DATE_RANGE_ROUTER")]
102    DateRangeRouter,
103    #[serde(rename = "HUNT_GROUP")]
104    HuntGroup,
105    #[serde(rename = "CLIENT")]
106    Client,
107    #[serde(rename = "TEAMS")]
108    Teams,
109    #[serde(rename = "SIP")]
110    SipExtension,
111    #[serde(rename = "SIP_GATEWAY")]
112    SipGateway,
113    #[serde(rename = "REMOTE")]
114    Remote,
115    #[serde(rename = "PLUGIN")]
116    Plugin,
117    #[serde(rename = "PLAY")]
118    Play,
119    #[serde(rename = "SAY")]
120    Say,
121    #[serde(rename = "VOICEMAIL")]
122    Voicemail,
123    #[serde(rename = "SCRIPT")]
124    Script,
125    #[serde(rename = "QUEUE")]
126    Queue,
127    #[serde(rename = "SMS")]
128    Sms,
129    #[serde(rename = "EMAIL")]
130    Email,
131    #[serde(rename = "TAG")]
132    Tag,
133    #[serde(rename = "TAG_ROUTER")]
134    TagRouter,
135    #[serde(rename = "MESSAGE_PLUGIN")]
136    MessagePlugin,
137    #[serde(rename = "MESSAGE_TEXT")]
138    MessageText,
139    #[serde(rename = "MESSAGE_BUTTONS")]
140    MessageButtons,
141    #[serde(rename = "MESSAGE_TEMPLATE")]
142    MessageTemplate,
143    #[serde(rename = "MESSAGE_ANI_ROUTER")]
144    MessageAniRouter,
145    #[serde(rename = "SERVICE")]
146    Service,
147    //todo MESSAGE_BUTTONS, MESSAGE_TEMPLATE
148}
149
150#[derive(Serialize, Deserialize, Clone)]
151#[serde(untagged)]
152pub enum Device {
153    InboundFlow(InboundFlow),
154    OutboundFlow(OutboundFlow),
155    WhatsAppFlow(WhatsAppFlow),
156    AppFlow(AppFlow),
157    AniRouter(ANIRouter),
158    DnisRouter(DNISRouter),
159    DigitRouter(DigitRouter),
160    TimeRangeRouter(TimeRangeRouter),
161    DayOfWeekRouter(DayOfWeekRouter),
162    DateRangeRouter(DateRangeRouter),
163    ZoneRouter(ZoneRouter),
164    HuntGroup(HuntGroup),
165    Client(Client),
166    Teams(Teams),
167    SipExtension(SipExtension),
168    SipGateway(SipGateway),
169    Remote(Remote),
170    Plugin(Plugin),
171    Play(Play),
172    Say(Say),
173    Voicemail(VoiceMail),
174    Script(Script),
175    Queue(Queue),
176    Sms(Sms),
177    Email(Email),
178    Tag(Tag),
179    TagRouter(TagRouter),
180    MessagePlugin(MessagePlugin),
181    MessageButtons(MessageButtons),
182    MessageText(MessageText),
183    MessageTemplate(MessageTemplate),
184    MessageAniRouter(MessageAniRouter),
185    Service(Service),
186}
187
188#[derive(Serialize, Deserialize, Clone)]
189#[cfg_attr(feature = "openapi", derive(ToSchema))]
190#[serde(rename_all = "camelCase")]
191pub struct DeviceStruct {
192    #[serde(rename = "_id")]
193    pub id: String,
194
195    #[serde(rename = "type")]
196    pub device_type: DeviceType,
197
198    pub name: String,
199
200    #[serde(deserialize_with = "from_str")]
201    pub extension: u16,
202
203    #[serde(default)]
204    pub tags: Vec<DeviceTag>,
205
206    #[serde(rename = "startRoute")]
207    #[serde(skip_serializing_if = "Option::is_none")]
208    pub start_route: Option<InboundFlow>,
209
210    #[serde(rename = "regexRoute")]
211    #[serde(skip_serializing_if = "Option::is_none")]
212    pub regex_route: Option<OutboundFlow>,
213
214    #[serde(rename = "appRoute")]
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub app_route: Option<AppFlow>,
217
218    #[serde(rename = "numberPlan")]
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub number_plan: Option<DigitRouter>,
221
222    #[serde(rename = "aniRouter")]
223    #[serde(skip_serializing_if = "Option::is_none")]
224    pub ani_router: Option<ANIRouter>,
225
226    #[serde(rename = "dnisRouter")]
227    #[serde(skip_serializing_if = "Option::is_none")]
228    pub dnis_router: Option<DNISRouter>,
229
230    #[serde(rename = "zoneRouter")]
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub zone_router: Option<ZoneRouter>,
233
234    #[serde(rename = "tagRouter")]
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub tag_router: Option<TagRouter>,
237
238    #[serde(rename = "timeRangeRoute")]
239    #[serde(skip_serializing_if = "Option::is_none")]
240    pub time_range_router: Option<TimeRangeRouter>,
241
242    #[serde(rename = "dayOfWeekRoute")]
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub day_of_week_router: Option<DayOfWeekRouter>,
245
246    #[serde(rename = "dateRangeRoute")]
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub date_range_router: Option<DateRangeRouter>,
249
250    #[serde(rename = "huntGroup")]
251    #[serde(skip_serializing_if = "Option::is_none")]
252    pub hunt_group: Option<HuntGroup>,
253
254    #[serde(rename = "client")]
255    #[serde(skip_serializing_if = "Option::is_none")]
256    pub client: Option<Client>,
257
258    #[serde(rename = "teams")]
259    #[serde(skip_serializing_if = "Option::is_none")]
260    pub teams: Option<Teams>,
261
262    #[serde(rename = "sipExtension")]
263    #[serde(skip_serializing_if = "Option::is_none")]
264    pub sip_extension: Option<SipExtension>,
265
266    #[serde(rename = "sipGateway")]
267    #[serde(skip_serializing_if = "Option::is_none")]
268    pub sip_gateway: Option<SipGateway>,
269
270    #[serde(rename = "remote")]
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub remote: Option<Remote>,
273
274    #[serde(rename = "voicemail")]
275    #[serde(skip_serializing_if = "Option::is_none")]
276    pub voice_mail: Option<VoiceMail>,
277
278    #[serde(rename = "queue")]
279    #[serde(skip_serializing_if = "Option::is_none")]
280    pub queue: Option<Queue>,
281
282    #[serde(rename = "plugin")]
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub plugin: Option<Plugin>,
285
286    #[serde(rename = "service")]
287    #[serde(skip_serializing_if = "Option::is_none")]
288    pub service: Option<Service>,
289
290    #[serde(rename = "play")]
291    #[serde(skip_serializing_if = "Option::is_none")]
292    pub play: Option<Play>,
293
294    #[serde(rename = "say")]
295    #[serde(skip_serializing_if = "Option::is_none")]
296    pub say: Option<Say>,
297
298    #[serde(rename = "script")]
299    #[serde(skip_serializing_if = "Option::is_none")]
300    pub script: Option<Script>,
301
302    #[serde(rename = "email")]
303    #[serde(skip_serializing_if = "Option::is_none")]
304    pub email: Option<Email>,
305
306    #[serde(rename = "sms")]
307    #[serde(skip_serializing_if = "Option::is_none")]
308    pub sms: Option<Sms>,
309
310    #[serde(rename = "tag")]
311    #[serde(skip_serializing_if = "Option::is_none")]
312    pub tag: Option<Tag>,
313
314    #[serde(rename = "event")]
315    #[serde(skip_serializing_if = "Option::is_none")]
316    pub event: Option<Event>,
317
318    #[serde(rename = "whatsAppRoute")]
319    #[serde(skip_serializing_if = "Option::is_none")]
320    pub whats_app_flow: Option<WhatsAppFlow>,
321
322    #[serde(rename = "messagePlugin")]
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub message_plugin: Option<MessagePlugin>,
325
326    #[serde(rename = "messageText")]
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub message_text: Option<MessageText>,
329
330    #[serde(rename = "messageButtons")]
331    #[serde(skip_serializing_if = "Option::is_none")]
332    pub message_buttons: Option<MessageButtons>,
333
334    #[serde(rename = "messageTemplate")]
335    #[serde(skip_serializing_if = "Option::is_none")]
336    pub message_template: Option<MessageTemplate>,
337
338    #[serde(rename = "messageANIRouter")]
339    #[serde(skip_serializing_if = "Option::is_none")]
340    pub message_ani_router: Option<MessageAniRouter>,
341
342    #[serde(rename = "messageDNISRouter")]
343    #[serde(skip_serializing_if = "Option::is_none")]
344    pub message_dnis_router: Option<MessageDnisRouter>,
345}
346
347fn from_str<'de, D>(deserializer: D) -> Result<u16, D::Error>
348where
349    D: Deserializer<'de>,
350{
351    let value = Value::deserialize(deserializer)?;
352    if value.is_string() {
353        Ok(value.as_str().unwrap().parse().unwrap())
354    } else if value.is_u64() {
355        Ok(value.as_u64().unwrap() as u16)
356    } else if value.is_i64() {
357        Ok(value.as_i64().unwrap() as u16)
358    } else {
359        Err(serde::de::Error::custom("Cannot map extension to u16"))
360    }
361}
362
363
364impl DeviceStruct {
365    pub fn record_options(&self) -> Option<RecordOptions> {
366        match &self.device_type {
367            DeviceType::HuntGroup => self.hunt_group.as_ref().map(|h| h.record_options.clone()), // Cloning here
368            DeviceType::Client => self.client.as_ref().map(|c| c.record_options.clone()), // Cloning here
369            DeviceType::Teams => self.teams.as_ref().map(|t| t.record_options.clone()), // Cloning here
370            DeviceType::SipExtension => self.sip_extension.as_ref().map(|s| s.record_options.clone()), // Cloning here
371            DeviceType::SipGateway => self.sip_gateway.as_ref().map(|s| s.record_options.clone()), // Cloning here
372            DeviceType::Remote => self.remote.as_ref().map(|r| r.record_options.clone()), // Cloning here
373            DeviceType::Plugin => self.plugin.as_ref().map(|p| p.record_options.clone()), // Cloning here
374            DeviceType::Voicemail => self.voice_mail.as_ref().map(|v| v.record_options.clone()), // Cloning here
375            _ => None,
376        }
377    }
378
379    pub fn transcribe_options(&self) -> Option<TranscribeOptions> {
380        match &self.device_type {
381            DeviceType::HuntGroup => self.hunt_group.as_ref().map(|h| h.transcribe_options.clone()),
382            DeviceType::Client => self.client.as_ref().map(|c| c.transcribe_options.clone()),
383            DeviceType::Teams => self.teams.as_ref().map(|t| t.transcribe_options.clone()),
384            DeviceType::SipExtension => self.sip_extension.as_ref().map(|s| s.transcribe_options.clone()),
385            DeviceType::SipGateway => self.sip_gateway.as_ref().map(|s| s.transcribe_options.clone()),
386            DeviceType::Remote => self.remote.as_ref().map(|r| r.transcribe_options.clone()),
387            DeviceType::Plugin => self.plugin.as_ref().map(|p| p.transcribe_options.clone()),
388            DeviceType::Voicemail => self.voice_mail.as_ref().map(|v| v.transcribe_options.clone()),
389            _ => None,
390        }
391    }
392
393    pub fn is_id(&self, _id: &str) -> bool {
394        self.id == _id
395    }
396
397    pub fn is_device_type(&self, device_type: DeviceType) -> bool {
398        self.device_type == device_type
399    }
400
401    pub fn match_device(&self, str: &str) -> bool {
402        let matched = match &self.device_type {
403            DeviceType::InboundFlow => {
404                self.start_route
405                    .as_ref()
406                    .map_or(false, |v| v.ddis.contains(&str.to_string()))
407            }
408            DeviceType::Client => {
409                self.client
410                    .as_ref()
411                    .map_or(false, |v| v.username.eq(str))
412            }
413            DeviceType::SipGateway => {
414                self.sip_gateway
415                    .as_ref()
416                    .map_or(false, |v| v.trunks.contains(&str.to_string()))
417            }
418            _ => false,
419        };
420
421        matched || self.id.eq(str) || self.extension.to_string().eq(str)
422    }
423
424    pub fn match_outbound_flow(&self) -> bool {
425        match &self.device_type {
426            DeviceType::OutboundFlow => true,
427            _ => false,
428        }
429    }
430
431    pub fn is_connector(&self) -> bool {
432        vec![
433            DeviceType::InboundFlow,
434            DeviceType::OutboundFlow,
435            DeviceType::AppFlow,
436            DeviceType::WhatsAppFlow,
437            DeviceType::AniRouter,
438            DeviceType::DnisRouter,
439            DeviceType::DigitRouter,
440            DeviceType::TimeRangeRouter,
441            DeviceType::DayOfWeekRouter,
442            DeviceType::DateRangeRouter,
443            DeviceType::Play,
444            DeviceType::Say,
445            DeviceType::Voicemail,
446            DeviceType::Script,
447            DeviceType::Queue,
448            DeviceType::Sms,
449            DeviceType::Email,
450            DeviceType::Tag,
451            DeviceType::TagRouter,
452            DeviceType::Service,
453        ]
454        .contains(&self.device_type)
455    }
456
457    pub fn is_call_handler(&self) -> bool {
458        vec![
459            DeviceType::HuntGroup,
460            DeviceType::Client,
461            DeviceType::Teams,
462            DeviceType::SipExtension,
463            DeviceType::SipGateway,
464            DeviceType::Remote,
465            DeviceType::Plugin,
466        ]
467        .contains(&self.device_type)
468    }
469}
470
471#[derive(Serialize, Deserialize, Clone)]
472#[serde(rename_all = "camelCase")]
473pub struct DeviceTag {
474    #[serde(rename = "type")]
475    pub tag_type: TagType,
476    pub name: String,
477    pub value: String,
478}
479
480#[derive(Serialize, Deserialize, Eq, PartialEq, Clone)]
481#[serde(rename_all = "camelCase")]
482pub enum TagType {
483    Session,
484    Global,
485}
486
487
488pub trait Endpoint {
489    fn get_caller_id(&self, state: &FlowState) -> String {
490        state.initial_request.from.clone()
491    }
492    fn get_called_id(&self, state: &FlowState) -> String {
493        state.initial_request.to.clone()
494    }
495    fn get_listen(&self, state: &FlowState) -> Option<Listen>;
496    fn get_proxy(&self, _state: &FlowState, _regions:Vec<Arc<Region>>) -> Option<VoiceServer> {
497        None
498    }
499    fn get_transcribe(&self, _state: &FlowState) -> Option<TranscribeDial> {
500        None
501    }
502}
503
504
505
506
507// New trait for endpoint devices that can terminate calls
508pub trait EndpointDevice: Connector {
509    fn is_endpoint(&self) -> bool {
510        true
511    }
512
513    // This method returns the device type name for logging
514    fn device_type_name(&self) -> &'static str;
515
516    // Whether this endpoint can also act as a connector (for post-dial routing)
517    fn supports_routing(&self) -> bool {
518        false
519    }
520}
521
522
523
524//DEBUG
525
526// DeviceType Debug Implementation
527impl Debug for DeviceType {
528    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
529        match self {
530            DeviceType::InboundFlow => write!(f, "InboundFlow"),
531            DeviceType::OutboundFlow => write!(f, "OutboundFlow"),
532            DeviceType::WhatsAppFlow => write!(f, "WhatsAppFlow"),
533            DeviceType::AppFlow => write!(f, "AppFlow"),
534            DeviceType::AniRouter => write!(f, "AniRouter"),
535            DeviceType::DnisRouter => write!(f, "DnisRouter"),
536            DeviceType::DigitRouter => write!(f, "DigitRouter"),
537            DeviceType::TimeRangeRouter => write!(f, "TimeRangeRouter"),
538            DeviceType::DayOfWeekRouter => write!(f, "DayOfWeekRouter"),
539            DeviceType::DateRangeRouter => write!(f, "DateRangeRouter"),
540            DeviceType::ZoneRouter => write!(f, "ZoneRouter"),
541            DeviceType::HuntGroup => write!(f, "HuntGroup"),
542            DeviceType::Client => write!(f, "Client"),
543            DeviceType::Teams => write!(f, "Teams"),
544            DeviceType::SipExtension => write!(f, "SipExtension"),
545            DeviceType::SipGateway => write!(f, "SipGateway"),
546            DeviceType::Remote => write!(f, "Remote"),
547            DeviceType::Plugin => write!(f, "Plugin"),
548            DeviceType::Play => write!(f, "Play"),
549            DeviceType::Say => write!(f, "Say"),
550            DeviceType::Voicemail => write!(f, "Voicemail"),
551            DeviceType::Script => write!(f, "Script"),
552            DeviceType::Queue => write!(f, "Queue"),
553            DeviceType::Sms => write!(f, "Sms"),
554            DeviceType::Email => write!(f, "Email"),
555            DeviceType::Tag => write!(f, "Tag"),
556            DeviceType::TagRouter => write!(f, "TagRouter"),
557            DeviceType::MessagePlugin => write!(f, "MessagePlugin"),
558            DeviceType::MessageText => write!(f, "MessageText"),
559            DeviceType::MessageButtons => write!(f, "MessageButtons"),
560            DeviceType::MessageTemplate => write!(f, "MessageTemplate"),
561            DeviceType::MessageAniRouter => write!(f, "MessageAniRouter"),
562            DeviceType::Service => write!(f, "Service"),
563        }
564    }
565}
566
567
568
569// Device Enum Debug Implementation
570impl Debug for Device {
571    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
572        match self {
573            Device::InboundFlow(_) => write!(f, "Device::InboundFlow"),
574            Device::OutboundFlow(_) => write!(f, "Device::OutboundFlow"),
575            Device::WhatsAppFlow(_) => write!(f, "Device::WhatsAppFlow"),
576            Device::AppFlow(_) => write!(f, "Device::AppFlow"),
577            Device::AniRouter(_) => write!(f, "Device::AniRouter"),
578            Device::DnisRouter(_) => write!(f, "Device::DnisRouter"),
579            Device::DigitRouter(_) => write!(f, "Device::DigitRouter"),
580            Device::TimeRangeRouter(_) => write!(f, "Device::TimeRangeRouter"),
581            Device::DayOfWeekRouter(_) => write!(f, "Device::DayOfWeekRouter"),
582            Device::DateRangeRouter(_) => write!(f, "Device::DateRangeRouter"),
583            Device::ZoneRouter(_) => write!(f, "Device::ZoneRouter"),
584            Device::HuntGroup(_) => write!(f, "Device::HuntGroup"),
585            Device::Client(_) => write!(f, "Device::Client"),
586            Device::Teams(_) => write!(f, "Device::Teams"),
587            Device::SipExtension(_) => write!(f, "Device::SipExtension"),
588            Device::SipGateway(_) => write!(f, "Device::SipGateway"),
589            Device::Remote(_) => write!(f, "Device::Remote"),
590            Device::Plugin(_) => write!(f, "Device::Plugin"),
591            Device::Play(_) => write!(f, "Device::Play"),
592            Device::Say(_) => write!(f, "Device::Say"),
593            Device::Voicemail(_) => write!(f, "Device::Voicemail"),
594            Device::Script(_) => write!(f, "Device::Script"),
595            Device::Queue(_) => write!(f, "Device::Queue"),
596            Device::Sms(_) => write!(f, "Device::Sms"),
597            Device::Email(_) => write!(f, "Device::Email"),
598            Device::Tag(_) => write!(f, "Device::Tag"),
599            Device::TagRouter(_) => write!(f, "Device::TagRouter"),
600            Device::MessagePlugin(_) => write!(f, "Device::MessagePlugin"),
601            Device::MessageButtons(_) => write!(f, "Device::MessageButtons"),
602            Device::MessageText(_) => write!(f, "Device::MessageText"),
603            Device::MessageTemplate(_) => write!(f, "Device::MessageTemplate"),
604            Device::MessageAniRouter(_) => write!(f, "Device::MessageAniRouter"),
605            Device::Service(_) => write!(f, "Device::Service"),
606        }
607    }
608}
609
610// DeviceStruct Debug Implementation
611impl Debug for DeviceStruct {
612    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
613        f.debug_struct("DeviceStruct")
614            .field("id", &self.id)
615            .field("device_type", &self.device_type)
616            .field("name", &self.name)
617            .field("extension", &self.extension)
618            .finish_non_exhaustive()
619    }
620}
621
622// TagType Debug Implementation
623impl Debug for TagType {
624    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
625        match self {
626            TagType::Session => write!(f, "Session"),
627            TagType::Global => write!(f, "Global"),
628        }
629    }
630}
631
632// DeviceTag Debug Implementation
633impl Debug for DeviceTag {
634    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
635        f.debug_struct("DeviceTag")
636            .field("tag_type", &self.tag_type)
637            .field("name", &self.name)
638            .field("value", &self.value)
639            .finish()
640    }
641}
642
643
644
645
646
647// RecordOptions Debug Implementation
648impl Debug for RecordOptions {
649    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
650        f.debug_struct("RecordOptions")
651            .field("enabled", &self.enabled)
652            .field("retention", &self.retention)
653            .field("mix_type", &self.mix_type)
654            .field("sample_rate", &self.sample_rate)
655            .finish()
656    }
657}
658
659// TranscribeOptions Debug Implementation
660impl Debug for TranscribeOptions {
661    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
662        f.debug_struct("TranscribeOptions")
663            .field("enabled", &self.enabled)
664            .field("language", &self.language)
665            .finish()
666    }
667}
668
669// AsrVendor Debug Implementation
670impl Debug for AsrVendor {
671    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
672
673        match self {
674            AsrVendor::Google => write!(f, "Google"),
675            AsrVendor::Deepgram => write!(f, "DeepGram"),
676            AsrVendor::Microsoft => write!(f, "Microsoft"),
677            AsrVendor::Aws => write!(f, "Aws"),
678            AsrVendor::Ibm => write!(f, "Ibm"),
679            AsrVendor::Nuance => write!(f, "Nuance"),
680            AsrVendor::Nvidia =>write!(f, "Nvidia"),
681            AsrVendor::Soniox => write!(f, "Soniox"),
682        }
683    }
684}