mirror of
https://github.com/szymon-jozef/checkers.git
synced 2026-10-27 19:20:44 +01:00
feat: add communication between newtwork client update loop and local client
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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,29 +86,57 @@ 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! {
|
||||||
|
oldest_msg = conn_reciever_incoming.recv() => {
|
||||||
|
if let Some(oldest_msg) = oldest_msg {
|
||||||
let (addr, msg) = oldest_msg;
|
let (addr, msg) = oldest_msg;
|
||||||
debug!("Got message from: {:?}", addr);
|
debug!("Got message from: {:?}", addr);
|
||||||
|
|
||||||
@@ -91,7 +147,7 @@ impl Client {
|
|||||||
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 => {
|
||||||
@@ -107,12 +163,8 @@ impl Client {
|
|||||||
identity,
|
identity,
|
||||||
board_view,
|
board_view,
|
||||||
} => {
|
} => {
|
||||||
info!("Server started the game!");
|
debug!("Got GameStart message! Identity: {}", identity);
|
||||||
info!("Our identity is: {}", identity);
|
let _ = update_sender.send(ClientData::GameStart { identity, board_view }).await;
|
||||||
/*
|
|
||||||
self.board_view = Some(board_view);
|
|
||||||
self.identity = Some(identity);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerMessage::AvailableCaptures { captures } => todo!(),
|
ServerMessage::AvailableCaptures { captures } => todo!(),
|
||||||
@@ -122,26 +174,62 @@ impl Client {
|
|||||||
ServerMessage::GameEnd { result } => todo!(),
|
ServerMessage::GameEnd { result } => todo!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error!("Connection broken");
|
error!("Connection broken!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oldest_cmd = commands_receiver.recv() => {
|
||||||
|
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>) {
|
async fn send_message(
|
||||||
|
msg: Result<Message<ClientMessage>, postcard::Error>,
|
||||||
|
sender: &Sender<Message<ClientMessage>>,
|
||||||
|
) {
|
||||||
debug!("Sending message to the server!");
|
debug!("Sending message to the server!");
|
||||||
let _ = match msg {
|
let _ = match msg {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -149,11 +237,10 @@ impl Client {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Ok(msg) => {
|
Ok(msg) => {
|
||||||
if let Err(e) = self.conn_sender_outgoing.send(msg).await {
|
if let Err(e) = sender.send(msg).await {
|
||||||
error!("Error while sending a message to connection thread: {}", e);
|
error!("Error while sending a message to connection thread: {}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user