From 8ee6ba16f2f743d6b3cb5f31f2e3568cefa81680 Mon Sep 17 00:00:00 2001 From: Luuk van Oijen Date: Sun, 12 Nov 2023 15:31:15 +0100 Subject: [PATCH] very early version of plugin system --- Cargo.lock | 89 ++++++++++++++++++++++++++++ Cargo.toml | 2 + Resources/Server/TestPlugin/main.lua | 1 + TODO.md | 2 + src/server/mod.rs | 63 +++++++++++++++++++- src/server/plugins/backend_lua.rs | 38 ++++++++++++ src/server/plugins/mod.rs | 51 ++++++++++++++++ 7 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 Resources/Server/TestPlugin/main.lua create mode 100644 src/server/plugins/backend_lua.rs create mode 100644 src/server/plugins/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 2b23c74..747ffb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,6 +99,7 @@ dependencies = [ "flate2", "lazy_static", "log", + "mlua", "nalgebra", "num_enum", "pretty_env_logger", @@ -121,6 +122,16 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "bstr" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.14.0" @@ -179,6 +190,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -354,6 +371,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + [[package]] name = "http" version = "0.2.9" @@ -509,6 +535,25 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lua-src" +version = "546.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c26d4af78361e025a3d03a2b964cd1592aff7495f4d4f7947218c084c6fdca8" +dependencies = [ + "cc", +] + +[[package]] +name = "luajit-src" +version = "210.4.8+resty107baaf" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05167e8b2a2185758d83ed23541e5bd8bce37072e4204e0ef2c9b322bc87c4e" +dependencies = [ + "cc", + "which", +] + [[package]] name = "matrixmultiply" version = "0.3.8" @@ -551,6 +596,32 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "mlua" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c3a7a7ff4481ec91b951a733390211a8ace1caba57266ccb5f4d4966704e560" +dependencies = [ + "bstr", + "mlua-sys", + "num-traits", + "once_cell", + "rustc-hash", +] + +[[package]] +name = "mlua-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec8b54eddb76093069cce9eeffb4c7b3a1a0fe66962d7bd44c4867928149ca3" +dependencies = [ + "cc", + "cfg-if", + "lua-src", + "luajit-src", + "pkg-config", +] + [[package]] name = "nalgebra" version = "0.31.4" @@ -887,6 +958,12 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustix" version = "0.38.21" @@ -1356,6 +1433,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "wide" version = "0.7.13" diff --git a/Cargo.toml b/Cargo.toml index fc85191..acc616f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,5 @@ serde_json = "*" toml = "0.5" flate2 = "1.0" + +mlua = { version = "0.9.1", features = ["lua54", "vendored"] } diff --git a/Resources/Server/TestPlugin/main.lua b/Resources/Server/TestPlugin/main.lua new file mode 100644 index 0000000..a968553 --- /dev/null +++ b/Resources/Server/TestPlugin/main.lua @@ -0,0 +1 @@ +MP.print("test from lua") diff --git a/TODO.md b/TODO.md index d9e3ba7..c31bf7b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,2 +1,4 @@ # Todo List - Redo the entire download process. Currently it is very very clunky, and the implementation is terrible. It essentially acts as a second client and it would be much better if this was either implemented as part of the original client (server-sided client), or if the entire download flow was redone both client and server side. +- Implement the Lua API (and discuss wanted changes). +- Implement the auth-key stuff to have public servers be possible. diff --git a/src/server/mod.rs b/src/server/mod.rs index 9a8b898..65a0dea 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,6 +1,7 @@ use std::net::SocketAddr; use std::sync::{Arc, Mutex, atomic::{AtomicBool, Ordering}}; use std::time::Instant; +use std::collections::HashMap; use tokio::net::{TcpListener, UdpSocket}; use tokio::task::{JoinHandle, JoinSet}; @@ -13,14 +14,64 @@ mod backend; mod car; mod client; mod packet; +mod plugins; pub use backend::*; pub use car::*; pub use client::*; pub use packet::*; +pub use plugins::*; pub use crate::config::Config; +fn load_plugins() -> Vec { + let mut plugins = Vec::new(); + + for res_entry in std::fs::read_dir("Resources/Server").expect("Failed to read Resources/Server!") { + if let Ok(res_entry) = res_entry { + let res_path = res_entry.path(); + if res_path.is_dir() { + + // TODO: Fix this (split into different functions) + if let Ok(read_dir) = std::fs::read_dir(&res_path) { + for entry in read_dir { + if let Ok(entry) = entry { + let path = entry.path(); + if path.is_file() { + trace!("Found a file! Path: {:?}", path); + if let Some(filename) = path.file_name() { + let filename = filename.to_string_lossy().to_string(); + let filename = filename.split(".").next().unwrap(); + if filename == "main" { + debug!("Found a potential plugin!"); + if let Ok(src) = std::fs::read_to_string(&path) { + let extension = path.extension().map(|s| s.to_string_lossy().to_string()).unwrap_or(String::new()); + if let Some(mut backend) = match extension.as_str() { + "lua" => Some(Box::new(backend_lua::BackendLua::new())), + _ => None, + } { + debug!("Loading plugin: {:?}", res_path); + if backend.load_api().is_ok() { + if backend.load(src).is_ok() { + plugins.push(Plugin::new(backend)); + } + } + } + } + } + } + } + } + } + } + + } + } + } + + plugins +} + #[derive(PartialEq, IntoPrimitive, Copy, Clone, Debug)] #[repr(u8)] enum ServerState { @@ -49,6 +100,8 @@ pub struct Server { config: Arc, last_plist_update: Instant, + + plugins: Vec, } impl Server { @@ -68,6 +121,10 @@ impl Server { Arc::new(UdpSocket::bind(bind_addr).await?) }; + // Load existing plugins + let plugins = load_plugins(); + + // Start client runtime let clients_incoming = Arc::new(Mutex::new(Vec::new())); let clients_incoming_ref = Arc::clone(&clients_incoming); debug!("Client acception runtime starting..."); @@ -86,7 +143,7 @@ impl Server { let mut client = Client::new(socket); match client.authenticate(&cfg_ref).await { - Ok(isClient) if isClient => { + Ok(is_client) if is_client => { let mut lock = ci_ref .lock() .map_err(|e| error!("{:?}", e)) @@ -94,7 +151,7 @@ impl Server { lock.push(client); drop(lock); }, - Ok(isClient) => { + Ok(_is_client) => { debug!("Downloader?"); }, Err(e) => { @@ -134,6 +191,8 @@ impl Server { config: config, last_plist_update: Instant::now(), + + plugins, }) } diff --git a/src/server/plugins/backend_lua.rs b/src/server/plugins/backend_lua.rs new file mode 100644 index 0000000..fc80d22 --- /dev/null +++ b/src/server/plugins/backend_lua.rs @@ -0,0 +1,38 @@ +use super::Backend; +use mlua::prelude::*; + +pub struct BackendLua { + lua: Lua, +} + +impl BackendLua { + pub fn new() -> Self { + let lua = Lua::new(); + + Self { + lua, + } + } +} + +impl Backend for BackendLua { + fn load(&mut self, code: String) -> anyhow::Result<()> { + self.lua.load(code).exec().map_err(|e| { error!("[LUA] {:?}", e); e })?; + Ok(()) + } + + fn load_api(&mut self) -> anyhow::Result<()> { + let print_fn = self.lua.create_function(|_lua, (msg,): (String,)| { + info!("[LUA] {}", msg); + Ok(()) + })?; + + let api = self.lua.create_table()?; + + api.set("print", print_fn)?; + + self.lua.globals().set("MP", api)?; + + Ok(()) + } +} diff --git a/src/server/plugins/mod.rs b/src/server/plugins/mod.rs new file mode 100644 index 0000000..e25b7a8 --- /dev/null +++ b/src/server/plugins/mod.rs @@ -0,0 +1,51 @@ +pub mod backend_lua; + +use tokio::runtime::Runtime; +use tokio::sync::mpsc::{self, Sender, Receiver}; + +pub trait Backend { + fn load(&mut self, code: String) -> anyhow::Result<()>; + fn load_api(&mut self) -> anyhow::Result<()> { Ok(()) } +} + +#[derive(Debug)] +pub enum PluginBoundPluginEvent { + +} + +#[derive(Debug)] +pub enum ServerBoundPluginEvent { + PluginLoaded, +} + +pub struct Plugin { + runtime: Runtime, + tx: Sender, + rx: Receiver, +} + +impl Plugin { + pub fn new(backend: Box) -> Self { + let runtime = Runtime::new().expect("Failed to create a tokio Runtime!"); + let (pb_tx, mut pb_rx) = mpsc::channel(1_000); + let (sb_tx, sb_rx) = mpsc::channel(1_000); + runtime.spawn(async move { + if sb_tx.send(ServerBoundPluginEvent::PluginLoaded).await.is_err() { + error!("Plugin communication channels somehow already closed!"); + return; + } + loop { + if let Some(message) = pb_rx.recv().await { + debug!("Received message: {:?}", message); + } else { + return; + } + } + }); + Self { + runtime, + tx: pb_tx, + rx: sb_rx, + } + } +}