adding user update support
This commit is contained in:
parent
5aa4f8caf6
commit
71b77de447
|
|
@ -4,4 +4,4 @@ members = [
|
||||||
'server',
|
'server',
|
||||||
'client',
|
'client',
|
||||||
'serverctl'
|
'serverctl'
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
hard_tabs = true
|
hard_tabs = true
|
||||||
max_width = 90
|
max_width = 100
|
||||||
|
|
@ -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'
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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"),
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue