Do not use cpu when waiting for opponent move.
This commit is contained in:
parent
2c4b339bc2
commit
c692be6159
@ -6,18 +6,18 @@ use std::collections::HashMap;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::net::{UnixListener, UnixStream};
|
use std::os::unix::net::{UnixListener, UnixStream};
|
||||||
use std::sync::mpsc::{channel, Receiver, TryRecvError};
|
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Condvar, Mutex};
|
||||||
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time;
|
|
||||||
|
|
||||||
struct Server {
|
struct Server {
|
||||||
id: usize,
|
id: usize,
|
||||||
chess_position: Arc<Mutex<Chess>>,
|
chess_position: Arc<Mutex<Chess>>,
|
||||||
players: Arc<Mutex<HashMap<usize, (Player, Arc<Mutex<String>>)>>>,
|
players: Arc<Mutex<HashMap<usize, (Player, Sender<String>, Arc<(Mutex<bool>, Condvar)>)>>>,
|
||||||
others_serv_msg_buf: Arc<Mutex<String>>,
|
others_serv_msg_recv: Receiver<String>,
|
||||||
client_message_recv: Receiver<String>,
|
client_message_recv: Receiver<String>,
|
||||||
|
cvar: Arc<(Mutex<bool>, Condvar)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -32,16 +32,20 @@ fn main() {
|
|||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
match stream {
|
match stream {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
let client_message_recv = setup_client_message_recv(&stream).unwrap();
|
let condvar_pair = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
let client_message_recv =
|
||||||
|
setup_client_message_recv(&stream, condvar_pair.clone()).unwrap();
|
||||||
|
let (others_serv_msg_sender, others_serv_msg_recv) = channel();
|
||||||
let server = Server {
|
let server = Server {
|
||||||
id: counter,
|
id: counter,
|
||||||
chess_position: chess.clone(),
|
chess_position: chess.clone(),
|
||||||
players: players.clone(),
|
players: players.clone(),
|
||||||
others_serv_msg_buf: Arc::new(Mutex::new(String::new())),
|
others_serv_msg_recv,
|
||||||
client_message_recv,
|
client_message_recv,
|
||||||
|
cvar: condvar_pair,
|
||||||
};
|
};
|
||||||
/* connection succeeded */
|
/* connection succeeded */
|
||||||
thread::spawn(move || handle_player(stream, server));
|
thread::spawn(move || handle_player(stream, server, others_serv_msg_sender));
|
||||||
counter += 1;
|
counter += 1;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -52,8 +56,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_player(mut stream: UnixStream, server: Server) {
|
fn handle_player(mut stream: UnixStream, server: Server, others_serv_msg_sender: Sender<String>) {
|
||||||
match initialize_client(&mut stream, &server) {
|
match initialize_client(&mut stream, &server, others_serv_msg_sender) {
|
||||||
Ok((player, player_turn)) => main_loop(&mut stream, &server, player, player_turn),
|
Ok((player, player_turn)) => main_loop(&mut stream, &server, player, player_turn),
|
||||||
Err(e) => println!("User id {} could not be initialized: {}", server.id, e),
|
Err(e) => println!("User id {} could not be initialized: {}", server.id, e),
|
||||||
};
|
};
|
||||||
@ -63,9 +67,10 @@ fn handle_player(mut stream: UnixStream, server: Server) {
|
|||||||
fn initialize_client(
|
fn initialize_client(
|
||||||
stream: &mut UnixStream,
|
stream: &mut UnixStream,
|
||||||
server: &Server,
|
server: &Server,
|
||||||
|
others_serv_msg_sender: Sender<String>,
|
||||||
) -> Result<(Player, Color), RecvPositionError> {
|
) -> Result<(Player, Color), RecvPositionError> {
|
||||||
//create player
|
//create player
|
||||||
let player = create_player(server, stream)?;
|
let player = create_player(server, stream, others_serv_msg_sender)?;
|
||||||
let player_turn: Color;
|
let player_turn: Color;
|
||||||
//send current position to the player
|
//send current position to the player
|
||||||
println!(
|
println!(
|
||||||
@ -106,9 +111,13 @@ fn main_loop(stream: &mut UnixStream, server: &Server, player: Player, mut playe
|
|||||||
Err(e) => println!("Error: {}", e),
|
Err(e) => println!("Error: {}", e),
|
||||||
};
|
};
|
||||||
let chessfen = fen::fen(&*chess);
|
let chessfen = fen::fen(&*chess);
|
||||||
for (id, (_, others_serv_msg_buf)) in players.iter() {
|
for (id, (_, others_serv_msg_sender, cvar_pair)) in players.iter() {
|
||||||
if server.id != *id {
|
if server.id != *id {
|
||||||
others_serv_msg_buf.lock().unwrap().push_str(&chessfen);
|
others_serv_msg_sender.send(chessfen.clone());
|
||||||
|
let (lock, cvar) = &**cvar_pair;
|
||||||
|
let mut message_sent = lock.lock().unwrap();
|
||||||
|
*message_sent = true;
|
||||||
|
cvar.notify_one();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if clichess::write_to_stream(stream, chessfen).is_err() {
|
if clichess::write_to_stream(stream, chessfen).is_err() {
|
||||||
@ -134,40 +143,44 @@ fn wait_for_opponent_move(server: &Server) -> Result<String, RecvPositionError>
|
|||||||
println!("server id: {}, waiting for move to send...", server.id);
|
println!("server id: {}, waiting for move to send...", server.id);
|
||||||
//wait: either we receive next position from other server threads, or we receive
|
//wait: either we receive next position from other server threads, or we receive
|
||||||
//"exit" from the client.
|
//"exit" from the client.
|
||||||
let returned_result: Result<String, RecvPositionError>;
|
let mut returned_result = Err(RecvPositionError::UserCanceledError);
|
||||||
loop {
|
let (lock, cvar) = &*server.cvar;
|
||||||
{
|
let mut message_sent = lock.lock().unwrap();
|
||||||
let mut others_serv_msg_buf = server.others_serv_msg_buf.lock().unwrap();
|
*message_sent = false;
|
||||||
if !others_serv_msg_buf.is_empty() {
|
while !*message_sent {
|
||||||
returned_result = Ok(others_serv_msg_buf.clone());
|
message_sent = cvar.wait(message_sent).unwrap();
|
||||||
others_serv_msg_buf.clear();
|
}
|
||||||
break;
|
*message_sent = false;
|
||||||
} else {
|
match server.others_serv_msg_recv.try_recv() {
|
||||||
|
Ok(msg) => {
|
||||||
|
returned_result = Ok(msg);
|
||||||
|
}
|
||||||
|
Err(TryRecvError::Disconnected) => {
|
||||||
|
println!("Error: other server thread disconnected while sending move.")
|
||||||
|
}
|
||||||
|
Err(TryRecvError::Empty) => { /*nothing to do*/ }
|
||||||
|
}
|
||||||
match server.client_message_recv.try_recv() {
|
match server.client_message_recv.try_recv() {
|
||||||
Ok(msg) => {
|
Ok(msg) => {
|
||||||
if msg == EXIT_MSG {
|
if msg == EXIT_MSG {
|
||||||
returned_result = Err(RecvPositionError::UserCanceledError);
|
returned_result = Err(RecvPositionError::UserCanceledError);
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
println!(
|
println!("Client sent message while it's not its turn, this is an error.");
|
||||||
"Client sent message while it's not its turn, this is an error."
|
|
||||||
);
|
|
||||||
println!("Here is the message: {}", msg);
|
println!("Here is the message: {}", msg);
|
||||||
returned_result = Err(RecvPositionError::UserCanceledError);
|
returned_result = Err(RecvPositionError::UserCanceledError);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(TryRecvError::Disconnected) => println!("Error: client disconnected."),
|
Err(TryRecvError::Disconnected) => println!("Error: client disconnected."),
|
||||||
Err(TryRecvError::Empty) => continue,
|
Err(TryRecvError::Empty) => {}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thread::sleep(time::Duration::from_millis(10));
|
|
||||||
}
|
}
|
||||||
returned_result
|
returned_result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_player(server: &Server, stream: &mut UnixStream) -> Result<Player, RecvPositionError> {
|
fn create_player(
|
||||||
|
server: &Server,
|
||||||
|
stream: &mut UnixStream,
|
||||||
|
others_serv_msg_sender: Sender<String>,
|
||||||
|
) -> 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 = server
|
let username_pubkey_json = server
|
||||||
@ -188,7 +201,7 @@ fn create_player(server: &Server, stream: &mut UnixStream) -> Result<Player, Rec
|
|||||||
};
|
};
|
||||||
players.insert(
|
players.insert(
|
||||||
server.id,
|
server.id,
|
||||||
(player.clone(), server.others_serv_msg_buf.clone()),
|
(player.clone(), others_serv_msg_sender, server.cvar.clone()),
|
||||||
);
|
);
|
||||||
println!("Created player {}", server.id);
|
println!("Created player {}", server.id);
|
||||||
Ok(player)
|
Ok(player)
|
||||||
@ -224,7 +237,7 @@ fn receive_user_role(
|
|||||||
let mut available_roles_after_choice =
|
let mut available_roles_after_choice =
|
||||||
vec![UserRole::White, UserRole::Black, UserRole::Spectator];
|
vec![UserRole::White, UserRole::Black, UserRole::Spectator];
|
||||||
let players = server.players.lock().unwrap();
|
let players = server.players.lock().unwrap();
|
||||||
for (_, (player, _)) in players.iter() {
|
for (_, (player, _, _)) in players.iter() {
|
||||||
match available_roles_after_choice
|
match available_roles_after_choice
|
||||||
.iter()
|
.iter()
|
||||||
.position(|r| *r == player.role)
|
.position(|r| *r == player.role)
|
||||||
@ -258,7 +271,7 @@ fn receive_user_role(
|
|||||||
fn compute_available_roles_to_str(server: &Server) -> String {
|
fn compute_available_roles_to_str(server: &Server) -> String {
|
||||||
let mut available_roles = vec![UserRole::White, UserRole::Black, UserRole::Spectator];
|
let mut available_roles = vec![UserRole::White, UserRole::Black, UserRole::Spectator];
|
||||||
let players = server.players.lock().unwrap();
|
let players = server.players.lock().unwrap();
|
||||||
for (_, (player, _)) in players.iter() {
|
for (_, (player, _, _)) in players.iter() {
|
||||||
match available_roles.iter().position(|r| *r == player.role) {
|
match available_roles.iter().position(|r| *r == player.role) {
|
||||||
Some(index) => available_roles.remove(index),
|
Some(index) => available_roles.remove(index),
|
||||||
None => continue,
|
None => continue,
|
||||||
@ -275,13 +288,16 @@ fn player_disconnected(server: &Server) {
|
|||||||
let mut players = server.players.lock().unwrap();
|
let mut players = server.players.lock().unwrap();
|
||||||
let player_and_receiving_buf = players.get(&server.id);
|
let player_and_receiving_buf = players.get(&server.id);
|
||||||
if player_and_receiving_buf.is_some() {
|
if player_and_receiving_buf.is_some() {
|
||||||
let (player, _) = player_and_receiving_buf.expect("is some");
|
let (player, _, _) = player_and_receiving_buf.expect("is some");
|
||||||
println!("Player {} disconnected.", player.username);
|
println!("Player {} disconnected.", player.username);
|
||||||
}
|
}
|
||||||
players.remove(&server.id);
|
players.remove(&server.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_client_message_recv(stream: &UnixStream) -> io::Result<Receiver<String>> {
|
fn setup_client_message_recv(
|
||||||
|
stream: &UnixStream,
|
||||||
|
cvar_pair: Arc<(Mutex<bool>, Condvar)>,
|
||||||
|
) -> io::Result<Receiver<String>> {
|
||||||
let (sender, receiver) = channel();
|
let (sender, receiver) = channel();
|
||||||
let thread_stream = stream.try_clone()?;
|
let thread_stream = stream.try_clone()?;
|
||||||
|
|
||||||
@ -290,6 +306,11 @@ fn setup_client_message_recv(stream: &UnixStream) -> io::Result<Receiver<String>
|
|||||||
//wait for client message
|
//wait for client message
|
||||||
let buffer =
|
let buffer =
|
||||||
clichess::read_line_from_stream(&thread_stream).expect("Error message from server");
|
clichess::read_line_from_stream(&thread_stream).expect("Error message from server");
|
||||||
|
//notify the server if waiting
|
||||||
|
let (lock, cvar) = &*cvar_pair;
|
||||||
|
let mut message_sent = lock.lock().unwrap();
|
||||||
|
*message_sent = true;
|
||||||
|
cvar.notify_one();
|
||||||
let send_result = sender.send(buffer);
|
let send_result = sender.send(buffer);
|
||||||
// stop the thread during a disconnection
|
// stop the thread during a disconnection
|
||||||
if send_result.is_err() {
|
if send_result.is_err() {
|
||||||
|
Loading…
Reference in New Issue
Block a user