adding user update support

This commit is contained in:
michael-bailey 2021-04-21 13:14:57 +00:00
parent 5aa4f8caf6
commit 71b77de447
11 changed files with 94 additions and 83 deletions

View File

@ -4,4 +4,4 @@ members = [
'server', 'server',
'client', 'client',
'serverctl' 'serverctl'
] ]

View File

@ -6,7 +6,7 @@ use uuid::Uuid;
#[derive(Deserialize, Serialize, Debug, Clone)] #[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ClientDetails { pub struct ClientDetails {
pub uuid: Uuid, pub uuid: Uuid,
pub username: String, pub username: String,
pub address: String, pub address: String,
} }

View File

@ -25,7 +25,7 @@ pub enum ClientStreamOut {
UserMessage { from: Uuid, content: String }, UserMessage { from: Uuid, content: String },
GlobalMessage { content: String }, GlobalMessage { content: String },
ConnectedClients {clients: Vec<ClientDetails>}, ConnectedClients { clients: Vec<ClientDetails> },
Disconnected, Disconnected,
} }

View File

@ -1,2 +1,2 @@
hard_tabs = true hard_tabs = true
max_width = 90 max_width = 100

View File

@ -13,6 +13,6 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
crossbeam = "0.8.0" crossbeam = "0.8.0"
crossbeam-channel = "0.5.0" crossbeam-channel = "0.5.0"
zeroize = "1.1.0"
[dependencies.foundation] foundation = {path = '../foundation'}
path = '../foundation'

View File

@ -13,10 +13,11 @@ use std::sync::Mutex;
use crossbeam_channel::{unbounded, Receiver, Sender}; use crossbeam_channel::{unbounded, Receiver, Sender};
use serde::Serialize; use serde::Serialize;
use uuid::Uuid; use uuid::Uuid;
use zeroize::Zeroize;
use foundation::ClientDetails;
use foundation::messages::client::{ClientStreamIn, ClientStreamOut}; use foundation::messages::client::{ClientStreamIn, ClientStreamOut};
use foundation::prelude::IMessagable; use foundation::prelude::IMessagable;
use foundation::ClientDetails;
/// # Client /// # Client
/// This struct represents a connected user. /// This struct represents a connected user.
@ -117,7 +118,7 @@ impl IPreemptive for Client {
let _ = std::thread::Builder::new() let _ = std::thread::Builder::new()
.name(format!("client thread recv [{:?}]", &arc.uuid)) .name(format!("client thread recv [{:?}]", &arc.uuid))
.spawn(move || { .spawn(move || {
use ClientMessage::{Disconnect}; use ClientMessage::Disconnect;
let arc = arc1; let arc = arc1;
let mut buffer = String::new(); let mut buffer = String::new();
@ -131,6 +132,7 @@ impl IPreemptive for Client {
} }
let command = serde_json::from_str::<ClientStreamIn>(buffer.as_str()); let command = serde_json::from_str::<ClientStreamIn>(buffer.as_str());
println!("[Client {:?}]: recieved {}", arc.uuid, &buffer);
match command { match command {
Ok(ClientStreamIn::Disconnect) => { Ok(ClientStreamIn::Disconnect) => {
println!("[Client {:?}]: Disconnect recieved", &arc.uuid); println!("[Client {:?}]: Disconnect recieved", &arc.uuid);
@ -138,10 +140,7 @@ impl IPreemptive for Client {
break 'main; break 'main;
} }
Ok(ClientStreamIn::SendMessage { to, content }) => { Ok(ClientStreamIn::SendMessage { to, content }) => {
println!( println!("[Client {:?}]: send message to: {:?}", &arc.uuid, &to);
"[Client {:?}]: send message to: {:?}",
&arc.uuid, &to
);
let lock = arc.server_channel.lock().unwrap(); let lock = arc.server_channel.lock().unwrap();
let sender = lock.as_ref().unwrap(); let sender = lock.as_ref().unwrap();
let _ = sender.send(ServerMessage::ClientSendMessage { let _ = sender.send(ServerMessage::ClientSendMessage {
@ -150,8 +149,14 @@ impl IPreemptive for Client {
content, content,
}); });
} }
Ok(ClientStreamIn::Update) => {
let lock = arc.server_channel.lock().unwrap();
let sender = lock.as_ref().unwrap();
let _ = sender.send(ServerMessage::ClientUpdate { to: arc.uuid });
}
_ => println!("[Client {:?}]: command not found", &arc.uuid), _ => println!("[Client {:?}]: command not found", &arc.uuid),
} }
buffer.zeroize();
} }
println!("[Client {:?}] exited thread 1", &arc.uuid); println!("[Client {:?}] exited thread 1", &arc.uuid);
}); });
@ -175,7 +180,7 @@ impl IPreemptive for Client {
'main: loop { 'main: loop {
for message in arc.output.iter() { for message in arc.output.iter() {
use ClientMessage::{Disconnect,Message, Update}; use ClientMessage::{Disconnect, Message, SendClients};
println!("[Client {:?}]: {:?}", &arc.uuid, message); println!("[Client {:?}]: {:?}", &arc.uuid, message);
match message { match message {
Disconnect => { Disconnect => {
@ -184,35 +189,33 @@ impl IPreemptive for Client {
.unwrap() .unwrap()
.as_mut() .as_mut()
.unwrap() .unwrap()
.send(ServerMessage::ClientDisconnected(arc.uuid)) .send(ServerMessage::ClientDisconnected { id: arc.uuid })
.unwrap(); .unwrap();
break 'main; break 'main;
} }
Message { from, content } => { Message { from, content } => {
let _ = writeln!( let msg = &ClientStreamOut::UserMessage { from, content };
buffer, let _ = writeln!(buffer, "{}", serde_json::to_string(msg).unwrap());
"{}",
serde_json::to_string(
&ClientStreamOut::UserMessage { from, content }
)
.unwrap()
);
let _ = writer.write_all(&buffer); let _ = writer.write_all(&buffer);
let _ = writer.flush(); let _ = writer.flush();
} }
Update {clients} => { SendClients { clients } => {
let client_details_vec: Vec<ClientDetails> = clients.iter().map(|client| &client.details).cloned().collect(); let client_details_vec: Vec<ClientDetails> = clients
let _ = writeln!( .iter()
buffer, .map(|client| &client.details)
"{}", .cloned()
serde_json::to_string( .collect();
&ClientStreamOut::ConnectedClients {clients: client_details_vec}
).unwrap() let msg = &ClientStreamOut::ConnectedClients {
); clients: client_details_vec,
};
let _ = writeln!(buffer, "{}", serde_json::to_string(msg).unwrap());
let _ = writer.write_all(&buffer); let _ = writer.write_all(&buffer);
let _ = writer.flush(); let _ = writer.flush();
} }
} }
buffer.zeroize();
} }
} }
println!("[Client {:?}]: exited thread 2", &arc.uuid); println!("[Client {:?}]: exited thread 2", &arc.uuid);

View File

@ -39,6 +39,13 @@ impl ClientManager {
receiver, receiver,
}) })
} }
fn send_to_client(&self, id: &Uuid, msg: ClientMessage) {
let lock = self.clients.lock().unwrap();
if let Some(client) = lock.get(id) {
client.send_message(msg)
}
}
} }
impl IMessagable<ClientMgrMessage, Sender<ServerMessage>> for ClientManager { impl IMessagable<ClientMgrMessage, Sender<ServerMessage>> for ClientManager {
@ -59,7 +66,7 @@ impl IPreemptive for ClientManager {
if !arc.receiver.is_empty() { if !arc.receiver.is_empty() {
for message in arc.receiver.try_iter() { for message in arc.receiver.try_iter() {
println!("[Client manager]: recieved message: {:?}", message); println!("[Client manager]: recieved message: {:?}", message);
use ClientMgrMessage::{Add, Remove, SendMessage, SendClients}; use ClientMgrMessage::{Add, Remove, SendClients, SendMessage};
match message { match message {
Add(client) => { Add(client) => {
@ -69,35 +76,27 @@ impl IPreemptive for ClientManager {
if lock.insert(client.uuid, client).is_none() { if lock.insert(client.uuid, client).is_none() {
println!("value is new"); println!("value is new");
} }
}, }
Remove(uuid) => { Remove(uuid) => {
println!("[Client Manager]: removing client: {:?}", &uuid); println!("[Client Manager]: removing client: {:?}", &uuid);
if let Some(client) = if let Some(client) = arc.clients.lock().unwrap().remove(&uuid) {
arc.clients.lock().unwrap().remove(&uuid)
{
client.send_message(ClientMessage::Disconnect); client.send_message(ClientMessage::Disconnect);
} }
}, }
SendMessage { to, from, content } => { SendMessage { to, from, content } => {
arc.send_to_client(&to, ClientMessage::Message { from, content })
}
SendClients { to } => {
let lock = arc.clients.lock().unwrap(); let lock = arc.clients.lock().unwrap();
if let Some(client) = lock.get(&to) { if let Some(client) = lock.get(&to) {
client.send_message(ClientMessage::Message { let clients_vec: Vec<Arc<Client>> =
from, lock.values().cloned().collect();
content,
})
}
},
SendClients {to} => {
let lock = arc.clients.lock().unwrap();
if let Some(client) = lock.get(&to) {
let clients_vec: Vec<Arc<Client>> = lock.values().cloned().collect();
client.send_message(ClientMessage::Update { client.send_message(ClientMessage::SendClients {
clients: clients_vec, clients: clients_vec,
}) })
} }
}, }
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
_ => println!("[Client manager]: not implemented"), _ => println!("[Client manager]: not implemented"),

View File

@ -11,17 +11,20 @@ use server::Server;
fn main() { fn main() {
let _args = App::new("--rust chat server--") let _args = App::new("--rust chat server--")
.version("0.1.5") .version("0.1.5")
.author("Mitchel Hardie <mitch161>, Michael Bailey <michael-bailey>") .author("Mitchel Hardie <mitch161>, Michael Bailey <michael-bailey>")
.about("this is a chat server developed in rust, depending on the version one of two implementations will be used") .about(
.arg( "this is a chat server developed in rust, depending on the version one of two implementations will be used",
Arg::with_name("config") )
.short("p") .arg(
.long("port") Arg::with_name("config")
.value_name("PORT") .short("p")
.help("sets the port the server runs on.") .long("port")
.takes_value(true)) .value_name("PORT")
.get_matches(); .help("sets the port the server runs on.")
.takes_value(true),
)
.get_matches();
let server = Server::new(); let server = Server::new();

View File

@ -7,7 +7,7 @@ use crate::client::Client;
pub enum ClientMessage { pub enum ClientMessage {
Message { from: Uuid, content: String }, Message { from: Uuid, content: String },
Update {clients: Vec<Arc<Client>>}, SendClients { clients: Vec<Arc<Client>> },
Disconnect, Disconnect,
} }
@ -16,7 +16,9 @@ pub enum ClientMessage {
pub enum ClientMgrMessage { pub enum ClientMgrMessage {
Remove(Uuid), Remove(Uuid),
Add(Arc<Client>), Add(Arc<Client>),
SendClients {to: Uuid}, SendClients {
to: Uuid,
},
SendMessage { SendMessage {
from: Uuid, from: Uuid,
to: Uuid, to: Uuid,
@ -26,12 +28,18 @@ pub enum ClientMgrMessage {
#[derive(Debug)] #[derive(Debug)]
pub enum ServerMessage { pub enum ServerMessage {
ClientConnected(Arc<Client>), ClientConnected {
client: Arc<Client>,
},
ClientSendMessage { ClientSendMessage {
from: Uuid, from: Uuid,
to: Uuid, to: Uuid,
content: String, content: String,
}, },
ClientDisconnected(Uuid), ClientDisconnected {
ClientUpdate(Uuid), id: Uuid,
},
ClientUpdate {
to: Uuid,
},
} }

View File

@ -19,10 +19,7 @@ pub struct NetworkManager {
} }
impl NetworkManager { impl NetworkManager {
pub fn new( pub fn new(port: String, server_channel: Sender<ServerMessage>) -> Arc<NetworkManager> {
port: String,
server_channel: Sender<ServerMessage>,
) -> Arc<NetworkManager> {
let mut address = "0.0.0.0:".to_string(); let mut address = "0.0.0.0:".to_string();
address.push_str(&port); address.push_str(&port);
@ -63,8 +60,7 @@ impl IPreemptive for NetworkManager {
let _ = writeln!( let _ = writeln!(
out_buffer, out_buffer,
"{}", "{}",
serde_json::to_string(&NetworkSockOut::Request) serde_json::to_string(&NetworkSockOut::Request).unwrap()
.unwrap()
); );
let _ = writer.write_all(&out_buffer); let _ = writer.write_all(&out_buffer);
@ -112,9 +108,9 @@ impl IPreemptive for NetworkManager {
server_channel.clone(), server_channel.clone(),
); );
server_channel server_channel
.send(ServerMessage::ClientConnected( .send(ServerMessage::ClientConnected {
new_client, client: new_client,
)) })
.unwrap_or_default(); .unwrap_or_default();
} }
} }

View File

@ -48,17 +48,19 @@ impl ICooperative for Server {
for message in self.receiver.try_iter() { for message in self.receiver.try_iter() {
println!("[server]: received message {:?}", &message); println!("[server]: received message {:?}", &message);
match message { match message {
ServerMessage::ClientConnected(client) => { ServerMessage::ClientConnected { client } => {
self.client_manager.send_message(Add(client)) self.client_manager.send_message(Add(client))
} }
ServerMessage::ClientDisconnected(uuid) => { ServerMessage::ClientDisconnected { id } => {
println!("disconnecting client {:?}", uuid); println!("disconnecting client {:?}", id);
self.client_manager.send_message(Remove(uuid)); self.client_manager.send_message(Remove(id));
} }
ServerMessage::ClientSendMessage { from, to, content } => self ServerMessage::ClientSendMessage { from, to, content } => self
.client_manager .client_manager
.send_message(SendMessage { from, to, content }), .send_message(SendMessage { from, to, content }),
ServerMessage::ClientUpdate (_uuid) => println!("not implemented"), ServerMessage::ClientUpdate { to } => self
.client_manager
.send_message(ClientMgrMessage::SendClients { to }),
} }
} }
} }