merge develop into master #20

Merged
michael-bailey merged 181 commits from develop into master 2023-12-01 21:48:28 +00:00
19 changed files with 408 additions and 166 deletions
Showing only changes of commit ff067f8e4b - Show all commits

View File

@ -31,7 +31,8 @@ tokio = { version = "1.9.0", features = ["full"] }
futures = "0.3.16"
async-trait = "0.1.52"
actix = "0.13"
mlua = { version = "0.7.3", features=["lua54", "async", "serde", "macros"] }
rhai = {version = "1.7.0"}
mlua = { version = "0.8.0", features=["lua54", "async", "serde", "macros", "vendored"] }
libloading = "0.7"
toml = "0.4.2"
aquamarine = "0.1.11"

33
server/src/lua/builder.rs Normal file
View File

@ -0,0 +1,33 @@
use actix::{Actor, Addr};
use mlua::Lua;
use rhai::{Engine, RegisterNativeFunction, Scope};
use crate::client_management::ClientManager;
use crate::lua::lua_manager::LuaManager;
use crate::network::NetworkManager;
use crate::Server;
pub struct Builder {
pub(crate) engine: Lua,
pub(super) server: Addr<Server>,
pub(super) network_manager: Addr<NetworkManager>,
pub(super) client_manager: Addr<ClientManager>,
}
impl Builder {
pub(super) fn new(
server: Addr<Server>,
network_manager: Addr<NetworkManager>,
client_manager: Addr<ClientManager>,
) -> Self {
Builder {
engine: Lua::new(),
server,
network_manager,
client_manager,
}
}
pub(crate) fn build(self) -> Addr<LuaManager> {
Addr::from(self)
}
}

View File

@ -1,41 +0,0 @@
use std::sync::Arc;
use mlua::prelude::LuaUserData;
use mlua::{UserDataFields, UserDataMethods};
use crate::client::Client;
use crate::messages::ClientMessage;
pub struct ClientLua<Out: 'static>(pub Arc<Client<Out>>)
where
Out: From<ClientMessage> + Send;
impl<Out> ClientLua<Out>
where
Out: From<ClientMessage> + Send
{
pub fn new(client: Arc<Client<Out>>) -> Self {
ClientLua(client)
}
}
impl<Out: 'static> LuaUserData for ClientLua<Out>
where
Out: From<ClientMessage> + Send
{
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("uuid", |_lua, this| {
Ok(this.0.details.uuid.to_string())
});
fields.add_field_method_get("username", |_lua, this| {
Ok(this.0.details.username.to_string())
});
fields.add_field_method_get("address", |_lua, this| {
Ok(this.0.details.address.to_string())
});
}
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {
}
}

View File

@ -1,63 +0,0 @@
use std::str::FromStr;
use std::sync::Arc;
use mlua::{Function, MetaMethod, Nil, ToLua, UserDataFields, UserDataMethods};
use mlua::prelude::LuaUserData;
use uuid::Uuid;
use crate::client_manager::{ClientManager, ClientMgrMessage};
use crate::lua::ClientLua;
#[derive(Clone)]
pub struct ClientManagerLua<'lua, Out: 'static>(pub Arc<ClientManager<Out>>, pub Vec<Function<'lua>>)
where
Out: From<ClientMgrMessage> + Send;
impl<Out: 'static> ClientManagerLua<'_, Out>
where
Out: From<ClientMgrMessage> + Send
{
pub fn new(manager: Arc<ClientManager<Out>>) -> Self {
ClientManagerLua(manager, Vec::new())
}
}
impl<Out: 'static> LuaUserData for ClientManagerLua<'_, Out>
where
Out: From<ClientMgrMessage> + Clone + Send
{
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
}
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_async_method("getCount", |_lua,this,()| {
let this = this.0.clone();
async move {
Ok(this.clients.lock().await.len())
}
});
methods.add_async_method("getClientList", |_lua,this,()| {
let this = this.0.clone();
async move {
let clients = this.clients.lock().await;
let clients: Vec<ClientLua<ClientMgrMessage>> = clients.iter()
.map(|(_id,c)| ClientLua::new(c.clone()))
.collect();
Ok(clients)
}
});
methods.add_async_meta_method(MetaMethod::Index, |lua, this, (index): (String)| {
let manager = this.0.clone();
async move {
if let Ok(id) = Uuid::from_str(&index) {
let map = manager.clients.lock().await;
if let Some(found) = map.get(&id) {
return Ok(ClientLua::new(found.clone()).to_lua(lua)?);
}
}
return Ok(Nil);
}
});
}
}

