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:
@@ -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"] }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
37
sdk/rust/dim_sdk/src/logger.rs
Normal file
37
sdk/rust/dim_sdk/src/logger.rs
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user