deleted old server version
This commit is contained in:
parent
d0c50366aa
commit
eb8a512c04
|
|
@ -20,7 +20,6 @@ use actix::Handler;
|
|||
use crate::client_management::ClientManagerMessage;
|
||||
use foundation::messages::network::NetworkSockOut;
|
||||
use foundation::ClientDetails;
|
||||
use server::Server;
|
||||
use crate::network::{NetworkManager, NetworkMessage};
|
||||
|
||||
/// This struct is the main actor of the server.
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
use crate::client::Client;
|
||||
use crate::messages::ServerMessage;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Message {
|
||||
content: String,
|
||||
sender: Weak<Client<>>,
|
||||
}
|
||||
|
||||
impl Message {
|
||||
#[allow(unused)]
|
||||
pub fn new(content: String, sender: Weak<Client<>>) -> Message {
|
||||
Message { content, sender }
|
||||
}
|
||||
}
|
||||
|
||||
enum ChatManagerMessage {
|
||||
AddMessage {sender: Weak<Client<>>, content: String}
|
||||
}
|
||||
|
||||
pub struct ChatManager {
|
||||
messages: Mutex<Vec<Message>>,
|
||||
server_channel: Sender<ServerMessage>,
|
||||
|
||||
#[allow(unused)]
|
||||
tx: Sender<ChatManagerMessage>,
|
||||
rx: Mutex<Receiver<ChatManagerMessage>>,
|
||||
}
|
||||
|
||||
impl ChatManager {
|
||||
#[allow(unused)]
|
||||
pub fn new(server_channel: Sender<ServerMessage>) -> Arc<Self> {
|
||||
let (tx, rx) = channel::<ChatManagerMessage>(1024);
|
||||
|
||||
let manager = Arc::new(ChatManager {
|
||||
messages: Mutex::new(Vec::new()),
|
||||
server_channel,
|
||||
tx,
|
||||
rx: Mutex::new(rx),
|
||||
});
|
||||
|
||||
manager.start();
|
||||
manager
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn start(self: &Arc<ChatManager>) {
|
||||
let manager = self.clone();
|
||||
tokio::spawn(async move {
|
||||
use ServerMessage::{BroadcastGlobalMessage};
|
||||
use ChatManagerMessage::{AddMessage};
|
||||
|
||||
while let Some(message) = manager.rx.lock().await.recv().await {
|
||||
|
||||
match message {
|
||||
AddMessage { content,sender } => {
|
||||
let sender = &sender.upgrade().unwrap().details.uuid;
|
||||
manager.server_channel.send(
|
||||
BroadcastGlobalMessage {sender: sender.clone(), content}
|
||||
).await.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn add_message(self: &Arc<Self>, sender: Weak<Client>, content: String) {
|
||||
let mut a = self.messages.lock().await;
|
||||
a.push(Message::new(content, sender))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub async fn get_all_messages(self: &Arc<Self>) -> Vec<Message> {
|
||||
self.messages.lock().await.clone()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,247 +0,0 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::io::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use mlua::prelude::LuaUserData;
|
||||
use mlua::{UserDataFields, UserDataMethods};
|
||||
|
||||
use tokio::select;
|
||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||
|
||||
use foundation::messages::client::{ClientStreamIn, ClientStreamOut};
|
||||
use foundation::ClientDetails;
|
||||
use foundation::connection::Connection;
|
||||
use foundation::messages::client::ClientStreamOut::{Connected, Disconnected};
|
||||
use foundation::prelude::IManager;
|
||||
|
||||
use crate::messages::{ClientMessage};
|
||||
|
||||
/// # ClientInMessage
|
||||
///
|
||||
/// Messages that are sent internally
|
||||
/// when functions are called on the client
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum ClientInMessage {
|
||||
MessageTo,
|
||||
UpdateRequest,
|
||||
}
|
||||
|
||||
/// # Client
|
||||
/// This struct represents a connected user.
|
||||
///
|
||||
/// ## Attributes
|
||||
/// - details: store of the clients infomation.
|
||||
///
|
||||
/// - stream: The socket for the connected client.
|
||||
/// - stream_reader: the buffered reader used to receive messages
|
||||
/// - stream_writer: the buffered writer used to send messages
|
||||
/// - owner: An optional reference to the owning object.
|
||||
#[derive(Debug)]
|
||||
pub struct Client<Out: 'static>
|
||||
where
|
||||
Out: From<ClientMessage> + Send
|
||||
{
|
||||
pub details: ClientDetails,
|
||||
out_channel: Sender<Out>,
|
||||
connection: Arc<Connection>,
|
||||
}
|
||||
|
||||
impl<Out> Client<Out>
|
||||
where
|
||||
Out: From<ClientMessage> + Send {
|
||||
pub fn new(
|
||||
uuid: Uuid,
|
||||
username: String,
|
||||
address: String,
|
||||
out_channel: Sender<Out>,
|
||||
connection: Arc<Connection>
|
||||
) -> Arc<Client<Out>> {
|
||||
Arc::new(Client {
|
||||
details: ClientDetails {
|
||||
uuid,
|
||||
username,
|
||||
address: address.to_string(),
|
||||
public_key: None,
|
||||
},
|
||||
connection,
|
||||
out_channel,
|
||||
})
|
||||
}
|
||||
|
||||
async fn handle_connection(&self, value: Result<ClientStreamIn, Error>) {
|
||||
match value {
|
||||
Ok(ClientStreamIn::Disconnect) => {
|
||||
println!(
|
||||
"[Client {:?}]: Disconnect received",
|
||||
self.details.uuid
|
||||
);
|
||||
self.disconnect().await;
|
||||
return;
|
||||
}
|
||||
Ok(ClientStreamIn::SendMessage { to, content }) => {
|
||||
let _ = self.out_channel.send(
|
||||
ClientMessage::IncomingMessage {from: self.details.uuid, to, content}.into()
|
||||
).await;
|
||||
}
|
||||
Ok(ClientStreamIn::SendGlobalMessage { content }) => {
|
||||
let _ = self.out_channel.send(
|
||||
ClientMessage::IncomingGlobalMessage {from: self.details.uuid, content}.into()
|
||||
).await;
|
||||
}
|
||||
_ => {
|
||||
self.error("Command not found").await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn broadcast_message(&self, from: Uuid, content: String) -> Result<(), Error> {
|
||||
self.connection.write(ClientStreamOut::GlobalMessage { from, content }).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn user_message(&self, from: Uuid, content: String) -> Result<(), Error> {
|
||||
self.connection.write(ClientStreamOut::UserMessage { from, content }).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn disconnect(&self) {
|
||||
let _ = self.out_channel
|
||||
.send(ClientMessage::Disconnect {
|
||||
id: self.details.uuid,
|
||||
}.into()).await;
|
||||
}
|
||||
|
||||
async fn error(&self, msg: &str) {
|
||||
let _ = self.connection.write(ClientStreamOut::Error).await;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Out> IManager for Client<Out>
|
||||
where
|
||||
Out: From<ClientMessage> + Send
|
||||
{
|
||||
async fn init(self: &Arc<Self>)
|
||||
where
|
||||
Self: Send + Sync + 'static
|
||||
{
|
||||
let _ = self.connection.write(Connected).await;
|
||||
}
|
||||
|
||||
async fn run(self: &Arc<Self>) {
|
||||
let client = self.clone();
|
||||
select! {
|
||||
val = self.connection.read::<ClientStreamIn>() => {
|
||||
tokio::spawn(async move {
|
||||
client.handle_connection(val).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - use to handle disconnecting
|
||||
impl<Out> Drop for Client<Out>
|
||||
where
|
||||
Out: From<ClientMessage> + Send
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
let connection = self.connection.clone();
|
||||
|
||||
let id = self.details.uuid.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let _ = connection.write(Disconnected).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - used for sorting.
|
||||
impl<Out> PartialEq for Client<Out>
|
||||
where
|
||||
Out: From<ClientMessage> + Send
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.details.uuid == other.details.uuid
|
||||
}
|
||||
}
|
||||
|
||||
impl<Out> Eq for Client<Out>
|
||||
where
|
||||
Out: From<ClientMessage> + Send
|
||||
{}
|
||||
|
||||
impl<Out> PartialOrd for Client<Out>
|
||||
where
|
||||
Out: From<ClientMessage> + Send
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Out: 'static> Ord for Client<Out>
|
||||
where
|
||||
Out: From<ClientMessage> + Send
|
||||
{
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.details.uuid.cmp(&other.details.uuid)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::io::Error;
|
||||
use tokio::sync::mpsc::channel;
|
||||
use uuid::Uuid;
|
||||
use foundation::connection::Connection;
|
||||
use foundation::messages::client::ClientStreamOut;
|
||||
use foundation::messages::client::ClientStreamOut::{Connected, Disconnected};
|
||||
use foundation::prelude::IManager;
|
||||
use foundation::test::create_connection_pair;
|
||||
use crate::client::{Client};
|
||||
use crate::messages::ClientMessage;
|
||||
use crate::messages::ClientMessage::Disconnect;
|
||||
|
||||
#[tokio::test]
|
||||
async fn create_client_and_drop() -> Result<(), Error> {
|
||||
let (sender, mut receiver) =
|
||||
channel::<ClientMessage>(1024);
|
||||
let (server, (client_conn, addr)) =
|
||||
create_connection_pair().await?;
|
||||
|
||||
// client details
|
||||
let uuid = Uuid::new_v4();
|
||||
let username = "TestUser".to_string();
|
||||
|
||||
let client = Client::new(
|
||||
uuid,
|
||||
username,
|
||||
addr.to_string(),
|
||||
sender.clone(),
|
||||
server
|
||||
);
|
||||
|
||||
client.start();
|
||||
|
||||
let res = client_conn.read::<ClientStreamOut>().await?;
|
||||
assert_eq!(res, Connected);
|
||||
|
||||
drop(client);
|
||||
|
||||
let res = client_conn.read::<ClientStreamOut>().await?;
|
||||
assert_eq!(res, Disconnected);
|
||||
|
||||
// fetch from out_channel
|
||||
let disconnect_msg = receiver.recv().await.unwrap();
|
||||
assert_eq!(disconnect_msg, Disconnect {id: uuid});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::future::join_all;
|
||||
use tokio::select;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use foundation::connection::Connection;
|
||||
use foundation::prelude::IManager;
|
||||
|
||||
use crate::client::Client;
|
||||
use crate::messages::ClientMessage;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ClientMgrMessage {
|
||||
#[allow(dead_code)]
|
||||
Remove {
|
||||
id: Uuid,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
SendClients {
|
||||
to: Uuid,
|
||||
},
|
||||
SendMessage {
|
||||
from: Uuid,
|
||||
to: Uuid,
|
||||
content: String,
|
||||
},
|
||||
BroadcastGlobalMessage {
|
||||
from: Uuid,
|
||||
content: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ClientMessage> for ClientMgrMessage {
|
||||
fn from(msg: ClientMessage) -> Self {
|
||||
use ClientMessage::{Disconnect, IncomingGlobalMessage, IncomingMessage};
|
||||
|
||||
match msg {
|
||||
IncomingMessage { from, to, content } => ClientMgrMessage::SendMessage { from, to, content },
|
||||
IncomingGlobalMessage { from, content } => {
|
||||
ClientMgrMessage::BroadcastGlobalMessage { from, content }
|
||||
}
|
||||
Disconnect { id } => ClientMgrMessage::Remove { id },
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # ClientManager
|
||||
/// This struct manages all users connected to the server.
|
||||
///
|
||||
/// ## Attributes
|
||||
/// - clients: a vector of all clients being managed.
|
||||
/// - server_channel: a channel to the parent that manages this object.
|
||||
/// - tx: the sender that clients will send their messages to.
|
||||
/// - rx: the receiver where messages are sent to.
|
||||
pub struct ClientManager<Out: 'static>
|
||||
where
|
||||
Out: From<ClientMgrMessage> + Send,
|
||||
{
|
||||
pub clients: Mutex<HashMap<Uuid, Arc<Client<ClientMgrMessage>>>>,
|
||||
|
||||
#[allow(dead_code)]
|
||||
server_channel: Mutex<Sender<Out>>,
|
||||
|
||||
tx: Sender<ClientMgrMessage>,
|
||||
rx: Mutex<Receiver<ClientMgrMessage>>,
|
||||
}
|
||||
|
||||
impl<Out> ClientManager<Out>
|
||||
where
|
||||
Out: From<ClientMgrMessage> + Send,
|
||||
{
|
||||
pub fn new(out_channel: Sender<Out>) -> Arc<Self> {
|
||||
let (tx, rx) = channel(1024);
|
||||
|
||||
Arc::new(ClientManager {
|
||||
clients: Mutex::default(),
|
||||
|
||||
server_channel: Mutex::new(out_channel),
|
||||
|
||||
tx,
|
||||
rx: Mutex::new(rx),
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_count(&self) -> usize {
|
||||
self.clients.lock().await.len()
|
||||
}
|
||||
|
||||
pub async fn add_client(
|
||||
&self,
|
||||
id: Uuid,
|
||||
username: String,
|
||||
address: String,
|
||||
connection: Arc<Connection>,
|
||||
) {
|
||||
let client = Client::new(id, username, address, self.tx.clone(), connection);
|
||||
client.start();
|
||||
let mut lock = self.clients.lock().await;
|
||||
lock.insert(client.details.uuid, client);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn remove_client(&self, id: Uuid) {
|
||||
let mut lock = self.clients.lock().await;
|
||||
lock.remove(&id);
|
||||
}
|
||||
|
||||
pub async fn handle_channel(&self, message: Option<ClientMgrMessage>) {
|
||||
use ClientMgrMessage::{BroadcastGlobalMessage, Remove, SendClients, SendMessage};
|
||||
println!("Handling channel");
|
||||
match message {
|
||||
Some(Remove { id }) => {
|
||||
println!("[Client Manager]: removing client: {:?}", &id);
|
||||
let mut lock = self.clients.lock().await;
|
||||
lock.remove(&id);
|
||||
}
|
||||
Some(SendClients { to: _ }) => {
|
||||
let lock = self.clients.lock().await;
|
||||
let futures = lock
|
||||
.iter()
|
||||
.map(|(_, _)| async { println!("Send message to Client") });
|
||||
join_all(futures).await;
|
||||
}
|
||||
Some(BroadcastGlobalMessage { from, content }) => {
|
||||
let lock = self.clients.lock().await;
|
||||
let futures =
|
||||
lock
|
||||
.iter()
|
||||
.map(|(_, c)| (c.clone(), content.clone()))
|
||||
.map(|(c, s)| async move {
|
||||
c.broadcast_message(from, s).await.unwrap();
|
||||
});
|
||||
join_all(futures).await;
|
||||
}
|
||||
Some(SendMessage { from, to, content }) => {
|
||||
let lock = self.clients.lock().await;
|
||||
let client = lock.get(&to).unwrap();
|
||||
let _ = client.user_message(from, content).await;
|
||||
}
|
||||
Some(Remove { id }) => {
|
||||
self.clients.lock().await.remove(&id);
|
||||
}
|
||||
_ => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Out> IManager for ClientManager<Out>
|
||||
where
|
||||
Out: From<ClientMgrMessage> + Send,
|
||||
{
|
||||
async fn run(self: &Arc<Self>) {
|
||||
loop {
|
||||
let mut receiver = self.rx.lock().await;
|
||||
|
||||
select! {
|
||||
val = receiver.recv() => {
|
||||
self.handle_channel(val).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::client_manager::{ClientManager, ClientMgrMessage};
|
||||
use foundation::messages::client::ClientStreamOut;
|
||||
use foundation::prelude::IManager;
|
||||
use foundation::test::create_connection_pair;
|
||||
use std::io::Error;
|
||||
use tokio::sync::mpsc::channel;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tokio::test]
|
||||
async fn add_new_client_to_manager() -> Result<(), Error> {
|
||||
let (sender, mut receiver) = channel::<ClientMgrMessage>(1024);
|
||||
let (server, (client, addr)) = create_connection_pair().await?;
|
||||
|
||||
let client_manager = ClientManager::new(sender);
|
||||
client_manager.start();
|
||||
|
||||
let id = Uuid::new_v4();
|
||||
let username = "TestUser".to_string();
|
||||
|
||||
client_manager
|
||||
.add_client(id, username.clone(), addr.to_string(), server)
|
||||
.await;
|
||||
|
||||
assert_eq!(client_manager.get_count().await, 1);
|
||||
let msg = client.read::<ClientStreamOut>().await?;
|
||||
assert_eq!(msg, ClientStreamOut::Connected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
use crate::client::Client;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub enum EventType<'a> {
|
||||
NewConnection,
|
||||
// Todo: - change client to use traits
|
||||
ClientAdded(Uuid),
|
||||
Custom(&'a str),
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// mod chat_manager;
|
||||
mod client;
|
||||
mod client_manager;
|
||||
mod event_type;
|
||||
mod lua;
|
||||
mod messages;
|
||||
mod network;
|
||||
mod network_manager;
|
||||
// pub mod plugin;
|
||||
mod prelude;
|
||||
mod server;
|
||||
|
||||
pub use server::Server;
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
// pub mod chat_manager;
|
||||
pub mod client;
|
||||
pub mod client_manager;
|
||||
mod event_type;
|
||||
mod lua;
|
||||
pub mod messages;
|
||||
mod network;
|
||||
pub mod network_manager;
|
||||
// mod plugin;
|
||||
mod prelude;
|
||||
pub mod server;
|
||||
|
||||
use std::io;
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
use server::Server;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
let server = Server::new().await.unwrap();
|
||||
|
||||
server.start().await;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
/// # ClientMessage
|
||||
///
|
||||
/// These messages are send from the client to a receiver
|
||||
/// when events from the client happen that need to be delegated
|
||||
///
|
||||
/// ## Variants
|
||||
///
|
||||
///
|
||||
/// ## Methods
|
||||
///
|
||||
#[derive(Debug)]
|
||||
pub enum ClientMessage {
|
||||
#[allow(dead_code)]
|
||||
Connected,
|
||||
|
||||
#[allow(dead_code)]
|
||||
IncomingMessage {
|
||||
from: Uuid,
|
||||
to: Uuid,
|
||||
content: String,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
IncomingGlobalMessage {
|
||||
from: Uuid,
|
||||
content: String,
|
||||
},
|
||||
#[allow(dead_code)]
|
||||
RequestedUpdate {
|
||||
from: Uuid,
|
||||
},
|
||||
|
||||
Disconnect {
|
||||
id: Uuid,
|
||||
},
|
||||
|
||||
Error,
|
||||
}
|
||||
|
||||
impl PartialEq for ClientMessage {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
use ClientMessage::{Connected, Disconnect, Error};
|
||||
|
||||
match (self, other) {
|
||||
(Connected, Connected) => true,
|
||||
(Error, Error) => true,
|
||||
(Disconnect { id, .. }, Disconnect { id: other_id, .. }) => id == other_id,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,257 +0,0 @@
|
|||
use std::io::{Error, ErrorKind};
|
||||
use std::sync::Arc;
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::select;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use foundation::connection::Connection;
|
||||
|
||||
use foundation::messages::network::{NetworkSockIn, NetworkSockOut};
|
||||
use foundation::prelude::IManager;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NetworkManagerMessage {
|
||||
ClientConnecting {
|
||||
uuid: Uuid,
|
||||
address: String,
|
||||
username: String,
|
||||
|
||||
connection: Arc<Connection>,
|
||||
},
|
||||
}
|
||||
|
||||
impl PartialEq for NetworkManagerMessage {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
use NetworkManagerMessage::ClientConnecting;
|
||||
|
||||
match (self, other) {
|
||||
(
|
||||
ClientConnecting {
|
||||
uuid,
|
||||
address,
|
||||
username,
|
||||
..
|
||||
},
|
||||
ClientConnecting {
|
||||
uuid: other_uuid,
|
||||
address: other_address,
|
||||
username: other_username,
|
||||
..
|
||||
},
|
||||
) => uuid == other_uuid && address == other_address && username == other_username,
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # NetworkManager
|
||||
///
|
||||
/// This handles all new incoming connections to the server, involved with the chat services.
|
||||
///
|
||||
/// ## Fields
|
||||
/// - address: the socket address that the server is listening on.
|
||||
/// - listener: the TcpListener that is receiving connections.
|
||||
/// - out_channel: the channel that will be sent events from NetworkManager.
|
||||
pub struct NetworkManager<Out>
|
||||
where
|
||||
Out: From<NetworkManagerMessage> + Send,
|
||||
{
|
||||
listener: Mutex<TcpListener>,
|
||||
out_channel: Sender<Out>,
|
||||
}
|
||||
|
||||
impl<Out> NetworkManager<Out>
|
||||
where
|
||||
Out: From<NetworkManagerMessage> + Send,
|
||||
{
|
||||
pub async fn new(
|
||||
address: &str,
|
||||
out_channel: Sender<Out>,
|
||||
) -> Result<Arc<NetworkManager<Out>>, Error> {
|
||||
let listener = TcpListener::bind(address).await?;
|
||||
|
||||
Ok(Arc::new(NetworkManager {
|
||||
listener: Mutex::new(listener),
|
||||
out_channel,
|
||||
}))
|
||||
}
|
||||
|
||||
/// This fetches the port from the NetworkManager
|
||||
pub async fn port(&self) -> u16 {
|
||||
self.listener.lock().await.local_addr().unwrap().port()
|
||||
}
|
||||
|
||||
/// This fetches the IP address from the NetworkManager
|
||||
#[allow(dead_code)]
|
||||
pub async fn address(&self) -> String {
|
||||
self
|
||||
.listener
|
||||
.lock()
|
||||
.await
|
||||
.local_addr()
|
||||
.unwrap()
|
||||
.ip()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
async fn handle_connection(&self, connection: Arc<Connection>) -> Result<(), Error> {
|
||||
use NetworkSockIn::{Connect, Info};
|
||||
use NetworkSockOut::{Connecting, GotInfo, Request};
|
||||
|
||||
connection.write(Request).await?;
|
||||
|
||||
match connection.read().await? {
|
||||
Info => {
|
||||
connection
|
||||
.write(GotInfo {
|
||||
server_name: "TestServer".into(),
|
||||
server_owner: "Michael".into(),
|
||||
})
|
||||
.await?
|
||||
}
|
||||
Connect {
|
||||
uuid,
|
||||
address,
|
||||
username,
|
||||
} => {
|
||||
connection.write(Connecting).await?;
|
||||
|
||||
let _ = self
|
||||
.out_channel
|
||||
.send(
|
||||
NetworkManagerMessage::ClientConnecting {
|
||||
uuid,
|
||||
address,
|
||||
username,
|
||||
|
||||
connection,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
"Did not receive valid message",
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<Out: 'static> IManager for NetworkManager<Out>
|
||||
where
|
||||
Out: From<NetworkManagerMessage> + Send,
|
||||
{
|
||||
async fn run(self: &Arc<Self>) {
|
||||
let lock = self.listener.lock().await;
|
||||
|
||||
select! {
|
||||
val = lock.accept() => {
|
||||
if let Ok((stream, _addr)) = val {
|
||||
let conn = self.clone();
|
||||
tokio::spawn(async move {
|
||||
let _ = conn.handle_connection(Arc::new(stream.into())).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::network_manager::{
|
||||
NetworkManager, NetworkManagerMessage, NetworkManagerMessage::ClientConnecting,
|
||||
};
|
||||
use foundation::connection::Connection;
|
||||
use foundation::messages::network::NetworkSockIn::{Connect, Info};
|
||||
use foundation::messages::network::NetworkSockOut;
|
||||
use foundation::messages::network::NetworkSockOut::{Connecting, GotInfo, Request};
|
||||
use foundation::prelude::IManager;
|
||||
use std::io::Error;
|
||||
use tokio::sync::mpsc::channel;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_network_fetch_info() -> Result<(), Error> {
|
||||
let (tx, _rx) = channel::<NetworkManagerMessage>(16);
|
||||
|
||||
let network_manager = NetworkManager::new("localhost:0", tx).await?;
|
||||
network_manager.start();
|
||||
let port = network_manager.port().await;
|
||||
|
||||
let client = Connection::new();
|
||||
client.connect(format!("localhost:{}", port)).await?;
|
||||
|
||||
assert_eq!(client.read::<NetworkSockOut>().await?, Request);
|
||||
client.write(Info).await?;
|
||||
|
||||
let out = client.read::<NetworkSockOut>().await?;
|
||||
assert_eq!(
|
||||
out,
|
||||
GotInfo {
|
||||
server_owner: "Michael".into(),
|
||||
server_name: "TestServer".into()
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_network_login() -> Result<(), Error> {
|
||||
let (tx, mut rx) = channel::<NetworkManagerMessage>(16);
|
||||
let network_manager = NetworkManager::new("localhost:0", tx).await?;
|
||||
network_manager.start();
|
||||
|
||||
let port = network_manager.port().await;
|
||||
let client = Connection::new();
|
||||
client.connect(format!("localhost:{}", port)).await?;
|
||||
|
||||
assert_eq!(client.read::<NetworkSockOut>().await?, Request);
|
||||
|
||||
// construct client data
|
||||
let uuid = Uuid::new_v4();
|
||||
let address = "localhost";
|
||||
let username = "TestUser";
|
||||
|
||||
client
|
||||
.write(Connect {
|
||||
uuid,
|
||||
address: address.to_string(),
|
||||
username: username.to_string(),
|
||||
})
|
||||
.await?;
|
||||
|
||||
let res: NetworkSockOut = client.read().await?;
|
||||
|
||||
assert_eq!(res, Connecting);
|
||||
|
||||
let network_out = rx.recv().await.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
network_out,
|
||||
ClientConnecting {
|
||||
uuid,
|
||||
address: address.to_string(),
|
||||
username: username.to_string(),
|
||||
connection: client
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
use foundation::connection::Connection;
|
||||
use std::io::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use tokio::sync::{
|
||||
mpsc::{channel, Receiver},
|
||||
Mutex,
|
||||
};
|
||||
|
||||
// use crate::plugin::{PluginManager, PluginManagerMessage};
|
||||
use crate::{
|
||||
client_manager::{ClientManager, ClientMgrMessage},
|
||||
network_manager::{NetworkManager, NetworkManagerMessage},
|
||||
};
|
||||
|
||||
use foundation::prelude::IManager;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ServerMessage {
|
||||
ClientConnected {
|
||||
uuid: Uuid,
|
||||
address: String,
|
||||
username: String,
|
||||
connection: Arc<Connection>,
|
||||
},
|
||||
BroadcastGlobalMessage {
|
||||
from: Uuid,
|
||||
content: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<NetworkManagerMessage> for ServerMessage {
|
||||
fn from(msg: NetworkManagerMessage) -> Self {
|
||||
use NetworkManagerMessage::ClientConnecting;
|
||||
|
||||
match msg {
|
||||
ClientConnecting {
|
||||
uuid,
|
||||
address,
|
||||
username,
|
||||
connection,
|
||||
} => ServerMessage::ClientConnected {
|
||||
uuid,
|
||||
address,
|
||||
username,
|
||||
connection,
|
||||
},
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ClientMgrMessage> for ServerMessage {
|
||||
fn from(msg: ClientMgrMessage) -> Self {
|
||||
use ClientMgrMessage::BroadcastGlobalMessage;
|
||||
|
||||
match msg {
|
||||
BroadcastGlobalMessage { from, content } => {
|
||||
ServerMessage::BroadcastGlobalMessage { from, content }
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl From<PluginManagerMessage> for ServerMessage {
|
||||
// fn from(_: PluginManagerMessage) -> Self {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
|
||||
/// # Server
|
||||
/// authors: @michael-bailey, @Mitch161
|
||||
/// This Represents a server instance.
|
||||
/// It is composed of a client manager and a network manager.
|
||||
///
|
||||
/// # Attributes
|
||||
/// - client_manager: The servers client manager.
|
||||
/// - network_manager: The servers network manager.
|
||||
/// - receiver: The servers channel for communication by managers.
|
||||
/// - lua: The servers lua context, used for running lua scripts.
|
||||
///
|
||||
pub struct Server {
|
||||
pub client_manager: Arc<ClientManager<ServerMessage>>,
|
||||
network_manager: Arc<NetworkManager<ServerMessage>>,
|
||||
// plugin_manager: Arc<PluginManager<ServerMessage>>,
|
||||
receiver: Mutex<Receiver<ServerMessage>>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
/// Create a new server object
|
||||
pub async fn new() -> Result<Arc<Server>, Error> {
|
||||
let (sender, receiver) = channel(1024);
|
||||
|
||||
let server = Arc::new(Server {
|
||||
client_manager: ClientManager::new(sender.clone()),
|
||||
network_manager: NetworkManager::new("0.0.0.0:5600", sender.clone()).await?,
|
||||
// plugin_manager: PluginManager::new(sender),
|
||||
receiver: Mutex::new(receiver),
|
||||
});
|
||||
|
||||
Ok(server)
|
||||
}
|
||||
|
||||
pub async fn port(self: &Arc<Server>) -> u16 {
|
||||
self.network_manager.port().await
|
||||
}
|
||||
|
||||
pub async fn start(self: &Arc<Server>) {
|
||||
// start client manager and network manager
|
||||
self.network_manager.clone().start();
|
||||
self.client_manager.clone().start();
|
||||
// let _ = self.plugin_manager.clone().load().await;
|
||||
|
||||
// clone block items
|
||||
let server = self.clone();
|
||||
|
||||
loop {
|
||||
let mut lock = server.receiver.lock().await;
|
||||
if let Some(message) = lock.recv().await {
|
||||
println!("[server]: received message {:?}", &message);
|
||||
|
||||
match message {
|
||||
ServerMessage::ClientConnected {
|
||||
uuid,
|
||||
address,
|
||||
username,
|
||||
connection,
|
||||
} => {
|
||||
server
|
||||
.client_manager
|
||||
.add_client(uuid, username, address, connection)
|
||||
.await
|
||||
}
|
||||
ServerMessage::BroadcastGlobalMessage {
|
||||
from: _,
|
||||
content: _,
|
||||
} => {
|
||||
// server
|
||||
// .client_manager
|
||||
// .clone()
|
||||
// .send_message(
|
||||
// ClientMgrMessage::BroadcastGlobalMessage {sender, content}
|
||||
// ).await
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue