Refactor messages between server and client

This commit is contained in:
2020-09-19 00:17:35 +02:00
parent 7a889356b3
commit 7f2ec8e957
5 changed files with 387 additions and 371 deletions

View File

@ -1,19 +1,15 @@
extern crate ctrlc;
use clichess::{GameInfo, RecvPositionError, UserRole, EXIT_MSG};
use serde_json::json;
use shakmaty::fen::Fen;
use shakmaty::{Chess, Color, Move, Outcome, Position, Setup};
use clichess::{ClientRequest, GameInfo, RecvPositionError, UserRole, EXIT_MSG};
use shakmaty::{Chess, Color, Outcome, Position, Setup};
use std::io;
use std::os::unix::net::UnixStream;
use std::sync::mpsc::{channel, Receiver, TryRecvError};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;
struct Client {
player: clichess::Player,
side: Color,
input_buffer: Arc<Mutex<String>>,
keyboard_input_recv: Receiver<String>,
server_message_recv: Receiver<String>,
opponent_name: Option<String>,
last_move: Option<String>,
@ -32,12 +28,7 @@ fn main() {
return;
}
};
let username_pubkey_json = json!({
"username": username,
"pubkey": public_key,
});
clichess::write_to_stream(&mut stream, username_pubkey_json.to_string()).unwrap();
let input_buffer = setup_input_buffer();
let keyboard_input_recv = setup_keyboard_input_recv();
//start a thread to listen to server messages
let server_message_recv = setup_server_message_recv(&stream).unwrap();
@ -48,16 +39,17 @@ fn main() {
public_key,
},
side: Color::White,
input_buffer: input_buffer.clone(),
keyboard_input_recv,
server_message_recv,
opponent_name: Option::None,
last_move: Option::None,
};
match prompt_user_for_role(&client, &mut stream) {
Some(role) => client.player.role = role.clone(),
None => return,
};
let login_result = login(&mut client, &mut stream);
if login_result == LoginResult::UserExited {
send_request(&client, &mut stream, ClientRequest::Exit);
return;
}
if client.player.role == UserRole::Black {
client.side = Color::Black;
}
@ -73,15 +65,14 @@ fn main() {
client.player.role.to_string()
);
}
let mut current_position = fetch_initial_chess_position(&client);
let mut current_position = fetch_initial_chess_position(&client, &mut stream);
loop {
if clichess::is_player_turn(&client.player, current_position.turn())
|| client.player.role == UserRole::Spectator
{
let is_player_turn = clichess::is_player_turn(&client.player, current_position.turn());
if is_player_turn || client.player.role == UserRole::Spectator {
client
.opponent_name
.clone()
.map(|name| print!("{} played", &name[1..(name.len() - 1)]));
.map(|name| print!("{} played", name));
client
.last_move
.clone()
@ -95,24 +86,30 @@ fn main() {
if current_position.is_game_over() {
break;
}
if clichess::is_player_turn(&client.player, current_position.turn()) {
if is_player_turn {
//it's the user turn, taking user input
let mut input = read_user_input(&client);
let mut input = client.keyboard_input_recv.recv().unwrap();
input = String::from(input.trim());
clichess::write_to_stream(&mut stream, input.clone()).unwrap();
if input == EXIT_MSG {
break;
}
client.last_move = Some(input);
}
//update position after playing.
match get_current_position(&mut client) {
Ok(position) => current_position = position,
Err(_) => {
clichess::write_to_stream(&mut stream, String::from(EXIT_MSG)).unwrap();
break;
let response = send_request(&client, &mut stream, ClientRequest::Play(input.clone()));
if response == String::from("KO") {
println!("Invalid move: {}", input);
//go back to taking user input
continue;
}
};
client.last_move = Some(input);
match get_current_position(&mut client, &mut stream) {
Ok(position) => current_position = position,
Err(_) => break,
};
} else {
match wait_for_next_move(&mut client, &mut stream) {
Ok(position) => current_position = position,
Err(_) => break,
};
}
}
match current_position.outcome() {
None => println!("Bye"),
@ -125,28 +122,65 @@ fn main() {
}
}
}
send_request(&client, &mut stream, ClientRequest::Exit);
}
fn setup_input_buffer() -> Arc<Mutex<String>> {
let buf = Arc::new(Mutex::new(String::new()));
let buf2 = buf.clone();
#[derive(PartialEq)]
enum LoginResult {
Success,
UserExited,
}
fn login(client: &mut Client, stream: &mut UnixStream) -> LoginResult {
let mut response = String::from("KO");
while &response != "OK" {
match prompt_user_for_role(client, stream) {
PromptedRoleResponse::Role(role) => {
client.player.role = role.clone();
response = send_request(
client,
stream,
ClientRequest::Login {
username: client.player.username.clone(),
pubkey: client.player.public_key.clone(),
role,
},
);
}
PromptedRoleResponse::Exit => return LoginResult::UserExited,
PromptedRoleResponse::Retry => continue,
};
}
LoginResult::Success
}
fn send_request(client: &Client, stream: &mut UnixStream, request: ClientRequest) -> String {
let response: String;
match serde_json::to_string(&request) {
Ok(request_str) => {
clichess::write_to_stream(stream, request_str).unwrap();
response = fetch_message_from_server(client);
}
Err(e) => {
println!("Error when parsing client request: {}", e);
response = String::from("KO");
}
};
response
}
fn setup_keyboard_input_recv() -> Receiver<String> {
let (sender, receiver) = channel();
thread::spawn(move || {
loop {
let mut buffer = String::new();
//wait for user input
io::stdin().read_line(&mut buffer).unwrap();
{
let mut user_input = buf2.lock().unwrap();
if user_input.is_empty() {
*user_input = buffer;
} else {
println!("It's not your turn !");
}
}
sender.send(buffer).unwrap();
}
});
buf
receiver
}
fn setup_server_message_recv(stream: &UnixStream) -> io::Result<Receiver<String>> {
@ -164,42 +198,57 @@ fn setup_server_message_recv(stream: &UnixStream) -> io::Result<Receiver<String>
Ok(receiver)
}
fn read_user_input(client: &Client) -> String {
//clear input before waiting for a new one
{
let mut user_input = client.input_buffer.lock().unwrap();
user_input.clear();
//get current position from server
fn get_current_position(
client: &mut Client,
stream: &mut UnixStream,
) -> Result<Chess, RecvPositionError> {
let response = send_request(client, stream, ClientRequest::GetGameInfo);
if response.is_empty() {
Err(RecvPositionError::UserCanceledError)
} else {
let game_info: GameInfo = serde_json::from_str(&response).unwrap();
update_client(&game_info, client);
Ok(clichess::parse_position(&game_info.game_fen))
}
let input;
}
fn wait_for_next_move(
client: &mut Client,
stream: &mut UnixStream,
) -> Result<Chess, RecvPositionError> {
println!("Waiting for opponent move...");
send_request(client, stream, ClientRequest::WaitForNextMove);
let response;
loop {
thread::sleep(time::Duration::from_millis(10));
{
let user_input = client.input_buffer.lock().unwrap();
if user_input.is_empty() {
continue;
} else {
input = user_input.clone();
break;
let server_response_recv = &client.server_message_recv;
match server_response_recv.try_recv() {
Ok(msg) => {
response = msg;
break;
}
Err(TryRecvError::Disconnected) => println!("Error: server disconnected."),
Err(TryRecvError::Empty) => continue,
}
}
}
input
}
//wait for next position from server, then return the current board.
fn get_current_position(client: &mut Client) -> Result<Chess, RecvPositionError> {
let response = fetch_message_from_server(client);
let game_info: GameInfo = serde_json::from_str(&response).unwrap();
if game_info.opponent_name != "" {
client.opponent_name = Some(game_info.opponent_name);
}
if game_info.last_move != "" {
client.last_move = Some(game_info.last_move);
}
if response.is_empty() {
Err(RecvPositionError::UserCanceledError)
} else {
Ok(parse_position(&game_info.game_fen))
let game_info: GameInfo = serde_json::from_str(&response).unwrap();
update_client(&game_info, client);
Ok(clichess::parse_position(&game_info.game_fen))
}
}
fn update_client(game_info: &GameInfo, client: &mut Client) {
if game_info.opponent_name != "" {
client.opponent_name = Some(game_info.opponent_name.clone());
}
if game_info.last_move != "" {
client.last_move = Some(game_info.last_move.clone());
}
}
@ -222,78 +271,56 @@ fn fetch_message_from_server(client: &Client) -> String {
response
}
fn parse_position(string: &str) -> Chess {
let setup: Fen = string.trim().parse().expect("Invalid message from server.");
let position: Chess = setup.position().expect("Invalid message from server.");
position
enum PromptedRoleResponse {
Role(UserRole),
Exit,
Retry,
}
fn prompt_user_for_role(client: &Client, stream: &mut UnixStream) -> Option<UserRole> {
let mut role = None;
loop {
let available_roles = fetch_available_roles(client);
let mut prompt = String::new();
if !available_roles.contains(&UserRole::White)
&& !available_roles.contains(&UserRole::Black)
{
prompt.push_str("You can only spectate this game. Press enter to start spectating.");
} else if available_roles.contains(&UserRole::White) {
prompt = String::from("Do you want to play as White (W)");
if available_roles.contains(&UserRole::Black) {
prompt.push_str(", Black (B)");
}
prompt.push_str(" or Spectate (S)?");
} else {
prompt = String::from("Do you want to play as Black (B) or Spectate (S)?");
fn prompt_user_for_role(client: &Client, stream: &mut UnixStream) -> PromptedRoleResponse {
let response = send_request(client, stream, ClientRequest::FetchAvailableRoles);
let available_roles = roles_from_str(&response).unwrap();
let mut prompt = String::new();
if !available_roles.contains(&UserRole::White) && !available_roles.contains(&UserRole::Black) {
prompt.push_str("You can only spectate this game. Press enter to start spectating.");
} else if available_roles.contains(&UserRole::White) {
prompt = String::from("Do you want to play as White (W)");
if available_roles.contains(&UserRole::Black) {
prompt.push_str(", Black (B)");
}
println!("{}", prompt);
//wait for user to give a correct answer.
let mut input = String::from(read_user_input(client).trim());
if input.trim() == EXIT_MSG {
clichess::write_to_stream(stream, String::from(EXIT_MSG)).unwrap();
break;
}
if !available_roles.contains(&UserRole::White)
&& !available_roles.contains(&UserRole::Black)
{
//we can only spectate
input = String::from("S");
}
match clichess::parse_to_role(&input) {
Ok(r) => role = Some(r),
Err(e) => {
println!("{}", e);
continue;
}
};
if role.is_some() && !available_roles.contains(&role.expect("role is some")) {
println!("Sorry, this side is not available.");
continue;
}
//send info to server
clichess::write_to_stream(stream, String::from(input)).unwrap();
//get confirmation from server
let response = fetch_message_from_server(&client);
if response != "OK" {
println!(
"There was an issue with the server. Maybe your choice is not available anymore?"
);
clichess::write_to_stream(stream, String::from("ACK")).unwrap();
continue;
}
clichess::write_to_stream(stream, String::from("OK")).unwrap();
break;
prompt.push_str(" or Spectate (S)?");
} else {
prompt = String::from("Do you want to play as Black (B) or Spectate (S)?");
}
role
println!("{}", prompt);
let mut input = String::from(client.keyboard_input_recv.recv().unwrap().trim());
if input.trim() == EXIT_MSG {
return PromptedRoleResponse::Exit;
}
if !available_roles.contains(&UserRole::White) && !available_roles.contains(&UserRole::Black) {
//we can only spectate
input = String::from("S");
}
match clichess::parse_to_role(&input) {
Ok(r) => {
if !available_roles.contains(&r) {
println!("Sorry, this side is not available.");
return PromptedRoleResponse::Retry;
}
return PromptedRoleResponse::Role(r);
}
Err(e) => {
println!("{}", e);
return PromptedRoleResponse::Retry;
}
};
}
fn fetch_initial_chess_position(client: &Client) -> Chess {
parse_position(&fetch_message_from_server(client))
}
fn fetch_available_roles(client: &Client) -> Vec<UserRole> {
roles_from_str(&fetch_message_from_server(client)).unwrap()
fn fetch_initial_chess_position(client: &Client, stream: &mut UnixStream) -> Chess {
let response = send_request(client, stream, ClientRequest::GetGameInfo);
let game_info: GameInfo = serde_json::from_str(&response).unwrap();
clichess::parse_position(&game_info.game_fen)
}
fn roles_from_str(s: &str) -> Result<Vec<UserRole>, String> {

View File

@ -1,7 +1,6 @@
use clichess;
use clichess::{GameInfo, Player, RecvPositionError, UserRole, EXIT_MSG};
use serde_json::Value;
use shakmaty::{fen, Chess, Color, Setup};
use clichess::{ClientRequest, GameInfo, Player, RecvPositionError, UserRole};
use shakmaty::{fen, Chess, Setup};
use std::collections::HashMap;
use std::fs;
use std::io;
@ -18,8 +17,8 @@ struct Server {
others_serv_msg_recv: Receiver<GameInfo>,
client_message_recv: Receiver<String>,
cvar: Arc<(Mutex<bool>, Condvar)>,
opponent_name: Option<String>,
last_move: Option<String>
opponent_name: Arc<Mutex<Option<String>>>,
last_move: Arc<Mutex<Option<String>>>,
}
fn main() {
@ -47,8 +46,8 @@ fn main() {
others_serv_msg_recv,
client_message_recv,
cvar: condvar_pair,
opponent_name: Option::None,
last_move: Option::None
opponent_name: Arc::new(Mutex::new(Option::None)),
last_move: Arc::new(Mutex::new(Option::None)),
};
/* connection succeeded */
thread::spawn(move || handle_player(stream, &mut server, others_serv_msg_sender));
@ -67,108 +66,123 @@ fn handle_player(
server: &mut Server,
others_serv_msg_sender: Sender<GameInfo>,
) {
match initialize_client(&mut stream, &server, others_serv_msg_sender) {
Ok((player, player_turn)) => main_loop(&mut stream, server, player, player_turn),
Err(e) => println!("User id {} could not be initialized: {}", server.id, e),
};
loop {
//wait for input
let input = server.client_message_recv.recv().unwrap();
println!("got input: {}", input);
//route to right function
match serde_json::from_str(&input) {
Ok(ClientRequest::FetchAvailableRoles) => fetch_available_roles(&mut stream, server),
Ok(ClientRequest::Login {
username,
pubkey,
role,
}) => login(
&mut stream,
server,
username,
pubkey,
role,
others_serv_msg_sender.clone(),
),
Ok(ClientRequest::GetGameInfo) => send_game_info(&mut stream, server),
Ok(ClientRequest::WaitForNextMove) => {
//return true if user exited.
if wait_for_next_move(&mut stream, server) {
break;
}
}
Ok(ClientRequest::Play(movestr)) => play(&mut stream, server, movestr),
Ok(ClientRequest::Exit) => {
send_ok(&mut stream);
break;
}
Err(e) => {
println!("Bad request: {}", e);
break;
}
}
}
player_disconnected(&server);
}
fn initialize_client(
fn login(
stream: &mut UnixStream,
server: &Server,
username: String,
pubkey: String,
role: UserRole,
others_serv_msg_sender: Sender<GameInfo>,
) -> Result<(Player, Color), RecvPositionError> {
//create player
let player = create_player(server, stream, others_serv_msg_sender)?;
let player_turn: Color;
//send current position to the player
println!(
"server {}, send current position to the player...",
server.id
);
) {
println!("server {}, player {} is logging in..", server.id, username);
//check_role
let mut available_roles_after_choice =
vec![UserRole::White, UserRole::Black, UserRole::Spectator];
{
let chess = server.chess_position.lock().unwrap();
player_turn = chess.turn();
clichess::write_to_stream(stream, fen::fen(&*chess)).unwrap();
}
println!("server {}, current position to the player sent", server.id);
Ok((player, player_turn))
}
fn main_loop(stream: &mut UnixStream, server: &mut Server, player: Player, mut player_turn: Color) {
loop {
if clichess::is_player_turn(&player, player_turn) {
//let go of the lock while waiting for user input.
println!("server {}, waiting for player move..", server.id);
let input;
match server.client_message_recv.recv() {
Ok(i) => input = i,
Err(e) => {
println!("Error while getting user input: {}", e);
break;
}
};
if input == EXIT_MSG {
break;
}
let players = server.players.lock().unwrap();
for (_, (player, _, _)) in players.iter() {
match available_roles_after_choice
.iter()
.position(|r| *r == player.role)
{
let mut chess = server.chess_position.lock().unwrap();
let players = server.players.lock().unwrap();
println!("User tried to play {}", input);
match clichess::try_to_play_move(&chess, input.clone()) {
Ok(played_chess) => *chess = played_chess,
Err(e) => println!("Error: {}", e),
};
let game_info_to_send = GameInfo {
game_fen: fen::fen(&*chess),
opponent_name: players
.get(&server.id)
.expect("current server is in the server list")
.0
.username
.clone(),
last_move: input.clone()
};
for (id, (_, others_serv_msg_sender, cvar_pair)) in players.iter() {
if server.id != *id {
others_serv_msg_sender
.send(game_info_to_send.clone())
.unwrap();
let (lock, cvar) = &**cvar_pair;
let mut message_sent = lock.lock().unwrap();
*message_sent = true;
cvar.notify_one();
}
}
if clichess::write_to_stream(
stream,
serde_json::to_string(&GameInfo {
game_fen: fen::fen(&*chess),
opponent_name: server.opponent_name.clone().unwrap_or_default(),
last_move: server.last_move.clone().unwrap_or_default(),
})
.unwrap(),
)
.is_err()
{
break;
}
player_turn = chess.turn();
}
} else {
let game_info_result = wait_for_opponent_move(server);
if game_info_result.is_err() {
break;
}
let game_info = game_info_result.unwrap();
clichess::write_to_stream(stream, serde_json::to_string(&game_info).unwrap()).unwrap();
server.opponent_name = Some(game_info.opponent_name);
server.last_move = Some(game_info.last_move);
let chess = server.chess_position.lock().unwrap();
player_turn = chess.turn();
Some(index) => available_roles_after_choice.remove(index),
None => continue,
};
}
}
if available_roles_after_choice.contains(&role) {
create_player(server, username, pubkey, role, others_serv_msg_sender);
send_ok(stream);
} else {
send_ko(stream);
}
}
fn fetch_available_roles(stream: &mut UnixStream, server: &Server) {
println!(
"server {}, sending available role to the player...",
server.id
);
let available_roles = compute_available_roles_to_str(server);
println!("Computed available_roles as str: {}", available_roles);
clichess::write_to_stream(stream, available_roles.clone()).unwrap();
}
fn send_game_info(stream: &mut UnixStream, server: &Server) {
println!("server {}, sending game info...", server.id);
let chess = server.chess_position.lock().unwrap();
let opponent_name = server
.opponent_name
.lock()
.unwrap()
.clone()
.unwrap_or_default();
let last_move = server.last_move.lock().unwrap().clone().unwrap_or_default();
let game_info = GameInfo {
game_fen: fen::fen(&*chess),
opponent_name,
last_move,
};
clichess::write_to_stream(stream, serde_json::to_string(&game_info).unwrap()).unwrap();
}
fn wait_for_next_move(stream: &mut UnixStream, server: &mut Server) -> bool {
println!("server {}, waiting for opponent move...", server.id);
//acknowledge the request to the client
send_ok(stream);
//wait either for the other server, or the client exit.
match wait_for_opponent_move(server) {
Ok(game_info) => {
update_from_game_info(server, &game_info);
let game_info_serialized = serde_json::to_string(&game_info).unwrap();
//send game_info to client
clichess::write_to_stream(stream, game_info_serialized).unwrap();
}
Err(_) => {
return true;
}
}
false
}
fn wait_for_opponent_move(server: &Server) -> Result<GameInfo, RecvPositionError> {
@ -193,38 +207,97 @@ fn wait_for_opponent_move(server: &Server) -> Result<GameInfo, RecvPositionError
Err(TryRecvError::Empty) => { /*nothing to do*/ }
}
match server.client_message_recv.try_recv() {
Ok(msg) => {
if msg == EXIT_MSG {
returned_result = Err(RecvPositionError::UserCanceledError);
} else {
println!("Client sent message while it's not its turn, this is an error.");
println!("Here is the message: {}", msg);
returned_result = Err(RecvPositionError::UserCanceledError);
}
}
Ok(_) => returned_result = Err(RecvPositionError::UserCanceledError),
Err(TryRecvError::Disconnected) => println!("Error: client disconnected."),
Err(TryRecvError::Empty) => {}
Err(TryRecvError::Empty) => { /*nothing to do*/ }
}
returned_result
}
fn update_from_game_info(server: &mut Server, game_info: &GameInfo) {
let mut chess_position = server.chess_position.lock().unwrap();
let mut opponent_name = server.opponent_name.lock().unwrap();
let mut last_move = server.last_move.lock().unwrap();
*chess_position = clichess::parse_position(&game_info.game_fen);
if game_info.opponent_name == "" {
*opponent_name = None;
} else {
*opponent_name = Some(game_info.opponent_name.clone());
}
if game_info.last_move == "" {
*last_move = None;
} else {
*last_move = Some(game_info.last_move.clone());
}
}
fn play(stream: &mut UnixStream, server: &Server, movestr: String) {
println!("server {}, user wants to play...", server.id);
let mut chess = server.chess_position.lock().unwrap();
let players = server.players.lock().unwrap();
let player = players.get(&server.id);
if player.is_none() || !clichess::is_player_turn(&player.unwrap().0, chess.turn()) {
send_ko(stream);
return;
}
println!("User tried to play {}", movestr.clone());
match clichess::try_to_play_move(&chess, movestr.clone()) {
Ok(played_chess) => *chess = played_chess,
Err(e) => println!("Error: {}", e),
};
let player_name = player
.expect("current server is in the server list")
.0
.username
.clone();
//send play to other servers
let game_info_to_send = GameInfo {
game_fen: fen::fen(&*chess),
opponent_name: player_name,
last_move: movestr.clone(),
};
for (id, (_, others_serv_msg_sender, cvar_pair)) in players.iter() {
if server.id != *id {
others_serv_msg_sender
.send(game_info_to_send.clone())
.unwrap();
let (lock, cvar) = &**cvar_pair;
let mut message_sent = lock.lock().unwrap();
*message_sent = true;
cvar.notify_one();
}
}
let opponent_name = server.opponent_name.lock().unwrap();
let last_move = server.last_move.lock().unwrap();
//send updated info to client
clichess::write_to_stream(
stream,
serde_json::to_string(&GameInfo {
game_fen: fen::fen(&*chess),
opponent_name: opponent_name.clone().unwrap_or_default(),
last_move: last_move.clone().unwrap_or_default(),
})
.unwrap(),
)
.unwrap();
}
fn send_ok(stream: &mut UnixStream) {
clichess::write_to_stream(stream, String::from("OK")).unwrap();
}
fn send_ko(stream: &mut UnixStream) {
clichess::write_to_stream(stream, String::from("KO")).unwrap();
}
fn create_player(
server: &Server,
stream: &mut UnixStream,
username: String,
public_key: String,
role: UserRole,
others_serv_msg_sender: Sender<GameInfo>,
) -> Result<Player, RecvPositionError> {
println!("Creating player {}...", server.id);
//get player name and pubkey
let username_pubkey_json = server
.client_message_recv
.recv()
.expect("Player closed connection.");
let username_pubkey_value: Value = serde_json::from_str(&username_pubkey_json).unwrap();
let username = username_pubkey_value["username"].to_string();
let public_key = username_pubkey_value["pubkey"].to_string();
println!("got username: {}", username);
println!("got pubkey: {}", public_key);
let role = receive_user_role(server, stream)?;
) {
let mut players = server.players.lock().unwrap();
let player = Player {
role,
@ -236,68 +309,6 @@ fn create_player(
(player.clone(), others_serv_msg_sender, server.cvar.clone()),
);
println!("Created player {}", server.id);
Ok(player)
}
fn receive_user_role(
server: &Server,
stream: &mut UnixStream,
) -> Result<UserRole, RecvPositionError> {
let mut chosen_role: UserRole;
loop {
//send available roles
let available_roles = compute_available_roles_to_str(server);
println!("Computed available_roles as str: {}", available_roles);
clichess::write_to_stream(stream, available_roles.clone()).unwrap();
//receive chosen role
let chosen_role_str = server
.client_message_recv
.recv()
.expect("Player closed connection.");
if chosen_role_str.trim() == EXIT_MSG {
return Err(RecvPositionError::UserCanceledError);
}
println!("Client id {} has chosen {}", server.id, chosen_role_str);
let chosen_role_parse = clichess::parse_to_role(&chosen_role_str);
if chosen_role_parse.is_err() {
return Err(RecvPositionError::ParsePositionError);
}
chosen_role = chosen_role_parse.unwrap();
//check if role is still available after the choice
{
let mut available_roles_after_choice =
vec![UserRole::White, UserRole::Black, UserRole::Spectator];
let players = server.players.lock().unwrap();
for (_, (player, _, _)) in players.iter() {
match available_roles_after_choice
.iter()
.position(|r| *r == player.role)
{
Some(index) => available_roles_after_choice.remove(index),
None => continue,
};
}
if available_roles_after_choice.contains(&chosen_role) {
println!("OK");
clichess::write_to_stream(stream, String::from("OK")).unwrap();
server
.client_message_recv
.recv()
.expect("Player closed connection.");
break;
} else {
println!("KO");
clichess::write_to_stream(stream, String::from("KO")).unwrap();
server
.client_message_recv
.recv()
.expect("Player closed connection.");
continue;
}
}
}
Ok(chosen_role)
}
fn compute_available_roles_to_str(server: &Server) -> String {