temporary changes - some interesting
This commit is contained in:
parent
d828948e85
commit
434b5c1e73
|
@ -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"
|
||||
|
|
@ -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<Player>; 3]; 3],
|
||||
current_turn: Player,
|
||||
moves_left: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MoveMessage {
|
||||
row: usize,
|
||||
col: usize,
|
||||
player: Player,
|
||||
}
|
||||
|
||||
struct TicTacToeApp {
|
||||
game_state: Arc<Mutex<GameState>>,
|
||||
val: Arc<Mutex<String>>,
|
||||
waku: WakuNodeHandle,
|
||||
game_topic: &'static str,
|
||||
tx: Arc<Mutex<mpsc::Sender<String>>>, // Sender to send `msg` to main thread
|
||||
}
|
||||
|
||||
impl TicTacToeApp {
|
||||
fn new(waku: WakuNodeHandle,
|
||||
game_topic: &'static str,
|
||||
tx: Arc<Mutex<mpsc::Sender<String>>>,) -> 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::<GameState>(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::<Multiaddr>().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<Player> {
|
||||
// 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::<String>(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(())
|
||||
}
|
|
@ -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::<String>() {
|
||||
*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::<char>() {
|
||||
if val != 'X' && val != 'O' {
|
||||
println!("The user role must be either X or O.");
|
||||
return;
|
||||
}
|
||||
|
||||
if let Ok(number) = input.trim().parse::<usize>() {
|
||||
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::<usize>() {
|
||||
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<Running>) -> 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::<Multiaddr>().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::<Multiaddr>().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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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::{
|
||||
|
|
|
@ -30,6 +30,9 @@ pub struct WakuNodeConfig {
|
|||
/// RLN configuration
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rln_relay: Option<RLNConfig>,
|
||||
// other settings
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub log_level: Option<&'static str>,
|
||||
}
|
||||
|
||||
/// RLN Relay configuration
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
// crates
|
||||
use libc::c_void;
|
||||
|
||||
pub struct WakuNodeContext {
|
||||
pub obj_ptr: *mut c_void,
|
||||
}
|
|
@ -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<F: FnMut(LibwakuResponse)>(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<F: FnMut(LibwakuResponse)>(&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)]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<State: WakuNodeState> {
|
||||
pub struct WakuNodeHandle {
|
||||
pub ctx: WakuNodeContext,
|
||||
phantom: PhantomData<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 fn waku_new(config: Option<WakuNodeConfig>) -> Result<WakuNodeHandle> {
|
||||
Ok(WakuNodeHandle {
|
||||
ctx: management::waku_new(config)?,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn waku_destroy(node: WakuNodeHandle<Initialized>) -> Result<()> {
|
||||
pub fn waku_destroy(node: WakuNodeHandle) -> Result<()> {
|
||||
management::waku_destroy(&node.ctx)
|
||||
}
|
||||
|
||||
impl WakuNodeHandle<Initialized> {
|
||||
// unsafe impl Send for WakuNodeHandle<Running> {}
|
||||
|
||||
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<WakuNodeHandle<Running>> {
|
||||
management::waku_start(&self.ctx).map(|_| WakuNodeHandle {
|
||||
ctx: self.ctx,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
pub fn start(&self) -> Result<()> {
|
||||
management::waku_start(&self.ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Running: WakuNodeState> 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,
|
||||
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<Running: WakuNodeState> WakuNodeHandle<Running> {
|
|||
|
||||
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<Duration>,
|
||||
) -> Result<MessageHash> {
|
||||
|
@ -130,14 +118,14 @@ impl<Running: WakuNodeState> WakuNodeHandle<Running> {
|
|||
pub fn relay_publish_message(
|
||||
&self,
|
||||
message: &WakuMessage,
|
||||
pubsub_topic: &str,
|
||||
pubsub_topic: &String,
|
||||
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: &str) -> Result<()> {
|
||||
pub fn relay_subscribe(&self, pubsub_topic: &String) -> Result<()> {
|
||||
relay::waku_relay_subscribe(&self.ctx, pubsub_topic)
|
||||
}
|
||||
|
||||
|
@ -146,7 +134,4 @@ impl<Running: WakuNodeState> WakuNodeHandle<Running> {
|
|||
relay::waku_relay_unsubscribe(&self.ctx, pubsub_topic)
|
||||
}
|
||||
|
||||
pub fn set_event_callback<F: Fn(LibwakuResponse)>(&self, closure: &F) {
|
||||
events::waku_set_event_callback(&self.ctx, closure)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`]
|
||||
|
|
|
@ -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/)
|
||||
|
|
Loading…
Reference in New Issue