View File

@ -0,0 +1,89 @@
use actix::{Actor, Addr, ArbiterHandle, AsyncContext, Context, Running};
use actix::fut::wrap_future;
use mlua::{Lua, Thread, ThreadStatus};
use rhai::{Engine, Func, Scope};
use crate::client_management::ClientManager;
use crate::lua::builder::Builder;
use crate::network::NetworkManager;
use crate::scripting::scriptable_server::ScriptableServer;
use crate::Server;
pub struct LuaManager {
pub(super) engine: Lua,
pub(super) server: Addr<Server>,
pub(super) network_manager: Addr<NetworkManager>,
pub(super) client_manager: Addr<ClientManager>,
}
impl LuaManager {
pub fn create(
server: Addr<Server>,
network_manager: Addr<NetworkManager>,
client_manager: Addr<ClientManager>
) -> Builder {
Builder::new(
server.clone(),
network_manager.clone(),
client_manager.clone()
)
}
fn create_lua(&self) -> Lua {
let engine = Lua::new();
let server = ScriptableServer::from(self.server.clone());
let api = engine.create_table().unwrap();
api.set::<&str, ScriptableServer>("server", server).unwrap();
api.set::<&str, i32>("a", 12).unwrap();
engine.globals().set("chat", api).unwrap();
engine
}
}
impl Actor for LuaManager {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
let engine = self.create_lua();
ctx.spawn(wrap_future(async move {
let coroutine: Thread = engine.load(r#"
coroutine.create(function ()
print("hello lua")
print(chat.server.Test)
print(chat.server:name())
end)
"#).eval().unwrap();
let coroutine = coroutine.into_async::<(),()>(());
coroutine.await.expect("TODO: panic message");
}));
}
}
// by implementing it for the addr type,
// we enforce the actor model on the consumer of the api.
impl From<Builder> for Addr<LuaManager> {
fn from(b: Builder) -> Addr<LuaManager> {
let mgr = LuaManager {
engine: b.engine,
server: b.server.clone(),
network_manager: b.network_manager.clone(),
client_manager: b.client_manager.clone()
};
let server = ScriptableServer::from(b.server);
let api = mgr.engine.create_table().unwrap();
api.set::<&str, ScriptableServer>("server", server).unwrap();
api.set::<&str, i32>("a", 12).unwrap();
let a = api.get::<&str, i32>("a").unwrap();
println!("Lua stored: {}", a);
mgr.engine.globals().set("chat", api).unwrap();
mgr.start()
}
}

View File

@ -1,7 +1,4 @@
mod client_lua;
mod client_manager_lua;
mod server_lua;
mod lua_manager;
mod builder;
pub use client_lua::ClientLua;
pub use client_manager_lua::ClientManagerLua;
pub use server_lua::ServerLua;
pub use lua_manager::LuaManager;

View File

@ -1,38 +0,0 @@
use std::sync::Arc;
use mlua::prelude::LuaUserData;
use mlua::{UserDataFields, UserDataMethods};
use crate::lua::ClientManagerLua;
use crate::Server;
/// # ServerLua
/// A wrapper struct for making the Server lua scriptable.
///
/// # Attributes
/// - 1: A reference to the server.
#[derive(Clone)]
pub struct ServerLua(Arc<Server>);
impl ServerLua {
pub fn new(server: Arc<Server>) -> Self {
ServerLua(server)
}
}
impl LuaUserData for ServerLua {
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("ClientManager", |lua,this| {
println!("Getting count");
Ok(ClientManagerLua(this.0.client_manager.clone(), vec![]))
});
fields.add_field_method_get("NetworkManager", |lua,this| {
Ok("unimplemented")
});
fields.add_field_method_get("address", |lua,this| {
Ok("unimplemented")
});
}
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(_methods: &mut M) {
}
}

