feat: add communication between newtwork client update loop and local client

This commit is contained in:
2026-08-17 17:25:37 +02:00
parent 4f024cae34
commit 10a874da32
2 changed files with 196 additions and 76 deletions

View File

@@ -4,7 +4,8 @@ use std::{
}; };
use checkers::network::client::Client; use checkers::network::client::Client;
use log::{error, info}; use log::{debug, error, info};
use tokio::sync::mpsc;
const QUIT_COMMAND: &str = "/quit"; const QUIT_COMMAND: &str = "/quit";
const HELP_COMMAND: &str = "/help"; const HELP_COMMAND: &str = "/help";
@@ -50,6 +51,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
return Ok(()); return Ok(());
}; };
let (client_sender, mut client_receiver) = mpsc::channel(1024);
client.set_update_sender(client_sender);
client.update();
let help_msg: String = format!( let help_msg: String = format!(
"\n┌────Help──── "\n┌────Help────
│\t {} - quit │\t {} - quit
@@ -60,8 +67,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
QUIT_COMMAND, HELP_COMMAND, READY_COMMAND, SEND_COMMAND, QUIT_COMMAND, HELP_COMMAND, READY_COMMAND, SEND_COMMAND,
); );
client.update();
info!("====== Type /help for help ========"); info!("====== Type /help for help ========");
let mut buffer = String::new(); let mut buffer = String::new();
loop { loop {
@@ -71,6 +76,34 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
io::stdin().read_line(&mut buffer)?; io::stdin().read_line(&mut buffer)?;
buffer.pop(); // remove \n buffer.pop(); // remove \n
match client_receiver.try_recv() {
Ok(checkers::network::client::ClientData::GameStart {
identity,
board_view,
}) => {
info!(
"Got new identity: {} and board_view. Game is about to start!",
identity
);
}
Ok(checkers::network::client::ClientData::AvailableCaptures(capture_paths)) => {
todo!()
}
Ok(checkers::network::client::ClientData::AvailableMoves(move_paths)) => todo!(),
Ok(checkers::network::client::ClientData::TextMessage(content)) => {
info!("Got message from the server: {}", content);
}
Ok(checkers::network::client::ClientData::GameEnd(game_result)) => {
info!("Game has ended with the result: {:?}", game_result);
}
_ => {}
}
if buffer.is_empty() { if buffer.is_empty() {
buffer.clear(); buffer.clear();
continue; continue;

View File

@@ -1,10 +1,17 @@
use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use log::{debug, error, info}; use log::{debug, error, info, warn};
use tokio::sync::mpsc::{self, Receiver, Sender}; use tokio::sync::mpsc::{self, Receiver, Sender};
use crate::{ use crate::{
logic::board::board_view::BoardView, logic::{
board::{
board_view::BoardView,
pawn::{CapturePath, MovePath},
},
game_master::GameResult,
math::position::Position,
},
network::{ network::{
connection::{Connection, ConnectionType}, connection::{Connection, ConnectionType},
message::{ message::{
@@ -21,14 +28,35 @@ pub struct ClientSettings {
name: String, name: String,
} }
pub enum ClientCommands {
SendCapture(CapturePath),
SendMove { from: Position, to: Position },
SendText(String),
SendReady,
}
/// Data that network client gives to normal client. I have no better idea for this name, hence this
/// comment
pub enum ClientData {
GameStart {
identity: NetworkIdentity,
board_view: BoardView,
},
AvailableCaptures(Vec<CapturePath>),
AvailableMoves(Vec<MovePath>),
TextMessage(String),
GameEnd(GameResult),
}
pub struct Client { pub struct Client {
conn_reciever_incoming: Option<Receiver<(SocketAddr, Message<ServerMessage>)>>, conn_reciever_incoming: Option<Receiver<(SocketAddr, Message<ServerMessage>)>>,
conn_sender_outgoing: Sender<Message<ClientMessage>>, conn_sender_outgoing: Sender<Message<ClientMessage>>,
settings: ClientSettings, settings: ClientSettings,
identity: Option<NetworkIdentity>, commands_sender: Option<Sender<ClientCommands>>,
board_view: Option<BoardView>, commands_receiver: Option<Receiver<ClientCommands>>,
update_reciever: Option<Receiver<Message<ServerMessage>>>,
update_sender: Option<Sender<ClientData>>,
} }
impl Client { impl Client {
@@ -40,12 +68,12 @@ impl Client {
let (conn_sender, conn_reciever) = let (conn_sender, conn_reciever) =
mpsc::channel::<(SocketAddr, Message<ServerMessage>)>(1024); mpsc::channel::<(SocketAddr, Message<ServerMessage>)>(1024);
let mut conn: Connection<ServerMessage, ClientMessage> = let mut conn: Connection<ServerMessage, ClientMessage> =
Connection::new(ConnectionType::Server, conn_sender); Connection::new(ConnectionType::Server, conn_sender);
let conn_sender_outgoing = conn.get_sender(); let conn_sender_outgoing = conn.get_sender();
let (commands_sender, commands_receiver) = mpsc::channel(1024);
if !conn.connect_to_server(settings.server_url).await { if !conn.connect_to_server(settings.server_url).await {
error!("Could not connect with the server: {}", settings.server_url); error!("Could not connect with the server: {}", settings.server_url);
return None; return None;
@@ -58,102 +86,161 @@ impl Client {
Some(Client { Some(Client {
conn_reciever_incoming: Some(conn_reciever), conn_reciever_incoming: Some(conn_reciever),
conn_sender_outgoing, conn_sender_outgoing,
settings, settings,
identity: None,
board_view: None, commands_receiver: Some(commands_receiver),
update_reciever: None, commands_sender: Some(commands_sender),
update_sender: None,
}) })
} }
pub fn get_commands_sender(&mut self) -> Option<Sender<ClientCommands>> {
if self.commands_sender.is_none() {
warn!("Tried taking commands sender a second time! This shouldn't happen");
}
self.commands_sender.take()
}
pub fn set_update_sender(&mut self, sender: Sender<ClientData>) {
if self.update_sender.is_some() {
warn!("Cannot set update sender a second time!");
return;
}
self.update_sender = Some(sender);
}
pub fn update(&mut self) { pub fn update(&mut self) {
let Some(mut conn_reciever_incoming) = self.conn_reciever_incoming.take() else { let Some(mut conn_reciever_incoming) = self.conn_reciever_incoming.take() else {
error!("Tried updating, but there's no conn_reciever of incoming messages!"); error!("Tried updating, but there's no conn_reciever of incoming messages!");
return; return;
}; };
let sender = self.conn_sender_outgoing.clone(); let conn_sender = self.conn_sender_outgoing.clone();
let Some(update_sender) = self.update_sender.take() else {
error!("Update sender is missing. Cannot update!");
return;
};
let Some(mut commands_receiver) = self.commands_receiver.take() else {
error!("Commands receiver is missing! Cannot update.");
return;
};
let settings = self.settings.clone(); let settings = self.settings.clone();
let (update_sender, update_reciever) = mpsc::channel::<Message<ServerMessage>>(1024);
self.update_reciever = Some(update_reciever);
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
if let Some(oldest_msg) = conn_reciever_incoming.recv().await { tokio::select! {
let (addr, msg) = oldest_msg; oldest_msg = conn_reciever_incoming.recv() => {
debug!("Got message from: {:?}", addr); if let Some(oldest_msg) = oldest_msg {
let (addr, msg) = oldest_msg;
debug!("Got message from: {:?}", addr);
match msg.content { match msg.content {
ServerMessage::RequestHandshake => { ServerMessage::RequestHandshake => {
info!("Server requested handshake!"); info!("Server requested handshake!");
let msg = Message::new(ClientMessage::AnswerHandshake { let msg = Message::new(ClientMessage::AnswerHandshake {
player_name: settings.name.clone(), player_name: settings.name.clone(),
}); });
let _ = sender.send(msg.unwrap()).await; let _ = conn_sender.send(msg.unwrap()).await;
} }
ServerMessage::AcceptHandshake => { ServerMessage::AcceptHandshake => {
info!("Server accepted us! Yay :D"); info!("Server accepted us! Yay :D");
} }
ServerMessage::DeclineHandshake { reason } => { ServerMessage::DeclineHandshake { reason } => {
error!("Server declined connection: {}", reason); error!("Server declined connection: {}", reason);
break;
}
ServerMessage::GameStart {
identity,
board_view,
} => {
debug!("Got GameStart message! Identity: {}", identity);
let _ = update_sender.send(ClientData::GameStart { identity, board_view }).await;
}
ServerMessage::AvailableCaptures { captures } => todo!(),
ServerMessage::AvailableMoves { moves } => todo!(),
ServerMessage::BroadcastBoardState { board } => todo!(),
ServerMessage::BroadcastCurrentTurn { active_player } => todo!(),
ServerMessage::GameEnd { result } => todo!(),
}
} else {
error!("Connection broken!");
break; break;
} }
ServerMessage::GameStart {
identity,
board_view,
} => {
info!("Server started the game!");
info!("Our identity is: {}", identity);
/*
self.board_view = Some(board_view);
self.identity = Some(identity);
*/
}
ServerMessage::AvailableCaptures { captures } => todo!(),
ServerMessage::AvailableMoves { moves } => todo!(),
ServerMessage::BroadcastBoardState { board } => todo!(),
ServerMessage::BroadcastCurrentTurn { active_player } => todo!(),
ServerMessage::GameEnd { result } => todo!(),
} }
} else {
error!("Connection broken"); oldest_cmd = commands_receiver.recv() => {
break; if let Some(oldest_cmd) = oldest_cmd {
match oldest_cmd {
ClientCommands::SendCapture(capture_path) => todo!(),
ClientCommands::SendMove { from, to } => todo!(),
ClientCommands::SendText(content) => {
debug!("Seding text message: {}", content);
let msg = Message::new(TextMessage(content));
send_message(msg, &conn_sender).await;
},
ClientCommands::SendReady => {
debug!("Signaling readiness!");
let msg = Message::new(SignalReadiness);
send_message(msg, &conn_sender).await;
},
}
} else {
error!("Couldn't decipher the command!");
break;
}
}
} }
} }
}); });
} }
pub async fn send_text_message(&mut self, content: String) { pub async fn send_text_message(&mut self, content: String) {
debug!("Seding text message: {}", content); if let Some(sender) = &self.commands_sender {
let msg = Message::new(TextMessage(content)); let _ = sender.send(ClientCommands::SendText(content)).await;
self.send_message(msg).await; } else {
error!("Command sender not set!");
}
} }
pub async fn signal_readiness(&mut self) { pub async fn signal_readiness(&mut self) {
debug!("Signaling readiness!"); if let Some(sender) = &self.commands_sender {
let msg = Message::new(SignalReadiness); let _ = sender.send(ClientCommands::SendReady).await;
self.send_message(msg).await; } else {
} error!("Command sender not set!");
}
async fn send_message(&mut self, msg: Result<Message<ClientMessage>, postcard::Error>) {
debug!("Sending message to the server!");
let _ = match msg {
Err(e) => {
error!("There was an error while creating the message: {}", e);
return;
}
Ok(msg) => {
if let Err(e) = self.conn_sender_outgoing.send(msg).await {
error!("Error while sending a message to connection thread: {}", e);
return;
}
}
};
} }
} }
async fn send_message(
msg: Result<Message<ClientMessage>, postcard::Error>,
sender: &Sender<Message<ClientMessage>>,
) {
debug!("Sending message to the server!");
let _ = match msg {
Err(e) => {
error!("There was an error while creating the message: {}", e);
return;
}
Ok(msg) => {
if let Err(e) = sender.send(msg).await {
error!("Error while sending a message to connection thread: {}", e);
return;
}
}
};
}