Further improvements for the server and client
This commit is contained in:
parent
50e4b6a380
commit
60bedb7ff6
@ -4,3 +4,5 @@ version = "0.2.0"
|
||||
authors = ["Lucien Cartier-Tilet <drakpa@drakpa.fr>"]
|
||||
|
||||
[dependencies]
|
||||
colored = "1.6"
|
||||
chrono = "0.4"
|
||||
|
@ -1,7 +1,11 @@
|
||||
extern crate chrono;
|
||||
extern crate colored;
|
||||
use std;
|
||||
use std::io::*;
|
||||
use std::net::TcpStream;
|
||||
use std::thread;
|
||||
use self::colored::*;
|
||||
use self::chrono::Local;
|
||||
|
||||
// static leave_msg: &str = "BYE";
|
||||
|
||||
@ -12,12 +16,11 @@ fn get_entry() -> String {
|
||||
buf.replace("\n", "").replace("\r", "")
|
||||
}
|
||||
|
||||
fn write_to_server(stream: TcpStream) {
|
||||
let mut writer = BufWriter::new(&stream);
|
||||
|
||||
// entrée du nom d'utilisateur
|
||||
fn get_name(writer: &mut BufWriter<&TcpStream>) {
|
||||
loop {
|
||||
match &*get_entry() {
|
||||
let mut line = &*get_entry();
|
||||
line = line.trim();
|
||||
match line {
|
||||
"" => {
|
||||
continue;
|
||||
}
|
||||
@ -25,11 +28,10 @@ fn write_to_server(stream: TcpStream) {
|
||||
println!("Disconnecting...");
|
||||
writeln!(writer, "BYE").unwrap();
|
||||
writer.flush().unwrap();
|
||||
println!("Disconnected!");
|
||||
return ();
|
||||
}
|
||||
line => {
|
||||
let line_str : String = String::from(line);
|
||||
let line_str: String = String::from(line);
|
||||
// let spliced: Vec<&str> = line_str.split(" ").collect();
|
||||
let spliced: Vec<&str> = line_str.split_whitespace().collect();
|
||||
if spliced.len() > 1 {
|
||||
@ -40,19 +42,24 @@ fn write_to_server(stream: TcpStream) {
|
||||
writer.flush().unwrap();
|
||||
}
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn write_to_server(stream: TcpStream) {
|
||||
let mut writer = BufWriter::new(&stream);
|
||||
|
||||
// entrée du nom d'utilisateur
|
||||
get_name(&mut writer);
|
||||
|
||||
loop {
|
||||
match &*get_entry() {
|
||||
"" => {
|
||||
;
|
||||
}
|
||||
let line = &*get_entry();
|
||||
line.trim();
|
||||
match line {
|
||||
"" => {}
|
||||
"/quit" => {
|
||||
println!("Disconnecting...");
|
||||
writeln!(writer, "BYE").unwrap();
|
||||
writer.flush().unwrap();
|
||||
println!("Disconnected!");
|
||||
return ();
|
||||
}
|
||||
"/clients" => {
|
||||
@ -74,17 +81,18 @@ fn exchange_with_server(stream: TcpStream) {
|
||||
let stream_cpy = stream.try_clone().unwrap();
|
||||
let mut reader = BufReader::new(&stream_cpy);
|
||||
|
||||
println!("Enter `/quit` when you want to leave");
|
||||
|
||||
macro_rules! receive {
|
||||
() => ({
|
||||
let mut line = String::new();
|
||||
match reader.read_line(&mut line) {
|
||||
Ok(len) => {
|
||||
if len == 0 {
|
||||
// Reader is at EOF. Could use ErrorKind::UnexpectedEOF, but still unstable.
|
||||
let ret = std::io::Error::new(std::io::ErrorKind::Other, "test");
|
||||
return Err(ret): std::result::Result<&str, std::io::Error>;
|
||||
// Reader is at EOF. Could use ErrorKind::UnexpectedEOF,
|
||||
// but still unstable.
|
||||
let ret = std::io::Error::new(
|
||||
std::io::ErrorKind::Other, "test");
|
||||
return
|
||||
Err(ret): std::result::Result<&str,std::io::Error>;
|
||||
}
|
||||
line.pop();
|
||||
}
|
||||
@ -101,13 +109,50 @@ fn exchange_with_server(stream: TcpStream) {
|
||||
match (|| loop {
|
||||
let input: String = String::from(receive!());
|
||||
let spliced_input: Vec<&str> = input.split(" ").collect();
|
||||
// if spliced_input[0] == "FROM" {
|
||||
// println!("<{}>: {}", spliced_input[1], spliced_input[3]);
|
||||
// continue;
|
||||
// }
|
||||
match spliced_input[0] {
|
||||
"WELCOME" => {
|
||||
println!("{}", "Successfully connected to the server.".green());
|
||||
println!("Type /clients to get the list of users connected");
|
||||
println!("Type /quit to disconnect and quit");
|
||||
}
|
||||
"FROM" => {
|
||||
println!("<{}>: {}", spliced_input[1], spliced_input[3]);
|
||||
let date = Local::now();
|
||||
let mut msg = String::new();
|
||||
for i in 3..spliced_input.len() {
|
||||
msg.push_str(" ");
|
||||
msg.push_str(spliced_input[i]);
|
||||
}
|
||||
println!(
|
||||
"{} <{}>:{}",
|
||||
date.format("%H:%M:%S").to_string().blue(),
|
||||
spliced_input[1].red(),
|
||||
msg
|
||||
);
|
||||
}
|
||||
"BYE" => {
|
||||
return Ok("Ok");
|
||||
}
|
||||
"LIST" => {
|
||||
println!("{}", ">>>> LIST OF CLIENTS CONNECTED <<<<".bold().yellow());
|
||||
for i in 2..spliced_input.len() {
|
||||
println!("\t\t{}", spliced_input[i]);
|
||||
}
|
||||
}
|
||||
"JOIN" => {
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"-------> ".green(),
|
||||
spliced_input[1],
|
||||
" has joined".green()
|
||||
);
|
||||
}
|
||||
"LOGOUT" => {
|
||||
println!(
|
||||
"{}{}{}",
|
||||
"<------- ".red(),
|
||||
spliced_input[1],
|
||||
" has left".red()
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
println!("{}", input);
|
||||
@ -117,23 +162,22 @@ fn exchange_with_server(stream: TcpStream) {
|
||||
})()
|
||||
{
|
||||
Ok(_) => {
|
||||
println!("Left?");
|
||||
println!("{}", ">>> Successfully left the room <<<".green());
|
||||
}
|
||||
Err(_) => {
|
||||
println!(">>> Successfully left the room <<<");
|
||||
Err(e) => {
|
||||
println!("{}: {}", "Error: Function terminated too early".red(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn client(server_address: String) {
|
||||
println!("Tentative de connexion a serveur...");
|
||||
println!("Trying to connect to the server...");
|
||||
match TcpStream::connect(server_address) {
|
||||
Ok(stream) => {
|
||||
println!("Connexion au serveur réussie !");
|
||||
exchange_with_server(stream);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("La connection au serveur a échoué : {}", e);
|
||||
println!("{} {}", "Connection to server failed:".red(), e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ use std::collections::HashMap;
|
||||
1.5 [ ]
|
||||
1.6 [ ]
|
||||
1.7 [X]
|
||||
1.8 [ ]
|
||||
1.8 [X]
|
||||
1.9 [ ]
|
||||
2.1 [X]
|
||||
2.2 [X]
|
||||
@ -26,19 +26,28 @@ use std::collections::HashMap;
|
||||
4.1.1 [X]
|
||||
4.1.2 [X]
|
||||
4.2.1 [X]
|
||||
4.2.2 [X]
|
||||
4.2.2 [-]
|
||||
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// code //
|
||||
// TYPES //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Map for all connected clients containing their name and stream
|
||||
type UserMapValue = (String, TcpStream);
|
||||
type UserMap = HashMap<SocketAddr, UserMapValue>;
|
||||
|
||||
fn distribute_message(msg: &str, not_to: &SocketAddr, lock: &mut MutexGuard<UserMap>) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CODE //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn distribute_message(
|
||||
msg: &str,
|
||||
not_to: &SocketAddr,
|
||||
lock: &mut MutexGuard<UserMap>,
|
||||
everyone: bool,
|
||||
) {
|
||||
let mut name = String::new();
|
||||
for (client, entry) in (*lock).iter() {
|
||||
if client == not_to {
|
||||
@ -47,29 +56,30 @@ fn distribute_message(msg: &str, not_to: &SocketAddr, lock: &mut MutexGuard<User
|
||||
}
|
||||
}
|
||||
for (other_client, entry) in (*lock).iter() {
|
||||
if other_client != not_to {
|
||||
let other_name = &entry.0;
|
||||
let other_stream = &entry.1;
|
||||
match (|| -> Result<()> {
|
||||
let mut writer = BufWriter::new(other_stream);
|
||||
// test if message begins with "MSG " /////////////////////////
|
||||
if &msg[..4] == "MSG " {
|
||||
try!(writeln!(writer, "FROM {} {}", name, msg));
|
||||
} else {
|
||||
try!(writeln!(writer, "{}", msg));
|
||||
}
|
||||
///////////////////////////////////////////////////////////////
|
||||
try!(writer.flush());
|
||||
return Ok(());
|
||||
})()
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!(
|
||||
"Client {} <{}> disappeared during message distribution: {}",
|
||||
other_client, other_name, e
|
||||
);
|
||||
}
|
||||
let other_name = &entry.0;
|
||||
let other_stream = &entry.1;
|
||||
if everyone == false && other_client == not_to {
|
||||
continue;
|
||||
}
|
||||
match (|| -> Result<()> {
|
||||
let mut writer = BufWriter::new(other_stream);
|
||||
// test if message begins with "MSG " /////////////////////////
|
||||
if &msg[..4] == "MSG " {
|
||||
try!(writeln!(writer, "FROM {} {}", name, msg));
|
||||
} else {
|
||||
try!(writeln!(writer, "{}", msg));
|
||||
}
|
||||
///////////////////////////////////////////////////////////////
|
||||
try!(writer.flush());
|
||||
return Ok(());
|
||||
})()
|
||||
{
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
println!(
|
||||
"Client {} <{}> disappeared during message distribution: {}",
|
||||
other_client, other_name, e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,16 +88,21 @@ fn distribute_message(msg: &str, not_to: &SocketAddr, lock: &mut MutexGuard<User
|
||||
fn send_clients_name(to: &SocketAddr, lock: &mut MutexGuard<UserMap>) {
|
||||
let mut clients = String::new();
|
||||
for (client, entry) in (*lock).iter() {
|
||||
if client != to {
|
||||
clients.push_str(&format!("{} ", &entry.0));
|
||||
}
|
||||
&entry.0.trim_left();
|
||||
&entry.0.trim_right();
|
||||
clients.push_str(&format!(
|
||||
"{}{} ",
|
||||
if client == to { "(You)" } else { "" },
|
||||
&entry.0
|
||||
));
|
||||
}
|
||||
clients.trim_left();
|
||||
println!("{}", clients);
|
||||
for (client, entry) in (*lock).iter() {
|
||||
if client == to {
|
||||
let stream = &entry.1;
|
||||
let mut writer = BufWriter::new(stream);
|
||||
writeln!(writer, "{}", clients).unwrap();
|
||||
writeln!(writer, "LIST CLIENTS {}", clients).unwrap();
|
||||
writer.flush().unwrap();
|
||||
return;
|
||||
}
|
||||
@ -96,7 +111,7 @@ fn send_clients_name(to: &SocketAddr, lock: &mut MutexGuard<UserMap>) {
|
||||
|
||||
fn disconnect_user(name: &str, client: &SocketAddr, lock: &mut MutexGuard<UserMap>) {
|
||||
(*lock).remove(&client);
|
||||
distribute_message(&format!("LOGOUT {}", name), client, lock);
|
||||
distribute_message(&format!("LOGOUT {}", name), client, lock, true);
|
||||
}
|
||||
|
||||
fn handle_client(stream: TcpStream, clients: Arc<Mutex<UserMap>>) {
|
||||
@ -144,7 +159,6 @@ fn handle_client(stream: TcpStream, clients: Arc<Mutex<UserMap>>) {
|
||||
send!("Please enter your name:");
|
||||
let name = receive!();
|
||||
println!("Client {} identified as {}", client, name);
|
||||
send!("DEBUG: You can now type messages. Leave this chat with the request `BYE`.");
|
||||
Ok(name)
|
||||
})()
|
||||
{
|
||||
@ -159,7 +173,7 @@ fn handle_client(stream: TcpStream, clients: Arc<Mutex<UserMap>>) {
|
||||
{
|
||||
let mut lock = clients.lock().unwrap();
|
||||
(*lock).insert(client, (name.clone(), stream.try_clone().unwrap()));
|
||||
distribute_message(&format!("JOIN {}", name), &client, &mut lock);
|
||||
distribute_message(&format!("JOIN {}", name), &client, &mut lock, false);
|
||||
}
|
||||
|
||||
writeln!(writer, "WELCOME").unwrap();
|
||||
@ -176,16 +190,14 @@ fn handle_client(stream: TcpStream, clients: Arc<Mutex<UserMap>>) {
|
||||
send!("PONG");
|
||||
}
|
||||
"REQ CLIENTS" => {
|
||||
{
|
||||
let mut lock = clients.lock().unwrap();
|
||||
send_clients_name(&client, &mut lock);
|
||||
}
|
||||
let mut lock = clients.lock().unwrap();
|
||||
send_clients_name(&client, &mut lock);
|
||||
}
|
||||
input => {
|
||||
println!("{} <{}>: {}", client, name, input);
|
||||
{
|
||||
let mut lock = clients.lock().unwrap();
|
||||
distribute_message(&format!("{}", input), &client, &mut lock);
|
||||
distribute_message(&format!("{}", input), &client, &mut lock, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user