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>"]
|
authors = ["Lucien Cartier-Tilet <drakpa@drakpa.fr>"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
colored = "1.6"
|
||||||
|
chrono = "0.4"
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
|
extern crate chrono;
|
||||||
|
extern crate colored;
|
||||||
use std;
|
use std;
|
||||||
use std::io::*;
|
use std::io::*;
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use self::colored::*;
|
||||||
|
use self::chrono::Local;
|
||||||
|
|
||||||
// static leave_msg: &str = "BYE";
|
// static leave_msg: &str = "BYE";
|
||||||
|
|
||||||
@ -12,12 +16,11 @@ fn get_entry() -> String {
|
|||||||
buf.replace("\n", "").replace("\r", "")
|
buf.replace("\n", "").replace("\r", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_server(stream: TcpStream) {
|
fn get_name(writer: &mut BufWriter<&TcpStream>) {
|
||||||
let mut writer = BufWriter::new(&stream);
|
|
||||||
|
|
||||||
// entrée du nom d'utilisateur
|
|
||||||
loop {
|
loop {
|
||||||
match &*get_entry() {
|
let mut line = &*get_entry();
|
||||||
|
line = line.trim();
|
||||||
|
match line {
|
||||||
"" => {
|
"" => {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -25,7 +28,6 @@ fn write_to_server(stream: TcpStream) {
|
|||||||
println!("Disconnecting...");
|
println!("Disconnecting...");
|
||||||
writeln!(writer, "BYE").unwrap();
|
writeln!(writer, "BYE").unwrap();
|
||||||
writer.flush().unwrap();
|
writer.flush().unwrap();
|
||||||
println!("Disconnected!");
|
|
||||||
return ();
|
return ();
|
||||||
}
|
}
|
||||||
line => {
|
line => {
|
||||||
@ -40,19 +42,24 @@ fn write_to_server(stream: TcpStream) {
|
|||||||
writer.flush().unwrap();
|
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 {
|
loop {
|
||||||
match &*get_entry() {
|
let line = &*get_entry();
|
||||||
"" => {
|
line.trim();
|
||||||
;
|
match line {
|
||||||
}
|
"" => {}
|
||||||
"/quit" => {
|
"/quit" => {
|
||||||
println!("Disconnecting...");
|
|
||||||
writeln!(writer, "BYE").unwrap();
|
writeln!(writer, "BYE").unwrap();
|
||||||
writer.flush().unwrap();
|
writer.flush().unwrap();
|
||||||
println!("Disconnected!");
|
|
||||||
return ();
|
return ();
|
||||||
}
|
}
|
||||||
"/clients" => {
|
"/clients" => {
|
||||||
@ -74,17 +81,18 @@ fn exchange_with_server(stream: TcpStream) {
|
|||||||
let stream_cpy = stream.try_clone().unwrap();
|
let stream_cpy = stream.try_clone().unwrap();
|
||||||
let mut reader = BufReader::new(&stream_cpy);
|
let mut reader = BufReader::new(&stream_cpy);
|
||||||
|
|
||||||
println!("Enter `/quit` when you want to leave");
|
|
||||||
|
|
||||||
macro_rules! receive {
|
macro_rules! receive {
|
||||||
() => ({
|
() => ({
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
match reader.read_line(&mut line) {
|
match reader.read_line(&mut line) {
|
||||||
Ok(len) => {
|
Ok(len) => {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
// Reader is at EOF. Could use ErrorKind::UnexpectedEOF, but still unstable.
|
// Reader is at EOF. Could use ErrorKind::UnexpectedEOF,
|
||||||
let ret = std::io::Error::new(std::io::ErrorKind::Other, "test");
|
// but still unstable.
|
||||||
return Err(ret): std::result::Result<&str, std::io::Error>;
|
let ret = std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other, "test");
|
||||||
|
return
|
||||||
|
Err(ret): std::result::Result<&str,std::io::Error>;
|
||||||
}
|
}
|
||||||
line.pop();
|
line.pop();
|
||||||
}
|
}
|
||||||
@ -101,13 +109,50 @@ fn exchange_with_server(stream: TcpStream) {
|
|||||||
match (|| loop {
|
match (|| loop {
|
||||||
let input: String = String::from(receive!());
|
let input: String = String::from(receive!());
|
||||||
let spliced_input: Vec<&str> = input.split(" ").collect();
|
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] {
|
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" => {
|
"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);
|
println!("{}", input);
|
||||||
@ -117,23 +162,22 @@ fn exchange_with_server(stream: TcpStream) {
|
|||||||
})()
|
})()
|
||||||
{
|
{
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("Left?");
|
println!("{}", ">>> Successfully left the room <<<".green());
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(e) => {
|
||||||
println!(">>> Successfully left the room <<<");
|
println!("{}: {}", "Error: Function terminated too early".red(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn client(server_address: String) {
|
pub fn client(server_address: String) {
|
||||||
println!("Tentative de connexion a serveur...");
|
println!("Trying to connect to the server...");
|
||||||
match TcpStream::connect(server_address) {
|
match TcpStream::connect(server_address) {
|
||||||
Ok(stream) => {
|
Ok(stream) => {
|
||||||
println!("Connexion au serveur réussie !");
|
|
||||||
exchange_with_server(stream);
|
exchange_with_server(stream);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("La connection au serveur a échoué : {}", e);
|
println!("{} {}", "Connection to server failed:".red(), e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ use std::collections::HashMap;
|
|||||||
1.5 [ ]
|
1.5 [ ]
|
||||||
1.6 [ ]
|
1.6 [ ]
|
||||||
1.7 [X]
|
1.7 [X]
|
||||||
1.8 [ ]
|
1.8 [X]
|
||||||
1.9 [ ]
|
1.9 [ ]
|
||||||
2.1 [X]
|
2.1 [X]
|
||||||
2.2 [X]
|
2.2 [X]
|
||||||
@ -26,19 +26,28 @@ use std::collections::HashMap;
|
|||||||
4.1.1 [X]
|
4.1.1 [X]
|
||||||
4.1.2 [X]
|
4.1.2 [X]
|
||||||
4.2.1 [X]
|
4.2.1 [X]
|
||||||
4.2.2 [X]
|
4.2.2 [-]
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// code //
|
// TYPES //
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Map for all connected clients containing their name and stream
|
// Map for all connected clients containing their name and stream
|
||||||
type UserMapValue = (String, TcpStream);
|
type UserMapValue = (String, TcpStream);
|
||||||
type UserMap = HashMap<SocketAddr, UserMapValue>;
|
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();
|
let mut name = String::new();
|
||||||
for (client, entry) in (*lock).iter() {
|
for (client, entry) in (*lock).iter() {
|
||||||
if client == not_to {
|
if client == not_to {
|
||||||
@ -47,9 +56,11 @@ fn distribute_message(msg: &str, not_to: &SocketAddr, lock: &mut MutexGuard<User
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (other_client, entry) in (*lock).iter() {
|
for (other_client, entry) in (*lock).iter() {
|
||||||
if other_client != not_to {
|
|
||||||
let other_name = &entry.0;
|
let other_name = &entry.0;
|
||||||
let other_stream = &entry.1;
|
let other_stream = &entry.1;
|
||||||
|
if everyone == false && other_client == not_to {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
match (|| -> Result<()> {
|
match (|| -> Result<()> {
|
||||||
let mut writer = BufWriter::new(other_stream);
|
let mut writer = BufWriter::new(other_stream);
|
||||||
// test if message begins with "MSG " /////////////////////////
|
// test if message begins with "MSG " /////////////////////////
|
||||||
@ -73,21 +84,25 @@ fn distribute_message(msg: &str, not_to: &SocketAddr, lock: &mut MutexGuard<User
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn send_clients_name(to: &SocketAddr, lock: &mut MutexGuard<UserMap>) {
|
fn send_clients_name(to: &SocketAddr, lock: &mut MutexGuard<UserMap>) {
|
||||||
let mut clients = String::new();
|
let mut clients = String::new();
|
||||||
for (client, entry) in (*lock).iter() {
|
for (client, entry) in (*lock).iter() {
|
||||||
if client != to {
|
&entry.0.trim_left();
|
||||||
clients.push_str(&format!("{} ", &entry.0));
|
&entry.0.trim_right();
|
||||||
}
|
clients.push_str(&format!(
|
||||||
|
"{}{} ",
|
||||||
|
if client == to { "(You)" } else { "" },
|
||||||
|
&entry.0
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
clients.trim_left();
|
||||||
println!("{}", clients);
|
println!("{}", clients);
|
||||||
for (client, entry) in (*lock).iter() {
|
for (client, entry) in (*lock).iter() {
|
||||||
if client == to {
|
if client == to {
|
||||||
let stream = &entry.1;
|
let stream = &entry.1;
|
||||||
let mut writer = BufWriter::new(stream);
|
let mut writer = BufWriter::new(stream);
|
||||||
writeln!(writer, "{}", clients).unwrap();
|
writeln!(writer, "LIST CLIENTS {}", clients).unwrap();
|
||||||
writer.flush().unwrap();
|
writer.flush().unwrap();
|
||||||
return;
|
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>) {
|
fn disconnect_user(name: &str, client: &SocketAddr, lock: &mut MutexGuard<UserMap>) {
|
||||||
(*lock).remove(&client);
|
(*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>>) {
|
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:");
|
send!("Please enter your name:");
|
||||||
let name = receive!();
|
let name = receive!();
|
||||||
println!("Client {} identified as {}", client, name);
|
println!("Client {} identified as {}", client, name);
|
||||||
send!("DEBUG: You can now type messages. Leave this chat with the request `BYE`.");
|
|
||||||
Ok(name)
|
Ok(name)
|
||||||
})()
|
})()
|
||||||
{
|
{
|
||||||
@ -159,7 +173,7 @@ fn handle_client(stream: TcpStream, clients: Arc<Mutex<UserMap>>) {
|
|||||||
{
|
{
|
||||||
let mut lock = clients.lock().unwrap();
|
let mut lock = clients.lock().unwrap();
|
||||||
(*lock).insert(client, (name.clone(), stream.try_clone().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();
|
writeln!(writer, "WELCOME").unwrap();
|
||||||
@ -176,16 +190,14 @@ fn handle_client(stream: TcpStream, clients: Arc<Mutex<UserMap>>) {
|
|||||||
send!("PONG");
|
send!("PONG");
|
||||||
}
|
}
|
||||||
"REQ CLIENTS" => {
|
"REQ CLIENTS" => {
|
||||||
{
|
|
||||||
let mut lock = clients.lock().unwrap();
|
let mut lock = clients.lock().unwrap();
|
||||||
send_clients_name(&client, &mut lock);
|
send_clients_name(&client, &mut lock);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
input => {
|
input => {
|
||||||
println!("{} <{}>: {}", client, name, input);
|
println!("{} <{}>: {}", client, name, input);
|
||||||
{
|
{
|
||||||
let mut lock = clients.lock().unwrap();
|
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