mirror of
https://github.com/logos-messaging/logos-messaging-rust-bindings.git
synced 2026-01-02 14:03:12 +00:00
wide adaptations to make the waku crate behave tokio-based async
This commit is contained in:
parent
9d73660c32
commit
e937e0541c
1
examples/Cargo.lock
generated
1
examples/Cargo.lock
generated
@ -4736,6 +4736,7 @@ dependencies = [
|
||||
"prost",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tui",
|
||||
"unicode-width 0.1.12",
|
||||
"waku-bindings",
|
||||
|
||||
@ -13,12 +13,14 @@ async fn main() -> Result<(), Error> {
|
||||
tcp_port: Some(60010), // TODO: use any available port.
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.expect("should instantiate");
|
||||
|
||||
let node2 = waku_new(Some(WakuNodeConfig {
|
||||
tcp_port: Some(60020), // TODO: use any available port.
|
||||
..Default::default()
|
||||
}))
|
||||
.await
|
||||
.expect("should instantiate");
|
||||
|
||||
// ========================================================================
|
||||
@ -31,7 +33,7 @@ async fn main() -> Result<(), Error> {
|
||||
|
||||
match event {
|
||||
WakuEvent::WakuMessage(evt) => {
|
||||
println!("WakuMessage event received: {:?}", evt.waku_message);
|
||||
// println!("WakuMessage event received: {:?}", evt.waku_message);
|
||||
let message = evt.waku_message;
|
||||
let payload = message.payload.to_vec();
|
||||
let msg = from_utf8(&payload).expect("should be valid message");
|
||||
@ -54,7 +56,7 @@ async fn main() -> Result<(), Error> {
|
||||
|
||||
match event {
|
||||
WakuEvent::WakuMessage(evt) => {
|
||||
println!("WakuMessage event received: {:?}", evt.waku_message);
|
||||
// println!("WakuMessage event received: {:?}", evt.waku_message);
|
||||
let message = evt.waku_message;
|
||||
let payload = message.payload.to_vec();
|
||||
let msg = from_utf8(&payload).expect("should be valid message");
|
||||
@ -69,8 +71,8 @@ async fn main() -> Result<(), Error> {
|
||||
})
|
||||
.expect("set event call back working");
|
||||
|
||||
let node1 = node1.start().expect("node1 should start");
|
||||
let node2 = node2.start().expect("node2 should start");
|
||||
let node1 = node1.start().await.expect("node1 should start");
|
||||
let node2 = node2.start().await.expect("node2 should start");
|
||||
|
||||
// ========================================================================
|
||||
// Subscribe to pubsub topic
|
||||
@ -78,10 +80,12 @@ async fn main() -> Result<(), Error> {
|
||||
|
||||
node1
|
||||
.relay_subscribe(&topic)
|
||||
.await
|
||||
.expect("node1 should subscribe");
|
||||
|
||||
node2
|
||||
.relay_subscribe(&topic)
|
||||
.await
|
||||
.expect("node2 should subscribe");
|
||||
|
||||
// ========================================================================
|
||||
@ -89,10 +93,12 @@ async fn main() -> Result<(), Error> {
|
||||
|
||||
let addresses2 = node2
|
||||
.listen_addresses()
|
||||
.await
|
||||
.expect("should obtain the addresses");
|
||||
|
||||
node1
|
||||
.connect(&addresses2[0], None)
|
||||
.await
|
||||
.expect("node1 should connect to node2");
|
||||
|
||||
// ========================================================================
|
||||
@ -119,6 +125,7 @@ async fn main() -> Result<(), Error> {
|
||||
);
|
||||
node1
|
||||
.relay_publish_message(&message, &topic, None)
|
||||
.await
|
||||
.expect("should have sent the message");
|
||||
|
||||
// ========================================================================
|
||||
@ -129,13 +136,13 @@ async fn main() -> Result<(), Error> {
|
||||
// ========================================================================
|
||||
// Stop both instances
|
||||
|
||||
let node1 = node1.stop().expect("should stop");
|
||||
let node2 = node2.stop().expect("should stop");
|
||||
let node1 = node1.stop().await.expect("should stop");
|
||||
let node2 = node2.stop().await.expect("should stop");
|
||||
|
||||
// ========================================================================
|
||||
// Free resources
|
||||
node1.waku_destroy().expect("should deallocate");
|
||||
node2.waku_destroy().expect("should deallocate");
|
||||
node1.waku_destroy().await.expect("should deallocate");
|
||||
node2.waku_destroy().await.expect("should deallocate");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::str::from_utf8;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{SystemTime, Duration};
|
||||
use tokio::task;
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use waku::{
|
||||
@ -48,7 +49,7 @@ impl TicTacToeApp<Initialized> {
|
||||
}
|
||||
}
|
||||
|
||||
fn start(self) -> TicTacToeApp<Running> {
|
||||
async fn start(self) -> TicTacToeApp<Running> {
|
||||
let tx_clone = self.tx.clone();
|
||||
|
||||
let my_closure = move |response| {
|
||||
@ -84,14 +85,14 @@ impl TicTacToeApp<Initialized> {
|
||||
self.waku.set_event_callback(my_closure).expect("set event call back working");
|
||||
|
||||
// Start the waku node
|
||||
let waku = self.waku.start().expect("waku should start");
|
||||
let waku = self.waku.start().await.expect("waku should start");
|
||||
|
||||
// Subscribe to desired topic using the relay protocol
|
||||
// self.waku.relay_subscribe(&self.game_topic.to_string()).expect("waku should subscribe");
|
||||
waku.relay_subscribe(&self.game_topic).await.expect("waku should subscribe");
|
||||
|
||||
let ctopic = WakuContentTopic::new("waku", "2", "tictactoegame", Encoding::Proto);
|
||||
let content_topics = vec![ctopic];
|
||||
waku.filter_subscribe(&self.game_topic, content_topics).expect("waku should subscribe");
|
||||
// let ctopic = WakuContentTopic::new("waku", "2", "tictactoegame", Encoding::Proto);
|
||||
// let content_topics = vec![ctopic];
|
||||
// waku.filter_subscribe(&self.game_topic, content_topics).await.expect("waku should subscribe");
|
||||
|
||||
// Connect to hard-coded node
|
||||
// let target_node_multi_addr =
|
||||
@ -114,7 +115,7 @@ impl TicTacToeApp<Initialized> {
|
||||
}
|
||||
|
||||
impl TicTacToeApp<Running> {
|
||||
fn send_game_state(&self, game_state: &GameState) {
|
||||
async fn send_game_state(&self, game_state: &GameState) {
|
||||
let serialized_game_state = serde_json::to_string(game_state).unwrap();
|
||||
let content_topic = WakuContentTopic::new("waku", "2", "tictactoegame", Encoding::Proto);
|
||||
|
||||
@ -132,9 +133,11 @@ impl TicTacToeApp<Running> {
|
||||
false,
|
||||
);
|
||||
|
||||
// self.waku.relay_publish_message(&message, &self.game_topic.to_string(), None)
|
||||
// .expect("Failed to send message");
|
||||
self.waku.lightpush_publish_message(&message, &self.game_topic).expect("Failed to send message");
|
||||
if let Ok(msg_hash) = self.waku.relay_publish_message(&message, &self.game_topic, None).await {
|
||||
dbg!(format!("message hash published: {}", msg_hash));
|
||||
}
|
||||
|
||||
// self.waku.lightpush_publish_message(&message, &self.game_topic);
|
||||
}
|
||||
|
||||
fn make_move(&mut self, row: usize, col: usize) {
|
||||
@ -159,7 +162,17 @@ impl TicTacToeApp<Running> {
|
||||
};
|
||||
}
|
||||
|
||||
self.send_game_state(&game_state); // Send updated state after a move
|
||||
// Call the async function in a blocking context
|
||||
task::block_in_place(|| {
|
||||
// Obtain the current runtime handle
|
||||
let handle = tokio::runtime::Handle::current();
|
||||
|
||||
// Block on the async function
|
||||
handle.block_on(async {
|
||||
// Assuming `self` is available in the current context
|
||||
self.send_game_state(&game_state).await;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -314,7 +327,7 @@ async fn main() -> eframe::Result<()> {
|
||||
// node_key: Some(SecretKey::from_str("2fc0515879e52b7b73297cfd6ab3abf7c344ef84b7a90ff6f4cc19e05a198027").unwrap()),
|
||||
max_message_size: Some("1024KiB".to_string()),
|
||||
relay_topics: vec![String::from(&game_topic)],
|
||||
log_level: Some("DEBUG"), // Supported: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL
|
||||
log_level: Some("FATAL"), // Supported: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL
|
||||
|
||||
keep_alive: Some(true),
|
||||
|
||||
@ -326,7 +339,7 @@ async fn main() -> eframe::Result<()> {
|
||||
// discv5_enr_auto_update: Some(false),
|
||||
|
||||
..Default::default()
|
||||
}))
|
||||
})).await
|
||||
.expect("should instantiate");
|
||||
|
||||
let game_state = GameState {
|
||||
@ -339,7 +352,7 @@ async fn main() -> eframe::Result<()> {
|
||||
let clone = shared_state.clone();
|
||||
let app = TicTacToeApp::new(waku, game_topic, clone, tx);
|
||||
|
||||
let app = app.start();
|
||||
let app = app.start().await;
|
||||
|
||||
let clone = shared_state.clone();
|
||||
// Listen for messages in the main thread
|
||||
|
||||
@ -15,4 +15,5 @@ tui = "0.19"
|
||||
crossterm = "0.25"
|
||||
unicode-width = "0.1"
|
||||
prost = "0.11"
|
||||
chrono = "0.4"
|
||||
chrono = "0.4"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
@ -1,6 +1,7 @@
|
||||
mod protocol;
|
||||
|
||||
use crate::protocol::{Chat2Message, TOY_CHAT_CONTENT_TOPIC};
|
||||
use tokio::task;
|
||||
use chrono::Utc;
|
||||
use crossterm::{
|
||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
|
||||
@ -48,7 +49,7 @@ struct App<State> {
|
||||
}
|
||||
|
||||
impl App<Initialized> {
|
||||
fn new(nick: String) -> Result<App<Initialized>> {
|
||||
async fn new(nick: String) -> Result<App<Initialized>> {
|
||||
let pubsub_topic = PubsubTopic::new(DEFAULT_PUBSUB_TOPIC);
|
||||
let waku = waku_new(Some(WakuNodeConfig {
|
||||
tcp_port: Some(60010),
|
||||
@ -69,7 +70,7 @@ impl App<Initialized> {
|
||||
// discv5_enr_auto_update: Some(false),
|
||||
|
||||
..Default::default()
|
||||
}))?;
|
||||
})).await?;
|
||||
|
||||
Ok(App {
|
||||
input: String::new(),
|
||||
@ -80,7 +81,7 @@ impl App<Initialized> {
|
||||
})
|
||||
}
|
||||
|
||||
fn start_waku_node(self) -> Result<App<Running>> {
|
||||
async fn start_waku_node(self) -> Result<App<Running>> {
|
||||
|
||||
let shared_messages = Arc::clone(&self.messages);
|
||||
|
||||
@ -116,10 +117,10 @@ impl App<Initialized> {
|
||||
}
|
||||
})?;
|
||||
|
||||
let waku = self.waku.start()?;
|
||||
let waku = self.waku.start().await?;
|
||||
|
||||
let pubsub_topic = PubsubTopic::new(DEFAULT_PUBSUB_TOPIC);
|
||||
waku.relay_subscribe(&pubsub_topic)?;
|
||||
waku.relay_subscribe(&pubsub_topic).await?;
|
||||
|
||||
Ok(App {
|
||||
input: self.input,
|
||||
@ -133,8 +134,8 @@ impl App<Initialized> {
|
||||
|
||||
impl App<Running> {
|
||||
|
||||
fn retrieve_history(&mut self) {
|
||||
let messages = self.waku.store_query(None, vec![TOY_CHAT_CONTENT_TOPIC.clone()], STORE_NODE).unwrap();
|
||||
async fn retrieve_history(&mut self) {
|
||||
let messages = self.waku.store_query(None, vec![TOY_CHAT_CONTENT_TOPIC.clone()], STORE_NODE).await.unwrap();
|
||||
let messages:Vec<_> = messages
|
||||
.iter()
|
||||
.map(|store_resp_msg| {
|
||||
@ -183,15 +184,25 @@ impl App<Running> {
|
||||
false,
|
||||
);
|
||||
|
||||
let pubsub_topic = PubsubTopic::new(DEFAULT_PUBSUB_TOPIC);
|
||||
if let Err(e) = self.waku.relay_publish_message(
|
||||
&waku_message,
|
||||
&pubsub_topic,
|
||||
None,
|
||||
) {
|
||||
let mut out = std::io::stderr();
|
||||
write!(out, "{e:?}").unwrap();
|
||||
}
|
||||
// Call the async function in a blocking context
|
||||
task::block_in_place(|| {
|
||||
// Obtain the current runtime handle
|
||||
let handle = tokio::runtime::Handle::current();
|
||||
|
||||
// Block on the async function
|
||||
handle.block_on(async {
|
||||
// Assuming `self` is available in the current context
|
||||
let pubsub_topic = PubsubTopic::new(DEFAULT_PUBSUB_TOPIC);
|
||||
if let Err(e) = self.waku.relay_publish_message(
|
||||
&waku_message,
|
||||
&pubsub_topic,
|
||||
None,
|
||||
).await {
|
||||
let mut out = std::io::stderr();
|
||||
write!(out, "{e:?}").unwrap();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
KeyCode::Char(c) => {
|
||||
self.input.push(c);
|
||||
@ -210,16 +221,17 @@ impl App<Running> {
|
||||
}
|
||||
}
|
||||
|
||||
fn stop_app(self) {
|
||||
self.waku.stop().expect("the node should stop properly");
|
||||
async fn stop_app(self) {
|
||||
self.waku.stop().await.expect("the node should stop properly");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> std::result::Result<(), Box<dyn Error>> {
|
||||
#[tokio::main]
|
||||
async fn main() -> std::result::Result<(), Box<dyn Error>> {
|
||||
let nick = std::env::args().nth(1).expect("Nick to be set");
|
||||
|
||||
let app = App::new(nick)?;
|
||||
let mut app = app.start_waku_node()?;
|
||||
let app = App::new(nick).await?;
|
||||
let mut app = app.start_waku_node().await?;
|
||||
|
||||
// setup terminal
|
||||
enable_raw_mode()?;
|
||||
@ -228,9 +240,9 @@ fn main() -> std::result::Result<(), Box<dyn Error>> {
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
app.retrieve_history();
|
||||
app.retrieve_history().await;
|
||||
let res = app.run_main_loop(&mut terminal);
|
||||
app.stop_app();
|
||||
app.stop_app().await;
|
||||
|
||||
// restore terminal
|
||||
disable_raw_mode()?;
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// std
|
||||
use crate::general::Result;
|
||||
use crate::utils::WakuDecode;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
@ -79,6 +81,12 @@ impl WakuContentTopic {
|
||||
}
|
||||
}
|
||||
|
||||
impl WakuDecode for WakuContentTopic {
|
||||
fn decode(input: &str) -> Result<Self> {
|
||||
Ok(serde_json::from_str(input).expect("could not parse store resp"))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for WakuContentTopic {
|
||||
type Err = String;
|
||||
|
||||
|
||||
@ -2,12 +2,28 @@ use crate::utils::WakuDecode;
|
||||
use hex::FromHex;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Waku message hash, hex encoded sha256 digest of the message
|
||||
#[derive(Debug, Serialize, Clone)]
|
||||
#[derive(Debug, Serialize, PartialEq, Eq, Clone)]
|
||||
pub struct MessageHash([u8; 32]);
|
||||
|
||||
impl MessageHash {
|
||||
fn to_hex_string(&self) -> String {
|
||||
let hex: String = self.0.iter().map(|b| format!("{:02x}", b)).collect();
|
||||
format!("0x{}", hex)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for MessageHash {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
// Use the inner array to contribute to the hash
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for MessageHash {
|
||||
type Err = String;
|
||||
|
||||
@ -45,6 +61,13 @@ impl<'de> Deserialize<'de> for MessageHash {
|
||||
|
||||
impl WakuDecode for MessageHash {
|
||||
fn decode(input: &str) -> Result<Self, String> {
|
||||
serde_json::from_str(input).expect("could not parse MessageHash")
|
||||
MessageHash::from_str(input)
|
||||
}
|
||||
}
|
||||
|
||||
// Implement the Display trait
|
||||
impl fmt::Display for MessageHash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.to_hex_string())
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn deserialize_message_event() {
|
||||
let s = "{\"eventType\":\"message\",\"messageHash\":\"0x26ff3d7fbc950ea2158ce62fd76fd745eee0323c9eac23d0713843b0f04ea27c\",\"pubsubTopic\":\"/waku/2/default-waku/proto\",\"wakuMessage\":{\"payload\":\"SGkgZnJvbSDwn6aAIQ==\",\"contentTopic\":\"/toychat/2/huilong/proto\",\"timestamp\":1665580926660}}";
|
||||
let s = "{\"eventType\":\"message\",\"messageHash\":[91, 70, 26, 8, 141, 232, 150, 200, 26, 206, 224, 175, 249, 74, 61, 140, 231, 126, 224, 160, 91, 80, 162, 65, 250, 171, 84, 149, 133, 110, 214, 101],\"pubsubTopic\":\"/waku/2/default-waku/proto\",\"wakuMessage\":{\"payload\":\"SGkgZnJvbSDwn6aAIQ==\",\"contentTopic\":\"/toychat/2/huilong/proto\",\"timestamp\":1665580926660}}";
|
||||
let evt: WakuEvent = serde_json::from_str(s).unwrap();
|
||||
assert!(matches!(evt, WakuEvent::WakuMessage(_)));
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
use std::ffi::CString;
|
||||
// crates
|
||||
use libc::*;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Notify;
|
||||
// internal
|
||||
use crate::general::contenttopic::WakuContentTopic;
|
||||
use crate::general::pubsubtopic::PubsubTopic;
|
||||
@ -11,22 +13,29 @@ use crate::general::Result;
|
||||
use crate::node::context::WakuNodeContext;
|
||||
use crate::utils::{get_trampoline, handle_no_response, LibwakuResponse};
|
||||
|
||||
pub fn waku_filter_subscribe(
|
||||
pub async fn waku_filter_subscribe(
|
||||
ctx: &WakuNodeContext,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
content_topics: Vec<WakuContentTopic>,
|
||||
) -> Result<()> {
|
||||
let content_topics = WakuContentTopic::join_content_topics(content_topics);
|
||||
|
||||
let pubsub_topic_ptr = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic")
|
||||
.into_raw();
|
||||
let content_topics_ptr = CString::new(content_topics)
|
||||
.expect("CString should build properly from content topic")
|
||||
.into_raw();
|
||||
let pubsub_topic = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic");
|
||||
let pubsub_topic_ptr = pubsub_topic.as_ptr();
|
||||
|
||||
let content_topics =
|
||||
CString::new(content_topics).expect("CString should build properly from content topic");
|
||||
let content_topics_ptr = content_topics.as_ptr();
|
||||
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
@ -38,31 +47,35 @@ pub fn waku_filter_subscribe(
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(pubsub_topic_ptr));
|
||||
drop(CString::from_raw(content_topics_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
pub fn waku_filter_unsubscribe(
|
||||
pub async fn waku_filter_unsubscribe(
|
||||
ctx: &WakuNodeContext,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
content_topics: Vec<WakuContentTopic>, // comma-separated list of content topics
|
||||
) -> Result<()> {
|
||||
let content_topics_topics = WakuContentTopic::join_content_topics(content_topics);
|
||||
|
||||
let pubsub_topic_ptr = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic")
|
||||
.into_raw();
|
||||
let content_topics_topics_ptr = CString::new(content_topics_topics)
|
||||
.expect("CString should build properly from content topic")
|
||||
.into_raw();
|
||||
let pubsub_topic = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic");
|
||||
let pubsub_topic_ptr = pubsub_topic.as_ptr();
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let content_topics_topics = CString::new(content_topics_topics)
|
||||
.expect("CString should build properly from content topic");
|
||||
let content_topics_topics_ptr = content_topics_topics.as_ptr();
|
||||
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
@ -74,18 +87,21 @@ pub fn waku_filter_unsubscribe(
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(pubsub_topic_ptr));
|
||||
drop(CString::from_raw(content_topics_topics_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
pub fn waku_filter_unsubscribe_all(ctx: &WakuNodeContext) -> Result<()> {
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
pub async fn waku_filter_unsubscribe_all(ctx: &WakuNodeContext) -> Result<()> {
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
@ -96,5 +112,6 @@ pub fn waku_filter_unsubscribe_all(ctx: &WakuNodeContext) -> Result<()> {
|
||||
)
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
use std::ffi::CString;
|
||||
// crates
|
||||
use libc::*;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Notify;
|
||||
// internal
|
||||
use crate::general::{messagehash::MessageHash, Result, WakuMessage};
|
||||
use crate::node::context::WakuNodeContext;
|
||||
@ -11,23 +13,30 @@ use crate::utils::{get_trampoline, handle_response, LibwakuResponse};
|
||||
|
||||
use crate::general::pubsubtopic::PubsubTopic;
|
||||
|
||||
pub fn waku_lightpush_publish_message(
|
||||
pub async fn waku_lightpush_publish_message(
|
||||
ctx: &WakuNodeContext,
|
||||
message: &WakuMessage,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
) -> Result<MessageHash> {
|
||||
let message_ptr = CString::new(
|
||||
let message = CString::new(
|
||||
serde_json::to_string(&message)
|
||||
.expect("WakuMessages should always be able to success serializing"),
|
||||
)
|
||||
.expect("CString should build properly from the serialized waku message")
|
||||
.into_raw();
|
||||
let pubsub_topic_ptr = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic")
|
||||
.into_raw();
|
||||
.expect("CString should build properly from the serialized waku message");
|
||||
let message_ptr = message.as_ptr();
|
||||
|
||||
let pubsub_topic = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic");
|
||||
let pubsub_topic_ptr = pubsub_topic.as_ptr();
|
||||
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
@ -39,11 +48,9 @@ pub fn waku_lightpush_publish_message(
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(message_ptr));
|
||||
drop(CString::from_raw(pubsub_topic_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_response(code, result)
|
||||
}
|
||||
|
||||
@ -5,37 +5,44 @@ use std::ffi::CString;
|
||||
// crates
|
||||
use libc::c_void;
|
||||
use multiaddr::Multiaddr;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Notify;
|
||||
// internal
|
||||
use super::config::WakuNodeConfig;
|
||||
use crate::general::Result;
|
||||
use crate::node::context::WakuNodeContext;
|
||||
use crate::utils::LibwakuResponse;
|
||||
use crate::utils::WakuDecode;
|
||||
use crate::utils::{get_trampoline, handle_json_response, handle_no_response, handle_response};
|
||||
use crate::utils::{get_trampoline, handle_no_response, handle_response};
|
||||
|
||||
/// Instantiates a Waku node
|
||||
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_newchar-jsonconfig)
|
||||
pub fn waku_new(config: Option<WakuNodeConfig>) -> Result<WakuNodeContext> {
|
||||
pub async fn waku_new(config: Option<WakuNodeConfig>) -> Result<WakuNodeContext> {
|
||||
let config = config.unwrap_or_default();
|
||||
let config_ptr = CString::new(
|
||||
let config = CString::new(
|
||||
serde_json::to_string(&config)
|
||||
.expect("Serialization from properly built NodeConfig should never fail"),
|
||||
)
|
||||
.expect("CString should build properly from the config")
|
||||
.into_raw();
|
||||
.expect("CString should build properly from the config");
|
||||
let config_ptr = config.as_ptr();
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let mut result = LibwakuResponse::default();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let obj_ptr = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
let out = waku_sys::waku_new(config_ptr, cb, &mut closure as *mut _ as *mut c_void);
|
||||
|
||||
drop(CString::from_raw(config_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
|
||||
match result {
|
||||
LibwakuResponse::MissingCallback => panic!("callback is required"),
|
||||
LibwakuResponse::Failure(v) => Err(v),
|
||||
@ -43,57 +50,81 @@ pub fn waku_new(config: Option<WakuNodeConfig>) -> Result<WakuNodeContext> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waku_destroy(ctx: &WakuNodeContext) -> Result<()> {
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
pub async fn waku_destroy(ctx: &WakuNodeContext) -> Result<()> {
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
waku_sys::waku_destroy(ctx.get_ptr(), cb, &mut closure as *mut _ as *mut c_void)
|
||||
};
|
||||
notify.notified().await; // Wait until a result is received
|
||||
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
/// Start a Waku node mounting all the protocols that were enabled during the Waku node instantiation.
|
||||
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_start)
|
||||
pub fn waku_start(ctx: &WakuNodeContext) -> Result<()> {
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
pub async fn waku_start(ctx: &WakuNodeContext) -> Result<()> {
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
waku_sys::waku_start(ctx.get_ptr(), cb, &mut closure as *mut _ as *mut c_void)
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
/// Stops a Waku node
|
||||
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_stop)
|
||||
pub fn waku_stop(ctx: &WakuNodeContext) -> Result<()> {
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
pub async fn waku_stop(ctx: &WakuNodeContext) -> Result<()> {
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
waku_sys::waku_stop(ctx.get_ptr(), cb, &mut closure as *mut _ as *mut c_void)
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
/// nwaku version
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub fn waku_version(ctx: &WakuNodeContext) -> Result<String> {
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
pub async fn waku_version(ctx: &WakuNodeContext) -> Result<String> {
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
waku_sys::waku_version(ctx.get_ptr(), cb, &mut closure as *mut _ as *mut c_void)
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_response(code, result)
|
||||
}
|
||||
|
||||
@ -110,45 +141,54 @@ impl WakuDecode for Vec<Multiaddr> {
|
||||
|
||||
/// Get the multiaddresses the Waku node is listening to
|
||||
/// as per [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_listen_addresses)
|
||||
pub fn waku_listen_addresses(ctx: &WakuNodeContext) -> Result<Vec<Multiaddr>> {
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
pub async fn waku_listen_addresses(ctx: &WakuNodeContext) -> Result<Vec<Multiaddr>> {
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
waku_sys::waku_listen_addresses(ctx.get_ptr(), cb, &mut closure as *mut _ as *mut c_void)
|
||||
};
|
||||
|
||||
handle_json_response(code, result)
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_response(code, result)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::waku_new;
|
||||
use crate::node::management::{waku_listen_addresses, waku_start, waku_stop, waku_version};
|
||||
use serial_test::serial;
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn waku_flow() {
|
||||
let node = waku_new(None).unwrap();
|
||||
#[tokio::test]
|
||||
async fn waku_flow() {
|
||||
let node = waku_new(None).await.unwrap();
|
||||
|
||||
waku_start(&node).unwrap();
|
||||
waku_start(&node).await.unwrap();
|
||||
|
||||
// test addresses
|
||||
let addresses = waku_listen_addresses(&node).unwrap();
|
||||
let addresses = waku_listen_addresses(&node).await.unwrap();
|
||||
dbg!(&addresses);
|
||||
assert!(!addresses.is_empty());
|
||||
|
||||
waku_stop(&node).unwrap();
|
||||
waku_stop(&node).await.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn nwaku_version() {
|
||||
let node = waku_new(None).unwrap();
|
||||
let version = waku_version(&node).expect("should return the version");
|
||||
#[tokio::test]
|
||||
async fn nwaku_version() {
|
||||
let node = waku_new(None).await.unwrap();
|
||||
|
||||
let version = waku_version(&node)
|
||||
.await
|
||||
.expect("should return the version");
|
||||
|
||||
print!("Current version: {}", version);
|
||||
|
||||
assert!(!version.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,34 +44,41 @@ pub struct WakuNodeHandle<State> {
|
||||
|
||||
/// Spawn a new Waku node with the given configuration (default configuration if `None` provided)
|
||||
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_newchar-jsonconfig)
|
||||
pub fn waku_new(config: Option<WakuNodeConfig>) -> Result<WakuNodeHandle<Initialized>> {
|
||||
pub async fn waku_new(config: Option<WakuNodeConfig>) -> Result<WakuNodeHandle<Initialized>> {
|
||||
Ok(WakuNodeHandle {
|
||||
ctx: management::waku_new(config)?,
|
||||
ctx: management::waku_new(config).await?,
|
||||
_state: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
impl<State> WakuNodeHandle<State> {
|
||||
/// Get the nwaku version
|
||||
pub fn version(&self) -> Result<String> {
|
||||
management::waku_version(&self.ctx)
|
||||
pub async fn version(&self) -> Result<String> {
|
||||
management::waku_version(&self.ctx).await
|
||||
}
|
||||
|
||||
pub fn waku_destroy(self) -> Result<()> {
|
||||
let res = management::waku_destroy(&self.ctx);
|
||||
pub async fn waku_destroy(self) -> Result<()> {
|
||||
let res = management::waku_destroy(&self.ctx).await;
|
||||
self.ctx.reset_ptr();
|
||||
res
|
||||
}
|
||||
|
||||
/// Subscribe to WakuRelay to receive messages matching a content filter.
|
||||
pub async fn relay_subscribe(&self, pubsub_topic: &PubsubTopic) -> Result<()> {
|
||||
relay::waku_relay_subscribe(&self.ctx, pubsub_topic).await
|
||||
}
|
||||
}
|
||||
|
||||
impl WakuNodeHandle<Initialized> {
|
||||
/// Start a Waku node mounting all the protocols that were enabled during the Waku node instantiation.
|
||||
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_start)
|
||||
pub fn start(self) -> Result<WakuNodeHandle<Running>> {
|
||||
management::waku_start(&self.ctx).map(|_| WakuNodeHandle {
|
||||
ctx: self.ctx,
|
||||
_state: PhantomData,
|
||||
})
|
||||
pub async fn start(self) -> Result<WakuNodeHandle<Running>> {
|
||||
management::waku_start(&self.ctx)
|
||||
.await
|
||||
.map(|_| WakuNodeHandle {
|
||||
ctx: self.ctx,
|
||||
_state: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_event_callback<F: FnMut(LibwakuResponse) + 'static + Sync + Send>(
|
||||
@ -85,17 +92,19 @@ impl WakuNodeHandle<Initialized> {
|
||||
impl WakuNodeHandle<Running> {
|
||||
/// Stops a Waku node
|
||||
/// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_stop)
|
||||
pub fn stop(self) -> Result<WakuNodeHandle<Initialized>> {
|
||||
management::waku_stop(&self.ctx).map(|_| WakuNodeHandle {
|
||||
ctx: self.ctx,
|
||||
_state: PhantomData,
|
||||
})
|
||||
pub async fn stop(self) -> Result<WakuNodeHandle<Initialized>> {
|
||||
management::waku_stop(&self.ctx)
|
||||
.await
|
||||
.map(|_| WakuNodeHandle {
|
||||
ctx: self.ctx,
|
||||
_state: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the multiaddresses the Waku node is listening to
|
||||
/// as per [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_listen_addresses)
|
||||
pub fn listen_addresses(&self) -> Result<Vec<Multiaddr>> {
|
||||
management::waku_listen_addresses(&self.ctx)
|
||||
pub async fn listen_addresses(&self) -> Result<Vec<Multiaddr>> {
|
||||
management::waku_listen_addresses(&self.ctx).await
|
||||
}
|
||||
|
||||
/// Dial peer using a multiaddress
|
||||
@ -103,11 +112,11 @@ impl WakuNodeHandle<Running> {
|
||||
/// If the function execution takes longer than `timeout` value, the execution will be canceled and an error returned.
|
||||
/// Use 0 for no timeout
|
||||
/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_connect_peerchar-address-int-timeoutms)
|
||||
pub fn connect(&self, address: &Multiaddr, timeout: Option<Duration>) -> Result<()> {
|
||||
peers::waku_connect(&self.ctx, address, timeout)
|
||||
pub async fn connect(&self, address: &Multiaddr, timeout: Option<Duration>) -> Result<()> {
|
||||
peers::waku_connect(&self.ctx, address, timeout).await
|
||||
}
|
||||
|
||||
pub fn relay_publish_txt(
|
||||
pub async fn relay_publish_txt(
|
||||
&self,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
msg_txt: &String,
|
||||
@ -129,60 +138,55 @@ impl WakuNodeHandle<Running> {
|
||||
false,
|
||||
);
|
||||
|
||||
relay::waku_relay_publish_message(&self.ctx, &message, pubsub_topic, timeout)
|
||||
relay::waku_relay_publish_message(&self.ctx, &message, pubsub_topic, timeout).await
|
||||
}
|
||||
|
||||
/// Publish a message using Waku Relay.
|
||||
/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_relay_publishchar-messagejson-char-pubsubtopic-int-timeoutms)
|
||||
/// The pubsub_topic parameter is optional and if not specified it will be derived from the contentTopic.
|
||||
pub fn relay_publish_message(
|
||||
pub async fn relay_publish_message(
|
||||
&self,
|
||||
message: &WakuMessage,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<MessageHash> {
|
||||
relay::waku_relay_publish_message(&self.ctx, message, pubsub_topic, timeout)
|
||||
}
|
||||
|
||||
/// Subscribe to WakuRelay to receive messages matching a content filter.
|
||||
pub fn relay_subscribe(&self, pubsub_topic: &PubsubTopic) -> Result<()> {
|
||||
relay::waku_relay_subscribe(&self.ctx, pubsub_topic)
|
||||
relay::waku_relay_publish_message(&self.ctx, message, pubsub_topic, timeout).await
|
||||
}
|
||||
|
||||
/// Closes the pubsub subscription to stop receiving messages matching a content filter. No more messages will be received from this pubsub topic
|
||||
pub fn relay_unsubscribe(&self, pubsub_topic: &PubsubTopic) -> Result<()> {
|
||||
relay::waku_relay_unsubscribe(&self.ctx, pubsub_topic)
|
||||
pub async fn relay_unsubscribe(&self, pubsub_topic: &PubsubTopic) -> Result<()> {
|
||||
relay::waku_relay_unsubscribe(&self.ctx, pubsub_topic).await
|
||||
}
|
||||
|
||||
pub fn filter_subscribe(
|
||||
pub async fn filter_subscribe(
|
||||
&self,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
content_topics: Vec<WakuContentTopic>,
|
||||
) -> Result<()> {
|
||||
filter::waku_filter_subscribe(&self.ctx, pubsub_topic, content_topics)
|
||||
filter::waku_filter_subscribe(&self.ctx, pubsub_topic, content_topics).await
|
||||
}
|
||||
|
||||
pub fn filter_unsubscribe(
|
||||
pub async fn filter_unsubscribe(
|
||||
&self,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
content_topics: Vec<WakuContentTopic>,
|
||||
) -> Result<()> {
|
||||
filter::waku_filter_unsubscribe(&self.ctx, pubsub_topic, content_topics)
|
||||
filter::waku_filter_unsubscribe(&self.ctx, pubsub_topic, content_topics).await
|
||||
}
|
||||
|
||||
pub fn filter_unsubscribe_all(&self) -> Result<()> {
|
||||
filter::waku_filter_unsubscribe_all(&self.ctx)
|
||||
pub async fn filter_unsubscribe_all(&self) -> Result<()> {
|
||||
filter::waku_filter_unsubscribe_all(&self.ctx).await
|
||||
}
|
||||
|
||||
pub fn lightpush_publish_message(
|
||||
pub async fn lightpush_publish_message(
|
||||
&self,
|
||||
message: &WakuMessage,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
) -> Result<MessageHash> {
|
||||
lightpush::waku_lightpush_publish_message(&self.ctx, message, pubsub_topic)
|
||||
lightpush::waku_lightpush_publish_message(&self.ctx, message, pubsub_topic).await
|
||||
}
|
||||
|
||||
pub fn store_query(
|
||||
pub async fn store_query(
|
||||
&self,
|
||||
pubsub_topic: Option<PubsubTopic>,
|
||||
content_topics: Vec<WakuContentTopic>,
|
||||
@ -212,7 +216,8 @@ impl WakuNodeHandle<Running> {
|
||||
Some(25), // pagination_limit,
|
||||
peer_addr,
|
||||
None, // timeout_millis
|
||||
)?;
|
||||
)
|
||||
.await?;
|
||||
|
||||
messages.extend(response.messages);
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@ use std::time::Duration;
|
||||
// crates
|
||||
use libc::*;
|
||||
use multiaddr::Multiaddr;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Notify;
|
||||
// internal
|
||||
use crate::general::Result;
|
||||
use crate::node::context::WakuNodeContext;
|
||||
@ -17,17 +19,23 @@ use crate::utils::{get_trampoline, handle_no_response};
|
||||
/// If the function execution takes longer than `timeout` value, the execution will be canceled and an error returned.
|
||||
/// Use 0 for no timeout
|
||||
/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_connect_peerchar-address-int-timeoutms)
|
||||
pub fn waku_connect(
|
||||
pub async fn waku_connect(
|
||||
ctx: &WakuNodeContext,
|
||||
address: &Multiaddr,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<()> {
|
||||
let address_ptr = CString::new(address.to_string())
|
||||
.expect("CString should build properly from multiaddress")
|
||||
.into_raw();
|
||||
let address =
|
||||
CString::new(address.to_string()).expect("CString should build properly from multiaddress");
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let address_ptr = address.as_ptr();
|
||||
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
@ -41,10 +49,9 @@ pub fn waku_connect(
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(address_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
@ -2,7 +2,9 @@
|
||||
|
||||
// std
|
||||
use std::ffi::CString;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::Notify;
|
||||
// crates
|
||||
use libc::*;
|
||||
// internal
|
||||
@ -15,25 +17,32 @@ use crate::utils::{get_trampoline, handle_no_response, handle_response, LibwakuR
|
||||
/// Create a content topic according to [RFC 23](https://rfc.vac.dev/spec/23/)
|
||||
/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_content_topicchar-applicationname-unsigned-int-applicationversion-char-contenttopicname-char-encoding)
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub fn waku_create_content_topic(
|
||||
pub async fn waku_create_content_topic(
|
||||
ctx: &WakuNodeContext,
|
||||
application_name: &str,
|
||||
application_version: u32,
|
||||
content_topic_name: &str,
|
||||
encoding: Encoding,
|
||||
) -> WakuContentTopic {
|
||||
let application_name_ptr = CString::new(application_name)
|
||||
.expect("Application name should always transform to CString")
|
||||
.into_raw();
|
||||
let content_topic_name_ptr = CString::new(content_topic_name)
|
||||
.expect("Content topic should always transform to CString")
|
||||
.into_raw();
|
||||
let encoding_ptr = CString::new(encoding.to_string())
|
||||
.expect("Encoding should always transform to CString")
|
||||
.into_raw();
|
||||
let application_name = CString::new(application_name)
|
||||
.expect("Application name should always transform to CString");
|
||||
let application_name_ptr = application_name.as_ptr();
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let content_topic_name =
|
||||
CString::new(content_topic_name).expect("Content topic should always transform to CString");
|
||||
let content_topic_name_ptr = content_topic_name.as_ptr();
|
||||
|
||||
let encoding =
|
||||
CString::new(encoding.to_string()).expect("Encoding should always transform to CString");
|
||||
let encoding_ptr = encoding.as_ptr();
|
||||
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
@ -47,43 +56,44 @@ pub fn waku_create_content_topic(
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(application_name_ptr));
|
||||
drop(CString::from_raw(content_topic_name_ptr));
|
||||
drop(CString::from_raw(encoding_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_response(code, result).expect("&str from result should always be extracted")
|
||||
}
|
||||
|
||||
/// Publish a message using Waku Relay
|
||||
/// As per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_relay_publishchar-messagejson-char-pubsubtopic-int-timeoutms)
|
||||
pub fn waku_relay_publish_message(
|
||||
pub async fn waku_relay_publish_message(
|
||||
ctx: &WakuNodeContext,
|
||||
message: &WakuMessage,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
timeout: Option<Duration>,
|
||||
) -> Result<MessageHash> {
|
||||
let message_ptr = CString::new(
|
||||
let message = CString::new(
|
||||
serde_json::to_string(&message)
|
||||
.expect("WakuMessages should always be able to success serializing"),
|
||||
)
|
||||
.expect("CString should build properly from the serialized waku message")
|
||||
.into_raw();
|
||||
let pubsub_topic_ptr = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic")
|
||||
.into_raw();
|
||||
.expect("CString should build properly from the serialized waku message");
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let pubsub_topic = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic");
|
||||
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
let out = waku_sys::waku_relay_publish(
|
||||
ctx.get_ptr(),
|
||||
pubsub_topic_ptr,
|
||||
message_ptr,
|
||||
pubsub_topic.as_ptr(),
|
||||
message.as_ptr(),
|
||||
timeout
|
||||
.map(|duration| {
|
||||
duration
|
||||
@ -96,22 +106,25 @@ pub fn waku_relay_publish_message(
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(message_ptr));
|
||||
drop(CString::from_raw(pubsub_topic_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_response(code, result)
|
||||
}
|
||||
|
||||
pub fn waku_relay_subscribe(ctx: &WakuNodeContext, pubsub_topic: &PubsubTopic) -> Result<()> {
|
||||
let pubsub_topic_ptr = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic")
|
||||
.into_raw();
|
||||
pub async fn waku_relay_subscribe(ctx: &WakuNodeContext, pubsub_topic: &PubsubTopic) -> Result<()> {
|
||||
let pubsub_topic = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic");
|
||||
let pubsub_topic_ptr = pubsub_topic.as_ptr();
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
@ -122,21 +135,28 @@ pub fn waku_relay_subscribe(ctx: &WakuNodeContext, pubsub_topic: &PubsubTopic) -
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(pubsub_topic_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
pub fn waku_relay_unsubscribe(ctx: &WakuNodeContext, pubsub_topic: &PubsubTopic) -> Result<()> {
|
||||
let pubsub_topic_ptr = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic")
|
||||
.into_raw();
|
||||
pub async fn waku_relay_unsubscribe(
|
||||
ctx: &WakuNodeContext,
|
||||
pubsub_topic: &PubsubTopic,
|
||||
) -> Result<()> {
|
||||
let pubsub_topic = CString::new(String::from(pubsub_topic))
|
||||
.expect("CString should build properly from pubsub topic");
|
||||
let pubsub_topic_ptr = pubsub_topic.as_ptr();
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
@ -147,10 +167,9 @@ pub fn waku_relay_unsubscribe(ctx: &WakuNodeContext, pubsub_topic: &PubsubTopic)
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(pubsub_topic_ptr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_no_response(code, result)
|
||||
}
|
||||
|
||||
@ -4,13 +4,15 @@
|
||||
use std::ffi::CString;
|
||||
// crates
|
||||
use libc::*;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Notify;
|
||||
// internal
|
||||
use crate::general::{
|
||||
contenttopic::WakuContentTopic, messagehash::MessageHash, pubsubtopic::PubsubTopic, Result,
|
||||
WakuStoreRespMessage,
|
||||
};
|
||||
use crate::node::context::WakuNodeContext;
|
||||
use crate::utils::{get_trampoline, handle_json_response, LibwakuResponse, WakuDecode};
|
||||
use crate::utils::{get_trampoline, handle_response, LibwakuResponse, WakuDecode};
|
||||
use multiaddr::Multiaddr;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -76,7 +78,7 @@ impl WakuDecode for StoreResponse {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn waku_store_query(
|
||||
pub async fn waku_store_query(
|
||||
ctx: &WakuNodeContext,
|
||||
request_id: String,
|
||||
include_data: bool,
|
||||
@ -107,37 +109,39 @@ pub fn waku_store_query(
|
||||
let json_query = CString::new(
|
||||
serde_json::to_string(&query).expect("StoreQuery should always be able to be serialized"),
|
||||
)
|
||||
.expect("CString should build properly from the serialized filter subscription")
|
||||
.into_raw();
|
||||
.expect("CString should build properly from the serialized filter subscription");
|
||||
let json_query_ptr = json_query.as_ptr();
|
||||
|
||||
peer_addr
|
||||
.parse::<Multiaddr>()
|
||||
.expect("correct multiaddress in store query");
|
||||
let peer_addr = CString::new(peer_addr)
|
||||
.expect("peer_addr CString should be created")
|
||||
.into_raw();
|
||||
let peer_addr = CString::new(peer_addr).expect("peer_addr CString should be created");
|
||||
let peer_addr_ptr = peer_addr.as_ptr();
|
||||
|
||||
let timeout_millis = timeout_millis.unwrap_or(10000i32);
|
||||
|
||||
let mut result: LibwakuResponse = Default::default();
|
||||
let result_cb = |r: LibwakuResponse| result = r;
|
||||
let mut result = LibwakuResponse::default();
|
||||
let notify = Arc::new(Notify::new());
|
||||
let notify_clone = notify.clone();
|
||||
let result_cb = |r: LibwakuResponse| {
|
||||
result = r;
|
||||
notify_clone.notify_one(); // Notify that the value has been updated
|
||||
};
|
||||
let code = unsafe {
|
||||
let mut closure = result_cb;
|
||||
let cb = get_trampoline(&closure);
|
||||
let out = waku_sys::waku_store_query(
|
||||
ctx.get_ptr(),
|
||||
json_query,
|
||||
peer_addr,
|
||||
json_query_ptr,
|
||||
peer_addr_ptr,
|
||||
timeout_millis,
|
||||
cb,
|
||||
&mut closure as *mut _ as *mut c_void,
|
||||
);
|
||||
|
||||
drop(CString::from_raw(json_query));
|
||||
drop(CString::from_raw(peer_addr));
|
||||
|
||||
out
|
||||
};
|
||||
|
||||
handle_json_response(code, result)
|
||||
notify.notified().await; // Wait until a result is received
|
||||
handle_response(code, result)
|
||||
}
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
use crate::general::Result;
|
||||
use core::str::FromStr;
|
||||
use std::convert::TryFrom;
|
||||
use std::{slice, str};
|
||||
use waku_sys::WakuCallBack;
|
||||
use waku_sys::{RET_ERR, RET_MISSING_CALLBACK, RET_OK};
|
||||
|
||||
#[derive(Debug, Default, PartialEq)]
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
pub enum LibwakuResponse {
|
||||
Success(Option<String>),
|
||||
Failure(String),
|
||||
@ -36,6 +35,12 @@ pub trait WakuDecode: Sized {
|
||||
fn decode(input: &str) -> Result<Self>;
|
||||
}
|
||||
|
||||
impl WakuDecode for String {
|
||||
fn decode(input: &str) -> Result<Self> {
|
||||
Ok(input.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode<T: WakuDecode>(input: String) -> Result<T> {
|
||||
T::decode(input.as_str())
|
||||
}
|
||||
@ -87,7 +92,7 @@ pub fn handle_no_response(code: i32, result: LibwakuResponse) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_json_response<F: WakuDecode>(code: i32, result: LibwakuResponse) -> Result<F> {
|
||||
pub fn handle_response<F: WakuDecode>(code: i32, result: LibwakuResponse) -> Result<F> {
|
||||
match result {
|
||||
LibwakuResponse::Success(v) => decode(v.unwrap_or_default()),
|
||||
LibwakuResponse::Failure(v) => Err(v),
|
||||
@ -98,21 +103,3 @@ pub fn handle_json_response<F: WakuDecode>(code: i32, result: LibwakuResponse) -
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_response<F: FromStr>(code: i32, result: LibwakuResponse) -> Result<F>
|
||||
where
|
||||
<F as FromStr>::Err: std::fmt::Debug,
|
||||
{
|
||||
match result {
|
||||
LibwakuResponse::Success(v) => v
|
||||
.unwrap_or_default()
|
||||
.parse()
|
||||
.map_err(|e| format!("could not parse value: {:?}", e)),
|
||||
LibwakuResponse::Failure(v) => Err(v),
|
||||
LibwakuResponse::MissingCallback => panic!("callback is required"),
|
||||
LibwakuResponse::Undefined => panic!(
|
||||
"undefined ffi state: code({}) was returned but callback was not executed",
|
||||
code
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,15 +18,13 @@ const ECHO_TIMEOUT: u64 = 1000;
|
||||
const ECHO_MESSAGE: &str = "Hi from 🦀!";
|
||||
const TEST_PUBSUBTOPIC: &str = "test";
|
||||
|
||||
fn try_publish_relay_messages(
|
||||
async fn try_publish_relay_messages(
|
||||
node: &WakuNodeHandle<Running>,
|
||||
msg: &WakuMessage,
|
||||
) -> Result<HashSet<MessageHash>, String> {
|
||||
Ok(HashSet::from([node.relay_publish_message(
|
||||
msg,
|
||||
&PubsubTopic::new(TEST_PUBSUBTOPIC),
|
||||
None,
|
||||
)?]))
|
||||
Ok(HashSet::from([node
|
||||
.relay_publish_message(msg, &PubsubTopic::new(TEST_PUBSUBTOPIC), None)
|
||||
.await?]))
|
||||
}
|
||||
|
||||
async fn test_echo_messages(
|
||||
@ -66,21 +64,23 @@ async fn test_echo_messages(
|
||||
.set_event_callback(closure)
|
||||
.expect("set event call back working"); // Set the event callback with the closure
|
||||
|
||||
let node1 = node1.start()?;
|
||||
let node2 = node2.start()?;
|
||||
let node1 = node1.start().await?;
|
||||
let node2 = node2.start().await?;
|
||||
|
||||
node1
|
||||
.relay_subscribe(&PubsubTopic::new(TEST_PUBSUBTOPIC))
|
||||
.await
|
||||
.unwrap();
|
||||
node2
|
||||
.relay_subscribe(&PubsubTopic::new(TEST_PUBSUBTOPIC))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
sleep(Duration::from_secs(3)).await;
|
||||
|
||||
// Interconnect nodes
|
||||
// Replace all matches with 127.0.0.1 to avoid issue with NAT or firewall.
|
||||
let addresses1 = node1.listen_addresses().unwrap();
|
||||
let addresses1 = node1.listen_addresses().await.unwrap();
|
||||
let addresses1 = &addresses1[0].to_string();
|
||||
|
||||
let re = Regex::new(r"\b(?:\d{1,3}\.){3}\d{1,3}\b").unwrap();
|
||||
@ -89,7 +89,7 @@ async fn test_echo_messages(
|
||||
let addresses1 = addresses1.parse::<Multiaddr>().expect("parse multiaddress");
|
||||
|
||||
println!("Connecting node1 to node2: {}", addresses1);
|
||||
node2.connect(&addresses1, None).unwrap();
|
||||
node2.connect(&addresses1, None).await.unwrap();
|
||||
|
||||
// Wait for mesh to form
|
||||
sleep(Duration::from_secs(3)).await;
|
||||
@ -108,7 +108,9 @@ async fn test_echo_messages(
|
||||
Vec::new(),
|
||||
false,
|
||||
);
|
||||
let _ids = try_publish_relay_messages(&node1, &message).expect("send relay messages");
|
||||
let _ids = try_publish_relay_messages(&node1, &message)
|
||||
.await
|
||||
.expect("send relay messages");
|
||||
|
||||
// Wait for the msg to arrive
|
||||
let rx_waku_message_cloned = rx_waku_message.clone();
|
||||
@ -118,8 +120,8 @@ async fn test_echo_messages(
|
||||
let payload = msg.payload.to_vec();
|
||||
let payload_str = from_utf8(&payload).expect("should be valid message");
|
||||
if payload_str == ECHO_MESSAGE {
|
||||
node1.stop()?;
|
||||
node2.stop()?;
|
||||
node1.stop().await?;
|
||||
node2.stop().await?;
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
@ -127,11 +129,11 @@ async fn test_echo_messages(
|
||||
}
|
||||
}
|
||||
|
||||
let node1 = node1.stop()?;
|
||||
let node2 = node2.stop()?;
|
||||
let node1 = node1.stop().await?;
|
||||
let node2 = node2.stop().await?;
|
||||
|
||||
node1.waku_destroy()?;
|
||||
node2.waku_destroy()?;
|
||||
node1.waku_destroy().await?;
|
||||
node2.waku_destroy().await?;
|
||||
|
||||
return Err("Unexpected test ending".to_string());
|
||||
}
|
||||
@ -143,11 +145,13 @@ async fn default_echo() -> Result<(), String> {
|
||||
let node1 = waku_new(Some(WakuNodeConfig {
|
||||
tcp_port: Some(60010),
|
||||
..Default::default()
|
||||
}))?;
|
||||
}))
|
||||
.await?;
|
||||
let node2 = waku_new(Some(WakuNodeConfig {
|
||||
tcp_port: Some(60020),
|
||||
..Default::default()
|
||||
}))?;
|
||||
}))
|
||||
.await?;
|
||||
|
||||
let content_topic = WakuContentTopic::new("toychat", "2", "huilong", Encoding::Proto);
|
||||
|
||||
@ -165,9 +169,8 @@ async fn default_echo() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn node_restart() {
|
||||
#[tokio::test]
|
||||
async fn node_restart() {
|
||||
let config = WakuNodeConfig {
|
||||
node_key: Some(
|
||||
SecretKey::from_str("05f381866cc21f6c1e2e80e07fa732008e36d942dce3206ad6dcd6793c98d609")
|
||||
@ -177,9 +180,14 @@ fn node_restart() {
|
||||
};
|
||||
|
||||
for _ in 0..3 {
|
||||
let node = waku_new(config.clone().into()).expect("default config should be valid");
|
||||
let node = node.start().expect("node should start with valid config");
|
||||
let node = node.stop().expect("node should stop");
|
||||
node.waku_destroy().expect("free resources");
|
||||
let node = waku_new(config.clone().into())
|
||||
.await
|
||||
.expect("default config should be valid");
|
||||
let node = node
|
||||
.start()
|
||||
.await
|
||||
.expect("node should start with valid config");
|
||||
let node = node.stop().await.expect("node should stop");
|
||||
node.waku_destroy().await.expect("free resources");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 1fa916589d3a69a2bb770aba27d4124b929cc4b2
|
||||
Subproject commit 1d206a5f5e89f7bac855bfd2e25066bcf1187ade
|
||||
Loading…
x
Reference in New Issue
Block a user