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:
		
							parent
							
								
									9f53240807
								
							
						
					
					
						commit
						026a68364b
					
				
							
								
								
									
										5
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| 
						 | 
					@ -93,6 +93,7 @@ version = "0.1.0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "dim_sdk",
 | 
					 "dim_sdk",
 | 
				
			||||||
 "lazy_static",
 | 
					 "lazy_static",
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -208,6 +209,7 @@ dependencies = [
 | 
				
			||||||
 "chrono",
 | 
					 "chrono",
 | 
				
			||||||
 "dim_sdk",
 | 
					 "dim_sdk",
 | 
				
			||||||
 "lazy_static",
 | 
					 "lazy_static",
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -236,6 +238,7 @@ dependencies = [
 | 
				
			||||||
 "bytes",
 | 
					 "bytes",
 | 
				
			||||||
 "lazy_static",
 | 
					 "lazy_static",
 | 
				
			||||||
 "libc",
 | 
					 "libc",
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -296,6 +299,7 @@ version = "0.1.0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "dim_sdk",
 | 
					 "dim_sdk",
 | 
				
			||||||
 "lazy_static",
 | 
					 "lazy_static",
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -599,6 +603,7 @@ dependencies = [
 | 
				
			||||||
 "anyhow",
 | 
					 "anyhow",
 | 
				
			||||||
 "dim_sdk",
 | 
					 "dim_sdk",
 | 
				
			||||||
 "lazy_static",
 | 
					 "lazy_static",
 | 
				
			||||||
 | 
					 "log",
 | 
				
			||||||
 "regex",
 | 
					 "regex",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "toml",
 | 
					 "toml",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,9 @@
 | 
				
			||||||
 | 
					refresh_ms=100
 | 
				
			||||||
 | 
					sock_path="~/dim.sock" # must be full path
 | 
				
			||||||
seperator=" | "
 | 
					seperator=" | "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[plugins]
 | 
					[plugins]
 | 
				
			||||||
 | 
					path="./plugins"
 | 
				
			||||||
blacklist=["example_c", "example_rust"]
 | 
					blacklist=["example_c", "example_rust"]
 | 
				
			||||||
as_whitelist=false
 | 
					as_whitelist=false
 | 
				
			||||||
template=["counter", "battery", "clock"]
 | 
					template=["counter", "battery", "clock"]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,9 @@
 | 
				
			||||||
 | 
					refresh_ms=100
 | 
				
			||||||
 | 
					sock_path="~/dim.sock" # must be full path
 | 
				
			||||||
seperator=" | "
 | 
					seperator=" | "
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[plugins]
 | 
					[plugins]
 | 
				
			||||||
 | 
					path="./plugins"
 | 
				
			||||||
blacklist=["example_c", "example_rust"]
 | 
					blacklist=["example_c", "example_rust"]
 | 
				
			||||||
as_whitelist=false
 | 
					as_whitelist=false
 | 
				
			||||||
template=["counter", "battery", "clock"]
 | 
					template=["counter", "battery", "clock"]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,3 +10,4 @@ crate-type=["cdylib"]
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
					dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
				
			||||||
lazy_static = "1.4.0"
 | 
					lazy_static = "1.4.0"
 | 
				
			||||||
 | 
					log = "0.4.21"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
use std::{fmt::Write, path::PathBuf};
 | 
					use std::{fmt::Write, path::PathBuf};
 | 
				
			||||||
use dim_sdk::{plugin_info, Context, DimPlugin};
 | 
					use dim_sdk::{plugin_info, Context, DimPlugin, Message, Result};
 | 
				
			||||||
use std::fs::read_to_string;
 | 
					use std::fs::read_to_string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugin_info!(
 | 
					plugin_info!(
 | 
				
			||||||
| 
						 | 
					@ -11,39 +11,38 @@ plugin_info!(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
struct Plug {
 | 
					struct Plug {
 | 
				
			||||||
}
 | 
					    ctx: Context
 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Plug {
 | 
					 | 
				
			||||||
    pub fn new() -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const BATT0: &'static str = "/sys/class/power_supply/BAT0/capacity";
 | 
					const BATT0: &'static str = "/sys/class/power_supply/BAT0/capacity";
 | 
				
			||||||
const BATT1: &'static str = "/sys/class/power_supply/BAT1/capacity";
 | 
					const BATT1: &'static str = "/sys/class/power_supply/BAT1/capacity";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DimPlugin for Plug {
 | 
					impl DimPlugin for Plug {
 | 
				
			||||||
    fn init(&mut self, _ctx: Context) {
 | 
					    fn init(ctx: Context) -> Result<Self> {
 | 
				
			||||||
 | 
					        dim_sdk::DimLogger::new(&ctx).init();
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            ctx
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
 | 
					    fn on_message(&mut self, msg: Message) -> Result<()> {
 | 
				
			||||||
        //TODO: Quick fix, make this better, more portable
 | 
					        self.ctx.buf.reset();
 | 
				
			||||||
        let path = if PathBuf::from(BATT0).exists() { BATT0 } else { BATT1 };
 | 
					        match msg.name.as_str() {
 | 
				
			||||||
 | 
					            "poll" => {
 | 
				
			||||||
 | 
					                //TODO: Quick fix, make this better, more portable
 | 
				
			||||||
 | 
					                let path = if PathBuf::from(BATT0).exists() { BATT0 } else { BATT1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let contents = read_to_string(path)?;
 | 
					                let contents = read_to_string(path)?;
 | 
				
			||||||
        let cleaned_contents: String = contents.chars().filter(|c| c.is_digit(10)).collect();
 | 
					                let cleaned_contents: String = contents.chars().filter(|c| c.is_digit(10)).collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        write!(f, "Battery: {}%", cleaned_contents)?;
 | 
					                write!(self.ctx, "Battery: {}%", cleaned_contents)?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => ()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn pre_reload(&mut self) {
 | 
					    fn pre_reload(&mut self) -> Result<()> { Ok(()) }
 | 
				
			||||||
    }
 | 
					    fn post_reload(&mut self) -> Result<()> { Ok(()) }
 | 
				
			||||||
    fn post_reload(&mut self) {
 | 
					    fn free(&mut self) -> Result<()> { Ok(()) }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    fn free(&mut self) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
use std::fmt::Write;
 | 
					use std::fmt::Write;
 | 
				
			||||||
use chrono::prelude::*;
 | 
					use chrono::prelude::*;
 | 
				
			||||||
use dim_sdk::{plugin_info, Context, DimPlugin};
 | 
					use dim_sdk::{plugin_info, Context, DimPlugin, Result};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugin_info!(
 | 
					plugin_info!(
 | 
				
			||||||
    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
					    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
				
			||||||
| 
						 | 
					@ -11,27 +11,31 @@ plugin_info!(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
struct Plug {
 | 
					struct Plug {
 | 
				
			||||||
 | 
					    ctx: Context
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Plug {
 | 
					 | 
				
			||||||
    pub fn new() -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DimPlugin for Plug {
 | 
					impl DimPlugin for Plug {
 | 
				
			||||||
    fn init(&mut self, _ctx: Context) {}
 | 
					    fn init(ctx: Context) -> Result<Self> {
 | 
				
			||||||
    fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
 | 
					        Ok(Self {
 | 
				
			||||||
        let local: DateTime<Local> = Local::now();
 | 
					            ctx
 | 
				
			||||||
        let formatted_time = local.format("%H:%M (%Y-%m-%d)").to_string();
 | 
					        })
 | 
				
			||||||
        log::info!("Hello from clocky :3");
 | 
					    }
 | 
				
			||||||
        write!(f, "Time: {}", formatted_time)?;
 | 
					    fn on_message(&mut self, msg: dim_sdk::Message) -> Result<()> {
 | 
				
			||||||
 | 
					        self.ctx.buf.reset();
 | 
				
			||||||
 | 
					        match msg.name.as_str() {
 | 
				
			||||||
 | 
					            "poll" => {
 | 
				
			||||||
 | 
					                let local: DateTime<Local> = Local::now();
 | 
				
			||||||
 | 
					                let formatted_time = local.format("%H:%M (%Y-%m-%d)").to_string();
 | 
				
			||||||
 | 
					                write!(self.ctx, "Time: {}", formatted_time)?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => ()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn pre_reload(&mut self) {}
 | 
					    fn pre_reload(&mut self) -> Result<()> { Ok(()) }
 | 
				
			||||||
    fn post_reload(&mut self) {}
 | 
					    fn post_reload(&mut self) -> Result<()> { Ok(()) }
 | 
				
			||||||
    fn free(&mut self) {}
 | 
					    fn free(&mut self) -> Result<()> { Ok(()) } 
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,3 +11,4 @@ crate-type=["cdylib"]
 | 
				
			||||||
chrono = "0.4.38"
 | 
					chrono = "0.4.38"
 | 
				
			||||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
					dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
				
			||||||
lazy_static = "1.4.0"
 | 
					lazy_static = "1.4.0"
 | 
				
			||||||
 | 
					log = "0.4.21"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
use std::fmt::Write;
 | 
					use std::fmt::Write;
 | 
				
			||||||
use dim_sdk::{plugin_info, Context, DimPlugin};
 | 
					use dim_sdk::{plugin_info, Context, DimPlugin, Message, Result};
 | 
				
			||||||
use chrono::{NaiveDate, Local};
 | 
					use chrono::{NaiveDate, Local};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugin_info!(
 | 
					plugin_info!(
 | 
				
			||||||
| 
						 | 
					@ -11,30 +11,32 @@ plugin_info!(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
struct Plug {
 | 
					struct Plug {
 | 
				
			||||||
}
 | 
					    ctx: Context
 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Plug {
 | 
					 | 
				
			||||||
    pub fn new() -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DimPlugin for Plug {
 | 
					impl DimPlugin for Plug {
 | 
				
			||||||
    fn init(&mut self, _ctx: Context) {}
 | 
					    fn init(ctx: Context) -> Result<Self> {
 | 
				
			||||||
    fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            ctx
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn on_message(&mut self, msg: Message) -> Result<()> {
 | 
				
			||||||
 | 
					        self.ctx.buf.reset();
 | 
				
			||||||
 | 
					        match msg.name.as_str() {
 | 
				
			||||||
 | 
					            "poll" => {
 | 
				
			||||||
 | 
					                let start_date = NaiveDate::from_ymd_opt(2024, 3, 8).expect("Invalid date");
 | 
				
			||||||
 | 
					                let current_date = Local::now().date_naive();
 | 
				
			||||||
 | 
					                let duration = current_date.signed_duration_since(start_date);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let start_date = NaiveDate::from_ymd_opt(2024, 3, 8).expect("Invalid date");
 | 
					                write!(self.ctx, "{} days <3", duration.num_days())?;
 | 
				
			||||||
        let current_date = Local::now().date_naive();
 | 
					            }
 | 
				
			||||||
        let duration = current_date.signed_duration_since(start_date);
 | 
					            _ => ()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        write!(f, "{} days <3", duration.num_days())?;
 | 
					 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn pre_reload(&mut self) {}
 | 
					    fn pre_reload(&mut self) -> Result<()> { Ok(()) }
 | 
				
			||||||
    fn post_reload(&mut self) {}
 | 
					    fn post_reload(&mut self) -> Result<()> { Ok(()) }
 | 
				
			||||||
    fn free(&mut self) {}
 | 
					    fn free(&mut self) -> Result<()> { Ok(()) }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,8 @@
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					// Only use this define once, cause it defines funcitons
 | 
				
			||||||
 | 
					#define PLUG_IMPL
 | 
				
			||||||
#include "dim_sdk.h"
 | 
					#include "dim_sdk.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PLUG_INFO("example_c", "0.0.1", "GPLv3")
 | 
					PLUG_INFO("example_c", "0.0.1", "GPLv3")
 | 
				
			||||||
| 
						 | 
					@ -9,31 +10,38 @@ PLUG_INFO("example_c", "0.0.1", "GPLv3")
 | 
				
			||||||
typedef struct plug_t {
 | 
					typedef struct plug_t {
 | 
				
			||||||
    char* some_data;
 | 
					    char* some_data;
 | 
				
			||||||
    int count;
 | 
					    int count;
 | 
				
			||||||
 | 
					    plug_ctx_t ctx;
 | 
				
			||||||
} plug_t;
 | 
					} plug_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plug_t* p = {0};
 | 
					plug_t* p = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void plug_init(plug_ctx_t* ctx) {
 | 
					// If any function returns 0/NULL the plugin will be disabled
 | 
				
			||||||
    (void) ctx;
 | 
					int plug_init(plug_ctx_t* ctx) {
 | 
				
			||||||
 | 
					    setup_ctx(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;
 | 
				
			||||||
 | 
					    p->ctx = *ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    printf("Hello from plugin");
 | 
					    // log(INFO, "Hewo fwom C :3");
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void* plug_pre_reload() {
 | 
					void* plug_pre_reload() {
 | 
				
			||||||
    return p;
 | 
					    return p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void plug_post_reload(void *state) {
 | 
					int plug_post_reload(void *state) {
 | 
				
			||||||
    p = state;
 | 
					    p = state;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void plug_poll(char *buf, size_t len) {
 | 
					int plug_on_msg(plug_msg_t* msg) {
 | 
				
			||||||
    snprintf(buf, len, "Hello from C! (%d)", p->count++);
 | 
					    snprintf(p->ctx.buf, BUF_SZ, "Hello from C! (%d)", p->count++);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void plug_free() {
 | 
					int plug_free() {
 | 
				
			||||||
    free(p);
 | 
					    free(p);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,3 +10,4 @@ crate-type=["cdylib"]
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
					dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
				
			||||||
lazy_static = "1.4.0"
 | 
					lazy_static = "1.4.0"
 | 
				
			||||||
 | 
					log = "0.4.21"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
use std::fmt::Write;
 | 
					use std::fmt::Write;
 | 
				
			||||||
use dim_sdk::{plugin_info, Context, DimPlugin};
 | 
					use dim_sdk::{plugin_info, Context, DimPlugin, Message, Result};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
plugin_info!(
 | 
					plugin_info!(
 | 
				
			||||||
    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
					    Plug,                    // Your main global structs name that implements `DimPlugin`
 | 
				
			||||||
| 
						 | 
					@ -10,37 +10,45 @@ plugin_info!(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
struct Plug {
 | 
					struct Plug {
 | 
				
			||||||
 | 
					    ctx: Context,
 | 
				
			||||||
    counter: usize,
 | 
					    counter: usize,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Plug {
 | 
					 | 
				
			||||||
    pub fn new() -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            counter: 0
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl DimPlugin for Plug {
 | 
					impl DimPlugin for Plug {
 | 
				
			||||||
    fn init(&mut self, _ctx: Context) {
 | 
					    fn init(ctx: Context) -> dim_sdk::Result<Self> {
 | 
				
			||||||
        // 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
 | 
				
			||||||
 | 
					        // log::info!("hewo from rust :3");
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            ctx,
 | 
				
			||||||
 | 
					            counter: 0
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
 | 
					    fn on_message(&mut self, msg: Message) -> dim_sdk::Result<()> {
 | 
				
			||||||
        // Write to buffer the text you want to display, keep this short
 | 
					        self.ctx.buf.reset();
 | 
				
			||||||
        write!(f, "Hello from rust! ({})", self.counter)?;
 | 
					        match msg.name.as_str() {
 | 
				
			||||||
        self.counter += 1;
 | 
					            "poll" => {
 | 
				
			||||||
 | 
					                // Write to buffer the text you want to display, keep this short
 | 
				
			||||||
 | 
					                write!(self.ctx, "Hello from rust! ({})", self.counter)?;
 | 
				
			||||||
 | 
					                self.counter += 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => ()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn pre_reload(&mut self) {
 | 
					    fn pre_reload(&mut self) -> Result<()> {
 | 
				
			||||||
        // Do stuff before reload, probably save important things because theres a good chance
 | 
					        // Do stuff before reload, probably save important things because theres a good chance
 | 
				
			||||||
        // (especially on rust) that if you change the data layout it will die
 | 
					        // (especially on rust) that if you change the data layout it will die
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn post_reload(&mut self) {
 | 
					    fn post_reload(&mut self) -> Result<()>{
 | 
				
			||||||
        // Do stuff after reloading plugin, state a.k.a this struct has the same data, will crash
 | 
					        // Do stuff after reloading plugin, state a.k.a this struct has the same data, will crash
 | 
				
			||||||
        // if the data layout changed
 | 
					        // if the data layout changed
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn free(&mut self) {
 | 
					    fn free(&mut self) -> Result<()> {
 | 
				
			||||||
        // Yout probably dont need this but its for freeing things before the plugin gets unloaded
 | 
					        // Yout probably dont need this but its for freeing things before the plugin gets unloaded
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ crate-type=["cdylib"]
 | 
				
			||||||
anyhow = "1.0.86"
 | 
					anyhow = "1.0.86"
 | 
				
			||||||
dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
					dim_sdk = {path="../../sdk/rust/dim_sdk"}
 | 
				
			||||||
lazy_static = "1.4.0"
 | 
					lazy_static = "1.4.0"
 | 
				
			||||||
 | 
					log = "0.4.21"
 | 
				
			||||||
regex = "1.10.5"
 | 
					regex = "1.10.5"
 | 
				
			||||||
serde = { version = "1.0.203", features = ["derive"] }
 | 
					serde = { version = "1.0.203", features = ["derive"] }
 | 
				
			||||||
toml = "0.8.14"
 | 
					toml = "0.8.14"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
use std::{fmt::Write, path::PathBuf, process::Stdio};
 | 
					use std::{fmt::Write, process::Stdio};
 | 
				
			||||||
use dim_sdk::{plugin_info, Context, DimPlugin};
 | 
					use anyhow::bail;
 | 
				
			||||||
use std::fs::read_to_string;
 | 
					use dim_sdk::{plugin_info, Context, DimPlugin, Message, Result};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod config;
 | 
					mod config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,57 +9,60 @@ plugin_info!(
 | 
				
			||||||
    "volume",                // Plugin name
 | 
					    "volume",                // Plugin name
 | 
				
			||||||
    "1.0.0",                 // Plugin Version (leave empty for none)
 | 
					    "1.0.0",                 // Plugin Version (leave empty for none)
 | 
				
			||||||
    "GPLv3"                  // Plugin license (leave empty for none)
 | 
					    "GPLv3"                  // Plugin license (leave empty for none)
 | 
				
			||||||
    );
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
struct Plug {
 | 
					struct Plug {
 | 
				
			||||||
    cfg: config::Config,
 | 
					    cfg: config::Config,
 | 
				
			||||||
}
 | 
					    ctx: Context
 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Plug {
 | 
					 | 
				
			||||||
    pub fn new() -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            cfg: config::Config::default()
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl DimPlugin for Plug {
 | 
					impl DimPlugin for Plug {
 | 
				
			||||||
    fn init(&mut self, ctx: Context) {
 | 
					    fn init(ctx: Context) -> Result<Self> {
 | 
				
			||||||
        match config::Config::parse(&ctx.config_dir.join("config.toml")) {
 | 
					        let cfg;
 | 
				
			||||||
            Ok(c) => self.cfg = c,
 | 
					        match config::Config::parse(&ctx.config_dir.join("config.toml").clone()) {
 | 
				
			||||||
 | 
					            Ok(c) => cfg = c,
 | 
				
			||||||
            Err(e) => {
 | 
					            Err(e) => {
 | 
				
			||||||
                eprintln!("ERROR: Failed to open config file: {e}");
 | 
					                log::error!("Failed to open config file: {e}");
 | 
				
			||||||
                // TODO: Add function to disable the plugin
 | 
					                // TODO: Add function to disable the plugin
 | 
				
			||||||
                return;
 | 
					                bail!("")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(Self { ctx, cfg })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
 | 
					    fn on_message(&mut self, msg: Message) -> Result<()> {
 | 
				
			||||||
        let mut proc = {
 | 
					        self.ctx.buf.reset();
 | 
				
			||||||
                let mut p = std::process::Command::new("sh");
 | 
					        match msg.name.as_str() {
 | 
				
			||||||
                p.arg("-c");
 | 
					            "poll" => {
 | 
				
			||||||
                p.arg(&self.cfg.commands.get_volume);
 | 
					                let mut proc = {
 | 
				
			||||||
                p.stdout(Stdio::piped());
 | 
					                        let mut p = std::process::Command::new("sh");
 | 
				
			||||||
                p
 | 
					                        p.arg("-c");
 | 
				
			||||||
            };
 | 
					                        p.arg(&self.cfg.commands.get_volume);
 | 
				
			||||||
 | 
					                        p.stdout(Stdio::piped());
 | 
				
			||||||
 | 
					                        p
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let output = String::from_utf8(proc.output()?.stdout)?;
 | 
					                let output = String::from_utf8(proc.output()?.stdout)?;
 | 
				
			||||||
        let re = regex::Regex::new(&self.cfg.commands.get_volume_regex)?;
 | 
					                let re = regex::Regex::new(&self.cfg.commands.get_volume_regex)?;
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        if let Some(caps) = re.captures(&output) {
 | 
					                if let Some(caps) = re.captures(&output) {
 | 
				
			||||||
            let volume = &caps["vol"];
 | 
					                    let volume = &caps["vol"];
 | 
				
			||||||
            write!(f, "Vol: {volume}%")?;
 | 
					                    write!(self.ctx, "Vol: {volume}%")?;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => ()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn pre_reload(&mut self) {
 | 
					    fn pre_reload(&mut self) -> Result<()> {
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn post_reload(&mut self) {
 | 
					    fn post_reload(&mut self) -> Result<()> {
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn free(&mut self) {
 | 
					    fn free(&mut self) -> Result<()> {
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,32 +4,83 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdio.h>
 | 
					#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 {
 | 
					typedef struct plug_info_t {
 | 
				
			||||||
    char* name;
 | 
					    char* name;
 | 
				
			||||||
    char* version;
 | 
					    char* version;
 | 
				
			||||||
    char* license;
 | 
					    char* license;
 | 
				
			||||||
} plug_info_t;
 | 
					} 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 {
 | 
					typedef struct plug_ctx_t {
 | 
				
			||||||
    char* config_dir;
 | 
					    char* config_dir;
 | 
				
			||||||
 | 
					    plug_funcs_ctx_t funcs;
 | 
				
			||||||
 | 
					    char* buf;
 | 
				
			||||||
} plug_ctx_t;
 | 
					} 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)}; \
 | 
					static plug_info_t PLUG_INFO_VAR = { .name=(_name), .version=(_version), .license=(_license)}; \
 | 
				
			||||||
void* plug_get_info() {     \
 | 
					void* plug_get_info() {                                                                        \
 | 
				
			||||||
    return &PLUG_INFO_VAR; \
 | 
					    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);
 | 
					#ifdef PLUG_IMPL
 | 
				
			||||||
#define PLUG_VERSION(s) volatile char* PLUG_VERSION = (s);
 | 
					static plug_ctx_t CTX = {0};
 | 
				
			||||||
#define PLUG_LICENSE(s) volatile char* PLUG_LICENSE = (s);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setup_ctx(plug_ctx_t* ctx) {
 | 
				
			||||||
 | 
					    CTX = *ctx;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void  plug_init(plug_ctx_t*);                        // Loads when DIM initialises
 | 
					void _log(char* module, log_level_t level, char* s) {
 | 
				
			||||||
void* plug_pre_reload();                  // Return a pointer to save state
 | 
					    (CTX.funcs.log)(module, level, s);
 | 
				
			||||||
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
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,3 +11,4 @@ anyhow = "1.0.86"
 | 
				
			||||||
bytes = "1.6.0"
 | 
					bytes = "1.6.0"
 | 
				
			||||||
lazy_static = { version = "1.4.0", features = ["spin"] }
 | 
					lazy_static = { version = "1.4.0", features = ["spin"] }
 | 
				
			||||||
libc = "0.2.155"
 | 
					libc = "0.2.155"
 | 
				
			||||||
 | 
					log = { version = "0.4.21", features = ["std"] }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,33 +1,40 @@
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct CBuffer<'a> {
 | 
					pub struct CBuffer {
 | 
				
			||||||
    inner: &'a mut [i8],
 | 
					    inner: Vec<u8>,
 | 
				
			||||||
    count: usize,
 | 
					    count: usize,
 | 
				
			||||||
    capacity: usize 
 | 
					    capacity: usize 
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(dead_code)] // rust_analyzer too dumb to see my macro magic
 | 
					#[allow(dead_code)] // rust_analyzer too dumb to see my macro magic
 | 
				
			||||||
                    // i hate that macro as much as you do
 | 
					                    // i hate that macro as much as you do
 | 
				
			||||||
impl CBuffer<'_> {
 | 
					impl CBuffer {
 | 
				
			||||||
    pub fn from_raw_parts_mut(buf: *mut i8, capacity: usize) -> Self {
 | 
					    pub fn from_raw_parts_mut(buf: *mut u8, capacity: usize) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            inner: unsafe {
 | 
					            inner: unsafe {
 | 
				
			||||||
                std::slice::from_raw_parts_mut(buf, capacity)
 | 
					                Vec::from_raw_parts(buf, capacity, capacity)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            capacity,
 | 
					            capacity,
 | 
				
			||||||
            count: 0,
 | 
					            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> { 
 | 
					    fn write_str(&mut self, buf: &str) -> Result<(), std::fmt::Error> { 
 | 
				
			||||||
        for c in buf.as_bytes() {
 | 
					        for c in buf.as_bytes() {
 | 
				
			||||||
            if self.count >= self.capacity - 1 {
 | 
					            if self.count >= self.capacity - 1 {
 | 
				
			||||||
                return Ok(());
 | 
					                return Ok(());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            self.inner[self.count] = *c as i8;
 | 
					            self.inner[self.count] = *c;
 | 
				
			||||||
            self.count += 1;
 | 
					            self.count += 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self.inner[self.count] = 0;
 | 
					        self.inner[self.count] = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,25 +1,46 @@
 | 
				
			||||||
use std::{ffi::{c_char, CStr}, path::PathBuf};
 | 
					use std::{ffi::{c_char, CStr}, path::PathBuf};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::CBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
#[repr(C)]
 | 
					#[repr(C)]
 | 
				
			||||||
pub struct ContextRaw {
 | 
					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)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
pub struct Context {
 | 
					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 {
 | 
					impl Context {
 | 
				
			||||||
    pub fn new(cr: *const ContextRaw) -> Self {
 | 
					    pub fn new(cr: ContextRaw) -> Self {
 | 
				
			||||||
        let config_dir = unsafe {
 | 
					        let config_dir = unsafe {
 | 
				
			||||||
            let v = CStr::from_ptr((*cr).config_dir);
 | 
					            let v = CStr::from_ptr(cr.config_dir);
 | 
				
			||||||
            PathBuf::from(v.to_string_lossy().to_string())
 | 
					            PathBuf::from(v.to_string_lossy().to_string().clone())
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					 | 
				
			||||||
        Self {
 | 
					        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 c_buffer;
 | 
				
			||||||
mod plugin_info;
 | 
					mod plugin_info;
 | 
				
			||||||
mod context;
 | 
					mod context;
 | 
				
			||||||
 | 
					mod logger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::ffi::{c_char, CStr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 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));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -14,61 +14,87 @@ macro_rules! plugin_info {
 | 
				
			||||||
            PLUGIN_INFO.get_raw_ptr()
 | 
					            PLUGIN_INFO.get_raw_ptr()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #[no_mangle]
 | 
					        impl $typ {
 | 
				
			||||||
        unsafe extern "C" fn plug_init(ctx: *const $crate::ContextRaw) {
 | 
					            pub fn get_plugin_info(&self) -> $crate::PluginInfo {
 | 
				
			||||||
            //PLUG = std::alloc::alloc(std::alloc::Layout::new::<$typ>()) as *mut $typ;
 | 
					                $crate::PluginInfo::new(
 | 
				
			||||||
            PLUG = Some(Plug::new());
 | 
					                    PLUGIN_INFO.name().as_str(),
 | 
				
			||||||
            
 | 
					                    PLUGIN_INFO.version().as_str(),
 | 
				
			||||||
            let ctx = $crate::Context::new(ctx);
 | 
					                    PLUGIN_INFO.license().as_str()
 | 
				
			||||||
            if let Some(p) = &mut PLUG {
 | 
					                    )
 | 
				
			||||||
                p.init(ctx)
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                unreachable!();
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #[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]
 | 
					        #[no_mangle]
 | 
				
			||||||
        unsafe extern "C" fn plug_pre_reload() -> *mut $typ {
 | 
					        unsafe extern "C" fn plug_pre_reload() -> *mut $typ {
 | 
				
			||||||
            //TODO: Untested 
 | 
					            //TODO: Untested 
 | 
				
			||||||
            if let Some(p) = &mut PLUG {
 | 
					            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;
 | 
					                return p as *mut $typ;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            unreachable!();
 | 
					            unreachable!();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #[no_mangle]
 | 
					        #[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());
 | 
					            PLUG = Some((*state).clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if let Some(p) = &mut PLUG {
 | 
					            if let Some(p) = &mut PLUG {
 | 
				
			||||||
                p.post_reload();
 | 
					                if let Err(e) = p.post_reload() {
 | 
				
			||||||
            } else {
 | 
					                    log::error!("Had an error on pre reload: {e}");
 | 
				
			||||||
                unreachable!();
 | 
					                    return 1;
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            //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?
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                unreachable!();
 | 
					                unreachable!();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            //TODO: Untested
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #[no_mangle]
 | 
					        #[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 {
 | 
					            if let Some(p) = &mut PLUG {
 | 
				
			||||||
                // std::alloc::dealloc(PLUG as *mut u8, std::alloc::Layout::new::<$typ>());
 | 
					                if let Err(e) = p.on_message(msg) {
 | 
				
			||||||
                p.free();
 | 
					                    log::error!("Had error on `on_msg`: {e}");
 | 
				
			||||||
 | 
					                    return 1;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                unreachable!();
 | 
					                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 {
 | 
					    pub fn get_raw_ptr(&self) -> *const c_void {
 | 
				
			||||||
        &self.ptrs as *const _ as *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 {}
 | 
					unsafe impl Sync for PluginInfo {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										46
									
								
								src/cli.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/cli.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					use clap::{Parser, Subcommand};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Parser)]
 | 
				
			||||||
 | 
					pub struct CliArgs {
 | 
				
			||||||
 | 
					    /// Directory where all *.dim plugin files are stored
 | 
				
			||||||
 | 
					    #[arg(long, short, default_value="./plugins")]
 | 
				
			||||||
 | 
					    pub plugin_dir: camino::Utf8PathBuf,
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Directory where all configurations are stored
 | 
				
			||||||
 | 
					    #[arg(long, short, default_value="./config")]
 | 
				
			||||||
 | 
					    pub config_dir: camino::Utf8PathBuf,
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Print more debug info
 | 
				
			||||||
 | 
					    #[arg(long, short)]
 | 
				
			||||||
 | 
					    pub debug: bool,
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Socket path
 | 
				
			||||||
 | 
					    #[arg(long, short)]
 | 
				
			||||||
 | 
					    pub sock_path: Option<camino::Utf8PathBuf>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[command(subcommand)]
 | 
				
			||||||
 | 
					    pub subcommand: Option<CliSubcommand>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Subcommand)]
 | 
				
			||||||
 | 
					pub enum CliSubcommand {
 | 
				
			||||||
 | 
					    /// Send a message through ipc to the running DIM instance
 | 
				
			||||||
 | 
					    Send {
 | 
				
			||||||
 | 
					        /// Command name, eg. `clock:reset`, 
 | 
				
			||||||
 | 
					        /// `clock:` will be stripped and the command will be sent
 | 
				
			||||||
 | 
					        /// only to plugin `clock`, dont include it to send it to all plugins
 | 
				
			||||||
 | 
					        #[arg(long, short)]
 | 
				
			||||||
 | 
					        name: String,
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        /// Value to send
 | 
				
			||||||
 | 
					        #[arg(long, short, default_value="")]
 | 
				
			||||||
 | 
					        value: String,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Reload one or all plugins
 | 
				
			||||||
 | 
					    Reload {
 | 
				
			||||||
 | 
					        /// (Optional) Which plugin to Reload
 | 
				
			||||||
 | 
					        name: Option<String>
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,14 @@ use std::path::{Path, PathBuf};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::cli::CliArgs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Serialize, Deserialize, Default)]
 | 
					#[derive(Debug, Serialize, Deserialize, Default)]
 | 
				
			||||||
pub struct Config {
 | 
					pub struct Config {
 | 
				
			||||||
    pub seperator: String,
 | 
					    pub seperator: String,
 | 
				
			||||||
 | 
					    pub refresh_ms: usize,
 | 
				
			||||||
 | 
					    pub sock_path: String,
 | 
				
			||||||
    pub plugins: ConfigPlugins,
 | 
					    pub plugins: ConfigPlugins,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[serde(skip)]
 | 
					    #[serde(skip)]
 | 
				
			||||||
| 
						 | 
					@ -14,24 +18,26 @@ pub struct Config {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Serialize, Deserialize, Default)]
 | 
					#[derive(Debug, Serialize, Deserialize, Default)]
 | 
				
			||||||
pub struct ConfigPlugins {
 | 
					pub struct ConfigPlugins {
 | 
				
			||||||
 | 
					    pub path: PathBuf,
 | 
				
			||||||
    pub blacklist: Vec<String>,
 | 
					    pub blacklist: Vec<String>,
 | 
				
			||||||
    pub as_whitelist: bool,
 | 
					    pub as_whitelist: bool,
 | 
				
			||||||
    pub template: Vec<String>,
 | 
					    pub template: Vec<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Config {
 | 
					impl Config {
 | 
				
			||||||
    pub fn new(path: &Path) -> Result<Self, ConfigError> {
 | 
					    pub fn new(cli: CliArgs) -> Result<Self, ConfigError> {
 | 
				
			||||||
        let cfg_path = path.join("main.toml");
 | 
					        let cfg_path = cli.config_dir.join("main.toml");
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        if !cfg_path.exists() {
 | 
					        if !cfg_path.exists() {
 | 
				
			||||||
            println!("ERROR: {:?} doesnt exist", path);
 | 
					            println!("ERROR: {:?} doesnt exist", cli.config_dir);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut cfg: Self = toml::from_str(
 | 
					        let mut cfg: Self = toml::from_str(
 | 
				
			||||||
                &std::fs::read_to_string(&cfg_path)?
 | 
					                &std::fs::read_to_string(&cfg_path)?
 | 
				
			||||||
            )?;
 | 
					            )?;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        cfg.config_dir = path.to_path_buf();
 | 
					        cfg.config_dir = cli.config_dir.as_std_path().to_path_buf();
 | 
				
			||||||
 | 
					        cfg.plugins.path = cli.plugin_dir.as_std_path().to_path_buf();
 | 
				
			||||||
        Ok(cfg)
 | 
					        Ok(cfg)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,7 +80,7 @@ impl Display {
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if !found {
 | 
					            if !found {
 | 
				
			||||||
                log::warn!("Plugin '{}' was not found even though it was included in the template", tv);
 | 
					                // log::warn!("Plugin '{}' was not found even though it was included in the template", tv);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										0
									
								
								src/ipc/client/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/ipc/client/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										63
									
								
								src/ipc/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/ipc/mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,63 @@
 | 
				
			||||||
 | 
					use std::ffi::{c_char, CString};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod client;
 | 
				
			||||||
 | 
					pub mod server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct Message {
 | 
				
			||||||
 | 
					    pub plugin: Option<String>,
 | 
				
			||||||
 | 
					    pub name: CString,
 | 
				
			||||||
 | 
					    pub value: CString,
 | 
				
			||||||
 | 
					    pub ffi: MessageFFI
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					#[repr(C)]
 | 
				
			||||||
 | 
					pub struct MessageFFI {
 | 
				
			||||||
 | 
					    pub name: *const c_char,
 | 
				
			||||||
 | 
					    pub value: *const c_char,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Message {
 | 
				
			||||||
 | 
					    pub fn from_string_kv<S: ToString>(name: S, value: S) -> Self {
 | 
				
			||||||
 | 
					        let mut name = name.to_string();
 | 
				
			||||||
 | 
					        let value = value.to_string();
 | 
				
			||||||
 | 
					        let plugin;
 | 
				
			||||||
 | 
					        if name.contains(':') {
 | 
				
			||||||
 | 
					            let ns: Vec<&str> = name.split(':').collect();
 | 
				
			||||||
 | 
					            plugin = Some(ns[0].to_string());
 | 
				
			||||||
 | 
					            name = ns[1..].join(":");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            plugin = None;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					           
 | 
				
			||||||
 | 
					        let name = CString::new(name).unwrap();
 | 
				
			||||||
 | 
					        let value = CString::new(value).unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            ffi: MessageFFI {
 | 
				
			||||||
 | 
					                name: name.as_ptr(),
 | 
				
			||||||
 | 
					                value: value.as_ptr()
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            plugin, 
 | 
				
			||||||
 | 
					            name, 
 | 
				
			||||||
 | 
					            value,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn from_string<S: ToString>(k: S) -> Self {
 | 
				
			||||||
 | 
					        let k = k.to_string();
 | 
				
			||||||
 | 
					        let mut v = String::new();
 | 
				
			||||||
 | 
					        let mut name = k.clone();
 | 
				
			||||||
 | 
					        if k.contains('=') {
 | 
				
			||||||
 | 
					            let kv: Vec<&str> = k.split('=').collect();
 | 
				
			||||||
 | 
					            name = kv[0].to_string();
 | 
				
			||||||
 | 
					            v = kv[1..].join("=");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self::from_string_kv(name, v)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/ipc/server/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/ipc/server/mod.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					use std::{io::Read, os::unix::net::UnixStream};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::config::Config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct IpcServer{
 | 
				
			||||||
 | 
					    sock: UnixStream
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IpcServer {
 | 
				
			||||||
 | 
					    pub fn start(cfg: &Config) -> std::io::Result<Self> {
 | 
				
			||||||
 | 
					        Ok(Self {
 | 
				
			||||||
 | 
					            sock: UnixStream::connect(&cfg.sock_path)?,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn poll(&mut self) -> Option<Message> {
 | 
				
			||||||
 | 
					        let mut buf = String::new();
 | 
				
			||||||
 | 
					        let _ = self.sock.read_to_string(&mut buf);
 | 
				
			||||||
 | 
					        if buf.is_empty() {
 | 
				
			||||||
 | 
					            return None;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Some(Message::from_string(buf))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/logger.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/logger.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					pub use crate::cli::CliArgs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn init(ca: &CliArgs) {
 | 
				
			||||||
 | 
					    if ca.debug {
 | 
				
			||||||
 | 
					        env_logger::builder()
 | 
				
			||||||
 | 
					            .filter(None, log::LevelFilter::Debug)
 | 
				
			||||||
 | 
					            .init();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        env_logger::builder()
 | 
				
			||||||
 | 
					            .filter(None, log::LevelFilter::Info)
 | 
				
			||||||
 | 
					            .init();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										39
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								src/main.rs
									
									
									
									
									
								
							| 
						 | 
					@ -1,48 +1,29 @@
 | 
				
			||||||
#![allow(internal_features)]
 | 
					#![allow(internal_features)]
 | 
				
			||||||
#![feature(core_intrinsics)]
 | 
					#![feature(core_intrinsics)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::{ffi::c_char, process::ExitCode, time::Duration};
 | 
					use std::{process::ExitCode, time::Duration};
 | 
				
			||||||
use clap::Parser;
 | 
					use clap::Parser;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod display;
 | 
					mod display;
 | 
				
			||||||
mod plugman;
 | 
					mod plugman;
 | 
				
			||||||
mod config;
 | 
					mod config;
 | 
				
			||||||
mod util;
 | 
					mod util;
 | 
				
			||||||
 | 
					mod cli;
 | 
				
			||||||
 | 
					mod logger;
 | 
				
			||||||
 | 
					mod ipc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Parser)]
 | 
					// TODO: Make function available in ctx that disables the plugin
 | 
				
			||||||
struct CliArgs {
 | 
					 | 
				
			||||||
    #[arg(long, short, default_value="./plugins")]
 | 
					 | 
				
			||||||
    pub plugin_dir: camino::Utf8PathBuf,
 | 
					 | 
				
			||||||
    #[arg(long, short, default_value="./config")]
 | 
					 | 
				
			||||||
    pub config_dir: camino::Utf8PathBuf,
 | 
					 | 
				
			||||||
    #[arg(long, short)]
 | 
					 | 
				
			||||||
    pub debug: bool
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[allow(non_camel_case_types)]
 | 
					 | 
				
			||||||
pub type c_str = *const c_char;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: Clean up main function
 | 
					 | 
				
			||||||
// TODO: Make ffi safe abstraction for logger
 | 
					 | 
				
			||||||
// TODO: Set up ipc with unix sockets
 | 
					// TODO: Set up ipc with unix sockets
 | 
				
			||||||
// TODO: Allow sending messages command -> running DIM instance -> plugin with ipc
 | 
					// TODO: Allow sending messages command -> running DIM instance -> plugin with ipc
 | 
				
			||||||
// TODO: Clickable bar: https://dwm.suckless.org/patches/statuscmd/
 | 
					// TODO: Clickable bar: https://dwm.suckless.org/patches/statuscmd/
 | 
				
			||||||
// TODO: Run code through clippy
 | 
					// TODO: Run code through clippy
 | 
				
			||||||
fn main() -> ExitCode {
 | 
					fn main() -> ExitCode {
 | 
				
			||||||
    let ca = CliArgs::parse();
 | 
					    let ca = cli::CliArgs::parse();
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    if ca.debug {
 | 
					    logger::init(&ca);
 | 
				
			||||||
        env_logger::builder()
 | 
					 | 
				
			||||||
            .filter(None, log::LevelFilter::Debug)
 | 
					 | 
				
			||||||
            .init();
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        env_logger::builder()
 | 
					 | 
				
			||||||
            .filter(None, log::LevelFilter::Info)
 | 
					 | 
				
			||||||
            .init();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let config;
 | 
					    let config;
 | 
				
			||||||
    match config::Config::new(ca.config_dir.as_std_path()) {
 | 
					    match config::Config::new(ca) {
 | 
				
			||||||
        Ok(v) => config = v,
 | 
					        Ok(v) => config = v,
 | 
				
			||||||
        Err(e) => {
 | 
					        Err(e) => {
 | 
				
			||||||
            log::error!("Failed to parse config: {e:?}");
 | 
					            log::error!("Failed to parse config: {e:?}");
 | 
				
			||||||
| 
						 | 
					@ -55,7 +36,7 @@ fn main() -> ExitCode {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut pm = plugman::PlugMan::new(1024); // idk tbh
 | 
					    let mut pm = plugman::PlugMan::new(1024); // idk tbh
 | 
				
			||||||
    if let Err(e) = pm.load(ca.plugin_dir.as_std_path().to_path_buf()){
 | 
					    if let Err(e) = pm.load(&config.plugins.path){
 | 
				
			||||||
        log::error!("Failed to load plugins: {e:?}");
 | 
					        log::error!("Failed to load plugins: {e:?}");
 | 
				
			||||||
        return ExitCode::from(3);
 | 
					        return ExitCode::from(3);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -64,6 +45,8 @@ fn main() -> ExitCode {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
        let vals = pm.poll_plugins();
 | 
					        let vals = pm.poll_plugins();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        log::debug!("vals: {vals:?}");
 | 
				
			||||||
        if let Err(e) = disp.write_with_vec(&config, vals) {
 | 
					        if let Err(e) = disp.write_with_vec(&config, vals) {
 | 
				
			||||||
            log::warn!("Failed to write too bar: {e}");
 | 
					            log::warn!("Failed to write too bar: {e}");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,6 @@
 | 
				
			||||||
use std::{collections::HashMap, path::PathBuf};
 | 
					use std::{collections::HashMap, path::{Path, PathBuf}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::ipc::Message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use self::plugin::Plugin;
 | 
					use self::plugin::Plugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +21,8 @@ impl PlugMan {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn load(&mut self, dir: PathBuf) -> Result<(), PluginError>{
 | 
					    pub fn load<P: AsRef<Path>>(&mut self, dir: P) -> Result<(), PluginError>{
 | 
				
			||||||
 | 
					        let dir: &Path = dir.as_ref();
 | 
				
			||||||
        log::debug!("Loading plugins from {:?}", dir);
 | 
					        log::debug!("Loading plugins from {:?}", dir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let files = std::fs::read_dir(dir)?;
 | 
					        let files = std::fs::read_dir(dir)?;
 | 
				
			||||||
| 
						 | 
					@ -50,7 +53,7 @@ impl PlugMan {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn init_plugins(&mut self, cfg: &crate::config::Config) {
 | 
					    pub fn init_plugins(&mut self, cfg: &crate::config::Config) {
 | 
				
			||||||
        for plugin in &self.plugins {
 | 
					        for plugin in &mut self.plugins {
 | 
				
			||||||
            plugin.init(cfg);
 | 
					            plugin.init(cfg);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -73,20 +76,16 @@ impl PlugMan {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn poll_plugins(&mut self) -> HashMap<String, PolledText> {
 | 
					    pub fn poll_plugins(&mut self) -> HashMap<String, PolledText> {
 | 
				
			||||||
        let mut answers = HashMap::new();
 | 
					        let mut answers = HashMap::new();
 | 
				
			||||||
        let len = self.len_cap / self.plugins.len();
 | 
					        for plugin in &mut self.plugins {
 | 
				
			||||||
        for plugin in &self.plugins {
 | 
					 | 
				
			||||||
            if !plugin.enabled() {
 | 
					            if !plugin.enabled() {
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            match plugin.poll(len) {
 | 
					            match plugin.poll() {
 | 
				
			||||||
                Ok(v) => {
 | 
					                Ok(v) => {
 | 
				
			||||||
                    let mut pth = (plugin.name().clone(), PolledText::new(v));
 | 
					                    let pth = (plugin.name().clone(), PolledText::new(v));
 | 
				
			||||||
                    if pth.1.text().is_empty() {
 | 
					                    if !pth.1.text().is_empty() {
 | 
				
			||||||
                        pth.1.disable()
 | 
					                        answers.insert(pth.0, pth.1);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    answers.insert(pth.0, pth.1);
 | 
					 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                Err(e) => log::error!("Failed to poll plugin: {e}"),
 | 
					                Err(e) => log::error!("Failed to poll plugin: {e}"),
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -94,6 +93,18 @@ impl PlugMan {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        answers
 | 
					        answers
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn send_msg(&mut self, msg: Message) {
 | 
				
			||||||
 | 
					        for plugin in &mut self.plugins {
 | 
				
			||||||
 | 
					            if let Some(pn) = &msg.plugin {
 | 
				
			||||||
 | 
					                if *pn != plugin.name() {
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            plugin.send_msg(msg);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone)]
 | 
					#[derive(Debug, Clone)]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
use std::ffi::{c_char, CString};
 | 
					use std::ffi::{c_char, CStr, CString};
 | 
				
			||||||
 | 
					use super::Plugin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct PluginContextContainer {
 | 
					pub struct PluginContextContainer {
 | 
				
			||||||
    pub inner: PluginContext,
 | 
					    pub inner: PluginContext,
 | 
				
			||||||
| 
						 | 
					@ -8,24 +9,42 @@ pub struct PluginContextContainer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[repr(C)]
 | 
					#[repr(C)]
 | 
				
			||||||
pub struct PluginContext {
 | 
					pub struct PluginContext {
 | 
				
			||||||
    pub config_dir: *const c_char
 | 
					    pub config_dir: *const c_char,
 | 
				
			||||||
 | 
					    funcs: PluginContextFuncs,
 | 
				
			||||||
 | 
					    buf: *mut u8
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[repr(C)]
 | 
				
			||||||
 | 
					pub struct PluginContextFuncs {
 | 
				
			||||||
 | 
					    log: unsafe extern "C" fn(module: *const c_char, level: log::Level, s: *const c_char),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl PluginContext {
 | 
					impl PluginContext {
 | 
				
			||||||
    pub fn new(config_dir: &CString) -> Self {
 | 
					    pub fn new(plug: &Plugin, config_dir: &CString) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            config_dir: config_dir.as_ptr()
 | 
					            config_dir: config_dir.as_ptr(),
 | 
				
			||||||
 | 
					            funcs: PluginContextFuncs {
 | 
				
			||||||
 | 
					                log: plug_log,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            buf: plug.buf
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl PluginContextContainer {
 | 
					impl PluginContextContainer {
 | 
				
			||||||
    pub fn new(config_dir: &String) -> Self {
 | 
					    pub fn new(plug: &Plugin, config_dir: &String) -> Self {
 | 
				
			||||||
        let _config_dir = CString::new(config_dir.clone()).unwrap();
 | 
					        let _config_dir = CString::new(config_dir.clone()).unwrap();
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            inner: PluginContext::new(&_config_dir),
 | 
					            inner: PluginContext::new(plug, &_config_dir),
 | 
				
			||||||
            _config_dir,
 | 
					            _config_dir,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub unsafe extern "C" fn plug_log(module: *const c_char, level: log::Level, s: *const c_char) {
 | 
				
			||||||
 | 
					    let module = CStr::from_ptr(module).to_string_lossy().to_string();
 | 
				
			||||||
 | 
					    let s = CStr::from_ptr(s).to_string_lossy().to_string();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    log::log!(target: &module, level, "{s}");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,16 @@
 | 
				
			||||||
use std::ffi::c_char;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use dlopen::raw::Library;
 | 
					use dlopen::raw::Library;
 | 
				
			||||||
 | 
					use crate::ipc::MessageFFI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{context::PluginContext, Plugin, PluginInfo};
 | 
					use super::{context::PluginContext, Plugin, PluginInfo};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone, Copy)]
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
pub struct PluginSyms {
 | 
					pub struct PluginSyms {
 | 
				
			||||||
    pub(super) init:        unsafe extern "C" fn(ctx: *const PluginContext),
 | 
					    pub(super) init:        unsafe extern "C" fn(ctx: *const PluginContext) -> i32,
 | 
				
			||||||
    pub(super) pre_reload:  unsafe extern "C" fn() -> *const (),
 | 
					    pub(super) pre_reload:  unsafe extern "C" fn() -> *const (),
 | 
				
			||||||
    pub(super) post_reload: unsafe extern "C" fn(state: *const ()),
 | 
					    pub(super) post_reload: unsafe extern "C" fn(state: *const ()) -> i32,
 | 
				
			||||||
    pub(super) poll:        unsafe extern "C" fn(buf: *mut c_char, len: usize),
 | 
					    pub(super) on_msg:      unsafe extern "C" fn(msg: *const MessageFFI) -> i32,
 | 
				
			||||||
    pub(super) free:        unsafe extern "C" fn(),
 | 
					    pub(super) free:        unsafe extern "C" fn() -> i32,
 | 
				
			||||||
    pub(super) get_info:    unsafe extern "C" fn() -> *const PluginInfo,
 | 
					    pub(super) get_info:    unsafe extern "C" fn() -> *const PluginInfo,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +22,7 @@ impl Plugin {
 | 
				
			||||||
            init: unsafe { lib.symbol("plug_init")? },
 | 
					            init: unsafe { lib.symbol("plug_init")? },
 | 
				
			||||||
            pre_reload: unsafe { lib.symbol("plug_pre_reload")? },
 | 
					            pre_reload: unsafe { lib.symbol("plug_pre_reload")? },
 | 
				
			||||||
            post_reload: unsafe { lib.symbol("plug_post_reload")? },
 | 
					            post_reload: unsafe { lib.symbol("plug_post_reload")? },
 | 
				
			||||||
            poll: unsafe { lib.symbol("plug_poll")? },
 | 
					            on_msg: unsafe { lib.symbol("plug_on_msg")? },
 | 
				
			||||||
            free: unsafe { lib.symbol("plug_free")? },
 | 
					            free: unsafe { lib.symbol("plug_free")? },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            get_info: unsafe { lib.symbol("plug_get_info")? },
 | 
					            get_info: unsafe { lib.symbol("plug_get_info")? },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,35 +2,46 @@ use std::{alloc::Layout, ffi::{c_char, CStr}, path::PathBuf};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use dlopen::raw::Library;
 | 
					use dlopen::raw::Library;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{c_str, config::Config};
 | 
					use crate::{config::Config, ipc::{Message, MessageFFI}};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use self::context::{PluginContext, PluginContextContainer};
 | 
					use self::context::{PluginContext, PluginContextContainer};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod loader;
 | 
					pub mod loader;
 | 
				
			||||||
pub mod context;
 | 
					pub mod context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MEM_LAYOUT: Result<Layout, std::alloc::LayoutError> = Layout::from_size_align(2048, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[repr(C)]
 | 
					#[repr(C)]
 | 
				
			||||||
pub struct PluginInfo {
 | 
					pub struct PluginInfo {
 | 
				
			||||||
    name: c_str,
 | 
					    name: *const c_char,
 | 
				
			||||||
    version: c_str,
 | 
					    version: *const c_char,
 | 
				
			||||||
    license: c_str,
 | 
					    license: *const c_char,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Default)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct Plugin {
 | 
					pub struct Plugin {
 | 
				
			||||||
    syms: Option<loader::PluginSyms>,
 | 
					    syms: Option<loader::PluginSyms>,
 | 
				
			||||||
    path: PathBuf,
 | 
					    path: PathBuf,
 | 
				
			||||||
    lib: Option<Library>,
 | 
					    lib: Option<Library>,
 | 
				
			||||||
    enabled: bool,
 | 
					    enabled: bool,
 | 
				
			||||||
 | 
					    buf: *mut u8
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 buf = unsafe {
 | 
				
			||||||
        s.enabled = true;
 | 
					            std::alloc::alloc_zeroed(MEM_LAYOUT.unwrap())
 | 
				
			||||||
        s.path = path;
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut s = Self {
 | 
				
			||||||
 | 
					            enabled: true,
 | 
				
			||||||
 | 
					            path,
 | 
				
			||||||
 | 
					            syms: None,
 | 
				
			||||||
 | 
					            lib: None,
 | 
				
			||||||
 | 
					            buf
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
        s.reload_symbols()?;
 | 
					        s.reload_symbols()?;
 | 
				
			||||||
        Ok(s)
 | 
					        Ok(s)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -39,51 +50,71 @@ impl Plugin {
 | 
				
			||||||
        self.syms.unwrap()
 | 
					        self.syms.unwrap()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn init(&self, cfg: &Config) {
 | 
					    pub fn init(&mut self, cfg: &Config) {
 | 
				
			||||||
        let conf_dir = &cfg.config_dir.join(self.name()).to_string_lossy().to_string();
 | 
					        let conf_dir = &cfg.config_dir.join(self.name()).to_string_lossy().to_string();
 | 
				
			||||||
        let _ = std::fs::create_dir(&conf_dir); // dont care 
 | 
					        let _ = std::fs::create_dir(&conf_dir); // dont care 
 | 
				
			||||||
        let ctx = PluginContextContainer::new(conf_dir);
 | 
					        let ctx = PluginContextContainer::new(self, conf_dir);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            (self.syms().init)(&ctx.inner as *const PluginContext)
 | 
					            if (self.syms().init)(&ctx.inner as *const PluginContext) != 0 {
 | 
				
			||||||
 | 
					                log::warn!("`init` had an error, disabling");
 | 
				
			||||||
 | 
					                self.disable();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn reload(&mut self) -> Result<(), dlopen::Error> { 
 | 
					    pub fn reload(&mut self) -> Result<(), dlopen::Error> { 
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            let state = (self.syms().pre_reload)();
 | 
					            let state = (self.syms().pre_reload)();
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if state.is_null() {
 | 
				
			||||||
 | 
					                log::warn!("`pre_reload` had an error, disabling");
 | 
				
			||||||
 | 
					                self.disable();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if let Err(e) = self.reload_symbols() {
 | 
					            if let Err(e) = self.reload_symbols() {
 | 
				
			||||||
                self.disable();
 | 
					                self.disable();
 | 
				
			||||||
                return Err(e);
 | 
					                return Err(e);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            (self.syms().post_reload)(state);
 | 
					            if (self.syms().post_reload)(state) != 0 {
 | 
				
			||||||
 | 
					                log::warn!("`post_reload` had an error, disabling");
 | 
				
			||||||
 | 
					                self.disable();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn poll(&self, cap: usize) -> Result<String, std::string::FromUtf8Error> {
 | 
					    pub fn send_msg(&mut self, msg: Message) {
 | 
				
			||||||
        let layout = Layout::from_size_align(cap, 1).unwrap();
 | 
					        unsafe {
 | 
				
			||||||
        let buf = unsafe {
 | 
					            // log::debug!("Sending message to '{}': {:?}", self.name(), msg);
 | 
				
			||||||
            std::alloc::alloc_zeroed(layout)
 | 
					            if (self.syms().on_msg)(&msg.ffi  as *const MessageFFI) != 0 {
 | 
				
			||||||
        };
 | 
					                log::warn!("`on_msg` had an error, disabling");
 | 
				
			||||||
        let s = unsafe {
 | 
					                self.disable();
 | 
				
			||||||
            (self.syms().poll)(buf as *mut i8, cap);
 | 
					 | 
				
			||||||
            let len = libc::strlen(buf as *const i8);
 | 
					 | 
				
			||||||
            if len > cap {
 | 
					 | 
				
			||||||
                panic!("String len is bigger than allocatd");
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            String::from_raw_parts(buf, len, cap)
 | 
					    pub fn poll(&mut self) -> Result<String, std::string::FromUtf8Error> {
 | 
				
			||||||
 | 
					        self.send_msg(Message::from_string("poll"));
 | 
				
			||||||
 | 
					        let s = unsafe {
 | 
				
			||||||
 | 
					            CStr::from_ptr(self.buf as *const c_char).to_string_lossy().to_string()
 | 
				
			||||||
        }; 
 | 
					        }; 
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        if !s.is_empty() {
 | 
					        if !s.is_empty() {
 | 
				
			||||||
            log::debug!("Polled: {}", s);
 | 
					            // log::debug!("Polled: {}", s);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(s)
 | 
					        Ok(s)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn free(self) {
 | 
					
 | 
				
			||||||
 | 
					    pub fn free(mut self) {
 | 
				
			||||||
        unsafe {
 | 
					        unsafe {
 | 
				
			||||||
            (self.syms().free)();
 | 
					            if (self.syms().free)() != 0 {
 | 
				
			||||||
 | 
					                log::warn!("`free` had an error, disabling");
 | 
				
			||||||
 | 
					                self.disable(); // Literaly useless but eh
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            std::alloc::dealloc(self.buf, MEM_LAYOUT.unwrap());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        drop(self.lib.unwrap()); 
 | 
					        drop(self.lib.unwrap()); 
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user