Moving files around and implementing more of the client manager.

This commit is contained in:
michael-bailey 2021-02-07 18:16:08 +00:00
parent f13ee42063
commit f06f4e3ca2
28 changed files with 1336 additions and 1351 deletions

View File

@ -8,6 +8,7 @@ edition = "2018"
[dependencies]
regex = "1"
uuid = "0.8"
crossbeam = "0.7"
crossbeam-channel = "0.4"
crossbeam-utils = "0.7"
@ -19,11 +20,8 @@ zeroize = "1.1.0"
crossterm = "0.17.7"
clap = "3.0.0-beta.1"
log = "0.4"
cursive = { version = "0.15.0", default-features = false, features = ["crossterm-backend"]}
openssl = { version = "0.10", features = ["vendored"] }
rustls = "0.18.1"
webpki = "0.21.3"
webpki-roots = "0.20.0"
serde = { version = "1.0", features = ["derive"] }
url = "2.2.0"
[profile.dev]

12
src/app/Traits.rs Normal file
View File

@ -0,0 +1,12 @@
use url::Url
pub trait TBundle {
fn main() -> Result<Self>;
fn initWithURL(url: Url) -> Result<Self>;
fn initWithPath(path: String) -> Result<Self>;
fn urlForResource(name: String, extention: String, subDirectory: Option<Strign>) -> Result<[u8]>;
}

11
src/app/bundle.rs Normal file
View File

@ -0,0 +1,11 @@
/**
* Bundle: inspired from NSBundle on macOS
*/
struct Bundle {
location:
}
impl Bundle {
}

2
src/app/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod bundle;
pub mod Traits

View File

@ -1,75 +0,0 @@
use std::{io::{Read, Write}, io, net::TcpStream};
use std::time::Duration;
use zeroize::Zeroize;
use crate::{
commands::Commands,
server::client::client_profile::Client,
};
#[allow(dead_code)]
pub struct ClientApi {
socket: TcpStream,
addr: String,
pub on_client_add_handle: fn(Client) -> (),
pub on_client_remove_handle: fn(String) -> (),
}
impl ClientApi {
#[allow(dead_code)]
pub fn new(addr: &str) -> Result<Self, io::Error> {
let socket = TcpStream::connect(addr)?;
let on_add = |_client: Client| {println!("Client_api: Client added {:?}", _client)};
let on_remove = |_uuid: String| {println!("Client_api: Client removed {}", _uuid)};
let a = Self {
socket,
addr: addr.to_string(),
on_client_add_handle: on_add,
on_client_remove_handle: on_remove,
};
Ok(a)
}
#[allow(dead_code)]
pub fn set_on_client_add(&mut self, func: fn(Client) -> ()) {
self.on_client_add_handle = func;
}
#[allow(dead_code)]
pub fn set_on_client_removed(&mut self, func: fn(String) -> ()) {
self.on_client_remove_handle = func;
}
#[allow(dead_code)]
pub fn get_info(host: &str) -> Result<Commands, io::Error> {
let mut buffer: [u8; 1024] = [0; 1024];
let addr = host.parse().unwrap();
let mut stream = TcpStream::connect_timeout(&addr, Duration::from_millis(1000))?;
let _ = stream.read(&mut buffer)?;
println!("data recieved: {:?}", &buffer[0..20]);
match Commands::from(&mut buffer) {
Commands::Request(None) => {
println!("zeroing");
buffer.zeroize();
println!("writing");
let sending_command = Commands::Info(None).to_string();
println!("sending string: {:?} as_bytes: {:?}", &sending_command, &sending_command.as_bytes());
stream.write_all(sending_command.as_bytes())?;
stream.flush()?;
println!("reading");
let bytes = stream.read(&mut buffer)?;
println!("new buffer size: {:?} contents: {:?}", bytes, &buffer[0..20]);
println!("commanding");
Ok(Commands::from(String::from(String::from_utf8_lossy(&buffer))))
},
_ => {
Err(io::Error::new(io::ErrorKind::InvalidData, "the data was not expected"))
}
}
}
}

View File

@ -1,106 +0,0 @@
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use crossbeam::{Receiver, Sender, unbounded};
enum Message {
NewJob(Job),
Terminate,
}
#[derive(Debug)]
pub struct ThreadPool{
workers: Vec<Worker>,
sender: Sender<Message>,
}
type Job = Box<dyn FnOnce() + Send + 'static>;
#[allow(dead_code)]
impl ThreadPool{
/// Create a new ThreadPool.
///
/// The size is the number of threads in the pool.
///
/// # Panics
///
/// The `new` function will panic if the size is zero.
pub fn new(size: usize) -> ThreadPool {
assert!(size > 0);
let (sender, receiver) = unbounded();
let receiver = Arc::new(Mutex::new(receiver));
let mut workers = Vec::with_capacity(size);
for id in 0..size {
// create some threads and store them in the vector
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
ThreadPool {
workers,
sender,
}
}
pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
let job = Box::new(f);
self.sender.send(Message::NewJob(job)).unwrap();
}
}
#[derive(Debug)]
struct Worker {
id: usize,
thread: Option<thread::JoinHandle<()>>,
}
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<Receiver<Message>>>) -> Worker {
let thread = thread::spawn(move || {
loop{
let message = receiver.lock().unwrap().recv().unwrap();
match message {
Message::NewJob(job) => {
println!("Worker {} got a job; executing.", id);
job();
},
Message::Terminate => {
println!("Worker {} was told to terminate.", id);
break;
},
}
}
});
Worker {
id,
thread: Some(thread),
}
}
}
impl Drop for ThreadPool {
fn drop(&mut self) {
println!("Sending terminate message to all workers.");
for _ in &mut self.workers {
self.sender.send(Message::Terminate).unwrap();
}
println!("Shutting down all workers.");
for worker in &mut self.workers {
println!("Shutting down worker {}", worker.id);
if let Some(thread) = worker.thread.take() {
thread.join().unwrap();
}
}
}
}

108
src/lib/mod.rs Normal file
View File

@ -0,0 +1,108 @@
// pub mod commands;
pub mod prelude;
pub mod server;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use crossbeam::{unbounded, Receiver, Sender};
enum Message {
NewJob(Job),
Terminate,
}
#[derive(Debug)]
pub struct ThreadPool {
workers: Vec<Worker>,
sender: Sender<Message>,
}
type Job = Box<dyn FnOnce() + Send + 'static>;
#[allow(dead_code)]
impl ThreadPool {
/// Create a new ThreadPool.
///
/// The size is the number of threads in the pool.
///
/// # Panics
///
/// The `new` function will panic if the size is zero.
pub fn new(size: usize) -> ThreadPool {
assert!(size > 0);
let (sender, receiver) = unbounded();
let receiver = Arc::new(Mutex::new(receiver));
let mut workers = Vec::with_capacity(size);
for id in 0..size {
// create some threads and store them in the vector
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
ThreadPool { workers, sender }
}
pub fn execute<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
let job = Box::new(f);
self.sender.send(Message::NewJob(job)).unwrap();
}
}
#[derive(Debug)]
struct Worker {
id: usize,
thread: Option<thread::JoinHandle<()>>,
}
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<Receiver<Message>>>) -> Worker {
let thread = thread::spawn(move || loop {
let message = receiver.lock().unwrap().recv().unwrap();
match message {
Message::NewJob(job) => {
println!("Worker {} got a job; executing.", id);
job();
}
Message::Terminate => {
println!("Worker {} was told to terminate.", id);
break;
}
}
});
Worker {
id,
thread: Some(thread),
}
}
}
impl Drop for ThreadPool {
fn drop(&mut self) {
println!("Sending terminate message to all workers.");
for _ in &mut self.workers {
self.sender.send(Message::Terminate).unwrap();
}
println!("Shutting down all workers.");
for worker in &mut self.workers {
println!("Shutting down worker {}", worker.id);
if let Some(thread) = worker.thread.take() {
thread.join().unwrap();
}
}
}
}

0
src/lib/prelude.rs Normal file
View File

View File

@ -6,7 +6,6 @@ use std::{
io::prelude::*,
net::{Shutdown, TcpStream},
sync::Arc,
//collections::HashMap,
sync::Mutex,
time::{Duration, Instant},
};

View File

@ -5,8 +5,6 @@ use std::{
io::Error,
io::prelude::*,
net::{Shutdown, TcpStream},
sync::Arc,
//collections::HashMap,
sync::Mutex,
time::{Duration, Instant},
};
@ -26,15 +24,18 @@ use crate::{
#[derive(Debug)]
pub struct Client {
parent: Option<&ClientManager>
uuid: String,
username: String,
address: String,
last_heartbeat: Instant,
last_heartbeat: Option<Instant>,
stream: Arc<Mutex<TcpStream>>,
stream: Option<Mutex<TcpStream>>,
pub sender: Sender<Commands>,
sender: Sender<Commands>,
receiver: Receiver<Commands>,
server_sender: Sender<ServerMessages>,
@ -48,7 +49,7 @@ impl Client {
stream.set_read_timeout(Some(Duration::from_secs(1))).unwrap();
Client {
stream: Arc::new(Mutex::new(stream)),
stream: Some(Mutex::new(stream)),
uuid: uuid.to_string(),
username: username.to_string(),
address: address.to_string(),
@ -58,7 +59,7 @@ impl Client {
server_sender,
last_heartbeat: Instant::now(),
last_heartbeat: Some(Instant::now()),
}
}
@ -215,3 +216,8 @@ impl Drop for Client {
let _ = self.stream.lock().unwrap().shutdown(Shutdown::Both);
}
}
#[cfg(test)]
mod test {
}

View File

@ -0,0 +1,30 @@
// pub mod client_profile;
// pub mod client_v3;
pub mod traits;
use serde::{Serialize, Deserialize};
use std::net::TcpStream;
use std::sync::Weak;
use uuid::Uuid;
use super::traits::TClientManager;
use super::ClientManager;
pub enum ClientMessage {
a,
b,
}
#[derive(Serialize, Deserialize)]
pub struct Client {
uuid: String,
username: String,
address: String,
#[serde(skip)]
stream: Option<TcpStream>,
#[serde(skip)]
owner: Option<Weak<ClientManager>>
}

View File

@ -0,0 +1,13 @@
use uuid::Uuid;
pub trait TClient<TClientMessage> {
fn new(uuid: Uuid, name: String, addr: String);
fn send(&self, bytes: Vec<u8>) -> Result<(), &str>;
fn recv(&self) -> Option<Vec<u8>>;
fn sendMsg(&self, msg: TClientMessage) -> Result<(), &str>;
fn recvMsg(&self) -> Option<TClientMessage>;
fn tick(&self);
}

View File

@ -0,0 +1,52 @@
mod traits;
pub mod client;
use std::sync::Weak;
use std::sync::Arc;
use crossbeam_channel::{Sender, Receiver};
use uuid::Uuid;
use self::client::Client;
use self::client::ClientMessage;
// use client::client_v3::Client;
use self::traits::TClientManager;
enum ClientManagerMessages {
}
pub struct ClientManager {
clients: Vec<Arc<Client>>,
weak_self: Option<Weak<Self>>,
sender: Sender<ClientManagerMessages>,
receiver: Receiver<ClientManagerMessages>,
}
impl TClientManager<Client, ClientMessage> for ClientManager {
fn addClient(&self, Client: std::sync::Arc<Client>) { todo!() }
fn removeClient(&self, uuid: Uuid) { todo!() }
fn messageClient(&self, id: Uuid, msg: ClientMessage) { todo!() }
fn tick(&self) { todo!() }
}
#[cfg(test)]
mod test {
#[test]
fn test_add_client() { todo!() }
#[test]
fn test_remove_client() { todo!() }
#[test]
fn test_remove_all_clients() { todo!() }
}

View File

@ -0,0 +1,12 @@
use std::sync::Arc;
use uuid::Uuid;
use super::client::traits;
pub trait TClientManager<TClient,TClientMessage> {
fn addClient(&self, client: Arc<TClient>);
fn removeClient(&self, id: Uuid);
fn messageClient(&self, id: Uuid, msg: TClientMessage);
fn tick(&self, );
}

9
src/lib/server/config.rs Normal file
View File

@ -0,0 +1,9 @@
pub struct ServerConfig {
pub name: String,
pub address: String,
pub owner: String,
pub host: String,
pub port: u16,
}

5
src/lib/server/mod.rs Normal file
View File

@ -0,0 +1,5 @@
pub mod client_management;
pub mod server;
pub mod server_v3;
pub struct Server {}

633
src/lib/server/server.rs Normal file
View File

@ -0,0 +1,633 @@
// extern crate regex;
// extern crate rayon;
// use super::client_management::client::client_profile::Client;
// use crate::commands::Commands;
// use std::{
// sync::{Arc, Mutex},
// net::{TcpStream, TcpListener},
// collections::HashMap,
// io::prelude::*,
// time::Duration,
// io::Error,
// thread,
// io
// };
// use log::info;
// use crossbeam_channel::{Sender, Receiver, unbounded};
// #[deprecated(
// since = "0.1",
// note = "Please use server v3"
// )]
// #[derive(Debug)]
// pub enum ServerMessages {
// RequestUpdate(Arc<Mutex<TcpStream>>),
// RequestInfo(String, Arc<Mutex<TcpStream>>),
// Disconnect(String),
// Shutdown,
// }
// // MARK: - server struct
// #[deprecated(
// since = "0.1",
// note = "Please use server v3"
// )]
// pub struct Server {
// name: String,
// host: String,
// port: String,
// author: Option<String>,
// //connected_clients: Arc<Mutex<HashMap<String, Client>>>,
// sender: Sender<ServerMessages>,
// receiver: Receiver<ServerMessages>,
// pub running: bool,
// client_list_changed_handle: Box<dyn Fn(&Server)>,
// }
// // MARK: - server implemetation
// #[deprecated(
// since = "0.1",
// note = "Please use server v3"
// )]
// impl Server {
// pub fn new(name: &str, host: &str, port: &str) -> Self {
// let (sender, receiver) = unbounded();
// Self {
// name: name.to_string(),
// host: host.to_string(),
// port: port.to_string()
// author: author.to_string(),
// //connected_clients: Arc::new(Mutex::new(HashMap::new())),
// sender,
// receiver,
// running: false,
// client_list_changed_handle: Box::new(|_s| println!("help"))
// }
// }
// #[allow(dead_code)]
// pub fn get_name(&self) -> String {
// self.name.to_string()
// }
// pub fn set_host() {
// }
// pub fn set_port() {
// }
// #[allow(dead_code)]
// pub fn get_author(&self) -> String {
// self.author.to_string()
// }
// pub fn set_client_update_handle(function: Box<dyn Fn(&Server)>) {
// }
// pub fn start(&mut self) -> Result<(), io::Error> {
// println!("server: starting server...");
// self.running = true;
// // MARK: - creating clones of the server property references
// let name = self.name.clone();
// #[allow(dead_code)]
// let address = self.address.clone();
// let author = self.author.clone();
// let connected_clients = self.connected_clients.clone();
// let sender = self.sender.clone();
// let receiver = self.receiver.clone();
// // set up listener and buffer
// let mut buffer = [0; 1024];
// let listener = TcpListener::bind(self.get_address())?;
// listener.set_nonblocking(true)?;
// println!("server: spawning threads");
// let _ = thread::Builder::new().name("Server Thread".to_string()).spawn(move || {
// 'outer: loop {
// std::thread::sleep(Duration::from_millis(100));
// // get messages from the servers channel.
// println!("server: getting messages");
// for i in receiver.try_iter() {
// match i {
// ServerMessages::Shutdown => {
// // TODO: implement disconnecting all clients and shutting down the server.
// println!("server: shutting down...");
// break 'outer;
// },
// ServerMessages::RequestUpdate(stream_arc) => {
// for (_k, v) in connected_clients.lock().unwrap().iter() {
// let mut stream = stream_arc.lock().unwrap();
// let _ = Server::transmit_data(&mut stream, v.to_string().as_str());
// if Server::read_data(&mut stream, &mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) {
// println!("Success Confirmed");
// } else {
// println!("no success read");
// let error = Commands::Error(None);
// let _ = Server::transmit_data(&mut stream, error.to_string().as_str());
// }
// }
// },
// ServerMessages::RequestInfo(uuid, stream_arc) => {
// let mut stream = stream_arc.lock().unwrap();
// if let Some(client) = connected_clients.lock().unwrap().get(&uuid) {
// let params: HashMap<String, String> = [(String::from("uuid"), client.get_uuid()), (String::from("name"), client.get_username()), (String::from("host"), client.get_address())].iter().cloned().collect();
// let command = Commands::Success(Some(params));
// let _ = Server::transmit_data(&mut stream, command.to_string().as_str());
// } else {
// let command = Commands::Success(None);
// let _ = Server::transmit_data(&mut stream, command.to_string().as_str());
// }
// },
// ServerMessages::Disconnect(uuid) => {
// let mut clients = connected_clients.lock().unwrap();
// clients.remove(&uuid.to_string());
// let params: HashMap<String, String> = [(String::from("uuid"), uuid)].iter().cloned().collect();
// let command = Commands::ClientRemove(Some(params));
// let _ = connected_clients.lock().unwrap().iter().map(move |(_k, v)| {v.get_sender().send(command.clone())});
// },
// }
// }
// println!("server: checking for new connections");
// if let Ok((mut stream, _addr)) = listener.accept() {
// stream.set_read_timeout(Some(Duration::from_millis(1000))).unwrap();
// let _ = stream.set_nonblocking(false);
// let request = Commands::Request(None);
// let _ = Server::transmit_data(&mut stream, &request.to_string().as_str());
// match Server::read_data(&mut stream, &mut buffer) {
// Ok(command) => {
// println!("Server: new connection sent - {:?}", command);
// match command {
// Commands::Connect(Some(data)) => {
// let uuid = data.get("uuid").unwrap();
// let username = data.get("name").unwrap();
// let address = data.get("host").unwrap();
// println!("{}", format!("Server: new Client connection: _addr = {}", address ));
// let client = Client::new(stream, sender.clone(), &uuid, &username, &address);
// connected_clients.lock().unwrap().insert(uuid.to_string(), client);
// let params: HashMap<String, String> = [(String::from("name"), username.clone()), (String::from("host"), address.clone()), (String::from("uuid"), uuid.clone())].iter().cloned().collect();
// let new_client = Commands::Client(Some(params));
// let _ = connected_clients.lock().unwrap().iter().map(|(_k, v)| v.sender.send(new_client.clone()));
// },
// // TODO: - correct connection reset error when getting info.
// Commands::Info(None) => {
// println!("Server: info requested");
// let params: HashMap<String, String> = [(String::from("name"), name.to_string().clone()), (String::from("owner"), author.to_string().clone())].iter().cloned().collect();
// let command = Commands::Info(Some(params));
// let _ = Server::transmit_data(&mut stream, command.to_string().as_str());
// },
// _ => {
// println!("Server: Invalid command sent");
// let _ = Server::transmit_data(&mut stream, Commands::Error(None).to_string().as_str());
// },
// }
// },
// Err(_) => println!("ERROR: stream closed"),
// }
// }
// // TODO: end -
// // handle each client for messages
// println!("server: handing control to clients");
// for (_k, client) in connected_clients.lock().unwrap().iter_mut() {
// client.handle_connection();
// }
// }
// info!("server: stopped");
// });
// info!("server: started");
// Ok(())
// }
// pub fn stop(&mut self) {
// info!("server: sending stop message");
// let _ = self.sender.send(ServerMessages::Shutdown);
// self.running = false;
// }
// fn transmit_data(stream: &mut TcpStream, data: &str) -> Result<(), Error>{
// println!("Transmitting...");
// println!("data: {}", data);
// /*
// * This will throw an error and crash any thread, including the main thread, if
// * the connection is lost before transmitting. Maybe change to handle any exceptions
// * that may occur.
// */
// let _ = stream.write(data.to_string().as_bytes())?;
// stream.flush()?;
// Ok(())
// }
// fn read_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result<Commands, Error> {
// let _ = stream.read(buffer)?;
// let command = Commands::from(buffer);
// Ok(command)
// }
// }
// impl ToString for Server {
// fn to_string(&self) -> std::string::String { todo!() }
// }
// impl Drop for Server {
// fn drop(&mut self) {
// println!("server dropped");
// let _ = self.sender.send(ServerMessages::Shutdown);
// }
// }
// /* The new version of the server no long works with these unit
// * tests.
// * They will be fixed soon!
// * TODO: fix unit tests
// */
// /*#[cfg(test)]
// #[deprecated(
// since = "0.1",
// note = "Please use server v3"
// )]
// mod tests{
// use super::*;
// use std::{thread, time};
// use std::sync::Once;
// use std::time::Duration;
// lazy_static!{
// static ref SERVER_NAME: &'static str = "test";
// static ref SERVER_ADDRESS: &'static str = "0.0.0.0:6000";
// static ref SERVER_AUTHOR: &'static str = "test";
// static ref SERVER: Server<'static> = Server::new(&SERVER_NAME, &SERVER_ADDRESS, &SERVER_AUTHOR);
// }
// static START: Once = Once::new();
// /*
// * These tests must be executed individually to ensure that no errors
// * occur, this is due to the fact that the server is created everytime.
// * Setup a system for the server to close after every test.
// */
// fn setup_server(){
// unsafe{
// START.call_once(|| {
// thread::spawn(|| {
// SERVER.start();
// });
// });
// let millis = time::Duration::from_millis(1000);
// thread::sleep(millis);
// }
// }
// fn establish_client_connection(uuid: &str) -> TcpStream {
// let mut buffer = [0; 1024];
// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap();
// let mut command = read_data(&stream, &mut buffer);
// assert_eq!(command, Commands::Request(None));
// let msg: String = format!("!connect: uuid:{uuid} name:\"{name}\" host:\"{host}\"", uuid=uuid, name="alice", host="127.0.0.1");
// transmit_data(&stream, msg.as_str());
// command = read_data(&stream, &mut buffer);
// assert_eq!(command, Commands::Success(None));
// stream
// }
// fn transmit_data(mut stream: &TcpStream, data: &str){
// stream.write(data.to_string().as_bytes()).unwrap();
// stream.flush().unwrap();
// }
// fn read_data(mut stream: &TcpStream, buffer: &mut [u8; 1024]) -> Commands {
// match stream.read(buffer) {
// Ok(_) => Commands::from(buffer),
// Err(_) => Commands::Error(None),
// }
// }
// fn force_disconnect(mut stream: &TcpStream){
// let msg = "!disconnect:";
// transmit_data(&stream, msg);
// }
// #[test]
// fn test_server_connect(){
// let mut buffer = [0; 1024];
// setup_server();
// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap();
// stream.read(&mut buffer).unwrap();
// let mut command = Commands::from(&mut buffer);
// assert_eq!(command, Commands::Request(None));
// let msg = b"!connect: uuid:123456-1234-1234-123456 name:\"alice\" host:\"127.0.0.1\"";
// stream.write(msg).unwrap();
// stream.read(&mut buffer).unwrap();
// command = Commands::from(&mut buffer);
// assert_eq!(command, Commands::Success(None));
// let msg = b"!disconnect:";
// stream.write(msg).unwrap();
// let dur = time::Duration::from_millis(500);
// thread::sleep(dur);
// }
// #[test]
// fn test_server_info(){
// let mut buffer = [0; 1024];
// setup_server();
// let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap();
// let command = read_data(&stream, &mut buffer);
// assert_eq!(command, Commands::Request(None));
// let msg = "!info:";
// transmit_data(&stream, msg);
// let command = read_data(&stream, &mut buffer);
// let params: HashMap<String, String> = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect();
// assert_eq!(command, Commands::Success(Some(params)));
// }
// #[test]
// fn test_client_info(){
// let mut buffer = [0; 1024];
// setup_server();
// let mut stream = establish_client_connection("1234-5542-2124-155");
// let msg = "!info:";
// transmit_data(&stream, msg);
// let command = read_data(&stream, &mut buffer);
// let params: HashMap<String, String> = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect();
// assert_eq!(command, Commands::Success(Some(params)));
// let msg = "!disconnect:";
// transmit_data(&stream, msg);
// let dur = time::Duration::from_millis(500);
// thread::sleep(dur);
// }
// #[test]
// fn test_clientUpdate_solo(){
// let mut buffer = [0; 1024];
// setup_server();
// let mut stream = establish_client_connection("1222-555-6-7");
// let msg = "!clientUpdate:";
// transmit_data(&stream, msg);
// let command = read_data(&stream, &mut buffer);
// assert_eq!(command, Commands::Success(None));
// let msg = "!disconnect:";
// transmit_data(&stream, msg);
// let dur = time::Duration::from_millis(500);
// thread::sleep(dur);
// }
// #[test]
// fn test_clientUpdate_multi(){
// let mut buffer = [0; 1024];
// setup_server();
// let mut stream_one = establish_client_connection("0001-776-6-5");
// let mut stream_two = establish_client_connection("0010-776-6-5");
// let mut stream_three = establish_client_connection("0011-776-6-5");
// let mut stream_four = establish_client_connection("0100-776-6-5");
// let client_uuids: [String; 3] = [String::from("0010-776-6-5"), String::from("0011-776-6-5"), String::from("0100-776-6-5")];
// let mut user_1 = true;
// let mut user_2 = true;
// let mut user_3 = true;
// for uuid in client_uuids.iter() {
// let command = read_data(&stream_one, &mut buffer);
// if *uuid == String::from("0010-776-6-5") && user_1 {
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command, Commands::Client(Some(params)));
// user_1 = false;
// } else if *uuid == String::from("0011-776-6-5") && user_2 {
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command, Commands::Client(Some(params)));
// user_2 = false;
// } else if *uuid == String::from("0100-776-6-5") && user_3 {
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command, Commands::Client(Some(params)));
// user_3 = false;
// } else {
// assert!(false);
// }
// let msg = "!success:";
// transmit_data(&stream_one, msg);
// }
// stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap();
// let mut unsuccessful = true;
// while unsuccessful {
// let msg = "!clientUpdate:";
// transmit_data(&stream_one, msg);
// let command = read_data(&stream_one, &mut buffer);
// match command.clone() {
// Commands::Error(None) => println!("resending..."),
// _ => {
// assert_eq!(command, Commands::Success(None));
// unsuccessful = false;
// },
// }
// }
// stream_one.set_read_timeout(None).unwrap();
// for x in 0..3 {
// let command = read_data(&stream_one, &mut buffer);
// let command_clone = command.clone();
// match command{
// Commands::Client(Some(params)) => {
// let uuid = params.get("uuid").unwrap();
// if *uuid == String::from("0010-776-6-5") {
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command_clone, Commands::Client(Some(params)));
// } else if *uuid == String::from("0011-776-6-5") {
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command_clone, Commands::Client(Some(params)));
// } else if *uuid == String::from("0100-776-6-5") {
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command_clone, Commands::Client(Some(params)));
// } else {
// assert!(false);
// }
// },
// _ => assert!(false),
// }
// let msg = "!success:";
// transmit_data(&stream_one, msg);
// }
// let dur = time::Duration::from_millis(500);
// thread::sleep(dur);
// let msg = "!disconnect:";
// transmit_data(&stream_one, msg);
// transmit_data(&stream_two, msg);
// transmit_data(&stream_three, msg);
// transmit_data(&stream_four, msg);
// let dur = time::Duration::from_millis(500);
// thread::sleep(dur);
// }
// #[test]
// fn test_clientInfo(){
// let mut buffer = [0; 1024];
// setup_server();
// let mut stream_one = establish_client_connection("0001-776-6-5");
// let mut stream_two = establish_client_connection("\"0010-776-6-5\"");
// let command = read_data(&stream_one, &mut buffer);
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command, Commands::Client(Some(params)));
// let msg = "!success:";
// transmit_data(&stream_one, msg);
// stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap();
// let mut unsuccessful = true;
// while unsuccessful {
// let msg = "!clientInfo: uuid:\"0010-776-6-5\"";
// transmit_data(&stream_one, msg);
// let command = read_data(&stream_one, &mut buffer);
// match command.clone() {
// Commands::Error(None) => println!("resending..."),
// _ => {
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command, Commands::Success(Some(params)));
// unsuccessful = false;
// },
// }
// }
// stream_one.set_read_timeout(None).unwrap();
// let msg = "!disconnect:";
// transmit_data(&stream_one, msg);
// transmit_data(&stream_two, msg);
// let dur = time::Duration::from_millis(500);
// thread::sleep(dur);
// }
// #[test]
// fn test_client_disconnect(){
// let mut buffer = [0; 1024];
// setup_server();
// let mut stream_one = establish_client_connection("0001-776-6-5");
// let mut stream_two = establish_client_connection("0010-776-6-5");
// let command = read_data(&stream_one, &mut buffer);
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
// assert_eq!(command, Commands::Client(Some(params)));
// let msg = "!success:";
// transmit_data(&stream_one, msg);
// let msg = "!disconnect:";
// transmit_data(&stream_two, msg);
// let command = read_data(&stream_one, &mut buffer);
// let params: HashMap<String, String> = [(String::from("uuid"), String::from("0010-776-6-5"))].iter().cloned().collect();
// assert_eq!(command, Commands::Client(Some(params)));
// let msg = "!success:";
// transmit_data(&stream_one, msg);
// stream_one.set_read_timeout(Some(Duration::from_millis(2000))).unwrap();
// match stream_one.peek(&mut buffer) {
// Ok(_) => assert!(false),
// Err(_) => assert!(true),
// }
// stream_one.set_read_timeout(None).unwrap();
// let msg = "!disconnect:";
// transmit_data(&stream_one, msg);
// let dur = time::Duration::from_millis(500);
// thread::sleep(dur);
// }
// }*/

