diff --git a/examples/tic-tac-toe-gui/Cargo.toml b/examples/tic-tac-toe-gui/Cargo.toml new file mode 100644 index 0000000..8349a2e --- /dev/null +++ b/examples/tic-tac-toe-gui/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "tic-tac-toe-gui" +version = "0.1.0" +edition = "2021" + +[dependencies] +waku = { path = "../../waku-bindings", package = "waku-bindings" } +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +ark-std = "0.4" +ctrlc = "3.2.4" +tokio = { version = "1", features = ["full"] } +tokio-util = "0.6" # for utility functions if needed +egui = "0.22" +eframe = "0.22" + diff --git a/examples/tic-tac-toe-gui/src/main.rs b/examples/tic-tac-toe-gui/src/main.rs new file mode 100644 index 0000000..88f2a4f --- /dev/null +++ b/examples/tic-tac-toe-gui/src/main.rs @@ -0,0 +1,366 @@ +use eframe::egui; +use serde::{Deserialize, Serialize}; +use tokio::sync::mpsc; +use std::sync::Arc; +use tokio::sync::Mutex; +use std::str::from_utf8; +use std::time::SystemTime; +use std::cell::OnceCell; +use waku::{ + waku_new, Event, WakuNodeConfig, + LibwakuResponse, Multiaddr, Running, WakuNodeHandle, + Initialized, WakuContentTopic, WakuMessage, Encoding, + WakuNodeContext, +}; + +#[derive(Serialize, Deserialize, PartialEq, Copy, Clone)] +enum Player { + X, + O, +} + +#[derive(Serialize, Deserialize, Clone)] +struct GameState { + board: [[Option; 3]; 3], + current_turn: Player, + moves_left: usize, +} + +#[derive(Clone)] +struct MoveMessage { + row: usize, + col: usize, + player: Player, +} + +struct TicTacToeApp { + game_state: Arc>, + val: Arc>, + waku: WakuNodeHandle, + game_topic: &'static str, + tx: Arc>>, // Sender to send `msg` to main thread +} + +impl TicTacToeApp { + fn new(waku: WakuNodeHandle, + game_topic: &'static str, + tx: Arc>>,) -> Self { + Self { + game_state: Arc::new(Mutex::new(GameState { + board: [[None; 3]; 3], + current_turn: Player::X, + moves_left: 9, + })), + val: Arc::new(Mutex::new("".to_string())), + waku, + game_topic, + tx: tx, + } + } + + fn start(&mut self) { + // Start the waku node + self.waku.start().expect("waku should start"); + + // let default_pubsub_topic = Arc::new(Mutex::new("".to_string())); + // let shared_data_clone = Arc::clone(&default_pubsub_topic); + // // Establish a closure that handles the incoming messages + // self.waku.ctx.waku_set_event_callback(|response| { + + // let mut data = shared_data_clone.lock().unwrap(); + // *data = "Updated from another thread".to_string(); // Write access + + // println!("funciona ?"); + + + let mut cloned = Arc::clone(&self.val); + + // Establish a closure that handles the incoming messages + self.waku.ctx.waku_set_event_callback(|response| { + + // if let Ok(mut tx) = tx_clone.try_lock() { + // Lock succeeded, proceed to send the message + // if tx.try_send(msg.to_string()).is_err() { + // eprintln!("Failed to send message to async task"); + // } + // } else { + // eprintln!("Failed to acquire lock on tx_clone"); + // } + if let Ok(mut aa) = cloned.try_lock() { + + } + + // match cloned.lock() { + // Ok(mut data) => { + // *data = "Modified Value".to_string(); + // println!("Thread updated value to: {}", data); + // }, + // Err(e) => { + // eprintln!("Failed to lock the mutex in thread: {}", e); + // } + // } + + + if let LibwakuResponse::Success(v) = response { + let event: Event = + serde_json::from_str(v.unwrap().as_str()).expect("Parsing event to succeed"); + + // let mut game_state = self.game_state.lock().unwrap(); + match event { + Event::WakuMessage(evt) => { + // println!("WakuMessage event received: {:?}", evt.waku_message); + let message = evt.waku_message; + let payload = message.payload.to_vec().clone(); + match from_utf8(&payload) { + Ok(msg) => { + println!("::::::::::::::::::::::::::::::::::::::::::::::::::::"); + println!("Message Received: {}", msg); + println!("::::::::::::::::::::::::::::::::::::::::::::::::::::"); + + // Send the message to the main thread + // if let Ok(mut tx) = tx_clone.try_lock() { + // Lock succeeded, proceed to send the message + // if tx.try_send(msg.to_string()).is_err() { + // eprintln!("Failed to send message to async task"); + // } + // } else { + // eprintln!("Failed to acquire lock on tx_clone"); + // } + + // Deserialize the JSON into the GameState struct + // Lock the game_state and update it + // match serde_json::from_str::(msg) { + // Ok(parsed_value) => { + // // Handle the parsed value here + // // self.game_state = parsed_value; + // println!("Parsed correctly"); + // } + // Err(e) => { + // eprintln!("Failed to parse JSON: {}", e); + // // Handle the error as needed, such as retrying, defaulting, etc. + // } + // } + // *game_state = serde_json::from_str(msg).expect("Failed to deserialize JSON"); + + // let tx_inner = tx_cloned.clone(); + // let msg_inner = msg.to_string(); + // tokio::spawn(async move { + // println!("do nothing"); + // if tx_inner.send(msg_inner.to_string()).await.is_err() { + // eprintln!("Failed to send message"); + // } + // }); + } + Err(e) => { + eprintln!("Failed to decode payload as UTF-8: {}", e); + // Handle the error as needed, or just log and skip + } + } + } + Event::Unrecognized(err) => panic!("Unrecognized waku event: {:?}", err), + _ => panic!("event case not expected"), + }; + } + }); + + // Subscribe to desired topic + self.waku.relay_subscribe(&self.game_topic.to_string()).expect("waku should subscribe"); + + // Connect to hard-coded node + let target_node_multi_addr = + "/ip4/24.144.78.119/tcp/30303/p2p/16Uiu2HAm3xVDaz6SRJ6kErwC21zBJEZjavVXg7VSkoWzaV1aMA3F" + .parse::().expect("parse multiaddress"); + + self.waku.connect(&target_node_multi_addr, None) + .expect("waku should connect to other node"); + } + + 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); + + let message = WakuMessage::new( + &serialized_game_state, + content_topic, + 0, + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_millis() + .try_into() + .unwrap(), + Vec::new(), + false, + ); + + // let waku_handle = self.waku.lock().unwrap(); + self.waku.relay_publish_message(&message, &self.game_topic.to_string(), None) + .expect("Failed to send message"); + } + + fn make_move(&mut self, row: usize, col: usize) { + if let Ok(mut game_state) = self.game_state.try_lock() { + if (*game_state).board[row][col].is_none() && (*game_state).moves_left > 0 { + (*game_state).board[row][col] = Some((*game_state).current_turn); + (*game_state).moves_left -= 1; + + if let Some(winner) = self.check_winner(&game_state) { + (*game_state).current_turn = winner; + } else { + (*game_state).current_turn = match (*game_state).current_turn { + Player::X => Player::O, + Player::O => Player::X, + }; + } + + self.send_game_state(&game_state); // Send updated state after a move + } + } + } + + fn check_winner(&self, game_state: &GameState) -> Option { + // Check rows, columns, and diagonals + for i in 0..3 { + if game_state.board[i][0] == game_state.board[i][1] && + game_state.board[i][1] == game_state.board[i][2] { + if let Some(player) = game_state.board[i][0] { + return Some(player); + } + } + if game_state.board[0][i] == game_state.board[1][i] && + game_state.board[1][i] == game_state.board[2][i] { + if let Some(player) = game_state.board[0][i] { + return Some(player); + } + } + } + if game_state.board[0][0] == game_state.board[1][1] && + game_state.board[1][1] == game_state.board[2][2] { + if let Some(player) = game_state.board[0][0] { + return Some(player); + } + } + if game_state.board[0][2] == game_state.board[1][1] && + game_state.board[1][1] == game_state.board[2][0] { + if let Some(player) = game_state.board[0][2] { + return Some(player); + } + } + None + } + + fn reset_game(&mut self) { + self.game_state = Arc::new(Mutex::new(GameState { + board: [[None; 3]; 3], + current_turn: Player::X, + moves_left: 9, + })); + } +} + +impl eframe::App for TicTacToeApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + egui::CentralPanel::default().show(ctx, |ui| { + ui.heading("Tic-Tac-Toe"); + + let text_size = 32.0; + let board_size = ui.available_size(); + let cell_size = board_size.x / 4.0; + + ui.horizontal(|ui| { + for row in 0..3 { + ui.vertical(|ui| { + for col in 0..3 { + let label; + { + if let Ok(game_state) = self.game_state.try_lock() { + label = match game_state.board[row][col] { + Some(Player::X) => "X", + Some(Player::O) => "O", + None => "-", + }; + } + else { + label = "#"; + } + } + + let button = ui.add(egui::Button::new(label).min_size(egui::vec2(cell_size, cell_size)).sense(egui::Sense::click())); + + if button.clicked() { + self.make_move(row, col); + } + } + }); + if row < 2 { + ui.add_space(4.0); + } + } + }); + + if let Ok(game_state) = self.game_state.try_lock() { + if let Some(winner) = self.check_winner(&game_state) { + ui.label(format!( + "Player {} wins!", + match winner { + Player::X => "X", + Player::O => "O", + } + )); + } else if game_state.moves_left == 0 { + ui.label("It's a tie!"); + } else { + ui.label(format!( + "Player {}'s turn", + match game_state.current_turn { + Player::X => "X", + Player::O => "O", + } + )); + } + } + + if ui.add(egui::Button::new("Restart Game")).clicked() { + self.reset_game(); + } + }); + } +} + +fn main() -> eframe::Result<()> { + let (tx, mut rx) = mpsc::channel::(3200); // Channel to communicate between threads + + // Create a Waku instance + let waku = waku_new(Some(WakuNodeConfig { + port: Some(60010), + cluster_id: Some(16), + log_level: Some("DEBUG"), // Supported: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL + ..Default::default() + })) + .expect("should instantiate"); + // Initialize Waku + let game_topic = "/waku/2/rs/16/64"; + let mut app = TicTacToeApp::new(waku, game_topic, Arc::new(Mutex::new(tx))); + + app.start(); + + eframe::run_native( + "Tic-Tac-Toe Multiplayer via Waku", + eframe::NativeOptions { + initial_window_size: Some(egui::vec2(400.0, 400.0)), + ..Default::default() + }, + Box::new(|_cc| Box::new(app)), + )?; + + // Listen for messages in the main thread + tokio::spawn(async move { + while let Some(msg) = rx.recv().await { + println!("Main thread received: {}", msg); + // Handle the received message, e.g., update the UI or game state + } + }); + + Ok(()) +} diff --git a/examples/tic-tac-toe/src/main.rs b/examples/tic-tac-toe/src/main.rs index 61e5e65..e401a86 100644 --- a/examples/tic-tac-toe/src/main.rs +++ b/examples/tic-tac-toe/src/main.rs @@ -1,5 +1,16 @@ extern crate termcolor; +use std::sync::mpsc; // For standard channels +use std::thread; +use tokio::sync::mpsc as tokio_mpsc; // For tokio's asynchronous channels +use tokio::io::{self, AsyncBufReadExt}; // For async I/O +use tokio::time::{sleep, Duration}; +use tokio::task::LocalSet; +use tokio::runtime::Builder; +use tokio::sync::OnceCell; + +use std::sync::{Arc, Mutex}; + use std::io::Write; use std::str::from_utf8; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; @@ -18,20 +29,20 @@ fn greeting() { ) } -fn print_player(player: &char) { +fn print_player(current_player: &char) { let mut stdout = StandardStream::stdout(ColorChoice::Always); - if player == &'X' { + if current_player == &'X' { stdout .set_color(ColorSpec::new().set_fg(Some(Color::Blue))) .unwrap(); - } else if player == &'O' { + } else if current_player == &'O' { stdout .set_color(ColorSpec::new().set_fg(Some(Color::Green))) .unwrap(); } - write!(&mut stdout, "{}", player).unwrap(); + write!(&mut stdout, "{}", current_player).unwrap(); stdout.reset().unwrap(); } @@ -53,40 +64,68 @@ fn draw(board: &[char]) { println!("-------------"); } -fn ask_user(board: &mut [char], player: char) { - loop { - print!("Player '"); - print_player(&player); - println!("', enter a number: "); +fn ask_game_name_to_user(game_name: &mut String) { + println!("Indicate the game name (arbitrary word)"); - let mut input = String::new(); - if std::io::stdin().read_line(&mut input).is_err() { - println!("Couldn't read line! Try again."); - continue; + let mut input = String::new(); + if std::io::stdin().read_line(&mut input).is_err() { + println!("Couldn't read line! Try again."); + } + + if let Ok(val) = input.trim().parse::() { + *game_name = val; + } else { + println!("Only chars are allowed."); + } +} + +fn ask_role_to_user(role: &mut char) { + println!("Select your role, X or O:"); + + let mut input = String::new(); + if std::io::stdin().read_line(&mut input).is_err() { + println!("Couldn't read line! Try again."); + } + + if let Ok(val) = input.trim().parse::() { + if val != 'X' && val != 'O' { + println!("The user role must be either X or O."); + return; } - if let Ok(number) = input.trim().parse::() { - if number < 1 || number > 9 { - println!("The field number must be between 1 and 9."); - continue; - } + *role = val; + } else { + println!("Only chars are allowed."); + } +} - let number = number - 1; +fn ask_user(board: &mut [char], current_player: char) { + print!("Player '"); + print_player(¤t_player); + println!("', enter a number: "); - if board[number] == 'X' || board[number] == 'O' { - print!("This field is already taken by '"); - print_player(&board[number]); - println!("'."); - continue; - } + let mut input = String::new(); + if std::io::stdin().read_line(&mut input).is_err() { + println!("Couldn't read line! Try again."); + return; + } - board[number] = player; - - break; - } else { - println!("Only numbers are allowed."); - continue; + if let Ok(number) = input.trim().parse::() { + if number < 1 || number > 9 { + println!("The field number must be between 1 and 9."); } + + let number = number - 1; + + if board[number] == 'X' || board[number] == 'O' { + print!("This field is already taken by '"); + print_player(&board[number]); + println!("'."); + } + + board[number] = current_player; + } else { + println!("Only numbers are allowed."); } } @@ -119,21 +158,14 @@ fn is_over(board: &[char]) -> bool { // Return true if the game should end. // false otherwise -fn game_logic(player: &mut char, board: &mut [char], +fn game_logic(current_player: &mut char, board: &mut [char], topic: &str, waku: &WakuNodeHandle) -> bool { - // Ask for user input - ask_user(board, *player); - - let board_string: String = board.iter().collect(); - let board_str_slice: &str = &board_string; - - let _ = waku.relay_publish_txt(topic, &board_str_slice, "tic-tac-toe-example", None); // Check if a player won if has_won(&board) { draw(&board); print!("Player '"); - print_player(&player); + print_player(¤t_player); println!("' won! \\(^.^)/"); return true; } @@ -145,20 +177,26 @@ fn game_logic(player: &mut char, board: &mut [char], return true; } - // Switch player - *player = if *player == 'X' { 'O' } else { 'X' }; return false; } -fn main() { +#[tokio::main] +async fn main() { + // Create a channel for communication + let buffer_size = 256; + // let (tx, mut rx) = tokio_mpsc::channel(buffer_size); + let mut board = ['1', '2', '3', '4', '5', '6', '7', '8', '9']; - let mut player = 'X'; - let topic = "/waku/2/rs/16/64"; + let mut current_player = 'X'; + let mut my_role = 'X'; // Keeps track of my role, X or O. + let mut game_name = "anonymous".to_string(); + let topic = "/waku/2/rs/16/64".to_string(); // Create a Waku instance let waku = waku_new(Some(WakuNodeConfig { port: Some(60010), cluster_id: Some(16), + log_level: Some("ERROR"), // Supported: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL ..Default::default() })) .expect("should instantiate"); @@ -167,9 +205,12 @@ fn main() { // println!("Ctrl+C detected. Exiting gracefully..."); // // waku.stop(); // }).expect("Error setting Ctrl+C handler"); - let waku = waku.start().expect("waku should start"); + // let tx_cloned = tx.clone(); + // Wait for tasks to complete + let _ = tokio::join!(setter, reader); + // Establish a closure that handles the incoming messages waku.set_event_callback(&|response| { if let LibwakuResponse::Success(v) = response { @@ -180,14 +221,21 @@ fn main() { Event::WakuMessage(evt) => { println!("WakuMessage event received: {:?}", evt.waku_message); let message = evt.waku_message; - let payload = message.payload.to_vec(); + let payload = message.payload.to_vec().clone(); match from_utf8(&payload) { Ok(msg) => { println!("::::::::::::::::::::::::::::::::::::::::::::::::::::"); println!("Message Received: {}", msg); println!("::::::::::::::::::::::::::::::::::::::::::::::::::::"); - // game_logic(&mut player, &mut board, topic, &waku); + // let tx_inner = tx_cloned.clone(); + let msg_inner = msg.to_string(); + // tokio::spawn(async move { + // println!("do nothing"); + // if tx_inner.send(msg_inner.to_string()).await.is_err() { + // eprintln!("Failed to send message"); + // } + // }); } Err(e) => { eprintln!("Failed to decode payload as UTF-8: {}", e); @@ -203,8 +251,11 @@ fn main() { waku.relay_subscribe(&topic).expect("waku should subscribe"); + // let target_node_multi_addr = + // "/dns4/store-01.do-ams3.status.staging.status.im/tcp/30303/p2p/16Uiu2HAm3xVDaz6SRJ6kErwC21zBJEZjavVXg7VSkoWzaV1aMA3F" + // .parse::().expect("parse multiaddress"); let target_node_multi_addr = - "/dns4/store-01.do-ams3.status.staging.status.im/tcp/30303/p2p/16Uiu2HAm3xVDaz6SRJ6kErwC21zBJEZjavVXg7VSkoWzaV1aMA3F" + "/ip4/24.144.78.119/tcp/30303/p2p/16Uiu2HAm3xVDaz6SRJ6kErwC21zBJEZjavVXg7VSkoWzaV1aMA3F" .parse::().expect("parse multiaddress"); waku.connect(&target_node_multi_addr, None) @@ -212,13 +263,51 @@ fn main() { // Welcome the player greeting(); + // Draw the field + draw(&board); - loop { - // Draw the field - draw(&board); + ask_role_to_user(&mut my_role); + ask_game_name_to_user(&mut game_name); + + println!("AAAA 1"); + let board_string: String = board.iter().collect(); + println!("AAAA 2"); + let _ = waku.relay_publish_txt(&topic, + &board_string, + "tic-tac-toe-example", + None); + println!("AAAA 3"); + + // Main receiver task + // tokio::spawn(async move { + + // loop { + // // Draw the field + // draw(&board); + + // if my_role == current_player { + // // is my turn + // // Ask for user input + // ask_user(&mut board, current_player); + // } + // else { + // // other player's turn + // println!("Waiting oponent's movement"); + // while let Some(message) = rx.recv().await { + // println!("Received: {}", message); + // break; + // } + // } + + // if game_logic(&mut current_player, &mut board, topic, &waku) { + // break; + // } + + // // Switch current_player + // current_player = if current_player == 'X' { 'O' } else { 'X' }; + // } + // }); + // .await + // .expect("Receiver task panicked"); +} - if game_logic(&mut player, &mut board, topic, &waku) { - break; - } - } -} \ No newline at end of file diff --git a/waku-bindings/src/lib.rs b/waku-bindings/src/lib.rs index ee98013..65a4f25 100644 --- a/waku-bindings/src/lib.rs +++ b/waku-bindings/src/lib.rs @@ -17,6 +17,7 @@ use rln; pub use node::{ waku_create_content_topic, waku_destroy, waku_new, Event, Initialized, Key, Multiaddr, PublicKey, RLNConfig, Running, SecretKey, WakuMessageEvent, WakuNodeConfig, WakuNodeHandle, + WakuNodeContext, }; pub use general::{ diff --git a/waku-bindings/src/node/config.rs b/waku-bindings/src/node/config.rs index eb9e5c0..fd718d7 100644 --- a/waku-bindings/src/node/config.rs +++ b/waku-bindings/src/node/config.rs @@ -30,6 +30,9 @@ pub struct WakuNodeConfig { /// RLN configuration #[serde(skip_serializing_if = "Option::is_none")] pub rln_relay: Option, + // other settings + #[serde(skip_serializing_if = "Option::is_none")] + pub log_level: Option<&'static str>, } /// RLN Relay configuration diff --git a/waku-bindings/src/node/context.rs b/waku-bindings/src/node/context.rs deleted file mode 100644 index 846ae67..0000000 --- a/waku-bindings/src/node/context.rs +++ /dev/null @@ -1,6 +0,0 @@ -// crates -use libc::c_void; - -pub struct WakuNodeContext { - pub obj_ptr: *mut c_void, -} diff --git a/waku-bindings/src/node/events.rs b/waku-bindings/src/node/events.rs index 4871c07..3465b7f 100644 --- a/waku-bindings/src/node/events.rs +++ b/waku-bindings/src/node/events.rs @@ -10,10 +10,13 @@ use std::ffi::c_void; use serde::{Deserialize, Serialize}; // internal use crate::general::WakuMessage; -use crate::node::context::WakuNodeContext; use crate::utils::{get_trampoline, LibwakuResponse}; use crate::MessageHash; +pub struct WakuNodeContext { + pub obj_ptr: *mut c_void, +} + /// Waku event /// For now just WakuMessage is supported #[non_exhaustive] @@ -37,13 +40,15 @@ pub struct WakuMessageEvent { pub waku_message: WakuMessage, } -/// Register callback to act as event handler and receive application events, -/// which are used to react to asynchronous events in Waku -pub fn waku_set_event_callback(ctx: &WakuNodeContext, closure: &F) { - unsafe { - let cb = get_trampoline(closure); - waku_sys::waku_set_event_callback(ctx.obj_ptr, cb, closure as *const _ as *mut c_void) - }; +impl WakuNodeContext { + /// Register callback to act as event handler and receive application events, + /// which are used to react to asynchronous events in Waku + pub fn waku_set_event_callback(&self, mut closure: F) { + unsafe { + let cb = get_trampoline(&closure); + waku_sys::waku_set_event_callback(self.obj_ptr, cb, &mut closure as *mut _ as *mut c_void) + }; + } } #[cfg(test)] diff --git a/waku-bindings/src/node/management.rs b/waku-bindings/src/node/management.rs index ff9fa8a..2926b4e 100644 --- a/waku-bindings/src/node/management.rs +++ b/waku-bindings/src/node/management.rs @@ -8,10 +8,10 @@ use multiaddr::Multiaddr; // internal use super::config::WakuNodeConfig; use crate::general::Result; -use crate::node::context::WakuNodeContext; use crate::utils::LibwakuResponse; use crate::utils::{get_trampoline, handle_json_response, handle_no_response, handle_response}; use crate::utils::WakuDecode; +use crate::node::events::WakuNodeContext; /// Instantiates a Waku node /// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_newchar-jsonconfig) diff --git a/waku-bindings/src/node/mod.rs b/waku-bindings/src/node/mod.rs index cd3b266..a3386c0 100644 --- a/waku-bindings/src/node/mod.rs +++ b/waku-bindings/src/node/mod.rs @@ -1,7 +1,6 @@ //! Waku node implementation mod config; -mod context; mod events; mod management; mod peers; @@ -11,16 +10,13 @@ mod relay; pub use aes_gcm::Key; pub use multiaddr::Multiaddr; pub use secp256k1::{PublicKey, SecretKey}; -use std::marker::PhantomData; use std::time::Duration; // internal use crate::general::{MessageHash, Result, WakuMessage}; -use crate::LibwakuResponse; -use context::WakuNodeContext; pub use config::RLNConfig; pub use config::WakuNodeConfig; -pub use events::{Event, WakuMessageEvent}; +pub use events::{Event, WakuMessageEvent, WakuNodeContext}; pub use relay::waku_create_content_topic; use crate::WakuContentTopic; @@ -40,43 +36,35 @@ impl WakuNodeState for Initialized {} impl WakuNodeState for Running {} /// Handle to the underliying waku node -pub struct WakuNodeHandle { +pub struct WakuNodeHandle { pub ctx: WakuNodeContext, - phantom: PhantomData, } /// 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) -> Result> { +pub fn waku_new(config: Option) -> Result { Ok(WakuNodeHandle { ctx: management::waku_new(config)?, - phantom: PhantomData, }) } -pub fn waku_destroy(node: WakuNodeHandle) -> Result<()> { +pub fn waku_destroy(node: WakuNodeHandle) -> Result<()> { management::waku_destroy(&node.ctx) } -impl WakuNodeHandle { +// unsafe impl Send for WakuNodeHandle {} + +impl WakuNodeHandle { /// 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> { - management::waku_start(&self.ctx).map(|_| WakuNodeHandle { - ctx: self.ctx, - phantom: PhantomData, - }) + pub fn start(&self) -> Result<()> { + management::waku_start(&self.ctx) } -} -impl WakuNodeHandle { /// Stops a Waku node /// as per the [specification](https://rfc.vac.dev/spec/36/#extern-char-waku_stop) - pub fn stop(self) -> Result> { - management::waku_stop(&self.ctx).map(|_| WakuNodeHandle { - ctx: self.ctx, - phantom: PhantomData, - }) + pub fn stop(&self) -> Result<()> { + management::waku_stop(&self.ctx) } /// Get the multiaddresses the Waku node is listening to @@ -101,8 +89,8 @@ impl WakuNodeHandle { pub fn relay_publish_txt( &self, - pubsub_topic: &str, - msg_txt: &str, + pubsub_topic: &String, + msg_txt: &String, content_topic_name: &'static str, timeout: Option, ) -> Result { @@ -130,14 +118,14 @@ impl WakuNodeHandle { pub fn relay_publish_message( &self, message: &WakuMessage, - pubsub_topic: &str, + pubsub_topic: &String, timeout: Option, ) -> Result { 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: &str) -> Result<()> { + pub fn relay_subscribe(&self, pubsub_topic: &String) -> Result<()> { relay::waku_relay_subscribe(&self.ctx, pubsub_topic) } @@ -146,7 +134,4 @@ impl WakuNodeHandle { relay::waku_relay_unsubscribe(&self.ctx, pubsub_topic) } - pub fn set_event_callback(&self, closure: &F) { - events::waku_set_event_callback(&self.ctx, closure) - } } diff --git a/waku-bindings/src/node/peers.rs b/waku-bindings/src/node/peers.rs index 2fa1087..ccdaf46 100644 --- a/waku-bindings/src/node/peers.rs +++ b/waku-bindings/src/node/peers.rs @@ -8,9 +8,9 @@ use libc::*; use multiaddr::Multiaddr; // internal use crate::general::Result; -use crate::node::context::WakuNodeContext; use crate::utils::LibwakuResponse; use crate::utils::{get_trampoline, handle_no_response}; +use crate::node::events::WakuNodeContext; /// Dial peer using a multiaddress /// If `timeout` as milliseconds doesn't fit into a `i32` it is clamped to [`i32::MAX`] diff --git a/waku-bindings/src/node/relay.rs b/waku-bindings/src/node/relay.rs index d45d33e..5848187 100644 --- a/waku-bindings/src/node/relay.rs +++ b/waku-bindings/src/node/relay.rs @@ -7,7 +7,7 @@ use std::time::Duration; use libc::*; // internal use crate::general::{Encoding, MessageHash, Result, WakuContentTopic, WakuMessage}; -use crate::node::context::WakuNodeContext; +use crate::node::events::WakuNodeContext; use crate::utils::{get_trampoline, handle_no_response, handle_response, LibwakuResponse}; /// Create a content topic according to [RFC 23](https://rfc.vac.dev/spec/23/)