View File

@ -7,6 +7,9 @@ pub(crate) mod server;
pub(crate) mod client_management;
pub(crate) mod network;
pub(crate) mod prelude;
pub(crate) mod rhai;
pub(crate) mod lua;
pub(crate) mod scripting;
use std::env::args;
use server::Server;

View File

@ -0,0 +1,58 @@
use actix::{Actor, Addr};
use mlua::Lua;
use rhai::{Engine, RegisterNativeFunction, Scope};
use crate::client_management::ClientManager;
use crate::rhai::rhai_manager::RhaiManager;
use crate::network::NetworkManager;
use crate::Server;
pub struct Builder {
engine: Engine,
server: Addr<Server>,
network_manager: Addr<NetworkManager>,
client_manager: Addr<ClientManager>,
scope: Scope<'static>,
}
impl Builder {
pub(super) fn new(
server: Addr<Server>,
network_manager: Addr<NetworkManager>,
client_manager: Addr<ClientManager>,
) -> Self {
Builder {
engine: Engine::new(),
server,
network_manager,
client_manager,
scope: Default::default()
}
}
pub fn scope_object<T: 'static>(mut self, name: &str, obj: T) -> Self
where
T: Clone {
self.engine.register_type::<T>();
self.scope.set_value(name, obj);
self
}
pub fn scope_fn<F, A>(mut self, name: &str, func: F ) -> Self
where
F: RegisterNativeFunction<A, ()>
{
self.engine.register_fn(name, func);
self
}
pub(crate) fn build(self) -> Addr<RhaiManager> {
RhaiManager {
engine: self.engine,
scope: self.scope,
server: self.server,
network_manager: self.network_manager,
client_manager: self.client_manager
}.start()
}
}

4
server/src/rhai/mod.rs Normal file
View File

@ -0,0 +1,4 @@
mod rhai_manager;
mod builder;
pub use rhai_manager::RhaiManager;

View File

@ -0,0 +1,37 @@
use actix::{Actor, Addr, ArbiterHandle, AsyncContext, Context, Running};
use actix::fut::wrap_future;
use rhai::{Engine, Func, Scope};
use crate::client_management::ClientManager;
use crate::rhai::builder::Builder;
use crate::network::NetworkManager;
use crate::Server;
pub struct RhaiManager {
pub(super) engine: Engine,
pub(super) scope: Scope<'static>,
pub(super) server: Addr<Server>,
pub(super) network_manager: Addr<NetworkManager>,
pub(super) client_manager: Addr<ClientManager>,
}
impl RhaiManager {
pub fn create(
server: Addr<Server>,
network_manager: Addr<NetworkManager>,
client_manager: Addr<ClientManager>
) -> Builder {
Builder::new(server.clone(), network_manager.clone(), client_manager.clone())
.scope_object("server", server)
}
}
impl Actor for RhaiManager {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
self.engine.run(r#"
print("hello rhai")
"#).unwrap();
}
}

View File

@ -0,0 +1,3 @@
pub(crate) mod scriptable_server;
pub(crate) mod scriptable_network_manager;
pub(crate) mod scriptable_client_manager;

View File

@ -0,0 +1,19 @@
use actix::Addr;
use mlua::UserData;
use crate::client_management::ClientManager;
pub(crate) struct ScriptableClientManager {
addr: Addr<ClientManager>
}
impl UserData for ScriptableClientManager {
}
impl From<Addr<ClientManager>> for ScriptableClientManager {
fn from(addr: Addr<ClientManager>) -> Self {
Self {
addr
}
}
}

View File

