feat: got library system loading working

This commit is contained in:
Byson94
2025-10-07 20:34:44 +05:30
parent bf1b24bb95
commit 5f62a00c60
9 changed files with 96 additions and 22 deletions

17
Cargo.lock generated
View File

@@ -502,6 +502,7 @@ dependencies = [
"gtk4",
"gtk4-layer-shell",
"itertools",
"libloading",
"log",
"nix",
"notify",
@@ -1264,6 +1265,16 @@ version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "libloading"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
dependencies = [
"cfg-if",
"windows-link",
]
[[package]]
name = "libredox"
version = "0.1.3"
@@ -2331,6 +2342,12 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.48.0"

View File

@@ -50,6 +50,8 @@ tokio = { workspace = true, features = ["full"] }
unescape.workspace = true
wait-timeout.workspace = true
rhai.workspace = true
# Plugin loading
libloading = "0.8.9"
[dev-dependencies]
pretty_assertions.workspace = true

View File

@@ -21,14 +21,15 @@ use crate::{
window_initiator::WindowInitiator,
*,
};
use rhai_impl::parser::ParseConfig;
use anyhow::{anyhow, bail};
use gdk::Monitor;
use gtk4::Window;
use gtk4::{gdk, glib};
use itertools::Itertools;
use once_cell::sync::OnceCell;
use rhai::Dynamic;
use rhai_impl::ast::WidgetNode;
use rhai_impl::parser::ParseConfig;
use serde::{de::Error as SerdeError, Deserialize, Deserializer};
use std::{
cell::{Cell, RefCell},
@@ -39,6 +40,13 @@ use std::{
};
use tokio::sync::mpsc::UnboundedSender;
static ACTIVE_PLUGIN: OnceCell<libloading::Library> = OnceCell::new();
fn set_active_plugin(lib: libloading::Library) {
// will panic if called more than once
ACTIVE_PLUGIN.set(lib).unwrap();
}
/// A command for the ewwii daemon.
/// While these are mostly generated from ewwii CLI commands (see [`opts::ActionWithServer`]),
/// they may also be generated from other places internally.
@@ -90,6 +98,10 @@ pub enum DaemonCommand {
print: bool,
sender: DaemonResponseSender,
},
SetPlugin {
file_path: String,
sender: DaemonResponseSender,
},
}
/// An opened window.
@@ -366,6 +378,12 @@ impl<B: DisplayBackend> App<B> {
Err(e) => sender.send_failure(e.to_string())?,
};
}
DaemonCommand::SetPlugin { file_path, sender } => {
match self.set_ewwii_plugin(file_path) {
Ok(_) => sender.send_success(String::new())?,
Err(e) => sender.send_failure(e.to_string())?,
}
}
}
Ok(())
}
@@ -483,7 +501,7 @@ impl<B: DisplayBackend> App<B> {
// so I guess that I will just let it stay right here.
let config_path = self.paths.get_rhai_path();
let compiled_ast = self.ewwii_config.get_owned_compiled_ast();
{
let mut stored_parser = self.config_parser.borrow_mut();
stored_parser.set_opt_level(get_opt_level_from(
@@ -799,6 +817,30 @@ impl<B: DisplayBackend> App<B> {
Ok(())
}
pub fn set_ewwii_plugin(&mut self, file_path: String) -> Result<()> {
let lib = unsafe {
libloading::Library::new(file_path)
.map_err(|e| anyhow!("Failed to load plugin: {}", e))?
};
unsafe {
// Each plugin exposes: extern "C" fn create_plugin() -> Box<dyn Plugin>
let constructor: libloading::Symbol<
unsafe extern "C" fn() -> Box<dyn ewwii_plugin_api::Plugin>,
> = lib
.get(b"create_plugin")
.map_err(|e| anyhow!("Failed to find create_plugin: {}", e))?;
let plugin = constructor(); // instantiate plugin
let host = crate::plugin::EwwiiImpl;
plugin.init(&host); // call init immediately
set_active_plugin(lib); // keep library alive
}
Ok(())
}
}
#[derive(Deserialize, Debug)]

View File

@@ -15,7 +15,10 @@ use rhai_impl::{ast::WidgetNode, parser::ParseConfig};
/// Load an [`EwwiiConfig`] from the config dir of the given [`crate::EwwiiPaths`],
/// resetting and applying the global YuckFiles object in [`crate::error_handling_ctx`].
pub fn read_from_ewwii_paths(eww_paths: &EwwiiPaths, parser: &mut ParseConfig) -> Result<EwwiiConfig> {
pub fn read_from_ewwii_paths(
eww_paths: &EwwiiPaths,
parser: &mut ParseConfig,
) -> Result<EwwiiConfig> {
EwwiiConfig::read_from_dir(eww_paths, parser)
}

View File

@@ -48,6 +48,7 @@ mod gen_diagnostic_macro;
mod ipc_server;
mod opts;
mod paths;
mod plugin;
mod server;
mod util;
mod widgets;

View File

@@ -217,6 +217,14 @@ pub enum ActionWithServer {
#[arg(long = "sprint", short = 'p')]
print: bool,
},
/// Set a plugin (.so) to the ewwii binary
#[command(name = "set-plugin")]
SetPlugin {
/// The .so file to load
#[arg(value_parser = absolute_file_path_parser)]
file_path: String,
},
}
impl Opt {
@@ -355,6 +363,12 @@ impl ActionWithServer {
sender,
})
}
ActionWithServer::SetPlugin { file_path } => {
return with_response_channel(|sender| app::DaemonCommand::SetPlugin {
file_path,
sender,
})
}
};
(command, None)
}
@@ -431,3 +445,10 @@ fn parse_inject_var_map(s: &str) -> Result<HashMap<String, String>, String> {
}
Ok(map)
}
fn absolute_file_path_parser(s: &str) -> Result<String, String> {
let p = std::path::Path::new(s);
std::fs::canonicalize(p)
.map_err(|e| format!("Failed to canonicalize '{}': {}", s, e))
.map(|abs_path| abs_path.to_string_lossy().into_owned())
}

View File

@@ -1,19 +1,13 @@
use ewwii_plugin_api::{EwwiiAPI, Plugin};
use ewwii_plugin_api::EwwiiAPI;
use rhai::Engine;
use rhai_impl::parser::ParseConfig;
use std::sync::{Arc, RwLock};
pub struct EwwiiImpl;
impl HostAPI for EwwiiImpl {
// General
impl EwwiiAPI for EwwiiImpl {
// General
fn log(&self, msg: &str) {
println!("[HOST LOG] {}", msg);
}
// Rhai Engine Stuff
fn get_rhai_engine(&self) {
}
fn set_rhai_engine(&self, engine: &Engine) {
}
}

View File

@@ -98,7 +98,7 @@ pub fn initialize_server<B: DisplayBackend>(
widget_reg_store: std::rc::Rc::new(std::sync::Mutex::new(None)),
pl_handler_store: None,
rt_engine_config: EngineConfValues::default(),
config_parser: config_parser,
config_parser,
paths,
gtk_main_loop: main_loop.clone(),
phantom: PhantomData,

View File

@@ -1,13 +1,7 @@
use rhai::Engine;
/// The shared trait defining the Ewwii plugin API
pub trait EwwiiAPI: Send + Sync {
// General stuff
fn log(&self, msg: &str);
// Rhai Manipulation Stuff
fn get_rhai_engine(&self) -> &mut Engine;
fn set_rhai_engine(&self, engine: &Engine);
}
/// The API format that the plugin should follow