Too lazy to make propper edit but i changed the

polling system to a message one so we can have
more ways we can interract with plugins
(reload/ reset/ on click events)
This commit is contained in:
2024-06-26 04:00:44 +03:00
parent 9f53240807
commit 026a68364b
33 changed files with 694 additions and 271 deletions

View File

@@ -4,32 +4,83 @@
#include <stdio.h>
#define BUF_SZ 2048
#ifdef _WIN32
#define PATH_SEP "\\"
#else
#define PATH_SEP "/"
#endif
typedef enum log_level_t {
ERROR=1,
WARN=2,
INFO=3,
DEBUG=4,
} log_level_t;
typedef struct plug_info_t {
char* name;
char* version;
char* license;
} plug_info_t;
typedef struct plug_funcs_ctx_t {
void (*log)(char* module, log_level_t level, char* s);
} plug_funcs_ctx_t;
typedef struct plug_ctx_t {
char* config_dir;
plug_funcs_ctx_t funcs;
char* buf;
} plug_ctx_t;
#define PLUG_INFO(_name, _version, _license) \
typedef struct plug_msg_t {
char* name;
char* value;
} plug_msg_t;
// Functions defs
// User defined funcs
int plug_init(plug_ctx_t*); // Loads when DIM initialises
void* plug_pre_reload(); // Return a pointer to save state
int plug_post_reload(void*); // returns the same pointer after reload
int plug_on_msg(plug_msg_t*); // Write the message to `buf` with max `size` characters
int plug_free(); // Free everything before being killed
// Lib funcs
void setup_ctx(plug_ctx_t* ctx);
void _log(char* module, log_level_t level, char* s);
// Macros
#define PLUG_INFO(_name, _version, _license) \
static plug_info_t PLUG_INFO_VAR = { .name=(_name), .version=(_version), .license=(_license)}; \
void* plug_get_info() { \
return &PLUG_INFO_VAR; \
void* plug_get_info() { \
return &PLUG_INFO_VAR; \
}
#define log(level, ...) do { \
char* buf = (char*)malloc(BUF_SZ*sizeof(char)); \
char* mod = (char*)malloc(BUF_SZ*sizeof(char)); \
snprintf(mod, BUF_SZ*sizeof(char), \
"(plug) %s/%s", PLUG_INFO_VAR.name, __FILE__); \
snprintf(buf, BUF_SZ*sizeof(char), __VA_ARGS__); \
_log(mod, level, buf); \
free(buf); \
free(mod); \
} while (0)
#define PLUG_NAME(s) volatile char* PLUG_NAME = (s);
#define PLUG_VERSION(s) volatile char* PLUG_VERSION = (s);
#define PLUG_LICENSE(s) volatile char* PLUG_LICENSE = (s);
#ifdef PLUG_IMPL
static plug_ctx_t CTX = {0};
void setup_ctx(plug_ctx_t* ctx) {
CTX = *ctx;
}
void plug_init(plug_ctx_t*); // Loads when DIM initialises
void* plug_pre_reload(); // Return a pointer to save state
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_free(); // Free everything before being killed
void _log(char* module, log_level_t level, char* s) {
(CTX.funcs.log)(module, level, s);
}
#endif
#endif

View File

@@ -11,3 +11,4 @@ anyhow = "1.0.86"
bytes = "1.6.0"
lazy_static = { version = "1.4.0", features = ["spin"] }
libc = "0.2.155"
log = { version = "0.4.21", features = ["std"] }

View File