372
src/lib/server/server_v3.rs Normal file
View File

@ -0,0 +1,372 @@
// use std::time::Duration;
// use std::{
// collections::HashMap,
// io,
// io::{Read, Write},
// net::{TcpListener, TcpStream},
// sync::{Arc, Mutex},
// };
// use crossbeam_channel::{unbounded, Receiver, SendError, Sender};
// use log::info;
// use crate::commands::Commands;
// use super::client_management;
// #[derive(Debug)]
// pub enum ServerMessages {
// RequestUpdate(Arc<Mutex<TcpStream>>),
// RequestInfo(String, Arc<Mutex<TcpStream>>),
// Disconnect(String),
// Shutdown,
// }
// pub enum ServerEvent {
// Stopped,
// Started,
// addedClient(Arc<Mutex<Client>>),
// }
// #[allow(dead_code)]
// #[derive(Eq, PartialEq, Debug)]
// pub enum ServerState {
// Starting,
// Started,
// Stopping,
// Stopped,
// }
// // MARK: - server struct
// #[allow(dead_code)]
// pub struct Server<T> {
// pub config: ,
// pub state: ServerState,
// // to be seperated into a different struct
// connected_clients: HashMap<String, Client>,
// server_event_sink: Sender<ServerEvent>,
// server_message_source: Receiver<T>,
// message_source_handler: fn(&Self, event: T) -> (),
// buffer: [u8; 1024],
// // metrics
// pub o2s_rqst: usize,
// pub c2s_msgs: usize,
// pub s2s_msgs: usize,
// pub s2c_msgs: usize,
// }
// // MARK: - server implemetation
// impl Server {
// pub fn new(name: &str, address: &str, author: &str) -> Result<Self, io::Error> {
// // creating server channels
// let (sender, receiver) = unbounded();
// Ok(Self {
// // server data
// name: name.to_string(),
// address: address.to_string(),
// owner: author.to_string(),
// connected_clients: HashMap::new(),
// state: ServerState::Stopped,
// // messages & connections
// sender,
// receiver,
// listener: None,
// buffer: [0; 1024],
// // metrics
// o2s_rqst: 0,
// c2s_msgs: 0,
// s2s_msgs: 0,
// s2c_msgs: 0,
// })
// }
// pub fn get_name(&self) -> String {
// self.name.clone()
// }
// pub fn get_address(&self) -> String {
// self.address.clone()
// }
// pub fn get_owner(&self) -> String {
// self.owner.clone()
// }
// fn handle_server_messages(&mut self) -> Result<(), Vec<Result<(), ServerError>>> {
// // check for any server messages in the channel
// println!("server: getting messages");
// self.receiver.try_iter().map(|msg| {
// let _ = match msg {
// // request the server to shutdown
// // TODO: - move this into the stop method
// ServerMessages::Shutdown => {
// println!("server: shutting down...");
// let results = self
// .connected_clients
// .iter()
// .map(|(_k, v)| v.sender.send(Commands::Disconnect(None)))
// .cloned()
// .collect();
// self.state = ServerState::Stopping;
// }
// // a client requests an updated list of clients
// ServerMessages::RequestUpdate(stream_arc) => {
// self.c2s_msgs += 1;
// self.connected_clients.iter().map(|(_k, v)| {
// let mut stream = stream_arc.lock().unwrap();
// let _ = Server::send_data(&mut stream, v.to_string().as_str());
// let data =
// Server::recv_data(&mut stream, &mut self.buffer).unwrap_or(Commands::Error(None));
// if data == Commands::Success(None) {
// println!("Success Confirmed");
// } else {
// println!("No success read");
// let error = Commands::Error(None);
// let _ = Server::send_data(&mut stream, error.to_string().as_str());
// }
// })
// }
// // a client requests for the servers info
// ServerMessages::RequestInfo(uuid, stream_arc) => {
// self.c2s_msgs += 1;
// let mut stream = stream_arc.lock().unwrap();
// if let Some(client) = self.connected_clients.get(&uuid) {
// let params: HashMap<String, String> = [
// (String::from("uuid"), client.get_uuid()),
// (String::from("name"), client.get_username()),
// (String::from("host"), client.get_address()),
// ]
// .iter()
// .cloned()
// .collect();
// let command = Commands::Success(Some(params));
// let _ = Server::send_data(&mut stream, command.to_string().as_str());
// } else {
// let command = Commands::Success(None);
// let _ = Server::send_data(&mut stream, command.to_string().as_str());
// }
// }
// // a client requests to disconnect
// ServerMessages::Disconnect(uuid) => {
// self.c2s_msgs += 1;
// self.connected_clients.remove(&uuid.to_string());
// let params: HashMap<String, String> =
// [(String::from("uuid"), uuid)].iter().cloned().collect();
// let command = Commands::ClientRemove(Some(params));
// let _ = self
// .connected_clients
// .iter()
// .map(move |(_k, v)| v.get_sender().send(command.clone()));
// }
// };
// });
// Ok(())
// }
// #[allow(dead_code)]
// pub fn tick(&mut self) -> Result<(), ServerError> {
// // check to see if this server is ready to execute things.
// if self.state == ServerState::Stopped {
// Err(ServerIsStopped)
// }
// self.handle_server_messages();
// println!("server: checking for new connections");
// if let Ok((mut stream, _addr)) = self
// .listener
// .as_ref()
// .expect("tcpListener not here")
// .accept()
// {
// let _ = stream.set_read_timeout(Some(Duration::from_millis(1000)));
// let _ = stream.set_nonblocking(false);
// let request = Commands::Request(None);
// let _ = Server::send_data(&mut stream, &request.to_string().as_str());
// match Server::recv_data(&mut stream, &mut self.buffer) {
// Ok(Commands::Connect(Some(data))) => {
// self.o2s_rqst += 1;
// let uuid = data.get("uuid").unwrap();
// let username = data.get("name").unwrap();
// let address = data.get("host").unwrap();
// info!("{}", format!("Server: new client from {}", address));
// let client = Client::new(stream, self.sender.clone(), &uuid, &username, &address);
// self.connected_clients.insert(uuid.to_string(), client);
// let params: HashMap<String, String> = [
// (String::from("name"), username.clone()),
// (String::from("host"), address.clone()),
// (String::from("uuid"), uuid.clone()),
// ]
// .iter()
// .cloned()
// .collect();
// let new_client = Commands::Client(Some(params));
// let _ = self
// .connected_clients
// .iter()
// .map(|(_k, v)| v.sender.send(new_client.clone()));
// }
// Ok(Commands::Info(None)) => {
// self.o2s_rqst += 1;
// println!("Server: info requested");
// let params: HashMap<String, String> = [
// (String::from("name"), self.name.to_string().clone()),
// (String::from("owner"), self.owner.to_string().clone()),
// ]
// .iter()
// .cloned()
// .collect();
// let command = Commands::Info(Some(params));
// let _ = Server::send_data(&mut stream, command.to_string().as_str());
// }
// Err(_) => println!("ERROR: stream closed"),
// // TODO: - correct connection reset error when getting info.
// _ => {
// println!("Server: Invalid command sent");
// let _ = Server::send_data(&mut stream, Commands::Error(None).to_string().as_str());
// }
// }
// }
// println!("server: handing control to clients");
// for (_k, client) in self.connected_clients.iter_mut() {
// client.handle_connection();
// }
// Ok(())
// }
// #[allow(dead_code)]
// pub fn start(&mut self) -> Result<(), io::Error> {
// let listener = TcpListener::bind(&self.address)?;
// listener.set_nonblocking(true)?;
// self.listener = Some(listener);
// self.state = ServerState::Started;
// Ok(())
// }
// #[allow(dead_code)]
// pub fn stop(&mut self) -> Result<(), SendError<ServerMessages>> {
// info!("server: sending stop message");
// self.sender.send(ServerMessages::Shutdown)?;
// self.state = ServerState::Stopping;
// Ok(())
// }
// #[allow(dead_code)]
// fn send_data(stream: &mut TcpStream, data: &str) -> Result<(), io::Error> {
// println!("Transmitting...");
// println!("data: {}", data);
// /*
// * This will throw an error and crash any thread, including the main thread, if
// * the connection is lost before transmitting. Maybe change to handle any exceptions
// * that may occur.
// */
// let _ = stream.write(data.to_string().as_bytes())?;
// stream.flush()?;
// Ok(())
// }
// #[allow(dead_code)]
// fn recv_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result<Commands, io::Error> {
// let _ = stream.read(buffer)?;
// let command = Commands::from(buffer);
// Ok(command)
// }
// }
// impl Drop for Server {
// // TODO: - implement the drop logic
// // this includes signaling all clients to disconnect
// fn drop(&mut self) {}
// }
// #[cfg(test)]
// mod server_v3_tests {
// use crate::server::server_v3::{Server, ServerState};
// #[test]
// fn test_creation_and_drop() {
// let server =
// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed");
// assert_eq!(server.name, "test server");
// assert_eq!(server.address, "0.0.0.0:6000");
// assert_eq!(server.owner, "michael");
// }
// #[test]
// fn test_server_start() {
// let mut server =
// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed");
// let result = server.start();
// assert!(result.is_ok());
// assert_eq!(server.state, ServerState::Started);
// }
// #[test]
// fn test_server_stop() {
// let mut server =
// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed");
// let _ = server.start();
// let result = server.stop();
// assert!(result.is_ok());
// assert_eq!(server.state, ServerState::Stopping);
// }
// #[test]
// fn test_server_start_stop_and_one_tick() {
// let mut server =
// Server::new("test server", "0.0.0.0:6000", "michael").expect("server creation failed");
// let _ = server.start();
// let result = server.stop();
// server.tick();
// assert!(result.is_ok());
// assert_eq!(server.state, ServerState::Stopped);
// }
// }

