Merge branch 'feature/lua-support' into develop

This commit is contained in:
michael-bailey 2022-07-04 08:30:27 +01:00
commit fe960a2018
32 changed files with 694 additions and 301 deletions

View File

@ -17,7 +17,7 @@ use uuid::Uuid;
* address: the ip address of the connected user.
* public_key: the public key used when sending messages to the user.
*/
#[derive(Deserialize, Serialize, Debug, Clone)]
#[derive(Deserialize, Serialize, Debug, Clone, Default)]
pub struct ClientDetails {
pub uuid: Uuid,
pub username: String,

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.1", features=["lua54", "async", "serde", "macros", "vendored"] }
libloading = "0.7"
toml = "0.4.2"
aquamarine = "0.1.11"

View File

@ -1,73 +1,18 @@
use actix::{Actor, Addr, AsyncContext, Context, Handler, Recipient};
use foundation::ClientDetails;
use foundation::messages::client::ClientStreamIn;
use std::net::SocketAddr;
use actix::{
Actor,
Addr,
ArbiterHandle,
AsyncContext,
Context,
Handler,
Message,
MessageResponse,
Recipient,
Running,
WeakAddr,
};
use foundation::{
messages::client::{ClientStreamIn, ClientStreamOut},
ClientDetails,
};
use serde_json::{from_str, to_string};
use uuid::Uuid;
use crate::{
client_management::client::ClientObservableMessage::{
SendGlobalMessageRequest,
SendMessageRequest,
UpdateRequest,
},
network::{
Connection,
ConnectionMessage,
ConnectionMessage::SendData,
ConnectionOuput,
},
prelude::{
messages::ObservableMessage,
messages::ObservableMessage::{Subscribe, Unsubscribe},
},
};
/// Message sent ot the clients delegate
#[derive(Message)]
#[rtype(result = "()")]
pub enum ClientMessage {
SendUpdate(Vec<ClientDetails>),
SendMessage { from: Uuid, content: String },
SendGlobalMessage { from: Uuid, content: String },
}
#[derive(Message)]
#[rtype(result = "ClientDetailsResponse")]
pub struct ClientDataMessage;
#[derive(MessageResponse)]
pub struct ClientDetailsResponse(pub ClientDetails);
use crate::client_management::client::messages::{ClientDataMessage, ClientDataResponse, ClientMessage, ClientObservableMessage};
use crate::client_management::client::messages::ClientObservableMessage::{SendGlobalMessageRequest, SendMessageRequest, UpdateRequest};
use crate::network::{Connection, ConnectionOuput};
use crate::prelude::messages::ObservableMessage;
/// messages the client will send to itself
enum SelfMessage {
ReceivedMessage(ClientStreamIn),
}
/// message that is sent to all observers of the current client.
#[derive(Message, Clone)]
#[rtype(result = "()")]
pub enum ClientObservableMessage {
SendMessageRequest(WeakAddr<Client>, Uuid, String),
SendGlobalMessageRequest(WeakAddr<Client>, String),
UpdateRequest(WeakAddr<Client>),
}
/// # Client
/// This represents a connected client.
/// it will handle received message from a connection.
@ -97,12 +42,13 @@ impl Client {
addr: SocketAddr,
data: String,
) {
use ClientStreamIn::{
use foundation::messages::client::ClientStreamIn::{
Disconnect,
SendGlobalMessage,
SendMessage,
Update,
};
use serde_json::from_str;
let msg = from_str::<ClientStreamIn>(data.as_str())
.expect("[Client] failed to decode incoming message");
match msg {
@ -161,8 +107,12 @@ impl Actor for Client {
// tells the client that it has been connected.
fn started(&mut self, ctx: &mut Self::Context) {
use ClientStreamOut::Connected;
use ConnectionMessage::SendData;
use foundation::messages::client::ClientStreamOut::Connected;
use serde_json::to_string;
use foundation::messages::client::ClientStreamOut;
use crate::network::ConnectionMessage::SendData;
use crate::network::ConnectionOuput;
use crate::prelude::messages::ObservableMessage::Subscribe;
println!("[Client] started");
self.connection
.do_send::<ObservableMessage<ConnectionOuput>>(Subscribe(ctx.address().recipient()));
@ -172,8 +122,12 @@ impl Actor for Client {
}
fn stopped(&mut self, ctx: &mut Self::Context) {
use ClientStreamOut::Disconnected;
use ConnectionMessage::SendData;
use foundation::messages::client::ClientStreamOut::Disconnected;
use serde_json::to_string;
use foundation::messages::client::ClientStreamOut;
use crate::network::ConnectionMessage::SendData;
use crate::network::ConnectionOuput;
use crate::prelude::messages::ObservableMessage::Unsubscribe;
self.connection
.do_send::<ObservableMessage<ConnectionOuput>>(Unsubscribe(ctx.address().recipient()));
self.connection.do_send(SendData(
@ -183,13 +137,16 @@ impl Actor for Client {
}
impl Handler<ClientDataMessage> for Client {
type Result = ClientDetailsResponse;
type Result = ClientDataResponse;
fn handle(
&mut self,
msg: ClientDataMessage,
ctx: &mut Self::Context,
) -> Self::Result {
ClientDetailsResponse(self.details.clone())
match msg {
ClientDataMessage::Details => ClientDataResponse::Details(self.details.clone()),
_ => todo!()
}
}
}
@ -201,8 +158,11 @@ impl Handler<ClientMessage> for Client {
msg: ClientMessage,
_ctx: &mut Self::Context,
) -> Self::Result {
use ClientMessage::{SendGlobalMessage, SendMessage, SendUpdate};
use ClientStreamOut::{ConnectedClients, GlobalMessage, UserMessage};
use crate::client_management::client::messages::ClientMessage::{SendGlobalMessage, SendMessage, SendUpdate};
use foundation::messages::client::ClientStreamOut::{ConnectedClients, GlobalMessage, UserMessage};
use serde_json::to_string;
use foundation::messages::client::ClientStreamOut;
use crate::network::ConnectionMessage::SendData;
match msg {
SendUpdate(clients) => self.connection.do_send(SendData(
@ -236,7 +196,7 @@ impl Handler<ConnectionOuput> for Client {
msg: ConnectionOuput,
ctx: &mut Self::Context,
) -> Self::Result {
use ConnectionOuput::RecvData;
use crate::network::ConnectionOuput::RecvData;
match msg {
RecvData(sender, addr, data) => {
self.handle_request(ctx, sender, addr, data)
@ -255,7 +215,7 @@ impl Handler<ObservableMessage<ClientObservableMessage>> for Client {
msg: ObservableMessage<ClientObservableMessage>,
ctx: &mut Self::Context,
) -> Self::Result {
use ObservableMessage::{Subscribe, Unsubscribe};
use crate::prelude::messages::ObservableMessage::{Subscribe, Unsubscribe};
match msg {
Subscribe(r) => {
println!("[Client] adding subscriber");

View File

@ -0,0 +1,39 @@
use actix::{WeakAddr, Message, MessageResponse};
use uuid::Uuid;
use foundation::ClientDetails;
use crate::client_management::client::client::Client;
/// Message sent ot the clients delegate
#[derive(Message)]
#[rtype(result = "()")]
pub enum ClientMessage {
SendUpdate(Vec<ClientDetails>),
SendMessage { from: Uuid, content: String },
SendGlobalMessage { from: Uuid, content: String },
}
#[derive(Message)]
#[rtype(result = "ClientDataResponse")]
pub enum ClientDataMessage {
Details,
Uuid,
Username,
Address,
}
#[derive(MessageResponse)]
pub enum ClientDataResponse {
Details(ClientDetails),
Uuid(Uuid),
Username(String),
Address(String),
}
/// message that is sent to all observers of the current client.
#[derive(Message, Clone)]
#[rtype(result = "()")]
pub enum ClientObservableMessage {
SendMessageRequest(WeakAddr<Client>, Uuid, String),
SendGlobalMessageRequest(WeakAddr<Client>, String),
UpdateRequest(WeakAddr<Client>),
}

View File

@ -0,0 +1,5 @@
mod messages;
mod client;
pub use messages::*;
pub use client::{Client};

View File

@ -1,7 +1,6 @@
use std::collections::HashMap;
use actix::{
fut::{wrap_future, wrap_stream},
Actor,
ActorFutureExt,
ActorStreamExt,
@ -9,6 +8,7 @@ use actix::{
ArbiterHandle,
AsyncContext,
Context,
fut::{wrap_future, wrap_stream},
Handler,
MailboxError,
Message,
@ -20,39 +20,23 @@ use actix::{
WeakRecipient,
};
use foundation::{
messages::client::{ClientStreamIn, ClientStreamIn::SendGlobalMessage},
ClientDetails,
messages::client::{ClientStreamIn, ClientStreamIn::SendGlobalMessage},
};
use futures::{SinkExt, TryStreamExt};
use tokio_stream::StreamExt;
use uuid::Uuid;
use crate::{
client_management::{
client::{
ClientDataMessage,
ClientMessage,
ClientMessage::SendMessage,
ClientObservableMessage,
},
Client,
},
network::NetworkOutput,
prelude::messages::ObservableMessage,
};
#[derive(Message)]
#[rtype(result = "()")]
pub(crate) enum ClientManagerMessage {
AddClient(Uuid, Addr<Client>),
RemoveClient(Uuid),
}
#[derive(Message)]
#[rtype(result = "()")]
pub enum ClientManagerOutput {
UpdateRequest(Addr<ClientManager>),
}
use crate::client_management::client::{Client, ClientDataResponse};
use crate::client_management::client::{ClientDataMessage, ClientMessage, ClientObservableMessage};
use crate::client_management::client::ClientDataResponse::Details;
use crate::client_management::client::ClientMessage::SendMessage;
use crate::client_management::messages::{ClientManagerDataMessage, ClientManagerDataResponse, ClientManagerMessage, ClientManagerOutput};
use crate::client_management::messages::ClientManagerDataResponse::{ClientCount, Clients};
pub struct ClientManager {
clients: HashMap<Uuid, Addr<Client>>,
@ -60,22 +44,31 @@ pub struct ClientManager {
}
impl ClientManager {
pub(crate) fn new(
delegate: WeakRecipient<ClientManagerOutput>,
) -> Addr<Self> {
ClientManager {
delegate,
clients: HashMap::new(),
}
.start()
}
pub(crate) fn send_update(
&mut self,
ctx: &mut Context<Self>,
addr: WeakAddr<Client>,
) {
println!("[ClientManager] sending update to client");
use ClientMessage::SendUpdate;
use crate::client_management::client::ClientMessage::SendUpdate;
let self_addr = ctx.address();
if let Some(to_send) = addr.upgrade() {
let client_addr: Vec<Addr<Client>> =
self.clients.iter().map(|(_, v)| v).cloned().collect();
let collection = tokio_stream::iter(client_addr)
.then(|addr| addr.send(ClientDataMessage))
.map(|val| val.unwrap().0)
// .filter(|val| )
.then(|addr| addr.send(ClientDataMessage::Details))
.map(|val| if let Details(details) = val.unwrap() { details } else { ClientDetails::default() })
.collect();
let fut = wrap_future(async move {
@ -99,18 +92,30 @@ impl ClientManager {
self.clients.iter().map(|(_, v)| v).cloned().collect();
let collection = tokio_stream::iter(client_addr)
.then(|addr| addr.send(ClientDataMessage))
.map(|val| val.unwrap().0)
.then(|addr| addr.send(ClientDataMessage::Details))
.map(|val| val.unwrap())
.map(|val: ClientDataResponse| if let Details(details) = val {
details
} else {
ClientDetails::default()
})
.collect();
let fut = wrap_future(async move {
if let Some(sender) = sender.upgrade() {
let from: Uuid =
sender.send(ClientDataMessage).await.unwrap().0.uuid;
let details: ClientDataResponse =
sender.send(ClientDataMessage::Details).await.unwrap();
let from = if let Details(details) = details {
details.uuid
} else {
ClientDetails::default().uuid
};
let client_details: Vec<ClientDetails> = collection.await;
let pos = client_details.iter().position(|i| i.uuid == from);
if let Some(pos) = pos {
sender.send(SendMessage { content, from }).await;
sender.send(SendMessage { content, from }).await.expect("TODO: panic message");
}
}
});
@ -124,14 +129,22 @@ impl ClientManager {
sender: WeakAddr<Client>,
content: String,
) {
use ClientMessage::SendGlobalMessage;
use crate::client_management::client::ClientMessage::SendGlobalMessage;
let client_addr: Vec<Addr<Client>> =
self.clients.iter().map(|(_, v)| v).cloned().collect();
if let Some(sender) = sender.upgrade() {
let fut = wrap_future(async move {
let from: Uuid =
sender.send(ClientDataMessage).await.unwrap().0.uuid;
let details: ClientDataResponse =
sender.send(ClientDataMessage::Details).await.unwrap();
let from = if let Details(details) = details {
details.uuid
} else {
ClientDetails::default().uuid
};
let collection = tokio_stream::iter(client_addr)
.then(move |addr| {
addr.send(SendGlobalMessage {
@ -145,18 +158,6 @@ impl ClientManager {
ctx.spawn(fut);
}
}
}
impl ClientManager {
pub(crate) fn new(
delegate: WeakRecipient<ClientManagerOutput>,
) -> Addr<Self> {
ClientManager {
delegate,
clients: HashMap::new(),
}
.start()
}
fn add_client(
&mut self,
@ -214,7 +215,7 @@ impl Handler<ClientObservableMessage> for ClientManager {
msg: ClientObservableMessage,
ctx: &mut Self::Context,
) -> Self::Result {
use ClientObservableMessage::{
use crate::client_management::client::ClientObservableMessage::{
SendGlobalMessageRequest,
SendMessageRequest,
UpdateRequest,
@ -231,3 +232,20 @@ impl Handler<ClientObservableMessage> for ClientManager {
}
}
}
impl Handler<ClientManagerDataMessage> for ClientManager {
type Result = ClientManagerDataResponse;
fn handle(&mut self, msg: ClientManagerDataMessage, ctx: &mut Self::Context) -> Self::Result {
match msg {
ClientManagerDataMessage::ClientCount => {
ClientCount(self.clients.values().count())
}
ClientManagerDataMessage::Clients => Clients(
self.clients.values()
.map(|a| a.downgrade())
.collect()
)
}
}
}

View File

@ -0,0 +1,30 @@
use actix::{Addr, Message, MessageResponse, WeakAddr};
use uuid::Uuid;
use crate::client_management::ClientManager;
use crate::client_management::client::Client;
#[derive(Message)]
#[rtype(result = "()")]
pub(crate) enum ClientManagerMessage {
AddClient(Uuid, Addr<Client>),
RemoveClient(Uuid),
}
#[derive(Message)]
#[rtype(result = "()")]
pub(crate) enum ClientManagerOutput {
UpdateRequest(Addr<ClientManager>),
}
#[derive(Message)]
#[rtype(result = "ClientManagerDataResponse")]
pub enum ClientManagerDataMessage {
ClientCount,
Clients
}
#[derive(MessageResponse)]
pub enum ClientManagerDataResponse {
ClientCount(usize),
Clients(Vec<WeakAddr<Client>>)
}

View File

@ -1,9 +1,12 @@
mod client;
pub mod client;
mod client_manager;
mod messages;
pub(crate) use client::Client;
pub(crate) use client_manager::{
ClientManager,
pub(crate) use client_manager::ClientManager;
pub(crate) use messages::{
ClientManagerMessage,
ClientManagerOutput,
ClientManagerDataMessage,
ClientManagerDataResponse,
};

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,78 @@
//! # lua_manager.rs
//!
//! Holds the LuaManger struct and implements it's methods
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;
/// # LuaManager
/// Holds common server objects
/// todo: change to weak references
pub struct LuaManager {
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,
network_manager,
client_manager
)
}
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();
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: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> {
LuaManager {
server: b.server,
network_manager: b.network_manager,
client_manager: b.client_manager
}.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

@ -38,5 +38,7 @@ use listener::{ListenerMessage, ListenerOutput, NetworkListener};
pub(crate) use network_manager::{
NetworkManager,
NetworkOutput,
NetworkMessage
NetworkMessage,
NetworkDataMessage,
NetworkDataOutput
};

View File

@ -1,7 +1,7 @@
use actix::Addr;
use foundation::ClientDetails;
use crate::network::Connection;
use actix::Message;
use actix::{Message, MessageResponse};
#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)]
#[rtype(result = "()")]
@ -15,4 +15,15 @@ pub enum NetworkMessage {
pub enum NetworkOutput {
NewClient(Addr<Connection>, ClientDetails),
InfoRequested(Addr<Connection>),
}
#[derive(Message, Debug, Ord, PartialOrd, Eq, PartialEq)]
#[rtype(result = "()")]
pub enum NetworkDataMessage {
IsListening
}
#[derive(MessageResponse)]
pub enum NetworkDataOutput {
IsListening(bool),
}

View File

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

View File

@ -1,6 +1,6 @@
use actix::{Actor, Addr, AsyncContext, Context, Handler, WeakRecipient};
use foundation::ClientDetails;
use crate::network::{Connection, ConnectionInitiator, InitiatorOutput};
use crate::network::{Connection, ConnectionInitiator, InitiatorOutput, NetworkDataMessage, NetworkDataOutput};
use crate::network::listener::{ListenerMessage, ListenerOutput};
use crate::network::listener::NetworkListener;
use crate::network::network_manager::Builder;
@ -135,6 +135,16 @@ impl Handler<NetworkMessage> for NetworkManager {
}
}
impl Handler<NetworkDataMessage> for NetworkManager {
type Result = ();
fn handle(&mut self, msg: NetworkDataMessage, ctx: &mut Self::Context) -> Self::Result {
match msg {
NetworkDataMessage::IsListening => NetworkDataOutput::IsListening(if self.)
}
}
}
impl Handler<ListenerOutput> for NetworkManager {
type Result = ();
fn handle(

View File

@ -7,12 +7,13 @@ pub mod actors {
//! exports all actors used in the program.
pub use crate::server::Server;
pub(crate) use crate::network::{Connection, ConnectionInitiator, NetworkManager};
pub(crate) use crate::client_management::{Client,ClientManager};
pub(crate) use crate::client_management::ClientManager;
pub(crate) use crate::client_management::client::Client;
}
pub mod messages {
//! exports all messages used in the program.
pub(crate) use super::observer::ObservableMessage;
pub(crate) use crate::network::{NetworkMessage,NetworkOutput,ConnectionMessage,ConnectionOuput};
pub(crate) use crate::client_management::{ClientManagerOutput,ClientManagerMessage};
pub(crate) use crate::network::{ConnectionMessage, ConnectionOuput, NetworkMessage, NetworkOutput};
pub(crate) use crate::client_management::{ClientManagerMessage, ClientManagerOutput};
}

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,4 @@
pub(crate) mod scriptable_server;
pub(crate) mod scriptable_network_manager;
pub(crate) mod scriptable_client_manager;
pub(crate) mod scriptable_client;

View File

@ -0,0 +1,50 @@
use actix::Addr;
use mlua::{Error, UserData, UserDataFields, UserDataMethods};
use crate::client_management::client::Client;
use crate::client_management::client::{ClientDataMessage, ClientDataResponse};
use crate::client_management::client::ClientDataResponse::{Username, Uuid};
use crate::server::ServerDataResponse::Name;
#[derive(Clone)]
pub(crate) struct ScriptableClient {
addr: Addr<Client>
}
impl UserData for ScriptableClient {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_async_method("username", |_lua, obj, ()| async move {
let name: Option<ClientDataResponse> = obj.addr.send(ClientDataMessage::Username).await.ok();
if let Some(Username(name)) = name {
Ok(name)
} else {
Err(Error::RuntimeError("Name returned null or other value".to_string()))
}
});
methods.add_async_method("uuid", |_lua, obj, ()| async move {
let uuid: Option<ClientDataResponse> = obj.addr.send(ClientDataMessage::Uuid).await.ok();
if let Some(Uuid(uuid)) = uuid {
Ok(uuid.to_string())
} else {
Err(Error::RuntimeError("Uuid returned null or other value".to_string()))
}
});
methods.add_async_method("address", |_lua, obj, ()| async move {
let address: Option<ClientDataResponse> = obj.addr.send(ClientDataMessage::Address).await.ok();
if let Some(Username(address)) = address {
Ok(address)
} else {
Err(Error::RuntimeError("address returned null or other value".to_string()))
}
});
}
}
impl From<Addr<Client>> for ScriptableClient {
fn from(addr: Addr<Client>) -> Self {
Self {
addr
}
}
}

View File

@ -0,0 +1,39 @@
use actix::{ActorStreamExt, Addr};
use mlua::{Error, UserData, UserDataFields, UserDataMethods};
use crate::client_management::{ClientManager, ClientManagerDataMessage};
use crate::client_management::ClientManagerDataResponse::Clients;
use crate::scripting::scriptable_client::ScriptableClient;
#[derive(Clone)]
pub(crate) struct ScriptableClientManager {
addr: Addr<ClientManager>
}
impl UserData for ScriptableClientManager {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_async_method("clients", |lua, obj, ()| async move {
let res = obj.addr.send(ClientManagerDataMessage::Clients).await;
if let Ok(Clients(clients)) = res {
let clients: Vec<ScriptableClient> = clients.into_iter()
.map(|a| a.upgrade())
.filter(|o| o.is_some())
.map(|o| o.unwrap())
.map(|a| ScriptableClient::from(a))
.collect();
Ok(clients)
} else {
Err(Error::RuntimeError("clients returned null or other value".to_string()))
}
})
}
}
impl From<Addr<ClientManager>> for ScriptableClientManager {
fn from(addr: Addr<ClientManager>) -> Self {
Self {
addr
}
}
}

View File

@ -0,0 +1,30 @@
use actix::Addr;
use mlua::{Error, UserData, UserDataMethods};
use crate::network::{NetworkDataMessage, NetworkManager};
use crate::network::NetworkDataOutput::IsListening;
#[derive(Clone)]
pub(crate) struct ScriptableNetworkManager {
addr: Addr<NetworkManager>
}
impl UserData for ScriptableNetworkManager {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_async_method("Listening", |_lua, obj, ()| async move {
let is_listening = obj.addr.send(NetworkDataMessage::IsListening).await.ok();
if let Some(IsListening(is_listening)) = is_listening {
Ok(is_listening)
} else {
Err(Error::RuntimeError("Uuid returned null or other value".to_string()))
}
});
}
}
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,21 @@
//! 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::{ClientManager, ClientManagerOutput};
use crate::client_management::client::Client;
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 +24,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 +76,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 +97,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 +143,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 +152,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
}
}
}