Merge branch 'feature/configuration-support' into develop
This commit is contained in:
commit
ecbc3aafb6
|
|
@ -17,3 +17,4 @@ Cargo.lock
|
|||
*.pem
|
||||
.vscode/settings.json
|
||||
*.dylib
|
||||
config_file.toml
|
||||
|
|
|
|||
|
|
@ -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"] }
|
||||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>),
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct Config {
|
||||
pub(super) port: u16,
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ pub enum NetworkOutput {
|
|||
}
|
||||
|
||||
#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[rtype(result = "()")]
|
||||
#[rtype(result = "NetworkDataOutput")]
|
||||
pub enum NetworkDataMessage {
|
||||
IsListening
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>>),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue