use std::ffi::{c_char, CStr};
use std::ops::Deref;
use std::sync::Mutex;
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use crate::general::{WakuMessage, WakuPubSubTopic};
use crate::MessageId;
#[derive(Serialize, Deserialize)]
pub struct Signal {
#[serde(alias = "type")]
_type: String,
event: Event,
}
impl Signal {
pub fn event(&self) -> &Event {
&self.event
}
}
#[non_exhaustive]
#[derive(Serialize, Deserialize)]
#[serde(untagged, rename_all = "camelCase")]
pub enum Event {
WakuMessage(WakuMessageEvent),
Unrecognized(serde_json::Value),
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WakuMessageEvent {
pubsub_topic: WakuPubSubTopic,
message_id: MessageId,
waku_message: WakuMessage,
}
impl WakuMessageEvent {
pub fn pubsub_topic(&self) -> &WakuPubSubTopic {
&self.pubsub_topic
}
pub fn message_id(&self) -> &String {
&self.message_id
}
pub fn waku_message(&self) -> &WakuMessage {
&self.waku_message
}
}
#[allow(clippy::type_complexity)]
static CALLBACK: Lazy<Mutex<Box<dyn FnMut(Signal) + Send + Sync>>> =
Lazy::new(|| Mutex::new(Box::new(|_| {})));
fn set_callback<F: FnMut(Signal) + Send + Sync + 'static>(f: F) {
*CALLBACK.lock().unwrap() = Box::new(f);
}
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()
.lock()
.expect("Access to the shared callback")
.as_mut())(data)
}
pub fn waku_set_event_callback<F: FnMut(Signal) + Send + Sync + 'static>(f: F) {
set_callback(f);
unsafe { waku_sys::waku_set_event_callback(callback as *mut std::ffi::c_void) };
}
#[cfg(test)]
mod tests {
use crate::events::waku_set_event_callback;
use crate::{Event, Signal};
#[test]
fn set_event_callback() {
waku_set_event_callback(|_signal| {});
}
#[test]
fn deserialize_signal() {
let s = "{\"type\":\"message\",\"event\":{\"messageId\":\"0x26ff3d7fbc950ea2158ce62fd76fd745eee0323c9eac23d0713843b0f04ea27c\",\"pubsubTopic\":\"/waku/2/default-waku/proto\",\"wakuMessage\":{\"payload\":\"SGkgZnJvbSDwn6aAIQ==\",\"contentTopic\":\"/toychat/2/huilong/proto\",\"timestamp\":1665580926660}}}";
let _: Signal = serde_json::from_str(s).unwrap();
}
#[test]
fn deserialize_event() {
let e = "{\"messageId\":\"0x26ff3d7fbc950ea2158ce62fd76fd745eee0323c9eac23d0713843b0f04ea27c\",\"pubsubTopic\":\"/waku/2/default-waku/proto\",\"wakuMessage\":{\"payload\":\"SGkgZnJvbSDwn6aAIQ==\",\"contentTopic\":\"/toychat/2/huilong/proto\",\"timestamp\":1665580926660}}";
let _: Event = serde_json::from_str(e).unwrap();
}
}