Merge branch 'feature/configuration-support' into develop

This commit is contained in:
michael-bailey 2022-09-15 08:06:01 +01:00
commit ecbc3aafb6
23 changed files with 576 additions and 248 deletions

1
.gitignore vendored
View File

@ -17,3 +17,4 @@ Cargo.lock
*.pem
.vscode/settings.json
*.dylib
config_file.toml

View File

@ -15,7 +15,7 @@ crossbeam-channel = "0.5.0"
crossbeam-queue = "0.3.1"
parking_lot = "0.11.1"
dashmap = "4.0.2"
rayon = "1.3.1"
rayon = "1.2.0"
zeroize = "1.1.0"
crossterm = "0.19.0"
log = "0.4"
@ -23,6 +23,6 @@ url = "2.2.0"
futures = "0.3.16"
serde_json = "1.0"
openssl = "0.10"
uuid = {version = "0.8", features = ["serde", "v4"]}
uuid = {version = "1.1.2", features = ["serde", "v4"]}
tokio = { version = "1.9.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }

View File

@ -19,8 +19,8 @@ name = "server"
path = "src/main.rs"
[dependencies]
clap = "3.2.5"
uuid = {version = "0.8", features = ["serde", "v4"]}
clap = {version = "3.2.5", features = ["derive"]}
uuid = {version = "1.1.2", features = ["serde", "v4"]}
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
crossbeam = "0.8.0"
@ -34,7 +34,7 @@ actix = "0.13"
rhai = {version = "1.7.0"}
mlua = { version = "0.8.1", features=["lua54", "async", "serde", "macros", "vendored"] }
libloading = "0.7"
toml = "0.4.2"
toml = "0.5.9"
aquamarine = "0.1.11"
tokio-stream = "0.1.9"

View File

@ -1,12 +1,18 @@
//! Contains code that handles the lifecycle of connected clients
//!
//! This collects all parts used by the client manager actor
//!
//! It's responsibility is:
//! - to handle client to client communication.
//! - to handle server to client communication.
//! - to handler client lifecycle events such as dicconection.
pub mod client;
mod client_manager;
mod messages;
pub(crate) use client_manager::ClientManager;
pub(crate) use messages::{
ClientManagerMessage,
ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage,
ClientManagerOutput,
ClientManagerDataMessage,
ClientManagerDataResponse,
};

View File

@ -0,0 +1,14 @@
use clap::Parser;
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
pub struct Arguments {
#[clap(short, long, value_parser = clap::value_parser!(u16).range(1..))]
pub port: Option<u16>,
#[clap(short, long, value_parser)]
pub name: Option<String>,
#[clap(short, long, value_parser)]
pub owner: Option<String>,
}

View File

@ -0,0 +1,40 @@
use actix::{Actor, Addr};
use crate::config_manager::{arg_parser::Arguments, ConfigManager};
pub(super) struct Builder {
pub(super) file_path: String,
pub(super) args: Option<Arguments>,
}
impl Builder {
pub(super) fn new() -> Self {
Self {
file_path: "./config_file.toml".to_owned(),
args: None,
}
}
#[allow(dead_code)]
pub fn config_path(mut self, path: impl Into<String>) -> Self {
self.file_path = path.into();
self
}
pub fn set_config_path(&mut self, path: impl Into<String>) {
self.file_path = path.into();
}
pub fn args(mut self, args: Arguments) -> Self {
self.args.replace(args);
self
}
pub fn set_args(&mut self, args: Arguments) {
self.args.replace(args);
}
pub(super) fn build(self) -> Addr<ConfigManager> {
ConfigManager::from(self).start()
}
}

View File

@ -0,0 +1,182 @@
use std::{
collections::BTreeMap,
fs::{File, OpenOptions},
io::Read,
sync::Once,
};
use actix::{Actor, Addr, Context, Handler, Recipient};
use clap::Parser;
use toml::Value;
use crate::{
config_manager::{
arg_parser::Arguments,
builder::Builder,
messages::{
ConfigManagerDataMessage, ConfigManagerDataResponse,
ConfigManagerOutput,
},
types::ConfigValue::{Dict, Number, String as ConfigString},
ConfigValue,
},
prelude::messages::ObservableMessage,
};
static mut SHARED: Option<Addr<ConfigManager>> = None;
static INIT: Once = Once::new();
#[allow(dead_code)]
pub(crate) struct ConfigManager {
file: File,
stored: ConfigValue,
root: ConfigValue,
subscribers: Vec<Recipient<ObservableMessage<ConfigManagerOutput>>>,
}
// static methods
impl ConfigManager {
pub fn shared() -> Addr<Self> {
INIT.call_once(|| {
let builder = Self::create().args(Arguments::parse()).build();
unsafe { SHARED = Some(builder) }
});
unsafe { SHARED.clone().unwrap() }
}
pub(super) fn create() -> Builder {
Builder::new()
}
}
// instance methods
impl ConfigManager {
pub fn get_value(&self, key: String) -> Option<ConfigValue> {
if let Dict(dict) = &self.root {
dict.get(&key).cloned()
} else {
None
}
}
pub fn set_value(
&mut self,
key: String,
value: Option<ConfigValue>,
) -> Option<ConfigValue> {
value.and_then(|value| {
if let (Dict(stored), Dict(root)) =
(&mut self.stored, &mut self.root)
{
stored.insert(key.clone(), value.clone());
root.insert(key.clone(), value.clone());
Some(value)
} else {
None
}
})
}
// this doesn't work for now
pub fn soft_set_value(
&mut self,
key: String,
value: Option<ConfigValue>,
) -> Option<ConfigValue> {
value.and_then(|value| {
if let Dict(root) = &mut self.root {
root.insert(key, value.clone());
Some(value)
} else {
None
}
})
}
}
impl Actor for ConfigManager {
type Context = Context<Self>;
fn started(&mut self, _ctx: &mut Self::Context) {
println!("[ConfigManager] starting");
println!("[ConfigManager] started");
}
}
impl Handler<ConfigManagerDataMessage> for ConfigManager {
type Result = ConfigManagerDataResponse;
fn handle(
&mut self,
msg: ConfigManagerDataMessage,
_ctx: &mut Self::Context,
) -> Self::Result {
use ConfigManagerDataResponse::{GotValue, SetValue, SoftSetValue};
match msg {
ConfigManagerDataMessage::GetValue(val) => {
GotValue(self.get_value(val))
}
ConfigManagerDataMessage::SetValue(key, value) => {
SetValue(key.clone(), self.set_value(key, value))
}
ConfigManagerDataMessage::SoftSetValue(key, value) => {
SoftSetValue(key.clone(), self.soft_set_value(key, value))
}
}
}
}
impl From<Builder> for ConfigManager {
fn from(builder: Builder) -> Self {
println!("got args: {:#?}", builder.args);
let mut file = OpenOptions::new()
.write(true)
.read(true)
.create(true)
.open(builder.file_path)
.ok()
.unwrap();
let mut output = String::new();
file.read_to_string(&mut output)
.expect("failed to read from file");
let stored = output
.parse::<Value>()
.map(|v| v.into())
.ok()
.unwrap_or_else(|| Dict(BTreeMap::new()));
let mut root = stored.clone();
if let Dict(root) = &mut root {
builder.args.map(|v| {
v.port.map(|p| {
root.insert("Network.Port".to_owned(), Number(p.into()))
});
v.name.map(|n| {
root.insert(
"Server.Name".to_owned(),
ConfigString(n.into()),
)
});
v.owner.map(|o| {
root.insert(
"Server.Owner".to_owned(),
ConfigString(o.into()),
)
});
});
}
Self {
file,
root,
stored,
subscribers: Vec::default(),
}
}
}

View File

@ -0,0 +1,23 @@
use crate::config_manager::types::ConfigValue;
use actix::{Message, MessageResponse};
#[derive(Message, Debug)]
#[rtype(result = "()")]
pub enum ConfigManagerOutput {
ConfigUpdated(String, ConfigValue),
}
#[derive(Message, Debug)]
#[rtype(result = "ConfigManagerDataResponse")]
pub enum ConfigManagerDataMessage {
GetValue(String),
SetValue(String, Option<ConfigValue>),
SoftSetValue(String, Option<ConfigValue>),
}
#[derive(MessageResponse, Debug)]
pub enum ConfigManagerDataResponse {
GotValue(Option<ConfigValue>),
SetValue(String, Option<ConfigValue>),
SoftSetValue(String, Option<ConfigValue>),
}

View File

@ -0,0 +1,15 @@
//! # config_manager
//! This module contains all the code that deals with server configuration.
//! It tries to implement a singleton actor, that will be fetchable globaly.
pub mod arg_parser;
mod builder;
mod config_manager;
mod messages;
mod types;
pub(crate) use config_manager::ConfigManager;
pub(crate) use messages::{
ConfigManagerDataMessage, ConfigManagerDataResponse,
};
pub(crate) use types::ConfigValue;

View File

@ -0,0 +1,51 @@
use std::collections::BTreeMap;
use toml::value::Value;
/// # ConfigValue
/// Each value type that can be used within a config file.
/// gets used when reading and writing to a config file.
#[derive(Clone, Debug)]
pub enum ConfigValue {
Dict(BTreeMap<String, Self>),
Array(Vec<Self>),
String(String),
Number(i64),
Float(f64),
Bool(bool),
}
impl From<ConfigValue> for Value {
fn from(v: ConfigValue) -> Self {
match v {
ConfigValue::Dict(dict) => Value::Table(
dict.into_iter().map(|(k, v)| (k, v.into())).collect(),
),
ConfigValue::Array(arr) => {
Value::Array(arr.into_iter().map(|v| v.into()).collect())
}
ConfigValue::String(s) => Value::String(s),
ConfigValue::Number(n) => Value::Integer(n),
ConfigValue::Float(f) => Value::Float(f),
ConfigValue::Bool(b) => Value::Boolean(b),
}
}
}
impl From<Value> for ConfigValue {
fn from(v: Value) -> Self {
match v {
Value::Table(dict) => ConfigValue::Dict(
dict.into_iter().map(|(k, v)| (k, v.into())).collect(),
),
Value::Array(arr) => {
ConfigValue::Array(arr.into_iter().map(|v| v.into()).collect())
}
Value::String(s) => ConfigValue::String(s),
Value::Integer(n) => ConfigValue::Number(n),
Value::Float(f) => ConfigValue::Float(f),
Value::Boolean(b) => ConfigValue::Bool(b),
Value::Datetime(d) => ConfigValue::String(d.to_string()),
}
}
}

View File

@ -1,74 +1,23 @@
//! # actor
//! This is the main module of the actix server.
//! It starts the actor runtime and then sleeps
//! for the duration of the program.
//! It starts the server and sleeps for the remainder of the program
pub(crate) mod server;
pub(crate) mod client_management;
pub(crate) mod config_manager;
pub(crate) mod lua;
pub(crate) mod network;
pub(crate) mod prelude;
pub(crate) mod rhai;
pub(crate) mod lua;
pub(crate) mod scripting;
pub(crate) mod server;
use std::env::args;
use server::Server;
use tokio::time::{sleep, Duration};
use clap::{App, Arg, value_parser};
use openssl::version::version;
use tokio::time::{sleep, Duration};
/// The main function
#[actix::main()]
async fn main() {
let args = App::new("Rust Chat Server")
.author("Michael Bailey & Mitchel Hardie")
.version("0.1.0")
.about("A chat server written in rust, with a custom json protocol, based on serde and actix")
.arg(
Arg::new("port")
.short('p')
.long("port")
.takes_value(true)
.value_parser(value_parser!(u16))
.default_value("5600")
.help("overrides the default port")
)
.arg(
Arg::new("server name")
.short('n')
.long("name")
.takes_value(true)
.help("overrides the default port of the server")
)
.arg(
Arg::new("server owner")
.short('o')
.long("owner")
.takes_value(true)
.help("overrides the owner of the server")
)
.after_help("This is a chat server made to test out writing a full application in rust \
It has evolved over time to use different frameworks\
It is currently using actix")
.get_matches();
let mut server_builder = Server::create();
if let Some(port) = args.get_one::<u16>("port") {
server_builder = server_builder.port(*port);
println!("got port number {:?}", port);
}
if let Some(name) = args.get_one::<String>("server name") {
server_builder = server_builder.name(name.clone());
println!("got server name number {:?}", name)
}
if let Some(owner) = args.get_one::<String>("server owner") {
server_builder = server_builder.owner(owner.clone());
println!("got server owner number {:?}", owner)
}
let _server = server_builder.build();
let _init = Server::create().build();
loop {
sleep(Duration::from_millis(1000)).await;
}

View File

@ -34,11 +34,8 @@ mod network_manager;
pub(crate) use connection::{Connection, ConnectionMessage, ConnectionOuput};
pub(crate) use connection_initiator::{ConnectionInitiator, InitiatorOutput};
use listener::{ListenerMessage, ListenerOutput, NetworkListener};
// use listener::{ListenerMessage, ListenerOutput, NetworkListener};
pub(crate) use network_manager::{
NetworkManager,
NetworkDataMessage, NetworkDataOutput, NetworkManager, NetworkMessage,
NetworkOutput,
NetworkMessage,
NetworkDataMessage,
NetworkDataOutput
};

View File

@ -1,26 +1,17 @@
use actix::{Actor, Addr, WeakRecipient};
use crate::network::network_manager::messages::NetworkOutput;
use crate::network::NetworkManager;
use actix::{Actor, Addr, WeakRecipient};
pub struct Builder {
pub(super) port: Option<u16>,
pub(super) delegate: WeakRecipient<NetworkOutput>,
}
impl Builder {
pub(super) fn new(delegate: WeakRecipient<NetworkOutput>) -> Self {
Self {
port: None,
delegate,
}
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
Self { delegate }
}
pub fn build(self) -> Addr<NetworkManager> {
NetworkManager::from(self).start()
}
}
}

View File

@ -1,5 +0,0 @@
#[derive(Debug)]
pub(super) struct Config {
pub(super) port: u16,
}

View File

@ -18,7 +18,7 @@ pub enum NetworkOutput {
}
#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)]
#[rtype(result = "()")]
#[rtype(result = "NetworkDataOutput")]
pub enum NetworkDataMessage {
IsListening
}

View File

@ -5,9 +5,9 @@
mod builder;
mod messages;
mod network_manager;
mod config;
use config::*;
pub(crate) use network_manager::{NetworkManager};
pub(crate) use builder::*;
pub(crate) use messages::{NetworkMessage, NetworkOutput, NetworkDataMessage, NetworkDataOutput};
pub(crate) use messages::{
NetworkDataMessage, NetworkDataOutput, NetworkMessage, NetworkOutput,
};
pub(crate) use network_manager::NetworkManager;

View File

@ -1,14 +1,29 @@
use actix::{Actor, Addr, AsyncContext, Context, Handler, WeakRecipient};
use foundation::ClientDetails;
use crate::network::{Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, NetworkDataOutput};
use crate::network::listener::{ListenerMessage, ListenerOutput};
use crate::config_manager::{
ConfigManager, ConfigManagerDataMessage, ConfigValue,
};
use crate::network::listener::NetworkListener;
use crate::network::network_manager::Builder;
use crate::network::network_manager::config::Config;
use crate::network::network_manager::messages::{NetworkMessage, NetworkOutput};
use crate::network::listener::{ListenerMessage, ListenerOutput};
use crate::network::network_manager::messages::{
NetworkMessage, NetworkOutput,
};
use crate::network::network_manager::Builder;
use crate::network::{
Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage,
NetworkDataOutput,
};
use actix::fut::wrap_future;
use actix::{
Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler, WeakAddr,
WeakRecipient,
};
use foundation::ClientDetails;
/// # NetworkManager
/// this struct will handle all networking functionality.
///
pub struct NetworkManager {
config: Config,
config_manager: WeakAddr<ConfigManager>,
listener_addr: Option<Addr<NetworkListener>>,
delegate: WeakRecipient<NetworkOutput>,
initiators: Vec<Addr<ConnectionInitiator>>,
@ -17,14 +32,12 @@ pub struct NetworkManager {
impl NetworkManager {
pub fn new(delegate: WeakRecipient<NetworkOutput>) -> Addr<NetworkManager> {
NetworkManager {
config: Config {
port: 5600
},
listener_addr: None,
delegate,
initiators: Vec::new(),
config_manager: ConfigManager::shared().downgrade(),
}
.start()
.start()
}
pub fn create(delegate: WeakRecipient<NetworkOutput>) -> Builder {
@ -33,6 +46,9 @@ impl NetworkManager {
fn start_listener(&mut self, _ctx: &mut <Self as actix::Actor>::Context) {
use ListenerMessage::StartListening;
println!("[NetworkManager] got Listen message");
if let Some(addr) = self.listener_addr.as_ref() {
addr.do_send(StartListening);
}
@ -113,10 +129,37 @@ impl Actor for NetworkManager {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
println!("[NetworkManager] started with config {:?}", self.config);
let recipient = ctx.address().recipient();
self.listener_addr
.replace(NetworkListener::new(format!("0.0.0.0:{}", self.config.port), recipient));
println!("[NetworkManager] Starting");
let config_mgr = self.config_manager.clone().upgrade();
if let Some(config_mgr) = config_mgr {
let fut = wrap_future(config_mgr.send(
ConfigManagerDataMessage::GetValue("Network.Port".to_owned()),
))
.map(
|out,
actor: &mut NetworkManager,
ctx: &mut Context<NetworkManager>| {
use crate::config_manager::ConfigManagerDataResponse::GotValue;
let recipient = ctx.address().recipient();
out.ok().map(|res| {
if let GotValue(Some(ConfigValue::Number(port))) = res {
println!("[NetworkManager] got port: {:?}", port);
let nl = NetworkListener::new(
format!("0.0.0.0:{}", port),
recipient,
);
nl.do_send(ListenerMessage::StartListening);
actor.listener_addr.replace(nl);
};
});
},
);
ctx.spawn(fut);
println!("[NetworkManager] Finished Starting");
}
}
}
@ -136,11 +179,17 @@ impl Handler<NetworkMessage> for NetworkManager {
}
impl Handler<NetworkDataMessage> for NetworkManager {
type Result = ();
type Result = NetworkDataOutput;
fn handle(&mut self, msg: NetworkDataMessage, ctx: &mut Self::Context) -> Self::Result {
fn handle(
&mut self,
msg: NetworkDataMessage,
_ctx: &mut Self::Context,
) -> Self::Result {
match msg {
NetworkDataMessage::IsListening => NetworkDataOutput::IsListening(if self.)
NetworkDataMessage::IsListening => {
NetworkDataOutput::IsListening(self.listener_addr.is_some())
}
}
}
}
@ -179,13 +228,11 @@ impl Handler<InitiatorOutput> for NetworkManager {
impl From<Builder> for NetworkManager {
fn from(builder: Builder) -> Self {
Self {
config: Config {
port: builder.port.unwrap_or_else(|| 5600),
},
listener_addr: None,
delegate: builder.delegate,
initiators: Vec::default()
initiators: Vec::default(),
config_manager: ConfigManager::shared().downgrade(),
}
}
}
}

View File

@ -1,70 +1,78 @@
use actix::Addr;
use mlua::{Error, UserData, UserDataFields, UserDataMethods};
use crate::scripting::scriptable_client_manager::ScriptableClientManager;
use crate::scripting::scriptable_network_manager::ScriptableNetworkManager;
use actix::Addr;
use mlua::{Error, UserData, UserDataMethods};
use crate::server::ServerDataResponse::{
ClientManager, Name, NetworkManager, Owner,
};
use crate::server::*;
use crate::server::ServerDataResponse::{ClientManager, Name, NetworkManager, Owner, Port};
#[derive(Clone)]
pub(crate) struct ScriptableServer {
pub(super) addr: Addr<Server>
pub(super) addr: Addr<Server>,
}
impl UserData for ScriptableServer {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_async_method("name", |_lua, obj, ()| async move {
let name: Option<ServerDataResponse> = obj.addr.send(ServerDataMessage::Name).await.ok();
let name: Option<ServerDataResponse> =
obj.addr.send(ServerDataMessage::Name).await.ok();
if let Some(Name(name)) = name {
Ok(name)
} else {
Err(Error::RuntimeError("Name returned null or other value".to_string()))
}
});
methods.add_async_method("port", |_lua, obj, ()| async move {
let port: Option<ServerDataResponse> = obj.addr.send(ServerDataMessage::Port).await.ok();
if let Some(Port(name)) = port {
Ok(name)
} else {
Err(Error::RuntimeError("Name returned null or other value".to_string()))
Err(Error::RuntimeError(
"Name returned null or other value".to_string(),
))
}
});
methods.add_async_method("owner", |_lua, obj, ()| async move {
let owner: Option<ServerDataResponse> = obj.addr.send(ServerDataMessage::Owner).await.ok();
let owner: Option<ServerDataResponse> =
obj.addr.send(ServerDataMessage::Owner).await.ok();
if let Some(Owner(name)) = owner {
Ok(name)
} else {
Err(Error::RuntimeError("Name returned null or other value".to_string()))
Err(Error::RuntimeError(
"Name returned null or other value".to_string(),
))
}
});
methods.add_async_method("client_manager", |_lua, obj, ()| async move {
let name: Option<ServerDataResponse> = obj.addr.send(ServerDataMessage::ClientManager).await.ok();
if let Some(ClientManager(Some(cm))) = name {
Ok(ScriptableClientManager::from(cm))
} else {
Err(Error::RuntimeError("Name returned null or other value".to_string()))
}
});
methods.add_async_method(
"client_manager",
|_lua, obj, ()| async move {
let name: Option<ServerDataResponse> =
obj.addr.send(ServerDataMessage::ClientManager).await.ok();
if let Some(ClientManager(Some(cm))) = name {
Ok(ScriptableClientManager::from(cm))
} else {
Err(Error::RuntimeError(
"Name returned null or other value".to_string(),
))
}
},
);
methods.add_async_method("network_manager", |_lua, obj, ()| async move {
let name: Option<ServerDataResponse> = obj.addr.send(ServerDataMessage::NetworkManager).await.ok();
if let Some(NetworkManager(Some(nm))) = name {
Ok(ScriptableNetworkManager::from(nm))
} else {
Err(Error::RuntimeError("Name returned null or other value".to_string()))
}
});
methods.add_async_method(
"network_manager",
|_lua, obj, ()| async move {
let name: Option<ServerDataResponse> =
obj.addr.send(ServerDataMessage::NetworkManager).await.ok();
if let Some(NetworkManager(Some(nm))) = name {
Ok(ScriptableNetworkManager::from(nm))
} else {
Err(Error::RuntimeError(
"Name returned null or other value".to_string(),
))
}
},
);
}
}
impl From<Addr<Server>> for ScriptableServer {
fn from(addr: Addr<Server>) -> Self {
Self {
addr
}
Self { addr }
}
}

View File

@ -1,37 +1,30 @@
use actix::{Actor, Addr};
use super::*;
use actix::{Actor, Addr};
pub struct ServerBuilder {
pub(super) name: Option<String>,
pub(super) port: Option<u16>,
pub(super) owner: Option<String>,
pub(super) name: String,
pub(super) owner: String,
}
impl<'rhai> ServerBuilder {
pub(super) fn new() -> Self {
Self {
name: None,
port: None,
owner: None,
name: "<UNKNOWN>".into(),
owner: "<UNKNOWN>".into(),
}
}
pub fn port(mut self, port: u16) -> Self {
self.port = Some(port);
self
}
pub fn name(mut self, name: String) -> Self {
self.name = Some(name);
self.name = name;
self
}
pub fn owner(mut self, owner: String) -> Self {
self.owner = Some(owner);
self.owner = owner;
self
}
pub fn build(self) -> Addr<Server> {
Server::from(self).start()
}
}
}

View File

@ -1,16 +0,0 @@
/// Configuration for the server
pub(super) struct ServerConfig {
pub(super) port: u16,
pub(super) name: String,
pub(super) owner: String,
}
impl Default for ServerConfig {
fn default() -> Self {
ServerConfig {
owner: "john_smith@example.com".to_string(),
name: "default server name".to_string(),
port: 5600,
}
}
}

View File

@ -1,13 +1,11 @@
use actix::{Addr, Message, MessageResponse};
use crate::client_management::ClientManager;
use crate::network::NetworkManager;
use actix::{Addr, Message, MessageResponse};
#[derive(Message, Clone)]
#[rtype(result = "ServerDataResponse")]
pub enum ServerDataMessage {
Name,
Port,
Owner,
ClientManager,
NetworkManager,
@ -20,4 +18,4 @@ pub enum ServerDataResponse {
Owner(String),
ClientManager(Option<Addr<ClientManager>>),
NetworkManager(Option<Addr<NetworkManager>>),
}
}

View File

@ -4,11 +4,10 @@
//! and supervisor to the actor system.
mod server;
mod config;
mod builder;
mod messages;
use config::ServerConfig;
pub use server::Server;
pub use builder::ServerBuilder;
pub use messages::*;
pub use messages::*;
pub use server::Server;

View File

@ -1,35 +1,42 @@
//! This crate holds the implementations and functions for the server
//! including server boot procedures
use actix::{Actor, ActorFutureExt, Addr, AsyncContext, Context, ContextFutureSpawner, Handler};
use actix::dev::MessageResponse;
use actix::fut::wrap_future;
use mlua::Lua;
use foundation::ClientDetails;
use foundation::messages::network::NetworkSockOut::GotInfo;
use crate::client_management::{ClientManager, ClientManagerOutput};
use crate::client_management::client::Client;
use crate::client_management::ClientManagerMessage::AddClient;
use crate::client_management::{ClientManager, ClientManagerOutput};
use crate::config_manager::{
ConfigManager, ConfigManagerDataMessage, ConfigManagerDataResponse,
ConfigValue,
};
use crate::lua::LuaManager;
use crate::rhai::RhaiManager;
use crate::network::{Connection, NetworkManager, NetworkMessage, NetworkOutput};
use crate::network::ConnectionMessage::{CloseConnection, SendData};
use crate::network::NetworkOutput::{InfoRequested, NewClient};
use crate::server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse};
use crate::server::config::ServerConfig;
use crate::network::{Connection, NetworkManager, NetworkOutput};
use crate::rhai::RhaiManager;
use crate::server::{
builder, ServerBuilder, ServerDataMessage, ServerDataResponse,
};
use actix::fut::wrap_future;
use actix::{Actor, ActorFutureExt, Addr, AsyncContext, Context, Handler};
use foundation::messages::network::NetworkSockOut::GotInfo;
use foundation::ClientDetails;
/// This struct is the main actor of the server.
/// all other actors are ran through here.
pub struct Server {
config: ServerConfig,
name: String,
owner: String,
network_manager: Option<Addr<NetworkManager>>,
client_management: Option<Addr<ClientManager>>,
client_manager: Option<Addr<ClientManager>>,
rhai_manager: Option<Addr<RhaiManager>>,
lua_manager: Option<Addr<LuaManager>>
lua_manager: Option<Addr<LuaManager>>,
}
impl Server {
pub fn create() -> builder::ServerBuilder {
pub(crate) fn create() -> builder::ServerBuilder {
ServerBuilder::new()
}
@ -39,7 +46,7 @@ impl Server {
addr: Addr<Connection>,
details: ClientDetails,
) {
if let Some(mgr) = self.client_management.as_ref() {
if let Some(mgr) = self.client_manager.as_ref() {
let client = Client::new(addr, details.clone());
mgr.do_send(AddClient(details.uuid, client));
}
@ -53,16 +60,16 @@ impl Server {
let fut = wrap_future(
sender.send(SendData(
serde_json::to_string(&GotInfo {
server_name: self.config.name.clone(),
server_owner: self.config.owner.clone(),
server_name: self.name.clone(),
server_owner: self.owner.clone(),
})
.expect("Failed to serialise"),
.expect("Failed to serialise"),
)),
)
// equivalent to using .then() in js
.map(move |_out, _act: &mut Self, _ctx| {
sender.do_send(CloseConnection);
});
// equivalent to using .then() in js
.map(move |_out, _act: &mut Self, _ctx| {
sender.do_send(CloseConnection);
});
ctx.spawn(fut);
}
}
@ -71,43 +78,73 @@ impl Actor for Server {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
use ConfigManagerDataMessage::GetValue;
use ConfigManagerDataResponse::GotValue;
let addr = ctx.address().downgrade();
let nm = NetworkManager::create(addr.clone().recipient())
.port(self.config.port)
.build();
let nm = NetworkManager::create(addr.clone().recipient()).build();
self.network_manager.replace(nm.clone());
let cm = ClientManager::new(
addr.clone().recipient(),
);
self.client_management.replace(cm.clone());
let cm = ClientManager::new(addr.clone().recipient());
self.client_manager.replace(cm.clone());
let rm = RhaiManager::create(ctx.address(), nm.clone(), cm.clone())
.build();
let rm =
RhaiManager::create(ctx.address(), nm.clone(), cm.clone()).build();
self.rhai_manager.replace(rm);
let lm = LuaManager::create(ctx.address(), nm, cm)
.build();
let lm = LuaManager::create(ctx.address(), nm, cm).build();
self.lua_manager.replace(lm);
if let Some(net_mgr) = self.network_manager.as_ref() {
net_mgr.do_send(NetworkMessage::StartListening);
}
let name_fut = wrap_future(
ConfigManager::shared().send(GetValue("Server.Name".to_owned())),
)
.map(|out, actor: &mut Server, _ctx| {
out.ok().map(|res| {
if let GotValue(Some(ConfigValue::String(val))) = res {
actor.name = val
};
});
});
let owner_fut = wrap_future(
ConfigManager::shared().send(GetValue("Server.Owner".to_owned())),
)
.map(|out, actor: &mut Server, _ctx| {
out.ok().map(|res| {
if let GotValue(Some(ConfigValue::String(val))) = res {
actor.owner = val
};
});
});
ctx.spawn(name_fut);
ctx.spawn(owner_fut);
}
}
impl Handler<ServerDataMessage> for Server {
type Result = ServerDataResponse;
fn handle(&mut self, msg: ServerDataMessage, ctx: &mut Self::Context) -> Self::Result {
fn handle(
&mut self,
msg: ServerDataMessage,
_ctx: &mut Self::Context,
) -> Self::Result {
println!("data message");
match msg {
ServerDataMessage::Name => ServerDataResponse::Name(self.config.name.clone()),
ServerDataMessage::Port => ServerDataResponse::Port(self.config.port.clone()),
ServerDataMessage::Owner => ServerDataResponse::Owner(self.config.owner.clone()),
ServerDataMessage::ClientManager => ServerDataResponse::ClientManager(self.client_management.clone()),
ServerDataMessage::NetworkManager => ServerDataResponse::NetworkManager(self.network_manager.clone()),
ServerDataMessage::Name => {
ServerDataResponse::Name(self.name.clone())
}
ServerDataMessage::Owner => {
ServerDataResponse::Owner(self.owner.clone())
}
ServerDataMessage::ClientManager => {
ServerDataResponse::ClientManager(self.client_manager.clone())
}
ServerDataMessage::NetworkManager => {
ServerDataResponse::NetworkManager(self.network_manager.clone())
}
}
}
}
@ -136,8 +173,8 @@ impl Handler<ClientManagerOutput> for Server {
fn handle(
&mut self,
msg: ClientManagerOutput,
ctx: &mut Self::Context,
_msg: ClientManagerOutput,
_ctx: &mut Self::Context,
) -> Self::Result {
todo!()
}
@ -146,15 +183,13 @@ impl Handler<ClientManagerOutput> for Server {
impl From<ServerBuilder> for Server {
fn from(builder: ServerBuilder) -> Self {
Server {
config: ServerConfig {
port: builder.port.unwrap_or(5600),
name: builder.name.unwrap_or_else(|| "Default Name".to_string()),
owner: builder.owner.unwrap_or_else(|| "Default owner".to_string()),
},
name: builder.name,
owner: builder.owner,
network_manager: None,
client_management: None,
client_manager: None,
rhai_manager: None,
lua_manager: None
lua_manager: None,
}
}
}
}