@ -0,0 +1,19 @@
use actix::Addr;
use mlua::UserData;
use crate::network::NetworkManager;
pub(crate) struct ScriptableNetworkManager {
addr: Addr<NetworkManager>
}
impl UserData for ScriptableNetworkManager {
}
impl From<Addr<NetworkManager>> for ScriptableNetworkManager {
fn from(addr: Addr<NetworkManager>) -> Self {
Self {
addr
}
}
}

View File

@ -0,0 +1,70 @@
use actix::Addr;
use mlua::{Error, UserData, UserDataFields, UserDataMethods};
use crate::scripting::scriptable_client_manager::ScriptableClientManager;
use crate::scripting::scriptable_network_manager::ScriptableNetworkManager;
use crate::server::*;
use crate::server::ServerDataResponse::{ClientManager, Name, NetworkManager, Owner, Port};
#[derive(Clone)]
pub(crate) struct ScriptableServer {
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();
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()))
}
});
methods.add_async_method("owner", |_lua, obj, ()| async move {
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()))
}
});
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()))
}
});
}
}
impl From<Addr<Server>> for ScriptableServer {
fn from(addr: Addr<Server>) -> Self {
Self {
addr
}
}
}

View File

@ -7,7 +7,7 @@ pub struct ServerBuilder {
pub(super) owner: Option<String>,
}
impl ServerBuilder {
impl<'rhai> ServerBuilder {
pub(super) fn new() -> Self {
Self {
name: None,

View File

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

View File

@ -6,7 +6,9 @@
mod server;
mod config;
mod builder;
mod messages;
use config::ServerConfig;
pub use server::Server;
pub(crate) use builder::ServerBuilder;
pub use builder::ServerBuilder;
pub use messages::*;

View File

@ -1,13 +1,20 @@
//! 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::{Client, ClientManager, ClientManagerOutput};
use crate::client_management::ClientManagerMessage::AddClient;
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};
use crate::server::{builder, ServerBuilder, ServerDataMessage, ServerDataResponse};
use crate::server::config::ServerConfig;
/// This struct is the main actor of the server.
@ -16,18 +23,11 @@ pub struct Server {
config: ServerConfig,
network_manager: Option<Addr<NetworkManager>>,
client_management: Option<Addr<ClientManager>>,
rhai_manager: Option<Addr<RhaiManager>>,
lua_manager: Option<Addr<LuaManager>>
}
impl Server {
pub(crate) fn new() -> Addr<Self> {
Server {
config: Default::default(),
network_manager: None,
client_management: None,
}
.start()
}
pub fn create() -> builder::ServerBuilder {
ServerBuilder::new()
}
@ -75,11 +75,20 @@ impl Actor for Server {
let nm = NetworkManager::create(addr.clone().recipient())
.port(self.config.port)
.build();
self.network_manager.replace(nm);
self.network_manager.replace(nm.clone());
self.client_management.replace(ClientManager::new(
let cm = ClientManager::new(
addr.clone().recipient(),
));
);
self.client_management.replace(cm.clone());
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();
self.lua_manager.replace(lm);
if let Some(net_mgr) = self.network_manager.as_ref() {
net_mgr.do_send(NetworkMessage::StartListening);
@ -87,6 +96,21 @@ impl Actor for Server {
}
}
impl Handler<ServerDataMessage> for Server {
type Result = ServerDataResponse;
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()),
}
}
}
impl Handler<NetworkOutput> for Server {
type Result = ();
fn handle(
@ -118,7 +142,7 @@ impl Handler<ClientManagerOutput> for Server {
}
}
impl From<builder::ServerBuilder> for Server {
impl From<ServerBuilder> for Server {
fn from(builder: ServerBuilder) -> Self {
Server {
config: ServerConfig {
@ -127,7 +151,9 @@ impl From<builder::ServerBuilder> for Server {
owner: builder.owner.unwrap_or_else(|| "Default owner".to_string()),
},
network_manager: None,
client_management: None
client_management: None,
rhai_manager: None,
lua_manager: None
}
}
}