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;
use clichess::RecvPositionError;
use serde_json::json;
use shakmaty::fen::Fen;
use shakmaty::{Chess, Color, Outcome, Position, Setup};
use std::io;
@ -7,7 +9,6 @@ use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;
use serde_json::json;
struct Client {
player: clichess::Player,
@ -17,12 +18,6 @@ struct Client {
server_message: Arc<Mutex<String>>,
}
enum RecvPositionError {
UserCanceledError,
CommunicationError,
ParsePositionError,
}
fn main() {
let running = setupctrlc();
let username = std::env::args().nth(1).expect("no name given");
@ -56,8 +51,10 @@ fn main() {
server_message: server_message.clone(),
};
let role = prompt_user_for_role(&client, &mut stream);
client.player.role = role.clone();
match prompt_user_for_role(&client, &mut stream) {
Some(role) => client.player.role = role.clone(),
None => return,
};
println!(
"Hello, {} !\n\r You're playing with the {} pieces",
client.player.username,
@ -218,8 +215,8 @@ fn parse_position(string: &str) -> Chess {
position
}
fn prompt_user_for_role(client: &Client, stream: &mut UnixStream) -> clichess::UserRole {
let mut role: clichess::UserRole;
fn prompt_user_for_role(client: &Client, stream: &mut UnixStream) -> Option<clichess::UserRole> {
let mut role = None;
loop {
println!("fetching roles from server...");
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);
//wait for user to give a correct answer.
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) {
Ok(r) => role = r,
Ok(r) => role = Some(r),
Err(e) => {
println!("{}", e);
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.");
continue;
}

View File

@ -1,5 +1,6 @@
use clichess;
use clichess::Player;
use clichess::RecvPositionError;
use clichess::UserRole;
use serde_json::Value;
use shakmaty::{fen, Chess, Color, Setup};
@ -49,9 +50,20 @@ fn main() {
}
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
let player = create_player(&server, &mut stream);
let mut player_turn: Color;
let player = create_player(server, stream)?;
let player_turn: Color;
//send current position to the player
println!(
"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();
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);
Ok((player, player_turn))
}
fn main_loop(stream: &mut UnixStream, server: &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 clichess::read_line_from_stream(&stream) {
match clichess::read_line_from_stream(stream) {
Ok(i) => input = i,
Err(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();
}
}
clichess::write_to_stream(&mut stream, chessfen).unwrap();
clichess::write_to_stream(stream, chessfen).unwrap();
player_turn = chess.turn();
}
} else {
@ -105,7 +121,7 @@ fn handle_player(mut stream: UnixStream, server: Server) {
buffer = cvar.wait(buffer).unwrap();
}
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(),
Err(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);
//get player name and pubkey
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();
println!("got username: {}", username);
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 player = Player {
role,
@ -139,10 +154,13 @@ fn create_player(server: &Server, stream: &mut UnixStream) -> Player {
};
players.insert(server.id, (player.clone(), server.receiving_buffer.clone()));
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;
loop {
//send available roles
@ -152,9 +170,16 @@ fn receive_user_role(server: &Server, stream: &mut UnixStream) -> UserRole {
//receive chosen role
let chosen_role_str =
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);
chosen_role =
clichess::parse_to_role(&chosen_role_str).expect("Client did not send parsable role.");
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 =
@ -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 {
@ -201,3 +226,7 @@ fn compute_available_roles_to_str(server: &Server) -> String {
.collect();
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::{BufReader, Write};
use std::os::unix::net::UnixStream;
use std::ops::Add;
#[derive(Clone)]
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 {
color: String,
background_color: String,
@ -205,7 +225,7 @@ pub fn parse_to_role(s: &str) -> Result<UserRole, String> {
"w" => Ok(UserRole::White),
"b" => Ok(UserRole::Black),
"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 {
UserRole::White => "w",
UserRole::Black => "b",
UserRole::Spectator => "s"
UserRole::Spectator => "s",
})
}