Further improvements for the server and client

This commit is contained in:
Phuntsok Drak-pa 2018-03-21 20:38:20 +01:00
parent 50e4b6a380
commit 60bedb7ff6
3 changed files with 127 additions and 69 deletions

View File

@ -4,3 +4,5 @@ version = "0.2.0"
authors = ["Lucien Cartier-Tilet <drakpa@drakpa.fr>"]
[dependencies]
colored = "1.6"
chrono = "0.4"

View File

@ -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;
}
}

View File

@ -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);
}
}
}