diff --git a/Cargo.lock b/Cargo.lock index aaaa27e..64b6a86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,11 +32,23 @@ dependencies = [ "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "clichess" version = "0.1.0" dependencies = [ "colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "shakmaty 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -52,6 +64,97 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ctrlc" +version = "3.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-channel" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-executor" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-io" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-macro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-sink" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-task" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-util" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.4" @@ -67,6 +170,23 @@ name = "libc" version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memchr" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-traits" version = "0.2.10" @@ -75,6 +195,26 @@ dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro-hack" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-nested" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro2" version = "1.0.6" @@ -134,6 +274,11 @@ dependencies = [ "btoi 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "1.0.11" @@ -149,6 +294,11 @@ name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.8" @@ -174,11 +324,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum btoi 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e4ced8205e70d9e553d008d53ded735808fa6133597318d48f74fc2bf9861471" +"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "433e7ac7d511768127ed85b0c4947f47a254131e37864b2dc13f52aa32cd37e5" +"checksum ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7dfd2d8b4c82121dfdff120f818e09fc4380b0b7e17a742081a89b94853e87f" +"checksum futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6f16056ecbb57525ff698bb955162d0cd03bee84e6241c27ff75c08d8ca5987" +"checksum futures-channel 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fcae98ca17d102fd8a3603727b9259fcf7fa4239b603d2142926189bc8999b86" +"checksum futures-core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "79564c427afefab1dfb3298535b21eda083ef7935b4f0ecbfcb121f0aec10866" +"checksum futures-executor 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e274736563f686a837a0568b478bdabfeaec2dca794b5649b04e2fe1627c231" +"checksum futures-io 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e676577d229e70952ab25f3945795ba5b16d63ca794ca9d2c860e5595d20b5ff" +"checksum futures-macro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "52e7c56c15537adb4f76d0b7a76ad131cb4d2f4f32d3b0bcabcbe1c7c5e87764" +"checksum futures-sink 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "171be33efae63c2d59e6dbba34186fe0d6394fb378069a76dfd80fdcffd43c16" +"checksum futures-task 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0bae52d6b29cf440e298856fec3965ee6fa71b06aa7495178615953fd669e5f9" +"checksum futures-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" +"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" +"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" +"checksum proc-macro-nested 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" @@ -186,8 +353,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" "checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" "checksum shakmaty 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "995611c42b955b8661f1eaf19e83beec36e72ec3ac51ed41a9018a19323c8022" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 7c236a9..3d792c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,5 @@ shakmaty = "0.16.0" colored = "1.9" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +ctrlc = "3.1.3" +futures = "0.3.1" diff --git a/src/bin/client.rs b/src/bin/client.rs index 5544e3c..4812830 100644 --- a/src/bin/client.rs +++ b/src/bin/client.rs @@ -1,10 +1,16 @@ +extern crate ctrlc; use shakmaty::fen::Fen; use shakmaty::{Chess, Color, Outcome, Position, Setup}; use std::io; use std::io::{BufRead, BufReader}; use std::os::unix::net::UnixStream; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time; fn main() { + let running = setupctrlc(); let username = std::env::args().nth(1).expect("no name given"); let public_key = std::env::args().nth(2).expect("no public key given"); println!("Name: {}, Public key: {}", username, public_key); @@ -18,7 +24,6 @@ fn main() { //send username and public key to server clichess::write_to_stream(&mut stream, username); clichess::write_to_stream(&mut stream, public_key); - let mut buffer = String::new(); let (client, chess) = get_connection_info_from_stream(&stream); //First prompt when connecting to the server println!( @@ -28,6 +33,7 @@ fn main() { ); //then we get the initial role of the connected client. let mut current_position = chess; + let input_buffer = setup_input_buffer(); loop { println!( "{}", @@ -39,18 +45,18 @@ fn main() { } if clichess::is_player_turn(&client, current_position.turn()) { //it's the user turn, taking user input - io::stdin().read_line(&mut buffer).unwrap(); - println!("trying to play {}", buffer); - clichess::write_to_stream(&mut stream, String::from(buffer.trim())); - buffer.clear(); + 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())); + if input.trim() == "exit" { + break; + } } //update position after playing. current_position = get_current_position(&stream); - - //come back at the beginning of the loop to wait for incoming moves. } match current_position.outcome() { - None => panic!("Game should be over."), + None => println!("Bye"), Some(Outcome::Draw) => println!("Draw game."), Some(Outcome::Decisive { winner }) => { if winner == Color::White { @@ -62,9 +68,62 @@ fn main() { } } +fn setup_input_buffer() -> Arc> { + let buf = Arc::new(Mutex::new(String::new())); + let buf2 = buf.clone(); + + 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 !"); + } + } + } + }); + buf +} + +fn setupctrlc() -> Arc { + let running = Arc::new(AtomicBool::new(true)); + let r = running.clone(); + ctrlc::set_handler(move || { + r.store(false, Ordering::SeqCst); + }) + .expect("Error setting Ctrl-C handler"); + running +} + +fn read_user_input(running: Arc, input_buffer: Arc>) -> String { + let mut input = String::new(); + while running.load(Ordering::SeqCst) { + thread::sleep(time::Duration::from_millis(10)); + { + let user_input = input_buffer.lock().unwrap(); + if user_input.is_empty() { + continue; + } else { + input = user_input.clone(); + break; + } + } + } + if running.load(Ordering::SeqCst) { + input + } else { + String::from("exit") + } +} + //wait for next position from server, then return the current board. fn get_current_position(stream: &UnixStream) -> Chess { - let response = clichess::read_line_from_stream(&stream); + let response = clichess::read_line_from_stream(&stream).expect("Server disconnected."); parse_position(&response) } diff --git a/src/bin/server.rs b/src/bin/server.rs index 441467a..7dcee9d 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -74,7 +74,17 @@ fn handle_client(mut stream: UnixStream, server: Server) { if clichess::is_player_turn(&client, player_turn) { //let go of the lock while waiting for user input. println!("server {}, waiting for client move..", server.id); - let input = clichess::read_line_from_stream(&stream); + let input; + match clichess::read_line_from_stream(&stream) { + Ok(i) => input = i, + Err(e) => { + println!("Error while getting user input: {}", e); + break; + } + }; + if input == "exit" { + break; + } { let mut chess = server.chess_position.lock().unwrap(); let clients = server.clients.lock().unwrap(); @@ -109,6 +119,7 @@ fn handle_client(mut stream: UnixStream, server: Server) { } } } + println!("Client disconnected.") } fn create_client(server: &Server, stream: &UnixStream) -> Client { @@ -120,12 +131,12 @@ fn create_client(server: &Server, stream: &UnixStream) -> Client { //first, username. reader .read_line(&mut buf) - .expect("Server closed connection."); + .expect("Client closed connection."); let username = String::from(buf.trim()); buf.clear(); reader .read_line(&mut buf) - .expect("Server closed connection."); + .expect("Client closed connection."); let public_key = String::from(buf.trim()); let role = match server.id { 0 => UserRole::White, diff --git a/src/lib.rs b/src/lib.rs index d260a65..0429447 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use shakmaty::san::ParseSanError; use shakmaty::san::San; use shakmaty::san::SanError; use shakmaty::{Chess, Color, IllegalMoveError, Position, Setup, Square}; +use std::io; use std::fmt; use std::io::prelude::*; use std::io::{BufReader, Write}; @@ -186,12 +187,12 @@ fn piece_char_to_utf8(piece: char) -> char { } } -pub fn read_line_from_stream(stream: &UnixStream) -> String { +pub fn read_line_from_stream(stream: &UnixStream) -> Result { let mut result = String::new(); let mut reader = BufReader::new(stream); - reader.read_line(&mut result).unwrap(); - String::from(result.trim_end()) + reader.read_line(&mut result)?; + Ok(String::from(result.trim_end())) } pub fn write_to_stream(stream: &mut UnixStream, msg: String) {