Added PluginContext

This commit is contained in:
Gvidas Juknevičius 2024-06-20 23:43:16 +03:00
parent 43a07debde
commit 19aee664c2
Signed by: MCorange
GPG Key ID: 12B1346D720B7FBB
25 changed files with 172 additions and 83 deletions

View File

@ -1,4 +1,12 @@
workspace = { members = [ "sdk/rust","dim_plugins/example_rust", "dim_plugins/clock", "dim_plugins/counter", "dim_plugins/battery"] } [workspace]
members = [
"sdk/rust/dim_sdk",
"dim_plugins/example_rust",
"dim_plugins/clock",
"dim_plugins/counter",
"dim_plugins/battery",
]
[package] [package]
name = "dim" name = "dim"
version = "0.1.0" version = "0.1.0"

View File

@ -1,14 +1,14 @@
[ [
{ {
"directory": "/home/xomf/git-stuff/dim2/dim/dim_plugins/example_c", "directory": "/home/mcorange/.dwm/sources/dim/dim_plugins/example_c",
"arguments": [ "arguments": [
"gcc", "gcc",
"-c", "-c",
"-o", "-o",
"/home/xomf/git-stuff/dim2/dim/target/objects/example_c/main.o", "/home/mcorange/.dwm/sources/dim/target/objects/example_c/main.o",
"src/main.c", "src/main.c",
"-pie", "-pie",
"-I/home/xomf/git-stuff/dim2/dim/sdk/c_cxx", "-I/home/mcorange/.dwm/sources/dim/sdk/c_cxx",
"-fPIC" "-fPIC"
], ],
"file": "src/main.c" "file": "src/main.c"

View File

@ -8,5 +8,5 @@ crate-type=["cdylib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
dim_sdk = {path="../../sdk/rust/"} dim_sdk = {path="../../sdk/rust/dim_sdk"}
lazy_static = "1.4.0" lazy_static = "1.4.0"

View File

@ -1,5 +1,5 @@
use std::fmt::Write; use std::fmt::Write;
use dim_sdk::{plugin_info, DimPlugin}; use dim_sdk::{plugin_info, Context, DimPlugin};
use std::fs::read_to_string; use std::fs::read_to_string;
plugin_info!( plugin_info!(
@ -20,7 +20,7 @@ impl Plug {
} }
impl DimPlugin for Plug { impl DimPlugin for Plug {
fn init(&mut self) { fn init(&mut self, _ctx: Context) {
} }
fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> { fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
let contents = read_to_string("/sys/class/power_supply/BAT0/capacity")?; let contents = read_to_string("/sys/class/power_supply/BAT0/capacity")?;

View File

@ -9,6 +9,6 @@ crate-type=["cdylib"]
[dependencies] [dependencies]
chrono = "0.4.38" chrono = "0.4.38"
dim_sdk = {path="../../sdk/rust/"} dim_sdk = {path="../../sdk/rust/dim_sdk"}
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4.21" log = "0.4.21"

View File

@ -1,13 +1,14 @@
use std::fmt::Write; use std::fmt::Write;
use chrono::prelude::*; use chrono::prelude::*;
use dim_sdk::{plugin_info, DimPlugin}; use dim_sdk::{plugin_info, Context, DimPlugin};
plugin_info!( plugin_info!(
Plug, // Your main global structs name that implements `DimPlugin` Plug, // Your main global structs name that implements `DimPlugin`
"clock", // Plugin name "clock", // Plugin name
"0.0.0", // Plugin Version (leave empty for none) "0.0.0", // Plugin Version (leave empty for none)
"GPLv3" // Plugin license (leave empty for none) "GPLv3" // Plugin license (leave empty for none)
); );
struct Plug { struct Plug {
} }
@ -20,9 +21,7 @@ impl Plug {
} }
impl DimPlugin for Plug { impl DimPlugin for Plug {
fn init(&mut self) { fn init(&mut self, _ctx: Context) {}
}
fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> { fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
let local: DateTime<Local> = Local::now(); let local: DateTime<Local> = Local::now();
let formatted_time = local.format("%H:%M (%Y-%m-%d)").to_string(); let formatted_time = local.format("%H:%M (%Y-%m-%d)").to_string();
@ -30,14 +29,9 @@ impl DimPlugin for Plug {
write!(f, "Time: {}", formatted_time)?; write!(f, "Time: {}", formatted_time)?;
Ok(()) Ok(())
} }
fn pre_reload(&mut self) { fn pre_reload(&mut self) {}
fn post_reload(&mut self) {}
} fn free(&mut self) {}
fn post_reload(&mut self) {
}
fn free(&mut self) {
}
} }

View File

@ -9,5 +9,5 @@ crate-type=["cdylib"]
[dependencies] [dependencies]
chrono = "0.4.38" chrono = "0.4.38"
dim_sdk = {path="../../sdk/rust/"} dim_sdk = {path="../../sdk/rust/dim_sdk"}
lazy_static = "1.4.0" lazy_static = "1.4.0"

View File

@ -1,5 +1,5 @@
use std::fmt::Write; use std::fmt::Write;
use dim_sdk::{plugin_info, DimPlugin}; use dim_sdk::{plugin_info, Context, DimPlugin};
use chrono::{NaiveDate, Local}; use chrono::{NaiveDate, Local};
plugin_info!( plugin_info!(
@ -21,7 +21,7 @@ impl Plug {
} }
impl DimPlugin for Plug { impl DimPlugin for Plug {
fn init(&mut self) {} fn init(&mut self, _ctx: Context) {}
fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> { fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
let start_date = NaiveDate::from_ymd_opt(2024, 3, 8).expect("Invalid date"); let start_date = NaiveDate::from_ymd_opt(2024, 3, 8).expect("Invalid date");

View File

@ -13,7 +13,8 @@ typedef struct plug_t {
plug_t* p = {0}; plug_t* p = {0};
void plug_init() { void plug_init(plug_ctx_t* ctx) {
(void) ctx;
p = malloc(sizeof(plug_t)); p = malloc(sizeof(plug_t));
assert(p != NULL && "Buy more ram KEKW"); assert(p != NULL && "Buy more ram KEKW");
p->count = 0; p->count = 0;

View File

@ -8,5 +8,5 @@ crate-type=["cdylib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
dim_sdk = {path="../../sdk/rust/"} dim_sdk = {path="../../sdk/rust/dim_sdk"}
lazy_static = "1.4.0" lazy_static = "1.4.0"

View File

@ -1,5 +1,5 @@
use std::fmt::Write; use std::fmt::Write;
use dim_sdk::{plugin_info, DimPlugin}; use dim_sdk::{plugin_info, Context, DimPlugin};
plugin_info!( plugin_info!(
Plug, // Your main global structs name that implements `DimPlugin` Plug, // Your main global structs name that implements `DimPlugin`
@ -21,7 +21,7 @@ impl Plug {
} }
impl DimPlugin for Plug { impl DimPlugin for Plug {
fn init(&mut self) { fn init(&mut self, _ctx: Context) {
// Initialise data, this will run once, it will not run again after reload // Initialise data, this will run once, it will not run again after reload
} }
fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> { fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {

View File

@ -10,6 +10,10 @@ typedef struct plug_info_t {
char* license; char* license;
} plug_info_t; } plug_info_t;
typedef struct plug_ctx_t {
char* config_dir;
} plug_ctx_t;
#define PLUG_INFO(_name, _version, _license) \ #define PLUG_INFO(_name, _version, _license) \
static plug_info_t PLUG_INFO_VAR = { .name=(_name), .version=(_version), .license=(_license)}; \ static plug_info_t PLUG_INFO_VAR = { .name=(_name), .version=(_version), .license=(_license)}; \
void* plug_get_info() { \ void* plug_get_info() { \
@ -22,7 +26,7 @@ void* plug_get_info() { \
#define PLUG_LICENSE(s) volatile char* PLUG_LICENSE = (s); #define PLUG_LICENSE(s) volatile char* PLUG_LICENSE = (s);
void plug_init(); // Loads when DIM initialises void plug_init(plug_ctx_t*); // Loads when DIM initialises
void* plug_pre_reload(); // Return a pointer to save state void* plug_pre_reload(); // Return a pointer to save state
void plug_post_reload(void*); // returns the same pointer after reload void plug_post_reload(void*); // returns the same pointer after reload
void plug_poll(char*, size_t); // Write the message to `buf` with max `size` characters void plug_poll(char*, size_t); // Write the message to `buf` with max `size` characters

View File

@ -0,0 +1,25 @@
use std::{ffi::{c_char, CStr}, path::PathBuf};
#[repr(C)]
pub struct ContextRaw {
pub config_dir: *const c_char
}
#[derive(Debug, Clone)]
pub struct Context {
pub config_dir: PathBuf
}
impl Context {
pub fn new(cr: *const ContextRaw) -> Self {
let config_dir = unsafe {
let v = CStr::from_ptr((*cr).config_dir);
PathBuf::from(v.to_string_lossy().to_string())
};
Self {
config_dir
}
}
}

View File

@ -4,14 +4,15 @@
mod magic; mod magic;
mod c_buffer; mod c_buffer;
mod plugin_info; mod plugin_info;
mod context;
pub use c_buffer::*; pub use c_buffer::*;
pub use plugin_info::*; pub use plugin_info::*;
pub use anyhow::Result; pub use anyhow::Result;
pub use context::*;
pub trait DimPlugin { pub trait DimPlugin {
fn init(&mut self); fn init(&mut self, ctx: Context);
fn pre_reload(&mut self); fn pre_reload(&mut self);
fn post_reload(&mut self); fn post_reload(&mut self);
fn poll(&mut self, f: &mut CBuffer) -> Result<()>; fn poll(&mut self, f: &mut CBuffer) -> Result<()>;
@ -23,3 +24,4 @@ pub trait DimPlugin {

View File

@ -15,10 +15,12 @@ macro_rules! plugin_info {
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn plug_init() { unsafe extern "C" fn plug_init(ctx: *const $crate::ContextRaw) {
PLUG = std::alloc::alloc(std::alloc::Layout::new::<$typ>()) as *mut $typ; PLUG = std::alloc::alloc(std::alloc::Layout::new::<$typ>()) as *mut $typ;
*PLUG = Plug::new(); *PLUG = Plug::new();
(&mut *PLUG).init();
let ctx = $crate::Context::new(ctx);
(&mut *PLUG).init(ctx);
} }
#[no_mangle] #[no_mangle]

View File

@ -21,14 +21,14 @@ pub struct ConfigPlugins {
impl Config { impl Config {
pub fn new(path: &Path) -> Result<Self, ConfigError> { pub fn new(path: &Path) -> Result<Self, ConfigError> {
let path = path.join("main.toml"); let cfg_path = path.join("main.toml");
if !path.exists() { if !cfg_path.exists() {
println!("ERROR: {:?} doesnt exist", path); println!("ERROR: {:?} doesnt exist", path);
} }
let mut cfg: Self = toml::from_str( let mut cfg: Self = toml::from_str(
&std::fs::read_to_string(&path)? &std::fs::read_to_string(&cfg_path)?
)?; )?;
cfg.config_dir = path.to_path_buf(); cfg.config_dir = path.to_path_buf();

View File

@ -1,13 +1,13 @@
#![allow(internal_features)] #![allow(internal_features)]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
use std::{process::ExitCode, time::Duration}; use std::{ffi::c_char, process::ExitCode, time::Duration};
use clap::Parser; use clap::Parser;
mod display; mod display;
mod plugman; mod plugman;
mod config; mod config;
mod util;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
struct CliArgs { struct CliArgs {
@ -19,6 +19,8 @@ struct CliArgs {
pub debug: bool pub debug: bool
} }
#[allow(non_camel_case_types)]
pub type c_str = *const c_char;
// TODO: Clean up main function // TODO: Clean up main function
// TODO: Make ffi safe abstraction for logger // TODO: Make ffi safe abstraction for logger
@ -57,7 +59,7 @@ fn main() -> ExitCode {
return ExitCode::from(3); return ExitCode::from(3);
} }
pm.init_plugins(); pm.init_plugins(&config);
loop { loop {
let vals = pm.poll_plugins(); let vals = pm.poll_plugins();

View File

@ -49,9 +49,9 @@ impl PlugMan {
Ok(()) Ok(())
} }
pub fn init_plugins(&mut self) { pub fn init_plugins(&mut self, cfg: &crate::config::Config) {
for plugin in &self.plugins { for plugin in &self.plugins {
plugin.init(); plugin.init(cfg);
} }
} }

View File

@ -0,0 +1,31 @@
use std::ffi::{c_char, CString};
pub struct PluginContextContainer {
pub inner: PluginContext,
_config_dir: CString
}
#[repr(C)]
pub struct PluginContext {
pub config_dir: *const c_char
}
impl PluginContext {
pub fn new(config_dir: &CString) -> Self {
Self {
config_dir: config_dir.as_ptr()
}
}
}
impl PluginContextContainer {
pub fn new(config_dir: &String) -> Self {
let _config_dir = CString::new(config_dir.clone()).unwrap();
Self {
inner: PluginContext::new(&_config_dir),
_config_dir,
}
}
}

View File

@ -0,0 +1,42 @@
use std::ffi::c_char;
use dlopen::raw::Library;
use super::{context::PluginContext, Plugin, PluginInfo};
#[derive(Debug, Clone, Copy)]
pub struct PluginSyms {
pub(super) init: unsafe extern "C" fn(ctx: *const PluginContext),
pub(super) pre_reload: unsafe extern "C" fn() -> *const (),
pub(super) post_reload: unsafe extern "C" fn(state: *const ()),
pub(super) poll: unsafe extern "C" fn(buf: *mut c_char, len: usize),
pub(super) free: unsafe extern "C" fn(),
pub(super) get_info: unsafe extern "C" fn() -> *const PluginInfo,
}
impl Plugin {
pub fn reload_symbols(&mut self) -> Result<(), dlopen::Error> {
log::debug!("Loading {:?}", self.path);
let lib = Library::open(&self.path)?;
let symbols = PluginSyms {
init: unsafe { lib.symbol("plug_init")? },
pre_reload: unsafe { lib.symbol("plug_pre_reload")? },
post_reload: unsafe { lib.symbol("plug_post_reload")? },
poll: unsafe { lib.symbol("plug_poll")? },
free: unsafe { lib.symbol("plug_free")? },
get_info: unsafe { lib.symbol("plug_get_info")? },
};
unsafe {
if (symbols.get_info)().is_null() {
log::error!("Info fields for plugin {:?} are null", self.path);
self.disable();
}
}
self.syms = Some(symbols);
self.lib = Some(lib);
Ok(())
}
}

View File

@ -2,32 +2,30 @@ use std::{alloc::Layout, ffi::{c_char, CStr}, path::PathBuf};
use dlopen::raw::Library; use dlopen::raw::Library;
#[derive(Debug, Clone, Copy,)] use crate::{c_str, config::Config};
pub struct PluginSyms {
init: unsafe extern "C" fn(), use self::context::{PluginContext, PluginContextContainer};
pre_reload: unsafe extern "C" fn() -> *const (),
post_reload: unsafe extern "C" fn(state: *const ()), pub mod loader;
poll: unsafe extern "C" fn(buf: *mut i8, len: usize), pub mod context;
free: unsafe extern "C" fn(),
get_info: unsafe extern "C" fn() -> *const PluginInfo,
}
#[repr(C)] #[repr(C)]
pub struct PluginInfo { pub struct PluginInfo {
name: *const c_char, name: c_str,
version: *const c_char, version: c_str,
license: *const c_char, license: c_str,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Plugin { pub struct Plugin {
syms: Option<PluginSyms>, syms: Option<loader::PluginSyms>,
path: PathBuf, path: PathBuf,
lib: Option<Library>, lib: Option<Library>,
enabled: bool, enabled: bool,
} }
impl Plugin { impl Plugin {
pub fn load(path: PathBuf) -> Result<Self, dlopen::Error> { pub fn load(path: PathBuf) -> Result<Self, dlopen::Error> {
let mut s = Self::default(); let mut s = Self::default();
@ -36,37 +34,17 @@ impl Plugin {
s.reload_symbols()?; s.reload_symbols()?;
Ok(s) Ok(s)
} }
fn reload_symbols(&mut self) -> Result<(), dlopen::Error> { pub fn syms(&self) -> loader::PluginSyms {
log::debug!("Loading {:?}", self.path);
let lib = Library::open(&self.path)?;
let symbols = PluginSyms {
init: unsafe { lib.symbol("plug_init")? },
pre_reload: unsafe { lib.symbol("plug_pre_reload")? },
post_reload: unsafe { lib.symbol("plug_post_reload")? },
poll: unsafe { lib.symbol("plug_poll")? },
free: unsafe { lib.symbol("plug_free")? },
get_info: unsafe { lib.symbol("plug_get_info")? },
};
unsafe {
if (symbols.get_info)().is_null() {
log::error!("Info fields for plugin {:?} are null", self.path);
self.disable();
}
}
self.syms = Some(symbols);
self.lib = Some(lib);
Ok(())
}
pub fn syms(&self) -> PluginSyms {
self.syms.unwrap() self.syms.unwrap()
} }
pub fn init(&self) { pub fn init(&self, cfg: &Config) {
unsafe { unsafe {
(self.syms().init)() let conf_dir = &cfg.config_dir.join(self.name()).to_string_lossy().to_string();
let ctx = PluginContextContainer::new(conf_dir);
(self.syms().init)(&ctx.inner as *const PluginContext)
} }
} }
pub fn reload(&mut self) -> Result<(), dlopen::Error> { pub fn reload(&mut self) -> Result<(), dlopen::Error> {

0
src/util.rs Normal file
View File