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?