2022-10-09 16:50:40 +02:00
|
|
|
//! Waku message [event](https://rfc.vac.dev/spec/36/#events) related items
|
|
|
|
|
//!
|
|
|
|
|
//! Asynchronous events require a callback to be registered.
|
|
|
|
|
//! An example of an asynchronous event that might be emitted is receiving a message.
|
|
|
|
|
//! When an event is emitted, this callback will be triggered receiving a [`Signal`]
|
|
|
|
|
|
2022-09-29 15:17:52 +02:00
|
|
|
// std
|
|
|
|
|
use std::ffi::{c_char, CStr};
|
2022-10-03 15:39:50 +02:00
|
|
|
use std::ops::Deref;
|
2022-10-09 16:50:40 +02:00
|
|
|
use std::sync::Mutex;
|
2022-09-29 15:17:52 +02:00
|
|
|
// crates
|
2022-10-03 15:39:50 +02:00
|
|
|
use once_cell::sync::Lazy;
|
2022-09-29 15:17:52 +02:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
// internal
|
2022-10-06 15:51:00 +02:00
|
|
|
use crate::general::{WakuMessage, WakuPubSubTopic};
|
2022-10-12 11:35:27 -05:00
|
|
|
use crate::MessageId;
|
2022-09-29 15:17:52 +02:00
|
|
|
|
2022-10-09 16:50:40 +02:00
|
|
|
/// Event signal
|
2022-09-29 15:17:52 +02:00
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
|
pub struct Signal {
|
2022-10-09 16:50:40 +02:00
|
|
|
/// Type of signal being emitted. Currently, only message is available
|
2022-09-29 15:17:52 +02:00
|
|
|
#[serde(alias = "type")]
|
|
|
|
|
_type: String,
|
2022-10-09 16:50:40 +02:00
|
|
|
/// Format depends on the type of signal
|
2022-09-29 15:17:52 +02:00
|
|
|
event: Event,
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-09 16:50:40 +02:00
|
|
|
impl Signal {
|
|
|
|
|
pub fn event(&self) -> &Event {
|
|
|
|
|
&self.event
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Waku event
|
|
|
|
|
/// For now just WakuMessage is supported
|
|
|
|
|
#[non_exhaustive]
|
2022-09-29 15:17:52 +02:00
|
|
|
#[derive(Serialize, Deserialize)]
|
2022-10-12 11:35:27 -05:00
|
|
|
#[serde(untagged, rename_all = "camelCase")]
|
2022-09-29 15:17:52 +02:00
|
|
|
pub enum Event {
|
|
|
|
|
WakuMessage(WakuMessageEvent),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Type of `event` field for a `message` event
|
|
|
|
|
#[derive(Serialize, Deserialize)]
|
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
|
pub struct WakuMessageEvent {
|
|
|
|
|
/// The pubsub topic on which the message was received
|
2022-10-06 15:51:00 +02:00
|
|
|
pubsub_topic: WakuPubSubTopic,
|
2022-09-29 15:17:52 +02:00
|
|
|
/// The message id
|
2022-10-12 11:35:27 -05:00
|
|
|
message_id: MessageId,
|
2022-09-29 15:17:52 +02:00
|
|
|
/// The message in [`WakuMessage`] format
|
|
|
|
|
waku_message: WakuMessage,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl WakuMessageEvent {
|
2022-10-06 15:51:00 +02:00
|
|
|
pub fn pubsub_topic(&self) -> &WakuPubSubTopic {
|
2022-09-29 15:17:52 +02:00
|
|
|
&self.pubsub_topic
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn message_id(&self) -> &String {
|
|
|
|
|
&self.message_id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn waku_message(&self) -> &WakuMessage {
|
|
|
|
|
&self.waku_message
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-03 15:39:50 +02:00
|
|
|
/// Shared callback slot. Callbacks are registered here so they can be accessed by the extern "C"
|
|
|
|
|
#[allow(clippy::type_complexity)]
|
2022-10-09 16:50:40 +02:00
|
|
|
static CALLBACK: Lazy<Mutex<Box<dyn FnMut(Signal) + Send + Sync>>> =
|
|
|
|
|
Lazy::new(|| Mutex::new(Box::new(|_| {})));
|
2022-10-03 15:39:50 +02:00
|
|
|
|
|
|
|
|
/// Register global callback
|
|
|
|
|
fn set_callback<F: FnMut(Signal) + Send + Sync + 'static>(f: F) {
|
2022-10-09 16:50:40 +02:00
|
|
|
*CALLBACK.lock().unwrap() = Box::new(f);
|
2022-10-03 15:39:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// 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()
|
2022-10-09 16:50:40 +02:00
|
|
|
.lock()
|
2022-10-03 15:39:50 +02:00
|
|
|
.expect("Access to the shared callback")
|
|
|
|
|
.as_mut())(data)
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-29 15:17:52 +02:00
|
|
|
/// Register callback to act as event handler and receive application signals,
|
|
|
|
|
/// which are used to react to asynchronous events in Waku
|
2022-10-03 15:39:50 +02:00
|
|
|
pub fn waku_set_event_callback<F: FnMut(Signal) + Send + Sync + 'static>(f: F) {
|
|
|
|
|
set_callback(f);
|
2022-10-12 11:35:27 -05:00
|
|
|
unsafe { waku_sys::waku_set_event_callback(callback as *mut std::ffi::c_void) };
|
2022-09-29 15:17:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use crate::events::waku_set_event_callback;
|
2022-10-12 11:35:27 -05:00
|
|
|
use crate::{Event, MessageId, Signal, WakuMessage, WakuPubSubTopic};
|
2022-09-29 15:17:52 +02:00
|
|
|
|
|
|
|
|
// TODO: how to actually send a signal and check if the callback is run?
|
|
|
|
|
#[test]
|
|
|
|
|
fn set_event_callback() {
|
|
|
|
|
waku_set_event_callback(|_signal| {});
|
|
|
|
|
}
|
2022-10-12 11:35:27 -05:00
|
|
|
|
|
|
|
|
#[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();
|
|
|
|
|
}
|
2022-09-29 15:17:52 +02:00
|
|
|
}
|