@@ -1,33 +1,40 @@
#[derive(Debug)]
pub struct CBuffer<'a> {
inner: &'a mut [i8],
#[derive(Debug, Clone)]
pub struct CBuffer {
inner: Vec<u8>,
count: usize,
capacity: usize
}
#[allow(dead_code)] // rust_analyzer too dumb to see my macro magic
// i hate that macro as much as you do
impl CBuffer<'_> {
pub fn from_raw_parts_mut(buf: *mut i8, capacity: usize) -> Self {
impl CBuffer {
pub fn from_raw_parts_mut(buf: *mut u8, capacity: usize) -> Self {
Self {
inner: unsafe {
std::slice::from_raw_parts_mut(buf, capacity)
Vec::from_raw_parts(buf, capacity, capacity)
},
capacity,
count: 0,
}
}
pub fn reset(&mut self) {
for i in 0..self.capacity {
self.inner[i] = 0;
}
self.count = 0;
}
}
impl std::fmt::Write for CBuffer<'_> {
impl std::fmt::Write for CBuffer {
fn write_str(&mut self, buf: &str) -> Result<(), std::fmt::Error> {
for c in buf.as_bytes() {
if self.count >= self.capacity - 1 {
return Ok(());
}
self.inner[self.count] = *c as i8;
self.inner[self.count] = *c;
self.count += 1;
}
self.inner[self.count] = 0;

View File

@@ -1,25 +1,46 @@
use std::{ffi::{c_char, CStr}, path::PathBuf};
use crate::CBuffer;
#[derive(Debug, Clone)]
#[repr(C)]
pub struct ContextRaw {
pub config_dir: *const c_char
pub config_dir: *const c_char,
pub funcs: PluginContextFuncs,
pub buf: *mut u8,
}
#[derive(Debug, Clone)]
pub struct Context {
pub config_dir: PathBuf
pub config_dir: PathBuf,
pub funcs: PluginContextFuncs,
pub buf: CBuffer
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct PluginContextFuncs {
pub log: unsafe extern "C" fn(module: *const c_char, level: log::Level, s: *const c_char),
}
impl Context {
pub fn new(cr: *const ContextRaw) -> Self {
pub fn new(cr: ContextRaw) -> Self {
let config_dir = unsafe {
let v = CStr::from_ptr((*cr).config_dir);
PathBuf::from(v.to_string_lossy().to_string())
let v = CStr::from_ptr(cr.config_dir);
PathBuf::from(v.to_string_lossy().to_string().clone())
};
Self {
config_dir
config_dir,
funcs: cr.funcs.clone(),
buf: CBuffer::from_raw_parts_mut(cr.buf, crate::BUF_SZ)
}
}
}
impl std::fmt::Write for Context {
fn write_str(&mut self, buf: &str) -> Result<(), std::fmt::Error> {
self.buf.write_str(buf)
}
}

View File

@@ -4,23 +4,55 @@ mod magic;
mod c_buffer;
mod plugin_info;
mod context;
mod logger;
use std::ffi::{c_char, CStr};
pub use c_buffer::*;
pub use plugin_info::*;
pub use anyhow::Result;
pub use context::*;
pub use logger::*;
pub const BUF_SZ: usize = 2048;
pub trait DimPlugin: Clone{
fn init(ctx: Context) -> Result<Self>;
fn pre_reload(&mut self) -> Result<()>;
fn post_reload(&mut self) -> Result<()>;
fn on_message(&mut self, msg: Message) -> Result<()>;
fn free(&mut self) -> Result<()>;
}
#[derive(Debug)]
pub struct Message {
pub name: String,
pub value: String,
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct MessageRaw {
pub name: *const c_char,
pub value: *const c_char,
}
impl Message {
pub fn new(msg: MessageRaw) -> Self {
unsafe {
Self {
name: CStr::from_ptr(msg.name.clone())
.to_string_lossy().to_string(),
value: CStr::from_ptr(msg.value.clone())
.to_string_lossy().to_string()
}
}
}
pub trait DimPlugin: Clone {
fn init(&mut self, ctx: Context);
fn pre_reload(&mut self);
fn post_reload(&mut self);
fn poll(&mut self, f: &mut CBuffer) -> Result<()>;
fn free(&mut self) {}
}

View File

@@ -0,0 +1,37 @@
use std::ffi::{c_char, CString};
use crate::Context;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct DimLogger {
log_fn: unsafe extern "C" fn(module: *const c_char, level: log::Level, s: *const c_char),
}
impl log::Log for DimLogger {
fn enabled(&self, _: &log::Metadata) -> bool {true}
fn log(&self, record: &log::Record) {
unsafe {
let module = format!("(plug) {}", record.module_path().unwrap_or("UNKNOWN"));
let module = CString::new(module).unwrap();
let s = CString::new(format!("{}", record.args())).unwrap();
(self.log_fn)(module.as_ptr(), record.level(), s.as_ptr());
}
}
fn flush(&self) {}
}
impl DimLogger {
pub fn new(ctx: &Context) -> Self {
Self {
log_fn: ctx.funcs.log,
}
}
pub fn init(&self) {
let _ = log::set_boxed_logger(Box::new(self.clone()))
.map(|()| log::set_max_level(log::LevelFilter::Debug));
}
}

View File

@@ -2,7 +2,7 @@
#[macro_export]
macro_rules! plugin_info {
($typ:ty, $name:literal, $version:literal, $license:literal) => {
lazy_static::lazy_static!(
static ref PLUGIN_INFO: $crate::PluginInfo = $crate::PluginInfo::new($name, $version, $license);
);
@@ -14,61 +14,87 @@ macro_rules! plugin_info {
PLUGIN_INFO.get_raw_ptr()
}
#[no_mangle]
unsafe extern "C" fn plug_init(ctx: *const $crate::ContextRaw) {
//PLUG = std::alloc::alloc(std::alloc::Layout::new::<$typ>()) as *mut $typ;
PLUG = Some(Plug::new());
let ctx = $crate::Context::new(ctx);
if let Some(p) = &mut PLUG {
p.init(ctx)
} else {
unreachable!();
impl $typ {
pub fn get_plugin_info(&self) -> $crate::PluginInfo {
$crate::PluginInfo::new(
PLUGIN_INFO.name().as_str(),
PLUGIN_INFO.version().as_str(),
PLUGIN_INFO.license().as_str()
)
}
}
#[no_mangle]
unsafe extern "C" fn plug_init(ctx: *const $crate::ContextRaw) -> i32 {
let ctx = $crate::Context::new((*ctx).clone());
$crate::DimLogger::new(&ctx).init();
match <$typ>::init(ctx) {
Ok(v) => {
PLUG = Some(v);
return 0;
}
Err(e) => {
log::error!("Had an error while initialising: {e}");
return 1;
}
};
}
#[no_mangle]
unsafe extern "C" fn plug_pre_reload() -> *mut $typ {
//TODO: Untested
if let Some(p) = &mut PLUG {
p.pre_reload();
if let Err(e) = p.pre_reload() {
log::error!("Had an error on pre reload: {e}");
return std::ptr::null_mut();
}
return p as *mut $typ;
}
unreachable!();
}
#[no_mangle]
unsafe extern "C" fn plug_post_reload(state: *mut $typ) {
unsafe extern "C" fn plug_post_reload(state: *mut $typ) -> i32 {
PLUG = Some((*state).clone());
if let Some(p) = &mut PLUG {
p.post_reload();
} else {
unreachable!();
}
//TODO: Untested
}
#[no_mangle]
unsafe extern "C" fn plug_poll(buf: *mut i8, len: std::ffi::c_uint) {
let mut buf = $crate::CBuffer::from_raw_parts_mut(buf, len as usize);
if let Some(p) = &mut PLUG {
if let Err(_e) = p.poll(&mut buf) {
// TODO: Handle error maybe?
if let Err(e) = p.post_reload() {
log::error!("Had an error on pre reload: {e}");
return 1;
}
} else {
unreachable!();
}
//TODO: Untested
return 0;
}
#[no_mangle]
unsafe extern "C" fn plug_free() {
unsafe extern "C" fn plug_on_msg(msg: *const $crate::MessageRaw) -> i32 {
let msg = $crate::Message::new((*msg).clone());
if let Some(p) = &mut PLUG {
// std::alloc::dealloc(PLUG as *mut u8, std::alloc::Layout::new::<$typ>());
p.free();
if let Err(e) = p.on_message(msg) {
log::error!("Had error on `on_msg`: {e}");
return 1;
}
} else {
unreachable!();
}
return 0;
}
#[no_mangle]
unsafe extern "C" fn plug_free() -> i32 {
if let Some(p) = &mut PLUG {
// std::alloc::dealloc(PLUG as *mut u8, std::alloc::Layout::new::<$typ>());
if let Err(e) = p.free() {
log::error!("Had error on `free`: {e}");
return 1;
}
} else {
unreachable!();
}
return 0;
}
};

View File

@@ -36,6 +36,16 @@ impl PluginInfo {
pub fn get_raw_ptr(&self) -> *const c_void {
&self.ptrs as *const _ as *const c_void
}
pub fn name(&self) -> String {
self._name.to_string_lossy().to_string()
}
pub fn version(&self) -> String {
self._version.to_string_lossy().to_string()
}
pub fn license(&self) -> String {
self._license.to_string_lossy().to_string()
}
}
unsafe impl Sync for PluginInfo {}