From 4e7e9406f5eead3715aced7c9b2e26de82b3d5de Mon Sep 17 00:00:00 2001 From: Kingtous Date: Sat, 8 Apr 2023 18:17:13 +0800 Subject: [PATCH] feat: add vt --- Cargo.lock | 1 + Cargo.toml | 1 + src/api.rs | 8 ++++++- src/plugins.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 64 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d2984abe..5e14f72bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5146,6 +5146,7 @@ dependencies = [ "include_dir", "jni 0.19.0", "lazy_static", + "libloading", "libpulse-binding", "libpulse-simple-binding", "mac_address", diff --git a/Cargo.toml b/Cargo.toml index 48bd16045..5410ee9d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ hex = "0.4" reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false } chrono = "0.4" cidr-utils = "0.5" +libloading = "0.7" [target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies] cpal = "0.14" diff --git a/src/api.rs b/src/api.rs index d62dc4d65..c8432f112 100644 --- a/src/api.rs +++ b/src/api.rs @@ -2,9 +2,11 @@ use std::{ffi::CStr, os::raw::c_char}; use crate::plugins::PLUGIN_REGISTRAR; +// API provided by RustDesk. pub type LoadPluginFunc = fn(*const i8) -> i32; pub type UnloadPluginFunc = fn(*const i8) -> i32; +#[repr(C)] pub struct RustDeskApiTable { pub register_plugin: LoadPluginFunc, pub unload_plugin: UnloadPluginFunc, @@ -20,9 +22,13 @@ fn unload_plugin(path: *const i8) -> i32 { PLUGIN_REGISTRAR.unload_plugin(path) } +#[no_mangle] +fn get_api_table() -> RustDeskApiTable { + RustDeskApiTable::default() +} + impl Default for RustDeskApiTable { fn default() -> Self { - let f = load_plugin; Self { register_plugin: load_plugin, unload_plugin: unload_plugin, diff --git a/src/plugins.rs b/src/plugins.rs index bca77f8cc..42c74e27f 100644 --- a/src/plugins.rs +++ b/src/plugins.rs @@ -1,22 +1,42 @@ -use std::{collections::HashMap, path::Path, sync::Arc, ffi::CStr}; +use std::{ + collections::HashMap, + ffi::CStr, + path::Path, + sync::{Arc, RwLock}, +}; use hbb_common::anyhow::{anyhow, Error}; use lazy_static::lazy_static; +use libloading::Library; lazy_static! { pub static ref PLUGIN_REGISTRAR: Arc> = Arc::new(PluginRegistar::::default()); } +// API needed to be implemented by plugins. +pub type PluginInitFunc = fn() -> i32; +// API needed to be implemented by plugins. +pub type PluginDisposeFunc = fn() -> i32; pub trait Plugin { // Return: the unique ID which identifies this plugin. fn plugin_id(&self) -> String; // Return: the name which is human-readable. fn plugin_name(&self) -> String; + // Return: the virtual table of the plugin. + fn plugin_vt(&self) -> &RustDeskPluginTable; +} + +#[repr(C)] +#[derive(Default, Clone)] +pub struct RustDeskPluginTable { + pub init: Option, + pub dispose: Option, } #[derive(Default, Clone)] pub struct PluginImpl { + vt: RustDeskPluginTable, id: String, name: String, } @@ -29,29 +49,57 @@ impl Plugin for PluginImpl { fn plugin_name(&self) -> String { self.name.to_owned() } + + fn plugin_vt(&self) -> &RustDeskPluginTable { + &self.vt + } } #[derive(Default, Clone)] pub struct PluginRegistar { - plugins: HashMap, + plugins: Arc>>, } impl PluginRegistar

{ pub fn load_plugin(&self, path: *const i8) -> i32 { let p = unsafe { CStr::from_ptr(path) }; - 0 + let lib_path = p.to_str().unwrap_or("").to_owned(); + let lib = unsafe { libloading::Library::new(lib_path.as_str()) }; + match lib { + Ok(lib) => match lib.try_into() { + Ok(plugin) => { + PLUGIN_REGISTRAR + .plugins + .write() + .unwrap() + .insert(lib_path, plugin); + return 0; + } + Err(err) => { + eprintln!("Load plugin failed: {}", err); + } + }, + Err(err) => { + eprintln!("Load plugin failed: {}", err); + } + } + -1 } pub fn unload_plugin(&self, path: *const i8) -> i32 { let p = unsafe { CStr::from_ptr(path) }; - 0 + let lib_path = p.to_str().unwrap_or("").to_owned(); + match PLUGIN_REGISTRAR.plugins.write().unwrap().remove(&lib_path) { + Some(_) => 0, + None => -1, + } } } -impl TryFrom<&Path> for PluginImpl { +impl TryFrom for PluginImpl { type Error = Error; - fn try_from(value: &Path) -> Result { - Err(anyhow!("Not implemented yet.")) + fn try_from(library: Library) -> Result { + todo!() } }