1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#![allow(dead_code)]
5include!("./bindings.rs");
6
7use std::ffi::CStr;
8use std::ffi::CString;
9use std::os::raw::{c_char, c_int, c_void};
10
11pub struct rLIPC {
12 conn: *mut LIPC,
13}
14
15macro_rules! code_to_result {
16 ($value:expr) => {
17 if $value == LIPCcode_LIPC_OK {
18 Ok(())
19 } else {
20 Err(format!(
21 "Failed to subscribe: {}",
22 rLIPC::code_to_string($value)
23 ))
24 }
25 };
26}
27
28#[derive(Debug)]
29pub enum LipcResult {
30 NUM(i32),
31 STR(String),
32}
33
34impl rLIPC {
35 pub fn new() -> Result<Self, String> {
38 let lipc;
39 unsafe {
40 lipc = LipcOpenNoName();
41 }
42 if lipc == (std::ptr::null_mut() as *mut c_void) {
43 return Err(String::from("Failed to open a connection!"));
44 }
45 Ok(Self { conn: lipc })
46 }
47
48 pub fn subscribe<F>(&self, service: &str, name: Option<&str>, callback: F) -> Result<(), String>
72 where
73 F: FnMut(&str, &str, Option<LipcResult>) + Send,
74 {
75 let _service = CString::new(service).unwrap();
76
77 let owned;
78 let c_name = match name {
79 None => std::ptr::null(),
80 Some(_name) => {
81 owned = CString::new(_name).unwrap();
82 owned.as_ptr()
83 }
84 };
85
86 let boxed_fn: Box<dyn FnMut(&str, &str, Option<LipcResult>) + Send> =
87 Box::new(callback) as _;
88 let double_box = Box::new(boxed_fn);
89 let ptr = Box::into_raw(double_box);
90 let result;
100 unsafe {
101 result = code_to_result!(LipcSubscribeExt(
109 self.conn,
110 _service.as_ptr(),
111 c_name,
112 Some(ugly_callback),
113 ptr as *mut c_void,
114 ));
115 }
116 result
117 }
118
119 pub fn get_str_prop(&self, service: &str, prop: &str) -> Result<String, String> {
127 let mut handle: *mut c_char = std::ptr::null_mut();
128 let handle_ptr: *mut *mut c_char = &mut handle;
129
130 let service = CString::new(service).unwrap();
131 let prop = CString::new(prop).unwrap();
132 unsafe {
133 code_to_result!(LipcGetStringProperty(
134 self.conn,
135 service.as_ptr(),
136 prop.as_ptr(),
137 handle_ptr
138 ))?;
139 };
140
141 let val;
142 unsafe {
143 val = CStr::from_ptr(handle).to_str().unwrap().into();
144 LipcFreeString(handle);
146 }
147 Ok(val)
148 }
149
150 pub fn get_int_prop(&self, service: &str, prop: &str) -> Result<i32, String> {
158 let mut val: c_int = 0;
159 let service = CString::new(service).unwrap();
160 let prop = CString::new(prop).unwrap();
161 unsafe {
162 code_to_result!(LipcGetIntProperty(
163 self.conn,
164 service.as_ptr(),
165 prop.as_ptr(),
166 &mut val
167 ))?;
168 };
169
170 Ok(val)
171 }
172
173 fn code_to_string(code: u32) -> String {
174 unsafe {
175 let cstr = CStr::from_ptr(LipcGetErrorString(code));
176 return String::from(cstr.to_str().unwrap());
177 }
178 }
179}
180
181unsafe extern "C" fn ugly_callback(
182 _: *mut LIPC,
183 name: *const c_char,
184 event: *mut LIPCevent,
185 data: *mut c_void,
186) -> LIPCcode {
187 let source = LipcGetEventSource(event);
189 let _name = CStr::from_ptr(name).to_str().unwrap();
190 let _source = CStr::from_ptr(source).to_str().unwrap();
191
192 let _int_param: Option<i32>;
193 let _str_param: Option<String>;
194
195 {
196 let mut int_param: c_int = 0;
197 _int_param = match ReturnCodes::from_u32(LipcGetIntParam(event, &mut int_param)).unwrap() {
198 ReturnCodes::OK => Some(int_param),
199 ReturnCodes::ERROR_NO_SUCH_PARAM => None,
200 e => {
201 println!(
202 "Error getting int param: {}",
203 rLIPC::code_to_string(e as u32)
204 );
205 None
206 }
207 }
208 }
209
210 {
211 let mut handle: *mut c_char = std::ptr::null_mut();
212 let handle_ptr: *mut *mut c_char = &mut handle;
213 _str_param = match ReturnCodes::from_u32(LipcGetStringParam(event, handle_ptr)).unwrap() {
214 ReturnCodes::OK => {
215 let val = CStr::from_ptr(handle).to_str().unwrap().into();
216 Some(val)
217 }
218 ReturnCodes::ERROR_NO_SUCH_PARAM => None,
219 e => {
220 println!(
221 "Error getting string param: {}",
222 rLIPC::code_to_string(e as u32)
223 );
224 None
225 }
226 }
227 }
228
229 let f = data as *mut Box<dyn FnMut(&str, &str, Option<LipcResult>) + Send>;
230 let _res = if let Some(val) = _int_param {
231 Some(LipcResult::NUM(val))
232 } else {
233 _str_param.map(LipcResult::STR)
234 };
235
236 (*f)(_source, _name, _res);
237 0
238}
239
240impl Drop for rLIPC {
241 fn drop(&mut self) {
242 unsafe {
243 LipcClose(self.conn);
244 }
245 println!("Disconnected");
246 }
247}
248
249unsafe impl Sync for rLIPC {}