Merge Interface branch onto development branch #5
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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]>;
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
/**
|
||||
* Bundle: inspired from NSBundle on macOS
|
||||
*/
|
||||
struct Bundle {
|
||||
location:
|
||||
}
|
||||
|
||||
impl Bundle {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
pub mod bundle;
|
||||
pub mod Traits
|
||||
|
|
@ -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"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
src/lib.rs
106
src/lib.rs
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ use std::{
|
|||
io::prelude::*,
|
||||
net::{Shutdown, TcpStream},
|
||||
sync::Arc,
|
||||
//collections::HashMap,
|
||||
sync::Mutex,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
|
@ -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 {
|
||||
|
||||
}
|
||||
|
|
@ -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>>
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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!() }
|
||||
}
|
||||
|
|
@ -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, );
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
pub struct ServerConfig {
|
||||
pub name: String,
|
||||
pub address: String,
|
||||
pub owner: String,
|
||||
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
pub mod client_management;
|
||||
pub mod server;
|
||||
pub mod server_v3;
|
||||
|
||||
pub struct Server {}
|
||||
|
|
@ -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);
|
||||
// }
|
||||
// }*/
|
||||
|
|
@ -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);
|
||||
// }
|
||||
// }
|
||||
138
src/main.rs
138
src/main.rs
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
pub mod client_profile;
|
||||
pub mod client_v3;
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
pub mod server_v3;
|
||||
pub mod client;
|
||||
pub mod server_profile;
|
||||
pub mod ui;
|
||||
|
|
@ -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);
|
||||
}
|
||||
}*/
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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();})
|
||||
)
|
||||
}
|
||||
|
|
@ -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()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -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())
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
pub mod server_view_controller;
|
||||
pub mod control_panel;
|
||||
pub mod about_panel;
|
||||
pub mod main_menu;
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue