diff --git a/Cargo.lock b/Cargo.lock index d680613..cf0a16b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -829,6 +829,7 @@ dependencies = [ "hex", "libsecp256k1", "multiaddr", + "once_cell", "serde", "serde_json", "waku-sys", diff --git a/waku/Cargo.toml b/waku/Cargo.toml index 8acbf30..0c23ead 100644 --- a/waku/Cargo.toml +++ b/waku/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" hex = "0.4" libsecp256k1 = "0.7" multiaddr = "0.14" +once_cell = "1.15" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" waku-sys = { path = "../waku-sys" } diff --git a/waku/src/events/mod.rs b/waku/src/events/mod.rs index 1d859d1..39ffdd2 100644 --- a/waku/src/events/mod.rs +++ b/waku/src/events/mod.rs @@ -1,6 +1,9 @@ // std use std::ffi::{c_char, CStr}; +use std::ops::Deref; +use std::sync::RwLock; // crates +use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; // internal use crate::general::{PubsubTopic, WakuMessage}; @@ -44,20 +47,35 @@ impl WakuMessageEvent { } } +/// Shared callback slot. Callbacks are registered here so they can be accessed by the extern "C" +#[allow(clippy::type_complexity)] +static CALLBACK: Lazy>> = + Lazy::new(|| RwLock::new(Box::new(|_| {}))); + +/// Register global callback +fn set_callback(f: F) { + *CALLBACK.write().unwrap() = Box::new(f); +} + +/// Wrapper callback, it transformst the `*const c_char` into a [`Signal`] +/// and executes the [`CALLBACK`] funtion with it +extern "C" fn callback(data: *const c_char) { + let raw_response = unsafe { CStr::from_ptr(data) } + .to_str() + .expect("Not null ptr"); + let data: Signal = serde_json::from_str(raw_response).expect("Parsing signal to succeed"); + (CALLBACK + .deref() + .write() + .expect("Access to the shared callback") + .as_mut())(data) +} + /// Register callback to act as event handler and receive application signals, /// which are used to react to asynchronous events in Waku -pub fn waku_set_event_callback(mut callback: F) { - let mut callback_wrapper = move |data: *const c_char| { - let raw_response = unsafe { CStr::from_ptr(data) } - .to_str() - .expect("Not null ptr"); - let data: Signal = serde_json::from_str(raw_response).expect("Parsing signal to succeed"); - callback(data); - }; - let mut callback_ptr: &mut dyn FnMut(*const c_char) = &mut callback_wrapper; - unsafe { - waku_sys::waku_set_event_callback(&mut callback_ptr as *mut &mut _ as *mut std::ffi::c_void) - }; +pub fn waku_set_event_callback(f: F) { + set_callback(f); + unsafe { waku_sys::waku_set_event_callback(&mut callback as *mut _ as *mut std::ffi::c_void) }; } #[cfg(test)]