freeswitch_rs/
event.rs

1use crate::utils::FSNewType;
2use freeswitch_sys::*;
3use std::{
4    ffi::{CStr, CString},
5    mem::MaybeUninit,
6};
7
8use crate::prelude::*;
9
10use crate::channel::Channel;
11
12/// Wrapper around FreeSWITCH event.
13#[repr(transparent)]
14pub struct Event(*mut switch_event_t);
15
16impl Event {
17    /// Reserve a subclass name for private use with a custom event. See: [`switch_event_reserve_subclass_detailed`](../../freeswitch_sys/fn.switch_event_reserve_subclass_detailed.html).
18    pub fn reserve_subclass(name: &CStr) -> Result<()> {
19        // SAFETY: file and name are copied
20        unsafe {
21            let file = CString::new(std::file!()).unwrap();
22            match switch_event_reserve_subclass_detailed(file.as_ptr(), name.as_ptr()) {
23                switch_status_t::SWITCH_STATUS_SUCCESS => Ok(()),
24                other => Err(other.into()),
25            }
26        }
27    }
28
29    /// Free a subclass name reserved for private use with a custom event. See: [`switch_event_free_subclass_detailed`](../../freeswitch_sys/fn.switch_event_free_subclass_detailed.html).
30    pub fn free_subclass(name: &CStr) -> Result<()> {
31        // SAFETY: file and name are copied
32        unsafe {
33            let file = CString::new(std::file!()).unwrap();
34            match switch_event_free_subclass_detailed(file.as_ptr(), name.as_ptr()) {
35                switch_status_t::SWITCH_STATUS_SUCCESS => Ok(()),
36                other => Err(other.into()),
37            }
38        }
39    }
40
41    /// Create a new custom event with the given subclass name.
42    pub fn new_custom_event(subclass: &CStr) -> Result<Self> {
43        Event::new_core_event(switch_event_types_t::SWITCH_EVENT_CUSTOM, Some(subclass))
44    }
45
46    /// Create an event. See: [`switch_event_create_subclass_detailed`](../../freeswitch_sys/fn.switch_event_create_subclass_detailed.html).
47    #[track_caller]
48    pub fn new_core_event(event: switch_event_types_t, subclass: Option<&CStr>) -> Result<Self> {
49        let mut e: MaybeUninit<*mut switch_event_t> = MaybeUninit::zeroed();
50
51        let subclass_ptr = match subclass.as_ref() {
52            None => std::ptr::null(),
53            Some(s) => s.as_ptr(),
54        };
55
56        // SAFETY: Initialise the event via fs function,
57        // where subclass is copied
58        unsafe {
59            let res = call_with_meta_prefix!(
60                switch_event_create_subclass_detailed,
61                e.as_mut_ptr(),
62                event,
63                subclass_ptr
64            );
65            match res {
66                switch_status_t::SWITCH_STATUS_SUCCESS => Ok(Self(e.assume_init())),
67                other => Err(other.into()),
68            }
69        }
70    }
71}
72
73impl Event {
74    /// Add information about a given channel to an event object. See: [`switch_channel_event_set_data`](../../freeswitch_sys/fn.switch_channel_event_set_data.html).
75    pub fn set_channel_data(&mut self, channel: &Channel) {
76        // SAFETY:
77        // we assume channel holds a valid ptr, which is validated by
78        // structs returning the reference
79        // set_data methods will take profile lock for us so its safe to
80        // call with shared reference
81        unsafe {
82            switch_channel_event_set_data(channel.as_ptr(), self.0);
83        }
84    }
85
86    /// Set the body of an event. See: [`switch_event_set_body`](../../freeswitch_sys/fn.switch_event_set_body.html).
87    pub fn set_body<T>(&mut self, body: T) -> Result<()>
88    where
89        T: Into<Vec<u8>>,
90    {
91        let cstr = CString::new(body).map_err(|_e| switch_status_t::SWITCH_STATUS_GENERR)?;
92        // body is copied within fs, just make sure we free this side
93        unsafe {
94            let res = switch_event_set_body(self.0, cstr.as_ptr());
95            match res {
96                switch_status_t::SWITCH_STATUS_SUCCESS => Ok(()),
97                other => Err(other.into()),
98            }
99        }
100    }
101
102    /// Fire an event. See: [`switch_event_fire_detailed`](../../freeswitch_sys/fn.switch_event_fire_detailed.html).
103    #[track_caller]
104    pub fn fire(mut self) -> Result<()> {
105        // SAFETY:
106        // switch_event_fire_detailed cleans up memory
107        // even if error, but just incase we will cleanup non null ptrs
108        unsafe {
109            let res = call_with_meta_prefix!(
110                switch_event_fire_detailed,
111                &mut self.0,
112                // Null for user data, same as the fs macro
113                std::ptr::null_mut()
114            );
115
116            match res {
117                switch_status_t::SWITCH_STATUS_SUCCESS => Ok(()),
118                other => {
119                    if !self.0.is_null() {
120                        switch_event_destroy(&mut self.0);
121                    }
122                    Err(other.into())
123                }
124            }
125        }
126    }
127}
128
129// NOTES:
130// Generally FS will null the ptr once the event is fired or Error'd
131// drop is only really necessary if user create events and DON'T use them ...
132// is it necessary?