fixed bug in findmatch, added a new command in test client, refactored how the server sends messages to the client

This commit is contained in:
2025-11-19 20:16:55 +01:00
parent 8d559f4b11
commit 5336aadf97
4 changed files with 98 additions and 52 deletions

View File

@@ -68,6 +68,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Welcome! Your player ID: {}", player_id);
}
}
"match_found" => {
println!(
"opponent: {}, match_id: {}, color: {}",
parsed.opponent.unwrap(),
parsed.match_id.unwrap(),
parsed.color.unwrap()
);
}
_ => {
println!("cucc: {:?}", parsed);
}
@@ -199,5 +207,6 @@ fn print_help() {
println!(" resign - Resign from current game");
println!(" help - Show this help");
println!(" quit - Exit the client");
println!(" requestmoves - Request the legal moves");
println!();
}

View File

@@ -28,18 +28,30 @@ pub fn new_waiting_queue() -> WaitingQueue {
Arc::new(Mutex::new(VecDeque::new()))
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Step {
pub from: String,
pub to: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct ServerMessage {
#[serde(rename = "type")]
message_type: String,
player_id: Option<String>,
match_id: Option<String>,
opponent: Option<String>,
color: Option<String>,
reason: Option<String>,
fen: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type")]
enum ClientEvent {
Join { username: String },
FindMatch,
Move { from: String, to: String },
Move { fen: String },
Resign,
Chat { text: String },
RequestLegalMoves { fen: String },
@@ -64,23 +76,19 @@ pub struct GameMatch {
pub player_white: Uuid,
pub player_black: Uuid,
pub board_state: String,
pub move_history: Vec<String>,
pub move_history: Vec<Step>,
}
// Message sending utilities
pub async fn send_message_to_player(
connections: &ConnectionMap,
player_id: Uuid,
pub async fn send_message_to_player_connection(
connection: &mut PlayerConnection,
message: &str,
) -> Result<(), Box<dyn std::error::Error>> {
let mut connections_lock = connections.lock().await;
if let Some(connection) = connections_lock.get_mut(&player_id) {
connection
.tx
.send(Message::Text(message.to_string()))
.await?;
}
Ok(())
) -> Result<(), tokio_tungstenite::tungstenite::Error> {
println!("sending message to: {}", connection.id);
let res = connection.tx.send(Message::Text(message.to_string())).await;
res
}
pub async fn broadcast_to_all(connections: &ConnectionMap, message: &str) {
@@ -108,8 +116,24 @@ pub async fn broadcast_to_match(
) -> Result<(), Box<dyn std::error::Error>> {
let matches_lock = matches.lock().await;
if let Some(game_match) = matches_lock.get(&match_id) {
send_message_to_player(connections, game_match.player_white, message).await?;
send_message_to_player(connections, game_match.player_black, message).await?;
send_message_to_player_connection(
connections
.lock()
.await
.get_mut(&game_match.player_white)
.unwrap(),
message,
)
.await?;
send_message_to_player_connection(
connections
.lock()
.await
.get_mut(&game_match.player_black)
.unwrap(),
message,
)
.await?;
}
Ok(())
}
@@ -144,14 +168,6 @@ pub async fn handle_connection(
println!("New connection: {}", player_id);
// Send welcome message
let _ = send_message_to_player(
&connections,
player_id,
&format!(r#"{{"type": "welcome", "player_id": "{}"}}"#, player_id),
)
.await;
// Message processing loop
while let Some(Ok(message)) = read.next().await {
if message.is_text() {
@@ -178,9 +194,9 @@ pub async fn handle_connection(
println!("response: {:?}", response);
let _ = send_message_to_player(
&connections,
player_id,
let mut conn_map = connections.lock().await;
let _ = send_message_to_player_connection(
conn_map.get_mut(&player_id).unwrap(),
&serde_json::to_string(&response).unwrap(),
)
.await;
@@ -191,12 +207,21 @@ pub async fn handle_connection(
println!("Appended {} to the waiting queue", player_id);
println!("queue {:?}", wait_queue);
}
Move { from, to } => {}
Move { fen } => {
let match_id = connections
.lock()
.await
.get(&player_id)
.unwrap()
.current_match
.unwrap();
let _ = broadcast_to_match(&connections, &matches, match_id, &fen).await;
}
RequestLegalMoves { fen } => {
let moves = get_available_moves(&fen);
let _ = send_message_to_player(
&connections,
player_id,
let _ = send_message_to_player_connection(
connections.lock().await.get_mut(&player_id).unwrap(),
&serde_json::to_string(&moves).unwrap(),
)
.await;
@@ -239,7 +264,11 @@ mod tests {
let connections = new_connection_map();
let player_id = Uuid::new_v4();
let result = send_message_to_player(&connections, player_id, "test message").await;
let result = send_message_to_player_connection(
connections.lock().await.get_mut(&player_id).unwrap(),
&"test message",
)
.await;
assert!(result.is_ok(), "Should handle missing player gracefully");
}

View File

@@ -1,4 +1,4 @@
use crate::connection::{ConnectionMap, GameMatch, MatchMap, WaitingQueue};
use crate::connection::{ConnectionMap, GameMatch, MatchMap, WaitingQueue, broadcast_to_match};
use rand::random;
use uuid::Uuid;
@@ -20,7 +20,7 @@ impl MatchmakingSystem {
pub async fn run(&self) {
loop {
self.try_create_match().await;
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
}
}
@@ -61,42 +61,50 @@ impl MatchmakingSystem {
}
// Notify players
println!(
"Notifying player for a match: {:?} | {:?}",
white_player, black_player
);
self.notify_players(white_player, black_player, match_id)
.await;
}
}
async fn notify_players(&self, white: Uuid, black: Uuid, match_id: Uuid) {
let conn_map = self.connections.lock().await;
// Get opponent names
let white_name = conn_map
.get(&black)
.and_then(|c| c.username.as_deref())
.unwrap_or("Opponent");
let black_name = conn_map
.get(&white)
.and_then(|c| c.username.as_deref())
.unwrap_or("Opponent");
let mut conn_map = self.connections.lock().await;
// Notify white player
if let Some(_) = conn_map.get(&white) {
let message = format!(
r#"{{"type": "match_found", "match_id": "{}", "opponent": "{}", "color": "white"}}"#,
match_id, black_name
match_id,
conn_map
.get(&white)
.and_then(|c| c.username.as_deref())
.unwrap_or("Opponent")
);
let _ =
crate::connection::send_message_to_player(&self.connections, white, &message).await;
let _ = crate::connection::send_message_to_player_connection(
conn_map.get_mut(&white).unwrap(),
&message,
)
.await;
}
// Notify black player
if let Some(_) = conn_map.get(&black) {
let message = format!(
r#"{{"type": "match_found", "match_id": "{}", "opponent": "{}", "color": "black"}}"#,
match_id, white_name
match_id,
conn_map
.get(&black)
.and_then(|c| c.username.as_deref())
.unwrap_or("Opponent")
);
let _ =
crate::connection::send_message_to_player(&self.connections, black, &message).await;
let _ = crate::connection::send_message_to_player_connection(
conn_map.get_mut(&black).unwrap(),
&message,
)
.await;
}
println!("Match created: {} (white) vs {} (black)", white, black);