View File

@ -1,95 +1,79 @@
mod client_api;
mod commands;
mod server;
mod lib;
use std::time::Duration;
use clap::{App, Arg};
use crossterm::ErrorKind;
use crate::server::server_v3::Server;
use crate::server::ui::server_view_controller::ServerViewController;
use lib::server::Server;
fn main() {
let args = App::new("--rust chat server--")
.version("0.1.5")
.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")
.arg(
Arg::with_name("config")
.short('p')
.long("port")
.value_name("PORT")
.about("sets the port the server listens on.")
.takes_value(true))
.get_matches();
fn main() -> Result<(), ErrorKind> {
let args = App::new("--rust chat server--")
.version("0.1.5")
.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")
.arg(Arg::with_name("graphical")
.short('g')
.takes_value(false)
.about("Enables graphical mode"))
.get_matches();
if args.is_present("graphical") {
let server = Server::new("server-001", "0.0.0.0:6000", "michael bailey");
ServerViewController::new(server.unwrap());
Ok(())
} else {
let mut server = crate::server::server_profile::Server::new("Server-01", "0.0.0.0:6000", "noreply@email.com");
server.start()?;
loop { std::thread::sleep(Duration::from_secs(1)); }
}
// creating the server object
}
// MARK: - general testing zone
#[cfg(test)]
mod tests {
use std::{thread, time};
use std::collections::HashMap;
// #[cfg(test)]
// mod tests {
// use crate::server::server_profile::Server;
// use crate::client_api::ClientApi;
// use std::collections::HashMap;
// use crate::commands::Commands;
// use std::{thread, time};
use crate::client_api::ClientApi;
use crate::commands::Commands;
use crate::server::server_profile::Server;
// #[test]
// fn test_server_info() {
// // setup the server
// let name = "Server-01";
// let address = "0.0.0.0:6000";
// let owner = "noreply@email.com";
#[test]
fn test_server_info() {
// setup the server
let name = "Server-01";
let address = "0.0.0.0:6000";
let owner = "noreply@email.com";
// let mut server = Server::new(name, address, owner);
// let result = server.start();
let mut server = Server::new(name, address, owner);
let result = server.start();
// assert_eq!(result.is_ok(), true);
assert_eq!(result.is_ok(), true);
let dur = time::Duration::from_millis(1000);
thread::sleep(dur);
// let dur = time::Duration::from_millis(1000);
// thread::sleep(dur);
let api = ClientApi::get_info("127.0.0.1:6000");
assert_eq!(api.is_ok(), true);
if let Ok(api) = api {
println!("received: {:?}", api);
let mut map = HashMap::new();
map.insert("name".to_string(), name.to_string());
map.insert("owner".to_string(), owner.to_string());
// let api = ClientApi::get_info("127.0.0.1:6000");
// assert_eq!(api.is_ok(), true);
// if let Ok(api) = api {
// println!("received: {:?}", api);
// let mut map = HashMap::new();
// map.insert("name".to_string(), name.to_string());
// map.insert("owner".to_string(), owner.to_string());
let expected = Commands::Info(Some(map));
println!("expected: {:?}", expected);
assert_eq!(api, expected);
}
}
// let expected = Commands::Info(Some(map));
// println!("expected: {:?}", expected);
// assert_eq!(api, expected);
// }
// }
#[test]
fn test_server_connect() {
let name = "Server-01";
let address = "0.0.0.0:6001";
let owner = "noreply@email.com";
// #[test]
// fn test_server_connect() {
// let name = "Server-01";
// let address = "0.0.0.0:6001";
// let owner = "noreply@email.com";
let mut server = Server::new(name, address, owner);
let _ = server.start().unwrap();
// let mut server = Server::new(name, address, owner);
// let _ = server.start().unwrap();
// let api_result = ClientApi::new(address);
// assert_eq!(api_result.is_ok(), true);
// if api_result.is_ok() {
// std::thread::sleep(std::time::Duration::from_secs(2));
// }
// }
// }
let api_result = ClientApi::new(address);
assert_eq!(api_result.is_ok(), true);
if api_result.is_ok() {
std::thread::sleep(std::time::Duration::from_secs(2));
}
}
}

View File

@ -1,2 +0,0 @@
pub mod client_profile;
pub mod client_v3;

View File

@ -1,4 +0,0 @@
pub mod server_v3;
pub mod client;
pub mod server_profile;
pub mod ui;

View File

@ -1,612 +0,0 @@
use std::{
collections::HashMap,
io,
io::Error,
io::prelude::*,
net::{TcpListener, TcpStream},
sync::{Arc, Mutex},
thread,
time::Duration
};
use crossbeam_channel::{Receiver, Sender, unbounded};
use log::info;
use crate::{
commands::Commands,
server::{
client::client_profile::Client,
}
};
use crate::lib::ThreadPool;
#[derive(Debug)]
pub enum ServerMessages {
RequestUpdate(Arc<Mutex<TcpStream>>),
RequestInfo(String, Arc<Mutex<TcpStream>>),
Disconnect(String),
Shutdown,
}
// MARK: - server struct
#[allow(dead_code)]
pub struct Server {
pub name: String,
pub address: String,
pub author: String,
connected_clients: Arc<Mutex<HashMap<String, Client>>>,
thread_pool: ThreadPool,
sender: Sender<ServerMessages>,
receiver: Receiver<ServerMessages>,
pub running: bool,
client_list_changed_handle: Box<dyn Fn(&Server)>,
}
// MARK: - server implemetation
impl Server {
pub fn new(name: &str, address: &str, author: &str) -> Self {
let (sender, receiver) = unbounded();
Self {
name: name.to_string(),
address: address.to_string(),
author: author.to_string(),
connected_clients: Arc::new(Mutex::new(HashMap::new())),
thread_pool: ThreadPool::new(16),
sender,
receiver,
running: false,
client_list_changed_handle: Box::new(|_s| println!("help"))
}
}
#[allow(dead_code)]
pub fn get_name(&self) -> String {
self.name.to_string()
}
#[allow(dead_code)]
pub fn get_address(&self) -> String {
self.address.to_string()
}
#[allow(dead_code)]
pub fn get_author(&self) -> String {
self.author.to_string()
}
pub fn start(&mut self) -> Result<(), io::Error> {
println!("server: starting server...");
self.running = true;
// MARK: - creating clones of the server property references
let name = self.name.clone();
#[allow(dead_code)]
let _ = self.address.clone();
let author = self.author.clone();
let connected_clients = self.connected_clients.clone();
let sender = self.sender.clone();
let receiver = self.receiver.clone();
// set up listener and buffer
let mut buffer = [0; 1024];
let listener = TcpListener::bind(self.get_address())?;
listener.set_nonblocking(true)?;
println!("server: spawning threads");
let _ = thread::Builder::new().name("Server Thread".to_string()).spawn(move || {
'outer: loop {
std::thread::sleep(Duration::from_millis(100));
// get messages from the servers channel.
println!("server: getting messages");
for i in receiver.try_iter() {
match i {
ServerMessages::Shutdown => {
// TODO: implement disconnecting all clients and shutting down the server.
println!("server: shutting down...");
break 'outer;
},
ServerMessages::RequestUpdate(stream_arc) => {
for (_k, v) in connected_clients.lock().unwrap().iter() {
let mut stream = stream_arc.lock().unwrap();
let _ = Server::transmit_data(&mut stream, v.to_string().as_str());
if Server::read_data(&mut stream, &mut buffer).unwrap_or(Commands::Error(None)) == Commands::Success(None) {
println!("Success Confirmed");
} else {
println!("No success read");
let error = Commands::Error(None);
let _ = Server::transmit_data(&mut stream, error.to_string().as_str());
}
}
},
ServerMessages::RequestInfo(uuid, stream_arc) => {
let mut stream = stream_arc.lock().unwrap();
if let Some(client) = connected_clients.lock().unwrap().get(&uuid) {
let params: HashMap<String, String> = [(String::from("uuid"), client.get_uuid()), (String::from("name"), client.get_username()), (String::from("host"), client.get_address())].iter().cloned().collect();
let command = Commands::Success(Some(params));
let _ = Server::transmit_data(&mut stream, command.to_string().as_str());
} else {
let command = Commands::Success(None);
let _ = Server::transmit_data(&mut stream, command.to_string().as_str());
}
},
ServerMessages::Disconnect(uuid) => {
let mut clients = connected_clients.lock().unwrap();
clients.remove(&uuid.to_string());
let params: HashMap<String, String> = [(String::from("uuid"), uuid)].iter().cloned().collect();
let command = Commands::ClientRemove(Some(params));
let _ = connected_clients.lock().unwrap().iter().map(move |(_k, v)| {v.get_sender().send(command.clone())});
},
}
}
println!("server: checking for new connections");
if let Ok((mut stream, _addr)) = listener.accept() {
stream.set_read_timeout(Some(Duration::from_millis(1000))).unwrap();
let _ = stream.set_nonblocking(false);
let request = Commands::Request(None);
let _ = Server::transmit_data(&mut stream, &request.to_string().as_str());
match Server::read_data(&mut stream, &mut buffer) {
Ok(command) => {
println!("Server: new connection sent - {:?}", command);
match command {
Commands::Connect(Some(data)) => {
let uuid = data.get("uuid").unwrap();
let username = data.get("name").unwrap();
let address = data.get("host").unwrap();
println!("{}", format!("Server: new Client connection: _addr = {}", address ));
let client = Client::new(stream, sender.clone(), &uuid, &username, &address);
connected_clients.lock().unwrap().insert(uuid.to_string(), client);
let params: HashMap<String, String> = [(String::from("name"), username.clone()), (String::from("host"), address.clone()), (String::from("uuid"), uuid.clone())].iter().cloned().collect();
let new_client = Commands::Client(Some(params));
let _ = connected_clients.lock().unwrap().iter().map(|(_k, v)| v.sender.send(new_client.clone()));
},
// TODO: - correct connection reset error when getting info.
Commands::Info(None) => {
println!("Server: info requested");
let params: HashMap<String, String> = [(String::from("name"), name.to_string().clone()), (String::from("owner"), author.to_string().clone())].iter().cloned().collect();
let command = Commands::Info(Some(params));
let _ = Server::transmit_data(&mut stream, command.to_string().as_str());
},
_ => {
println!("Server: Invalid command sent");
let _ = Server::transmit_data(&mut stream, Commands::Error(None).to_string().as_str());
},
}
},
Err(_) => println!("ERROR: stream closed"),
}
}
// TODO: end -
// handle each client for messages
println!("server: handing control to clients");
for (_k, client) in connected_clients.lock().unwrap().iter_mut() {
client.handle_connection();
}
}
info!("server: stopped");
});
info!("server: started");
Ok(())
}
#[allow(dead_code)]
pub fn stop(&mut self) {
info!("server: sending stop message");
let _ = self.sender.send(ServerMessages::Shutdown);
self.running = false;
}
fn transmit_data(stream: &mut TcpStream, data: &str) -> Result<(), Error>{
println!("Transmitting...");
println!("data: {}", data);
/*
* This will throw an error and crash any thread, including the main thread, if
* the connection is lost before transmitting. Maybe change to handle any exceptions
* that may occur.
*/
let _ = stream.write(data.to_string().as_bytes())?;
stream.flush()?;
Ok(())
}
fn read_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result<Commands, Error> {
let _ = stream.read(buffer)?;
let command = Commands::from(buffer);
Ok(command)
}
}
impl ToString for Server {
fn to_string(&self) -> std::string::String { todo!() }
}
impl Drop for Server {
fn drop(&mut self) {
println!("server dropped");
let _ = self.sender.send(ServerMessages::Shutdown);
}
}
/* The new version of the server No long works with these unit
* tests.
* They will be fixed soon!
* TODO: fix unit tests
*/
/*#[cfg(test)]
mod tests{
use super::*;
use std::{thread, time};
use std::sync::Once;
use std::time::Duration;
lazy_static!{
static ref SERVER_NAME: &'static str = "test";
static ref SERVER_ADDRESS: &'static str = "0.0.0.0:6000";
static ref SERVER_AUTHOR: &'static str = "test";
static ref SERVER: Server<'static> = Server::new(&SERVER_NAME, &SERVER_ADDRESS, &SERVER_AUTHOR);
}
static START: Once = Once::new();
/*
* These tests must be executed individually to ensure that No errors
* occur, this is due to the fact that the server is created everytime.
* Setup a system for the server to close after every test.
*/
fn setup_server(){
unsafe{
START.call_once(|| {
thread::spawn(|| {
SERVER.start();
});
});
let millis = time::Duration::from_millis(1000);
thread::sleep(millis);
}
}
fn establish_client_connection(uuid: &str) -> TcpStream {
let mut buffer = [0; 1024];
let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap();
let mut command = read_data(&stream, &mut buffer);
assert_eq!(command, Commands::Request(None));
let msg: String = format!("!connect: uuid:{uuid} name:\"{name}\" host:\"{host}\"", uuid=uuid, name="alice", host="127.0.0.1");
transmit_data(&stream, msg.as_str());
command = read_data(&stream, &mut buffer);
assert_eq!(command, Commands::Success(None));
stream
}
fn transmit_data(mut stream: &TcpStream, data: &str){
stream.write(data.to_string().as_bytes()).unwrap();
stream.flush().unwrap();
}
fn read_data(mut stream: &TcpStream, buffer: &mut [u8; 1024]) -> Commands {
match stream.read(buffer) {
Ok(_) => Commands::from(buffer),
Err(_) => Commands::Error(None),
}
}
fn force_disconnect(mut stream: &TcpStream){
let msg = "!disconnect:";
transmit_data(&stream, msg);
}
#[test]
fn test_server_connect(){
let mut buffer = [0; 1024];
setup_server();
let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap();
stream.read(&mut buffer).unwrap();
let mut command = Commands::from(&mut buffer);
assert_eq!(command, Commands::Request(None));
let msg = b"!connect: uuid:123456-1234-1234-123456 name:\"alice\" host:\"127.0.0.1\"";
stream.write(msg).unwrap();
stream.read(&mut buffer).unwrap();
command = Commands::from(&mut buffer);
assert_eq!(command, Commands::Success(None));
let msg = b"!disconnect:";
stream.write(msg).unwrap();
let dur = time::Duration::from_millis(500);
thread::sleep(dur);
}
#[test]
fn test_server_info(){
let mut buffer = [0; 1024];
setup_server();
let mut stream = TcpStream::connect("0.0.0.0:6000").unwrap();
let command = read_data(&stream, &mut buffer);
assert_eq!(command, Commands::Request(None));
let msg = "!info:";
transmit_data(&stream, msg);
let command = read_data(&stream, &mut buffer);
let params: HashMap<String, String> = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect();
assert_eq!(command, Commands::Success(Some(params)));
}
#[test]
fn test_client_info(){
let mut buffer = [0; 1024];
setup_server();
let mut stream = establish_client_connection("1234-5542-2124-155");
let msg = "!info:";
transmit_data(&stream, msg);
let command = read_data(&stream, &mut buffer);
let params: HashMap<String, String> = [(String::from("name"), String::from("test")), (String::from("owner"), String::from("test"))].iter().cloned().collect();
assert_eq!(command, Commands::Success(Some(params)));
let msg = "!disconnect:";
transmit_data(&stream, msg);
let dur = time::Duration::from_millis(500);
thread::sleep(dur);
}
#[test]
fn test_clientUpdate_solo(){
let mut buffer = [0; 1024];
setup_server();
let mut stream = establish_client_connection("1222-555-6-7");
let msg = "!clientUpdate:";
transmit_data(&stream, msg);
let command = read_data(&stream, &mut buffer);
assert_eq!(command, Commands::Success(None));
let msg = "!disconnect:";
transmit_data(&stream, msg);
let dur = time::Duration::from_millis(500);
thread::sleep(dur);
}
#[test]
fn test_clientUpdate_multi(){
let mut buffer = [0; 1024];
setup_server();
let mut stream_one = establish_client_connection("0001-776-6-5");
let mut stream_two = establish_client_connection("0010-776-6-5");
let mut stream_three = establish_client_connection("0011-776-6-5");
let mut stream_four = establish_client_connection("0100-776-6-5");
let client_uuids: [String; 3] = [String::from("0010-776-6-5"), String::from("0011-776-6-5"), String::from("0100-776-6-5")];
let mut user_1 = true;
let mut user_2 = true;
let mut user_3 = true;
for uuid in client_uuids.iter() {
let command = read_data(&stream_one, &mut buffer);
if *uuid == String::from("0010-776-6-5") && user_1 {
let params: HashMap<String, String> = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command, Commands::Client(Some(params)));
user_1 = false;
} else if *uuid == String::from("0011-776-6-5") && user_2 {
let params: HashMap<String, String> = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command, Commands::Client(Some(params)));
user_2 = false;
} else if *uuid == String::from("0100-776-6-5") && user_3 {
let params: HashMap<String, String> = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command, Commands::Client(Some(params)));
user_3 = false;
} else {
assert!(false);
}
let msg = "!success:";
transmit_data(&stream_one, msg);
}
stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap();
let mut unsuccessful = true;
while unsuccessful {
let msg = "!clientUpdate:";
transmit_data(&stream_one, msg);
let command = read_data(&stream_one, &mut buffer);
match command.clone() {
Commands::Error(None) => println!("resending..."),
_ => {
assert_eq!(command, Commands::Success(None));
unsuccessful = false;
},
}
}
stream_one.set_read_timeout(None).unwrap();
for x in 0..3 {
let command = read_data(&stream_one, &mut buffer);
let command_clone = command.clone();
match command{
Commands::Client(Some(params)) => {
let uuid = params.get("uuid").unwrap();
if *uuid == String::from("0010-776-6-5") {
let params: HashMap<String, String> = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command_clone, Commands::Client(Some(params)));
} else if *uuid == String::from("0011-776-6-5") {
let params: HashMap<String, String> = [(String::from("uuid"), String::from("0011-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command_clone, Commands::Client(Some(params)));
} else if *uuid == String::from("0100-776-6-5") {
let params: HashMap<String, String> = [(String::from("uuid"), String::from("0100-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command_clone, Commands::Client(Some(params)));
} else {
assert!(false);
}
},
_ => assert!(false),
}
let msg = "!success:";
transmit_data(&stream_one, msg);
}
let dur = time::Duration::from_millis(500);
thread::sleep(dur);
let msg = "!disconnect:";
transmit_data(&stream_one, msg);
transmit_data(&stream_two, msg);
transmit_data(&stream_three, msg);
transmit_data(&stream_four, msg);
let dur = time::Duration::from_millis(500);
thread::sleep(dur);
}
#[test]
fn test_clientInfo(){
let mut buffer = [0; 1024];
setup_server();
let mut stream_one = establish_client_connection("0001-776-6-5");
let mut stream_two = establish_client_connection("\"0010-776-6-5\"");
let command = read_data(&stream_one, &mut buffer);
let params: HashMap<String, String> = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command, Commands::Client(Some(params)));
let msg = "!success:";
transmit_data(&stream_one, msg);
stream_one.set_read_timeout(Some(Duration::from_millis(3000))).unwrap();
let mut unsuccessful = true;
while unsuccessful {
let msg = "!clientInfo: uuid:\"0010-776-6-5\"";
transmit_data(&stream_one, msg);
let command = read_data(&stream_one, &mut buffer);
match command.clone() {
Commands::Error(None) => println!("resending..."),
_ => {
let params: HashMap<String, String> = [(String::from("uuid"), String::from("\"0010-776-6-5\"")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command, Commands::Success(Some(params)));
unsuccessful = false;
},
}
}
stream_one.set_read_timeout(None).unwrap();
let msg = "!disconnect:";
transmit_data(&stream_one, msg);
transmit_data(&stream_two, msg);
let dur = time::Duration::from_millis(500);
thread::sleep(dur);
}
#[test]
fn test_client_disconnect(){
let mut buffer = [0; 1024];
setup_server();
let mut stream_one = establish_client_connection("0001-776-6-5");
let mut stream_two = establish_client_connection("0010-776-6-5");
let command = read_data(&stream_one, &mut buffer);
let params: HashMap<String, String> = [(String::from("uuid"), String::from("0010-776-6-5")), (String::from("name"), String::from("\"alice\"")), (String::from("host"), String::from("\"127.0.0.1\""))].iter().cloned().collect();
assert_eq!(command, Commands::Client(Some(params)));
let msg = "!success:";
transmit_data(&stream_one, msg);
let msg = "!disconnect:";
transmit_data(&stream_two, msg);
let command = read_data(&stream_one, &mut buffer);
let params: HashMap<String, String> = [(String::from("uuid"), String::from("0010-776-6-5"))].iter().cloned().collect();
assert_eq!(command, Commands::Client(Some(params)));
let msg = "!success:";
transmit_data(&stream_one, msg);
stream_one.set_read_timeout(Some(Duration::from_millis(2000))).unwrap();
match stream_one.peek(&mut buffer) {
Ok(_) => assert!(false),
Err(_) => assert!(true),
}
stream_one.set_read_timeout(None).unwrap();
let msg = "!disconnect:";
transmit_data(&stream_one, msg);
let dur = time::Duration::from_millis(500);
thread::sleep(dur);
}
}*/

View File

@ -1,311 +0,0 @@
use std::{collections::HashMap, io, io::{Read, Write}, net::{TcpListener, TcpStream}, sync::{Arc, Mutex}};
use std::time::Duration;
use crossbeam_channel::{Receiver, Sender, unbounded};
use log::info;
use crate::{
commands::Commands
};
use crate::server::client::client_v3::Client;
#[derive(Debug)]
pub enum ServerMessages {
RequestUpdate(Arc<Mutex<TcpStream>>),
RequestInfo(String, Arc<Mutex<TcpStream>>),
Disconnect(String),
Shutdown,
}
#[allow(dead_code)]
#[derive(Eq, PartialEq)]
pub enum ServerState {
Starting,
Started,
Stopping,
Stopped,
}
// MARK: - server struct
#[allow(dead_code)]
pub struct Server {
pub name: String,
pub address: String,
pub owner: String,
pub state: ServerState,
connected_clients: HashMap<String, Client>,
sender: Sender<ServerMessages>,
receiver: Receiver<ServerMessages>,
listener: Option<TcpListener>,
buffer: [u8; 1024],
client_list_changed_handle: Box<dyn Fn(&Server)>,
// metrics
pub o2s_rqst: usize,
pub c2s_msgs: usize,
pub s2s_msgs: usize,
pub s2c_msgs: usize,
}
// MARK: - server implemetation
impl Server {
pub fn new(name: &str, address: &str, author: &str) -> Result<Self, io::Error> {
// creating server channels
let (sender, receiver) = unbounded();
Ok(
Self {
// server data
name: name.to_string(),
address: address.to_string(),
owner: author.to_string(),
connected_clients: HashMap::new(),
state: ServerState::Stopped,
// messages & connections
sender,
receiver,
listener: None,
buffer: [0; 1024],
// event handles
client_list_changed_handle: Box::new(|_s| info!("Server: client list changed.")),
// metrics
o2s_rqst: 0,
c2s_msgs: 0,
s2s_msgs: 0,
s2c_msgs: 0,
}
)
}
#[allow(dead_code)]
pub fn get_name(&self) -> String {
self.name.clone()
}
#[allow(dead_code)]
pub fn get_address(&self) -> String {
self.address.clone()
}
#[allow(dead_code)]
pub fn get_owner(&self) -> String {
self.owner.clone()
}
#[allow(dead_code)]
pub fn tick(&mut self) {
// check to see if this server is ready to execute things.
if self.state == ServerState::Stopped {
()
}
// check for any server messages in the channel
println!("server: getting messages");
for i in self.receiver.try_iter() {
match i {
// server calls
ServerMessages::Shutdown => {
self.s2s_msgs += 1;
println!("server: shutting down...");
for (_k, v) in self.connected_clients.iter() {
let _ = v.sender.send(Commands::Disconnect(None));
}
self.state = ServerState::Stopping;
},
// client requests
ServerMessages::RequestUpdate(stream_arc) => {
self.c2s_msgs += 1;
for (_k, v) in self.connected_clients.iter() {
let mut stream = stream_arc.lock().unwrap();
let _ = Server::send_data(&mut stream, v.to_string().as_str());
let data = Server::recv_data(&mut stream, &mut self.buffer).unwrap_or(Commands::Error(None));
if data == Commands::Success(None) {
println!("Success Confirmed");
} else {
println!("No success read");
let error = Commands::Error(None);
let _ = Server::send_data(&mut stream, error.to_string().as_str());
}
}
},
// client requests for info
ServerMessages::RequestInfo(uuid, stream_arc) => {
self.c2s_msgs += 1;
let mut stream = stream_arc.lock().unwrap();
if let Some(client) = self.connected_clients.get(&uuid) {
let params: HashMap<String, String> = [
(String::from("uuid"), client.get_uuid()),
(String::from("name"), client.get_username()),
(String::from("host"), client.get_address())
].iter().cloned().collect();
let command = Commands::Success(Some(params));
let _ = Server::send_data(&mut stream, command.to_string().as_str());
} else {
let command = Commands::Success(None);
let _ = Server::send_data(&mut stream, command.to_string().as_str());
}
},
// client disconnect requests
ServerMessages::Disconnect(uuid) => {
self.c2s_msgs += 1;
self.connected_clients.remove(&uuid.to_string());
let params: HashMap<String, String> = [(String::from("uuid"), uuid)].iter().cloned().collect();
let command = Commands::ClientRemove(Some(params));
let _ = self.connected_clients.iter().map(move |(_k, v)| {v.get_sender().send(command.clone())});
},
}
}
println!("server: checking for new connections");
if let Ok((mut stream, _addr)) = self.listener.as_ref().expect("tcpListener not here").accept() {
let _ = stream.set_read_timeout(Some(Duration::from_millis(1000)));
let _ = stream.set_nonblocking(false);
let request = Commands::Request(None);
let _ = Server::send_data(&mut stream, &request.to_string().as_str());
match Server::recv_data(&mut stream, &mut self.buffer) {
Ok(Commands::Connect(Some(data))) => {
self.o2s_rqst += 1;
let uuid = data.get("uuid").unwrap();
let username = data.get("name").unwrap();
let address = data.get("host").unwrap();
info!("{}", format!("Server: new client from {}", address ));
let client = Client::new(stream, self.sender.clone(), &uuid, &username, &address);
self.connected_clients.insert(uuid.to_string(), client);
let params: HashMap<String, String> = [(String::from("name"), username.clone()), (String::from("host"), address.clone()), (String::from("uuid"), uuid.clone())].iter().cloned().collect();
let new_client = Commands::Client(Some(params));
let _ = self.connected_clients.iter().map( |(_k, v)| v.sender.send(new_client.clone()));
},
Ok(Commands::Info(None)) => {
self.o2s_rqst += 1;
println!("Server: info requested");
let params: HashMap<String, String> = [(String::from("name"), self.name.to_string().clone()), (String::from("owner"), self.owner.to_string().clone())].iter().cloned().collect();
let command = Commands::Info(Some(params));
let _ = Server::send_data(&mut stream, command.to_string().as_str());
},
Err(_) => println!("ERROR: stream closed"),
// TODO: - correct connection reset error when getting info.
_ => {
println!("Server: Invalid command sent");
let _ = Server::send_data(&mut stream, Commands::Error(None).to_string().as_str());
},
}
}
println!("server: handing control to clients");
for (_k, client) in self.connected_clients.iter_mut() {
client.handle_connection();
}
}
#[allow(dead_code)]
pub fn start(&mut self) -> Result<(), io::Error> {
let listener = TcpListener::bind(&self.address)?;
listener.set_nonblocking(true)?;
self.listener = Some(listener);
Ok(())
}
#[allow(dead_code)]
pub fn stop(&mut self) {
info!("server: sending stop message");
let _ = self.sender.send(ServerMessages::Shutdown);
self.state = ServerState::Stopping;
}
#[allow(dead_code)]
fn send_data(stream: &mut TcpStream, data: &str) -> Result<(), io::Error>{
println!("Transmitting...");
println!("data: {}", data);
/*
* This will throw an error and crash any thread, including the main thread, if
* the connection is lost before transmitting. Maybe change to handle any exceptions
* that may occur.
*/
let _ = stream.write(data.to_string().as_bytes())?;
stream.flush()?;
Ok(())
}
#[allow(dead_code)]
fn recv_data(stream: &mut TcpStream, buffer: &mut [u8; 1024]) -> Result<Commands, io::Error> {
let _ = stream.read(buffer)?;
let command = Commands::from(buffer);
Ok(command)
}
}
impl ToString for Server {
fn to_string(&self) -> std::string::String { todo!() }
}
impl Drop for Server {
fn drop(&mut self) {
println!("server dropped");
let _ = self.sender.send(ServerMessages::Shutdown);
}
}
#[cfg(test)]
mod tests {
use crate::server::server_v3::Server;
#[test]
fn test_creation() {
let server = Server::new(
"test server",
"0.0.0.0:6000",
"michael"
);
assert_eq!(server.name, "test server");
assert_eq!(server.address, "0.0.0.0:6000");
assert_eq!(server.owner, "michael");
}
}

View File

@ -1,10 +0,0 @@
use cursive::views::{Dialog, TextView};
use cursive::View;
pub fn about() -> Box<dyn View> {
Box::new(
Dialog::new()
.content(TextView::new("rust chat server written by Mitchel Hardie & Michael Bailey (c) 2020"))
.button("Close", |s| {s.pop_layer();})
)
}

View File

@ -1,67 +0,0 @@
use cursive::{Cursive, View};
use cursive::view::SizeConstraint;
use cursive::views::{LinearLayout, ListView, Panel, ResizedView, TextView};
use crate::server::server_v3::Server;
#[allow(dead_code)]
pub fn control_panel(s: &mut Cursive) -> Box<dyn View> {
Box::new(
ResizedView::new(
SizeConstraint::Fixed(s.screen_size().x-8),
SizeConstraint::Fixed(s.screen_size().y-8),
Panel::new(
LinearLayout::horizontal()
.child(
LinearLayout::vertical()
.child(
TextView::new(" ═════╡ Server ╞═════ ")
)
.child(
TextView::new(
format!("Server name: {}", s.user_data::<Server>().unwrap().get_name())
)
)
.child(
TextView::new(
format!("Server host: {}", s.user_data::<Server>().unwrap().get_address())
)
)
.child(
TextView::new(
format!("Server owner: {}", s.user_data::<Server>().unwrap().get_owner())
)
)
.child(
TextView::new(
format!(" ═════╡ metrics ╞═════ ")
)
)
.child(
TextView::new(
format!("Server o2s_rqst: {}", s.user_data::<Server>().unwrap().o2s_rqst)
)
)
.child(
TextView::new(
format!("Server c2s_msgs: {}", s.user_data::<Server>().unwrap().c2s_msgs)
)
)
.child(
TextView::new(
format!("Server s2s_msgs: {}", s.user_data::<Server>().unwrap().s2s_msgs)
)
)
.child(
TextView::new(
format!("Server s2c_msgs: {}", s.user_data::<Server>().unwrap().s2c_msgs)
)
)
)
.child(
ListView::new()
)
)
)
)
}

View File

@ -1,10 +0,0 @@
use cursive::menu::MenuTree;
use crate::server::ui::about_panel::about;
pub fn main_menu() -> MenuTree {
MenuTree::new()
.leaf("About ^+A", |s| s.add_layer(about()))
.delimiter()
.leaf("Quit ^+Q", |s| s.quit())
}

View File

@ -1,4 +0,0 @@
pub mod server_view_controller;
pub mod control_panel;
pub mod about_panel;
pub mod main_menu;

View File

@ -1,60 +0,0 @@
use cursive::{CbSink, Cursive, CursiveExt};
use crate::server::server_v3::Server;
use crate::server::ui::about_panel::about;
use crate::server::ui::main_menu::main_menu;
use cursive::event::Event;
#[allow(dead_code)]
pub enum UpdateTypes {
AddClient()
}
/// # ServerViewConroller
///
/// This Struct contains all the controller logic to allow the server to interact with the view
#[allow(dead_code)]
pub struct ServerViewController {
display: Cursive,
server_name: String,
server_host: String,
server_owner: String,
client_list: Vec<String>,
running: String,
}
#[allow(dead_code)]
impl ServerViewController {
pub fn new(server: Server) {
let mut v = Self {
display: Cursive::default(),
server_name: server.get_name().to_string(),
server_host: server.get_address().to_string(),
server_owner: server.get_owner().to_string(),
client_list: Vec::new(),
running: "None".to_string()
};
// set global shortcuts
v.display.add_global_callback(Event::CtrlChar('q'), |s| s.quit());
v.display.add_global_callback(Event::CtrlChar('a'), |s| s.add_layer(about()));
// seting up menubar
v.display.menubar().add_subtree("Server", main_menu());
v.display.set_autohide_menu(false)
// setup the display menubar.
// TODO: - this will be tied to the server run function
// v.display.add_global_callback(Event::Refresh, |s| s.user_data::<Arc<Server>>().unwrap().);
}
fn get_display_channel() -> CbSink {
Cursive::default().cb_sink().clone()
}
}