diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 77666d9..1d8a70a 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -361,6 +361,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -945,6 +955,12 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "embed-resource" version = "3.0.6" @@ -1026,6 +1042,12 @@ dependencies = [ "syn 2.0.110", ] +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "equivalent" version = "1.0.2" @@ -1185,6 +1207,7 @@ dependencies = [ "image", "keyring", "lazy_static", + "mlua", "objc2 0.6.3", "objc2-app-kit", "objc2-foundation 0.3.2", @@ -2281,6 +2304,25 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +[[package]] +name = "lua-src" +version = "547.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edaf29e3517b49b8b746701e5648ccb5785cde1c119062cbabbc5d5cd115e42" +dependencies = [ + "cc", +] + +[[package]] +name = "luajit-src" +version = "210.5.12+a4f56a4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a8e7962a5368d5f264d045a5a255e90f9aa3fc1941ae15a8d2940d42cac671" +dependencies = [ + "cc", + "which", +] + [[package]] name = "mac" version = "0.1.1" @@ -2388,6 +2430,32 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "mlua" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d111deb18a9c9bd33e1541309f4742523bfab01d276bfa9a27519f6de9c11dc7" +dependencies = [ + "bstr", + "mlua-sys", + "num-traits", + "once_cell", + "rustc-hash", +] + +[[package]] +name = "mlua-sys" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380c1f7e2099cafcf40e51d3a9f20a346977587aa4d012eae1f043149a728a93" +dependencies = [ + "cc", + "cfg-if", + "lua-src", + "luajit-src", + "pkg-config", +] + [[package]] name = "moxcms" version = "0.7.11" @@ -3624,6 +3692,12 @@ dependencies = [ "url", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -5628,6 +5702,18 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" +[[package]] +name = "which" +version = "7.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" +dependencies = [ + "either", + "env_home", + "rustix", + "winsafe", +] + [[package]] name = "winapi" version = "0.3.9" @@ -6200,6 +6286,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + [[package]] name = "wit-bindgen" version = "0.46.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b6f44f6..b68af70 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -45,6 +45,7 @@ gif = "0.14.1" raw-window-handle = "0.6" enigo = { version = "0.6.1", features = ["wayland"] } lazy_static = "1.5.0" +mlua = { version = "0.9", default-features = false, features = ["lua54", "vendored"] } [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-global-shortcut = "2" tauri-plugin-positioner = "2" diff --git a/src-tauri/src/services/modules/mod.rs b/src-tauri/src/services/modules/mod.rs index 3b59db5..a642804 100644 --- a/src-tauri/src/services/modules/mod.rs +++ b/src-tauri/src/services/modules/mod.rs @@ -1,10 +1,12 @@ use tauri::Manager; use tracing::{error, info, warn}; -use crate::get_app_handle; +use crate::{get_app_handle, lock_w}; use serde::{Deserialize, Serialize}; use serde_json; -use std::{fs, path::PathBuf}; +use std::fs; + +pub mod runtime; #[derive(Serialize, Deserialize, Debug)] pub struct ModuleMetadata { @@ -13,7 +15,7 @@ pub struct ModuleMetadata { pub description: Option, } -fn get_module_metadata(path: PathBuf) -> Option { +fn get_module_metadata(path: &std::path::Path) -> Option { let metadata_path = path.join("metadata.json"); if metadata_path.exists() { match fs::read_to_string(&metadata_path) { @@ -65,6 +67,15 @@ pub fn init_modules() { } }; + let state = lock_w!(crate::state::FDOLL); + let mut state_guard = match state.module_handles.lock() { + Ok(guard) => guard, + Err(e) => { + error!("Failed to lock module handles: {}", e); + return; + } + }; + for entry in entries { let entry = match entry { Ok(entry) => entry, @@ -76,12 +87,26 @@ pub fn init_modules() { let path = entry.path(); if path.is_dir() { - let module_metadata = match get_module_metadata(path) { + let module_metadata = match get_module_metadata(&path) { Some(metadata) => metadata, None => continue, }; - dbg!(module_metadata); - // TODO: Initialize the module based on metadata + let script_path = path.join("main.lua"); + if script_path.exists() { + match runtime::spawn_lua_runtime_from_path(&script_path) { + Ok(handle) => { + state_guard.push(handle); + } + Err(e) => { + error!( + "Failed to spawn runtime for module {}: {}", + module_metadata.name, e + ); + } + } + } else { + warn!("Module {} has no main.lua script", module_metadata.name); + } } } } diff --git a/src-tauri/src/services/modules/runtime.rs b/src-tauri/src/services/modules/runtime.rs new file mode 100644 index 0000000..bd0e4bf --- /dev/null +++ b/src-tauri/src/services/modules/runtime.rs @@ -0,0 +1,50 @@ +use mlua::{Lua, UserData, UserDataMethods}; +use std::{path::Path, thread, time::Duration}; +use tracing::{error, info}; + +pub struct Engine; + +impl UserData for Engine { + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_method("log", |_, _, message: String| { + info!("{}", message); + Ok(()) + }); + methods.add_method("sleep", |_, _, seconds: u64| { + thread::sleep(Duration::from_secs(seconds)); + Ok(()) + }); + } +} + +fn load_script(path: &Path) -> Result { + std::fs::read_to_string(path) +} + +fn setup_engine_globals(lua: &Lua) -> Result<(), mlua::Error> { + let globals = lua.globals(); + globals.set("engine", Engine) +} + +pub fn spawn_lua_runtime(script: &str) -> thread::JoinHandle<()> { + let script = script.to_string(); + + thread::spawn(move || { + let lua = Lua::new(); + + if let Err(e) = setup_engine_globals(&lua) { + error!("Failed to set engine global: {}", e); + return; + } + + if let Err(e) = lua.load(&script).exec() { + error!("Failed to execute lua script: {}", e); + return; + } + }) +} + +pub fn spawn_lua_runtime_from_path(path: &Path) -> Result, std::io::Error> { + let script = load_script(path)?; + Ok(spawn_lua_runtime(&script)) +} diff --git a/src-tauri/src/state/mod.rs b/src-tauri/src/state/mod.rs index 5c2e91a..6a0ffa8 100644 --- a/src-tauri/src/state/mod.rs +++ b/src-tauri/src/state/mod.rs @@ -19,6 +19,7 @@ pub struct AppState { pub auth: AuthState, pub user_data: AppData, pub tray: Option, + pub module_handles: std::sync::Mutex>>, } // Global application state @@ -36,6 +37,7 @@ pub fn init_app_state() { guard.network = init_network_state(); guard.auth = init_auth_state(); guard.user_data = AppData::default(); + guard.module_handles = std::sync::Mutex::new(Vec::new()); } update_display_dimensions_for_scene_state(); info!("Initialized FDOLL state (WebSocket client & user data initializing asynchronously)");