new serevr message enum for easier message handling

This commit is contained in:
2025-11-24 10:07:20 +01:00
parent 6fc1b6c3fd
commit 622bef963f
4 changed files with 109 additions and 55 deletions

View File

@@ -1,9 +1,11 @@
use engine::gameend::GameEnd;
use engine::{boardsquare::BoardSquare, chessmove::ChessMove, piecetype::PieceType};
use futures_util::{SinkExt, StreamExt};
use serde::{Deserialize, Serialize};
use std::io::{self, Write};
use tokio_tungstenite::{connect_async, tungstenite::Message};
use url::Url;
use uuid::Uuid;
#[derive(Serialize, Deserialize, Debug)]
struct Step {
@@ -33,6 +35,21 @@ struct ServerMessage {
reason: Option<String>,
}
#[derive(Serialize, Deserialize)]
pub enum ServerMessage2 {
GameEnd {
winner: GameEnd,
},
UIUpdate {
fen: String,
},
MatchFound {
match_id: Uuid,
color: String,
opponent_name: String,
},
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Knightly Chess Client");
@@ -68,23 +85,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("\nServer: {}", text);
// Try to parse as structured message
if let Ok(parsed) = serde_json::from_str::<ServerMessage>(text) {
match parsed.message_type.as_str() {
"welcome" => {
if let Some(player_id) = parsed.player_id {
println!("Welcome! Your player ID: {}", player_id);
}
}
"match_found" => {
if let Ok(parsed) = serde_json::from_str::<ServerMessage2>(text) {
match parsed {
ServerMessage2::MatchFound {
match_id,
color,
opponent_name,
} => {
println!(
"opponent: {}, match_id: {}, color: {}",
parsed.opponent.unwrap(),
parsed.match_id.unwrap(),
parsed.color.unwrap()
opponent_name, match_id, color
);
}
_ => {
println!("cucc: {:?}", parsed);
println!("cucc");
}
}
}

View File

@@ -1,6 +1,7 @@
use crate::connection::ClientEvent::*;
use engine::chessmove::ChessMove;
use engine::get_available_moves;
use engine::gameend::GameEnd::{self, *};
use engine::{get_available_moves, is_game_over};
use futures_util::{SinkExt, StreamExt};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, VecDeque};
@@ -35,7 +36,7 @@ pub struct Step {
pub to: String,
}
#[derive(Serialize, Deserialize, Debug)]
/*#[derive(Serialize, Deserialize, Debug)]
struct ServerMessage {
#[serde(rename = "type")]
message_type: String,
@@ -45,6 +46,21 @@ struct ServerMessage {
color: Option<String>,
reason: Option<String>,
response: Option<String>,
}*/
#[derive(Serialize, Deserialize)]
pub enum ServerMessage2 {
GameEnd {
winner: GameEnd,
},
UIUpdate {
fen: String,
},
MatchFound {
match_id: Uuid,
color: String,
opponent_name: String,
},
}
#[derive(Serialize, Deserialize)]
@@ -52,7 +68,7 @@ struct ServerMessage {
enum ClientEvent {
Join { username: String },
FindMatch,
Move { step: ChessMove, fen: String },
Move { step: ChessMove },
Resign,
Chat { text: String },
RequestLegalMoves { fen: String },
@@ -205,7 +221,7 @@ pub async fn handle_connection(
println!("Appended {} to the waiting queue", player_id);
println!("queue {:?}", wait_queue);
}
Move { step, fen } => {
Move { step } => {
let match_id = connections
.lock()
.await
@@ -214,25 +230,22 @@ pub async fn handle_connection(
.current_match
.unwrap();
// TODO: discuss if the fen sent by the client is before or after the move
let new_fen = engine::get_board_after_move(&fen, &step);
let message: ServerMessage = ServerMessage {
message_type: String::from("move"),
player_id: (Some(player_id.clone())),
match_id: (Some(match_id.clone())),
opponent: (None),
color: (None),
reason: (Some(String::from(
"after player stepped we update the position for opponent board, and move history",
))),
response: (Some(String::from(
&serde_json::to_string(&Move {
step: step,
fen: fen,
})
.unwrap(),
))),
{
let mut matches = matches.lock().await;
matches.get_mut(&match_id).unwrap().board_state =
engine::get_board_after_move(
&matches.get(&match_id).unwrap().board_state,
&step,
);
}
let message = ServerMessage2::UIUpdate {
fen: matches
.lock()
.await
.get(&match_id)
.unwrap()
.board_state
.clone(),
};
let _ = broadcast_to_match(
@@ -243,7 +256,25 @@ pub async fn handle_connection(
)
.await;
let res = engine::is_game_over(&new_fen); // TODO: discuss how to handle this
{
match engine::is_game_over(
&matches.lock().await.get(&match_id).unwrap().board_state,
) {
Some(res) => {
let message = ServerMessage2::GameEnd { winner: res };
let _ = broadcast_to_match(
&connections,
&matches,
match_id,
&serde_json::to_string(&message).unwrap(),
)
.await;
}
None => {
println!("No winner match continues.")
}
}
}
}
RequestLegalMoves { fen } => {
let moves = get_available_moves(&fen);
@@ -291,6 +322,7 @@ async fn cleanup_player(
mod tests {
use super::*;
use uuid::Uuid;
#[tokio::test]
async fn test_send_message_to_nonexistent_player() {
let connections = new_connection_map();
@@ -300,7 +332,7 @@ mod tests {
let result = send_message_to_player_connection(None, "test message").await;
assert!(result.is_err(), "Should return error for None connection");
println!("Test passed: Handles None connection correctly");
println!("Test passed: Handles None connection correctly");
// Test 2: Try to get non-existent player from map
let mut conn = connections.lock().await;
@@ -313,7 +345,7 @@ mod tests {
result2.is_err(),
"Should return error for non-existent player"
);
println!("Test passed: Handles non-existent player in map correctly");
println!("Test passed: Handles non-existent player in map correctly");
}
#[tokio::test]

View File

@@ -1,3 +1,4 @@
use crate::connection::ServerMessage2;
use crate::connection::{ConnectionMap, GameMatch, MatchMap, WaitingQueue, broadcast_to_match};
use rand::random;
use uuid::Uuid;
@@ -75,34 +76,38 @@ impl MatchmakingSystem {
// Notify white player
if let Some(_) = conn_map.get(&white) {
let message = format!(
r#"{{"type": "match_found", "match_id": "{}", "opponent": "{}", "color": "white"}}"#,
match_id,
conn_map
let message = ServerMessage2::MatchFound {
match_id: match_id.clone(),
color: String::from("white"),
opponent_name: conn_map
.get(&white)
.and_then(|c| c.username.as_deref())
.unwrap_or("Opponent")
);
.to_string(),
};
let _ = crate::connection::send_message_to_player_connection(
conn_map.get_mut(&white),
&message,
&serde_json::to_string(&message).unwrap(),
)
.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,
conn_map
let message = ServerMessage2::MatchFound {
match_id: match_id.clone(),
color: String::from("black"),
opponent_name: conn_map
.get(&black)
.and_then(|c| c.username.as_deref())
.unwrap_or("Opponent")
);
.to_string(),
};
let _ = crate::connection::send_message_to_player_connection(
conn_map.get_mut(&black),
&message,
conn_map.get_mut(&white),
&serde_json::to_string(&message).unwrap(),
)
.await;
}