Manage client disconnect case where he is waiting

This commit is contained in:
Artlef 2020-01-26 13:42:17 +01:00
parent c558c42b09
commit 2cd79b6715
3 changed files with 82 additions and 16 deletions

View File

@ -9,11 +9,18 @@ use std::sync::{Arc, Mutex};
use std::thread; use std::thread;
use std::time; use std::time;
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");
let public_key = std::env::args().nth(2).expect("no public key given"); let public_key = std::env::args().nth(2).expect("no public key given");
println!("Name: {}, Public key: {}", username, public_key); println!("Name: {}, Public key: {}", username, public_key);
//send username and public key to server
let mut stream = match UnixStream::connect("/tmp/clichess.socket") { let mut stream = match UnixStream::connect("/tmp/clichess.socket") {
Ok(sock) => sock, Ok(sock) => sock,
Err(_) => { Err(_) => {
@ -21,9 +28,8 @@ fn main() {
return; return;
} }
}; };
//send username and public key to server clichess::write_to_stream(&mut stream, username).unwrap();
clichess::write_to_stream(&mut stream, username); clichess::write_to_stream(&mut stream, public_key).unwrap();
clichess::write_to_stream(&mut stream, public_key);
let (client, chess) = get_connection_info_from_stream(&stream); let (client, chess) = get_connection_info_from_stream(&stream);
//First prompt when connecting to the server //First prompt when connecting to the server
println!( println!(
@ -34,6 +40,8 @@ fn main() {
//then we get the initial role of the connected client. //then we get the initial role of the connected client.
let mut current_position = chess; let mut current_position = chess;
let input_buffer = setup_input_buffer(); let input_buffer = setup_input_buffer();
//start a thread to listen to server messages
let server_message = setup_server_message_recv(&stream).unwrap();
loop { loop {
println!( println!(
"{}", "{}",
@ -46,14 +54,18 @@ fn main() {
if clichess::is_player_turn(&client, current_position.turn()) { if clichess::is_player_turn(&client, current_position.turn()) {
//it's the user turn, taking user input //it's the user turn, taking user input
let input = read_user_input(running.clone(), input_buffer.clone()); let input = read_user_input(running.clone(), input_buffer.clone());
println!("trying to play {}", input); clichess::write_to_stream(&mut stream, String::from(input.trim())).unwrap();
clichess::write_to_stream(&mut stream, String::from(input.trim()));
if input.trim() == "exit" { if input.trim() == "exit" {
break; break;
} }
} }
//update position after playing. //update position after playing.
current_position = get_current_position(&stream); match get_current_position(running.clone(), server_message.clone()) {
Ok(position) => current_position = position,
Err(RecvPositionError::UserCanceledError) => break,
Err(RecvPositionError::CommunicationError) => break,
Err(RecvPositionError::ParsePositionError) => break,
};
} }
match current_position.outcome() { match current_position.outcome() {
None => println!("Bye"), None => println!("Bye"),
@ -100,7 +112,35 @@ fn setupctrlc() -> Arc<AtomicBool> {
running running
} }
fn setup_server_message_recv(stream: &UnixStream) -> io::Result<Arc<Mutex<String>>> {
let buf = Arc::new(Mutex::new(String::new()));
let buf2 = buf.clone();
let thread_stream = stream.try_clone()?;
thread::spawn(move || {
loop {
//wait for server message
let buffer =
clichess::read_line_from_stream(&thread_stream).expect("Error message from server");
{
let mut server_message = buf2.lock().unwrap();
if server_message.is_empty() {
*server_message = buffer;
} else {
println!("Warning: server tried to send a message while the current one has not been computed yet.");
}
}
}
});
Ok(buf)
}
fn read_user_input(running: Arc<AtomicBool>, input_buffer: Arc<Mutex<String>>) -> String { fn read_user_input(running: Arc<AtomicBool>, input_buffer: Arc<Mutex<String>>) -> String {
//clear input before waiting for a new one
{
let mut user_input = input_buffer.lock().unwrap();
user_input.clear();
}
let mut input = String::new(); let mut input = String::new();
while running.load(Ordering::SeqCst) { while running.load(Ordering::SeqCst) {
thread::sleep(time::Duration::from_millis(10)); thread::sleep(time::Duration::from_millis(10));
@ -122,9 +162,29 @@ fn read_user_input(running: Arc<AtomicBool>, input_buffer: Arc<Mutex<String>>) -
} }
//wait for next position from server, then return the current board. //wait for next position from server, then return the current board.
fn get_current_position(stream: &UnixStream) -> Chess { fn get_current_position(
let response = clichess::read_line_from_stream(&stream).expect("Server disconnected."); running: Arc<AtomicBool>,
parse_position(&response) server_message: Arc<Mutex<String>>,
) -> Result<Chess, RecvPositionError> {
let mut response = String::new();
while running.load(Ordering::SeqCst) {
thread::sleep(time::Duration::from_millis(10));
{
let mut server_response = server_message.lock().unwrap();
if server_response.is_empty() {
continue;
} else {
response = server_response.clone();
server_response.clear();
break;
}
}
}
if response.is_empty() {
Err(RecvPositionError::UserCanceledError)
} else {
Ok(parse_position(&response))
}
} }
fn parse_position(string: &str) -> Chess { fn parse_position(string: &str) -> Chess {

View File

@ -67,7 +67,7 @@ fn handle_client(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)); clichess::write_to_stream(&mut stream, fen::fen(&*chess)).unwrap();
} }
println!("server {}, current position to the client sent", server.id); println!("server {}, current position to the client sent", server.id);
loop { loop {
@ -100,7 +100,7 @@ fn handle_client(mut stream: UnixStream, server: Server) {
cvar_buffer.1.notify_one(); cvar_buffer.1.notify_one();
} }
} }
clichess::write_to_stream(&mut stream, chessfen); clichess::write_to_stream(&mut stream, chessfen).unwrap();
player_turn = chess.turn(); player_turn = chess.turn();
} }
} else { } else {
@ -112,8 +112,13 @@ fn handle_client(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);
clichess::write_to_stream(&mut stream, buffer.clone()); match clichess::write_to_stream(&mut stream, buffer.clone()) {
buffer.clear(); Ok(()) => buffer.clear(),
Err(e) => {
println!("{}", e);
break;
}
}
let chess = server.chess_position.lock().unwrap(); let chess = server.chess_position.lock().unwrap();
player_turn = chess.turn(); player_turn = chess.turn();
} }

View File

@ -4,8 +4,8 @@ use shakmaty::san::ParseSanError;
use shakmaty::san::San; use shakmaty::san::San;
use shakmaty::san::SanError; use shakmaty::san::SanError;
use shakmaty::{Chess, Color, IllegalMoveError, Position, Setup, Square}; use shakmaty::{Chess, Color, IllegalMoveError, Position, Setup, Square};
use std::io;
use std::fmt; use std::fmt;
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;
@ -195,8 +195,9 @@ pub fn read_line_from_stream(stream: &UnixStream) -> Result<String, io::Error> {
Ok(String::from(result.trim_end())) Ok(String::from(result.trim_end()))
} }
pub fn write_to_stream(stream: &mut UnixStream, msg: String) { pub fn write_to_stream(stream: &mut UnixStream, msg: String) -> io::Result<()> {
stream.write_all(&(msg + "\n").as_bytes()).unwrap(); stream.write_all(&(msg + "\n").as_bytes())?;
Ok(())
} }
pub fn get_default_side(role: UserRole) -> Color { pub fn get_default_side(role: UserRole) -> Color {