diff --git a/examples/tic-tac-toe-gui/Cargo.toml b/examples/tic-tac-toe-gui/Cargo.toml index 8349a2e..21e41d9 100644 --- a/examples/tic-tac-toe-gui/Cargo.toml +++ b/examples/tic-tac-toe-gui/Cargo.toml @@ -13,4 +13,5 @@ tokio = { version = "1", features = ["full"] } tokio-util = "0.6" # for utility functions if needed egui = "0.22" eframe = "0.22" +secp256k1 = { version = "0.26", features = ["rand", "recovery", "serde"] } diff --git a/examples/tic-tac-toe-gui/src/main.rs b/examples/tic-tac-toe-gui/src/main.rs index fc21aac..3dbd4f0 100644 --- a/examples/tic-tac-toe-gui/src/main.rs +++ b/examples/tic-tac-toe-gui/src/main.rs @@ -1,10 +1,14 @@ use eframe::egui; +use secp256k1::SecretKey; use serde::{Deserialize, Serialize}; use std::cell::OnceCell; use std::str::from_utf8; use std::sync::Arc; use std::sync::Mutex; +use std::str::FromStr; use std::time::SystemTime; +use std::time::{Duration, Instant}; + use tokio::sync::mpsc; use waku::{ waku_new, Encoding, Event, Initialized, LibwakuResponse, Multiaddr, Running, WakuContentTopic, @@ -33,28 +37,23 @@ struct MoveMessage { struct TicTacToeApp { game_state: Arc>, - val: Arc>, waku: WakuNodeHandle, game_topic: &'static str, - tx: Arc>>, // Sender to send `msg` to main thread + tx: mpsc::Sender, // Sender to send `msg` to main thread } impl TicTacToeApp { fn new( waku: WakuNodeHandle, game_topic: &'static str, - tx: Arc>>, + game_state: Arc>, + tx: mpsc::Sender, ) -> 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())), + game_state, waku, game_topic, - tx: tx, + tx, } } @@ -62,94 +61,24 @@ impl TicTacToeApp { // 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); - let tx_clone = self.tx.clone(); let my_closure = move |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(); + let payload = message.payload.to_vec(); 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.blocking_send(msg.to_string()).is_err() { - eprintln!("Failed to send message to async task"); - } else { - eprintln!("Sent!!!!"); - } - } else { - eprintln!("Failed to acquire lock on tx_clone"); + // Lock succeeded, proceed to send the message + if tx_clone.blocking_send(msg.to_string()).is_err() { + eprintln!("Failed to send message to async task"); } - // 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); @@ -170,12 +99,14 @@ impl TicTacToeApp { 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"); + // let target_node_multi_addr = + // "/ip4/159.223.242.94/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT" + // // "/dns4/store-01.do-ams3.status.prod.status.im/tcp/30303/p2p/16Uiu2HAmAUdrQ3uwzuE4Gy4D56hX6uLKEeerJAnhKEHZ3DxF1EfT" + // // "/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"); + // self.waku.connect(&target_node_multi_addr, None) + // .expect("waku should connect to other node"); } fn send_game_state(&self, game_state: &GameState) { @@ -263,6 +194,10 @@ impl TicTacToeApp { impl eframe::App for TicTacToeApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + + // Request a repaint every second + ctx.request_repaint_after(Duration::from_secs(1)); + egui::CentralPanel::default().show(ctx, |ui| { ui.heading("Tic-Tac-Toe"); @@ -334,20 +269,61 @@ impl eframe::App for TicTacToeApp { async fn main() -> eframe::Result<()> { let (tx, mut rx) = mpsc::channel::(3200); // Channel to communicate between threads + let game_topic = "/waku/2/rs/16/32"; // Create a Waku instance let waku = waku_new(Some(WakuNodeConfig { port: Some(60010), cluster_id: Some(16), + shards: vec![1, 32, 64, 128, 256], + // node_key: Some(SecretKey::from_str("2fc0515879e52b7b73297cfd6ab3abf7c344ef84b7a90ff6f4cc19e05a198027").unwrap()), + max_message_size: Some("1024KiB".to_string()), + relay_topics: vec![game_topic.to_string()], log_level: Some("DEBUG"), // Supported: TRACE, DEBUG, INFO, NOTICE, WARN, ERROR or FATAL + + keep_alive: Some(true), + + // Discovery + dns_discovery: Some(true), + dns_discovery_url: Some("enrtree://AMOJVZX4V6EXP7NTJPMAYJYST2QP6AJXYW76IU6VGJS7UVSNDYZG4@boot.prod.status.nodes.status.im"), + discv5_discovery: Some(true), + discv5_udp_port: Some(9000), + discv5_enr_auto_update: Some(false), + ..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))); + + let game_state = GameState { + board: [[None; 3]; 3], + current_turn: Player::X, + moves_left: 9, + }; + let shared_state = Arc::new(Mutex::new(game_state)); + + let clone = shared_state.clone(); + let mut app = TicTacToeApp::new(waku, game_topic, clone, tx); app.start(); + let clone = shared_state.clone(); + // Listen for messages in the main thread + tokio::spawn(async move { + while let Some(msg) = rx.recv().await { + println!("MSG received: {}", msg); + // Handle the received message, e.g., update the UI or game state + if let Ok(parsed_value) = serde_json::from_str::(&msg) + { + if let Ok(mut unclocked_game_state) = clone.lock(){ + *unclocked_game_state = parsed_value; + } + } + else { + eprintln!("Failed to parse JSON: "); + } + } + }); + eframe::run_native( "Tic-Tac-Toe Multiplayer via Waku", eframe::NativeOptions { @@ -357,13 +333,6 @@ async fn main() -> eframe::Result<()> { 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/waku-bindings/src/node/config.rs b/waku-bindings/src/node/config.rs index fd718d7..8149088 100644 --- a/waku-bindings/src/node/config.rs +++ b/waku-bindings/src/node/config.rs @@ -23,16 +23,37 @@ pub struct WakuNodeConfig { /// Cluster id that the node is running in #[default(Some(0))] pub cluster_id: Option, - /// Enable relay protocol. Default `true` + + /// Relay protocol #[default(Some(true))] pub relay: Option, pub relay_topics: Vec, + pub shards: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub max_message_size: Option, + /// RLN configuration #[serde(skip_serializing_if = "Option::is_none")] pub rln_relay: Option, + + // Discovery + #[default(Some(false))] + pub dns_discovery: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub dns_discovery_url: Option<&'static str>, + + #[default(Some(false))] + pub discv5_discovery: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub discv5_udp_port: Option, + #[default(Some(false))] + pub discv5_enr_auto_update: Option, + // other settings #[serde(skip_serializing_if = "Option::is_none")] pub log_level: Option<&'static str>, + #[serde(skip_serializing_if = "Option::is_none")] + pub keep_alive: Option, } /// RLN Relay configuration diff --git a/waku-bindings/src/node/events.rs b/waku-bindings/src/node/events.rs index 6095477..1d9c950 100644 --- a/waku-bindings/src/node/events.rs +++ b/waku-bindings/src/node/events.rs @@ -5,14 +5,14 @@ //! When an event is emitted, this callback will be triggered receiving an [`Event`] // std -use std::ffi::{c_char, c_int, c_void, CStr}; +use std::ffi::c_void; // crates use serde::{Deserialize, Serialize}; // internal use crate::general::WakuMessage; use std::{slice, str}; -use crate::utils::{get_trampoline, LibwakuResponse}; +use crate::utils::LibwakuResponse; use crate::MessageHash; use std::ops::Deref; use std::sync::Mutex;