Manage when user leave during connection.

This commit is contained in:
Artlef 2020-03-01 19:09:39 +01:00
parent 175e8fafe6
commit 0a2aba9619
3 changed files with 80 additions and 30 deletions

View File

@ -1,4 +1,6 @@
extern crate ctrlc; extern crate ctrlc;
use clichess::RecvPositionError;
use serde_json::json;
use shakmaty::fen::Fen; use shakmaty::fen::Fen;
use shakmaty::{Chess, Color, Outcome, Position, Setup}; use shakmaty::{Chess, Color, Outcome, Position, Setup};
use std::io; use std::io;
@ -7,7 +9,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use std::time; use std::time;
use serde_json::json;
struct Client { struct Client {
player: clichess::Player, player: clichess::Player,
@ -17,12 +18,6 @@ struct Client {
server_message: Arc<Mutex<String>>, server_message: Arc<Mutex<String>>,
} }
enum RecvPositionError {
UserCanceledError,
CommunicationError,
ParsePositionError,
}
fn main() { fn main() {
let running = setupctrlc(); let running = setupctrlc();
let username = std::env::args().nth(1).expect("no name given"); let username = std::env::args().nth(1).expect("no name given");
@ -56,8 +51,10 @@ fn main() {
server_message: server_message.clone(), server_message: server_message.clone(),
}; };
let role = prompt_user_for_role(&client, &mut stream); match prompt_user_for_role(&client, &mut stream) {
client.player.role = role.clone(); Some(role) => client.player.role = role.clone(),
None => return,
};
println!( println!(
"Hello, {} !\n\r You're playing with the {} pieces", "Hello, {} !\n\r You're playing with the {} pieces",
client.player.username, client.player.username,
@ -218,8 +215,8 @@ fn parse_position(string: &str) -> Chess {
position position
} }
fn prompt_user_for_role(client: &Client, stream: &mut UnixStream) -> clichess::UserRole { fn prompt_user_for_role(client: &Client, stream: &mut UnixStream) -> Option<clichess::UserRole> {
let mut role: clichess::UserRole; let mut role = None;
loop { loop {
println!("fetching roles from server..."); println!("fetching roles from server...");
let available_roles = fetch_available_roles(client); let available_roles = fetch_available_roles(client);
@ -241,14 +238,18 @@ fn prompt_user_for_role(client: &Client, stream: &mut UnixStream) -> clichess::U
println!("{}", prompt); println!("{}", prompt);
//wait for user to give a correct answer. //wait for user to give a correct answer.
let input = String::from(read_user_input(client).trim()); let input = String::from(read_user_input(client).trim());
if input.trim() == "exit" {
clichess::write_to_stream(stream, String::from("exit")).unwrap();
break;
}
match clichess::parse_to_role(&input) { match clichess::parse_to_role(&input) {
Ok(r) => role = r, Ok(r) => role = Some(r),
Err(e) => { Err(e) => {
println!("{}", e); println!("{}", e);
continue; continue;
} }
}; };
if !available_roles.contains(&role) { if role.is_some() && !available_roles.contains(&role.expect("role is some")) {
println!("Sorry, this side is not available."); println!("Sorry, this side is not available.");
continue; continue;
} }

View File

@ -1,5 +1,6 @@
use clichess; use clichess;
use clichess::Player; use clichess::Player;
use clichess::RecvPositionError;
use clichess::UserRole; use clichess::UserRole;
use serde_json::Value; use serde_json::Value;
use shakmaty::{fen, Chess, Color, Setup}; use shakmaty::{fen, Chess, Color, Setup};
@ -49,9 +50,20 @@ fn main() {
} }
fn handle_player(mut stream: UnixStream, server: Server) { fn handle_player(mut stream: UnixStream, server: Server) {
match initialize_client(&mut stream, &server) {
Ok((player, player_turn)) => main_loop(&mut stream, &server, player, player_turn),
Err(e) => println!("User id {} could not be initialized: {}", server.id, e),
};
player_disconnected();
}
fn initialize_client(
stream: &mut UnixStream,
server: &Server,
) -> Result<(Player, Color), RecvPositionError> {
//create player //create player
let player = create_player(&server, &mut stream); let player = create_player(server, stream)?;
let mut player_turn: Color; let player_turn: Color;
//send current position to the player //send current position to the player
println!( println!(
"server {}, send current position to the player...", "server {}, send current position to the player...",
@ -60,15 +72,19 @@ fn handle_player(mut stream: UnixStream, server: Server) {
{ {
let chess = server.chess_position.lock().unwrap(); let chess = server.chess_position.lock().unwrap();
player_turn = chess.turn(); player_turn = chess.turn();
clichess::write_to_stream(&mut stream, fen::fen(&*chess)).unwrap(); clichess::write_to_stream(stream, fen::fen(&*chess)).unwrap();
} }
println!("server {}, current position to the player sent", server.id); println!("server {}, current position to the player sent", server.id);
Ok((player, player_turn))
}
fn main_loop(stream: &mut UnixStream, server: &Server, player: Player, mut player_turn: Color) {
loop { loop {
if clichess::is_player_turn(&player, player_turn) { if clichess::is_player_turn(&player, player_turn) {
//let go of the lock while waiting for user input. //let go of the lock while waiting for user input.
println!("server {}, waiting for player move..", server.id); println!("server {}, waiting for player move..", server.id);
let input; let input;
match clichess::read_line_from_stream(&stream) { match clichess::read_line_from_stream(stream) {
Ok(i) => input = i, Ok(i) => input = i,
Err(e) => { Err(e) => {
println!("Error while getting user input: {}", e); println!("Error while getting user input: {}", e);
@ -93,7 +109,7 @@ fn handle_player(mut stream: UnixStream, server: Server) {
cvar_buffer.1.notify_one(); cvar_buffer.1.notify_one();
} }
} }
clichess::write_to_stream(&mut stream, chessfen).unwrap(); clichess::write_to_stream(stream, chessfen).unwrap();
player_turn = chess.turn(); player_turn = chess.turn();
} }
} else { } else {
@ -105,7 +121,7 @@ fn handle_player(mut stream: UnixStream, server: Server) {
buffer = cvar.wait(buffer).unwrap(); buffer = cvar.wait(buffer).unwrap();
} }
println!("server id: {}, sending {}", server.id, buffer); println!("server id: {}, sending {}", server.id, buffer);
match clichess::write_to_stream(&mut stream, buffer.clone()) { match clichess::write_to_stream(stream, buffer.clone()) {
Ok(()) => buffer.clear(), Ok(()) => buffer.clear(),
Err(e) => { Err(e) => {
println!("{}", e); println!("{}", e);
@ -117,10 +133,9 @@ fn handle_player(mut stream: UnixStream, server: Server) {
} }
} }
} }
println!("Player disconnected.")
} }
fn create_player(server: &Server, stream: &mut UnixStream) -> Player { fn create_player(server: &Server, stream: &mut UnixStream) -> Result<Player, RecvPositionError> {
println!("Creating player {}...", server.id); println!("Creating player {}...", server.id);
//get player name and pubkey //get player name and pubkey
let username_pubkey_json = let username_pubkey_json =
@ -130,7 +145,7 @@ fn create_player(server: &Server, stream: &mut UnixStream) -> Player {
let public_key = username_pubkey_value["pubkey"].to_string(); let public_key = username_pubkey_value["pubkey"].to_string();
println!("got username: {}", username); println!("got username: {}", username);
println!("got pubkey: {}", public_key); println!("got pubkey: {}", public_key);
let role = receive_user_role(server, stream); let role = receive_user_role(server, stream)?;
let mut players = server.players.lock().unwrap(); let mut players = server.players.lock().unwrap();
let player = Player { let player = Player {
role, role,
@ -139,10 +154,13 @@ fn create_player(server: &Server, stream: &mut UnixStream) -> Player {
}; };
players.insert(server.id, (player.clone(), server.receiving_buffer.clone())); players.insert(server.id, (player.clone(), server.receiving_buffer.clone()));
println!("Created player {}", server.id); println!("Created player {}", server.id);
player Ok(player)
} }
fn receive_user_role(server: &Server, stream: &mut UnixStream) -> UserRole { fn receive_user_role(
server: &Server,
stream: &mut UnixStream,
) -> Result<UserRole, RecvPositionError> {
let mut chosen_role: UserRole; let mut chosen_role: UserRole;
loop { loop {
//send available roles //send available roles
@ -152,9 +170,16 @@ fn receive_user_role(server: &Server, stream: &mut UnixStream) -> UserRole {
//receive chosen role //receive chosen role
let chosen_role_str = let chosen_role_str =
clichess::read_line_from_stream(stream).expect("Player closed connection."); clichess::read_line_from_stream(stream).expect("Player closed connection.");
if chosen_role_str == "exit" {
return Err(RecvPositionError::UserCanceledError);
}
println!("Client id {} has chosen {}", server.id, chosen_role_str); println!("Client id {} has chosen {}", server.id, chosen_role_str);
chosen_role = let chosen_role_parse = clichess::parse_to_role(&chosen_role_str);
clichess::parse_to_role(&chosen_role_str).expect("Client did not send parsable role.");
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 //check if role is still available after the choice
{ {
let mut available_roles_after_choice = let mut available_roles_after_choice =
@ -183,7 +208,7 @@ fn receive_user_role(server: &Server, stream: &mut UnixStream) -> UserRole {
} }
} }
} }
chosen_role Ok(chosen_role)
} }
fn compute_available_roles_to_str(server: &Server) -> String { fn compute_available_roles_to_str(server: &Server) -> String {
@ -201,3 +226,7 @@ fn compute_available_roles_to_str(server: &Server) -> String {
.collect(); .collect();
available_roles_str.join(",") available_roles_str.join(",")
} }
fn player_disconnected() {
println!("Player disconnected.");
}

View File

@ -8,7 +8,6 @@ use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::{BufReader, Write}; use std::io::{BufReader, Write};
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::ops::Add;
#[derive(Clone)] #[derive(Clone)]
pub struct Player { pub struct Player {
@ -38,6 +37,27 @@ impl fmt::Display for UserRole {
} }
} }
pub enum RecvPositionError {
UserCanceledError,
CommunicationError,
ParsePositionError,
}
impl fmt::Display for RecvPositionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match self {
RecvPositionError::CommunicationError =>
"Error during the communication between client and server.",
RecvPositionError::ParsePositionError => "Error when parsing current position.",
RecvPositionError::UserCanceledError => "Cancelled by user.",
}
)
}
}
struct SquareToPrint { struct SquareToPrint {
color: String, color: String,
background_color: String, background_color: String,
@ -205,7 +225,7 @@ pub fn parse_to_role(s: &str) -> Result<UserRole, String> {
"w" => Ok(UserRole::White), "w" => Ok(UserRole::White),
"b" => Ok(UserRole::Black), "b" => Ok(UserRole::Black),
"s" => Ok(UserRole::Spectator), "s" => Ok(UserRole::Spectator),
_ => Err(String::from("Please enter a valid answer.")) _ => Err(String::from("Please enter a valid answer.")),
} }
} }
@ -213,7 +233,7 @@ pub fn role_to_str(r: &UserRole) -> String {
String::from(match *r { String::from(match *r {
UserRole::White => "w", UserRole::White => "w",
UserRole::Black => "b", UserRole::Black => "b",
UserRole::Spectator => "s" UserRole::Spectator => "s",
}) })
} }