From ed64813aa0391de2254e5e70ec95bb0c088f05ee Mon Sep 17 00:00:00 2001 From: Kingtous Date: Tue, 25 Apr 2023 21:03:20 +0800 Subject: [PATCH 1/7] opt: move api to plugins --- src/{ => plugin}/api.rs | 19 ++++++++----------- src/plugin/mod.rs | 1 + 2 files changed, 9 insertions(+), 11 deletions(-) rename src/{ => plugin}/api.rs (81%) diff --git a/src/api.rs b/src/plugin/api.rs similarity index 81% rename from src/api.rs rename to src/plugin/api.rs index a0ea5df1c..086cb246d 100644 --- a/src/api.rs +++ b/src/plugin/api.rs @@ -7,8 +7,6 @@ use crate::{ }; // API provided by RustDesk. -pub type LoadPluginFunc = fn(*const c_char) -> i32; -pub type UnloadPluginFunc = fn(*const c_char) -> i32; pub type AddSessionFunc = fn(session_id: String) -> bool; pub type RemoveSessionFunc = fn(session_id: &String) -> bool; pub type AddSessionHookFunc = fn(session_id: String, key: String, hook: SessionHook) -> bool; @@ -22,8 +20,6 @@ pub enum SessionHook { // #[repr(C)] pub struct RustDeskApiTable { - pub(crate) load_plugin: LoadPluginFunc, - pub(crate) unload_plugin: UnloadPluginFunc, pub add_session: AddSessionFunc, pub remove_session: RemoveSessionFunc, pub add_session_hook: AddSessionHookFunc, @@ -39,11 +35,14 @@ fn unload_plugin(path: *const c_char) -> i32 { } fn add_session(session_id: String) -> bool { - // let mut sessions = SESSIONS.write().unwrap(); - // if sessions.contains_key(&session.id) { - // return false; - // } - // let _ = sessions.insert(session.id.to_owned(), session); + let mut sessions = SESSIONS.write().unwrap(); + // Create a dummy session in SESSIONS. + let mut session: Session = Session::default(); + session.id = session_id; + if sessions.contains_key(&session.id) { + return false; + } + let _ = sessions.insert(session.id.to_owned(), session); // true false } @@ -76,8 +75,6 @@ fn remove_session_hook(session_id: String, key: &String) -> bool { impl Default for RustDeskApiTable { fn default() -> Self { Self { - load_plugin, - unload_plugin, add_session, remove_session, add_session_hook, diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index 898630910..09d0c63cb 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -8,6 +8,7 @@ mod errno; pub mod ipc; mod plog; mod plugins; +pub mod api; pub use plugins::{ handle_client_event, handle_listen_event, handle_server_event, handle_ui_event, load_plugin, From 4acc3052cc905c06aec6cb8452abfe92b0f499c4 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 27 Apr 2023 21:19:56 +0800 Subject: [PATCH 2/7] feat: add callable trait --- src/plugin/api.rs | 82 ++++------------------------------------------- 1 file changed, 6 insertions(+), 76 deletions(-) diff --git a/src/plugin/api.rs b/src/plugin/api.rs index 086cb246d..744032e88 100644 --- a/src/plugin/api.rs +++ b/src/plugin/api.rs @@ -1,84 +1,14 @@ use std::ffi::{c_char}; +use lazy_static::lazy_static; + use crate::{ flutter::{FlutterHandler, SESSIONS}, plugins::PLUGIN_REGISTRAR, ui_session_interface::Session, }; -// API provided by RustDesk. -pub type AddSessionFunc = fn(session_id: String) -> bool; -pub type RemoveSessionFunc = fn(session_id: &String) -> bool; -pub type AddSessionHookFunc = fn(session_id: String, key: String, hook: SessionHook) -> bool; -pub type RemoveSessionHookFunc = fn(session_id: String, key: &String) -> bool; - -/// Hooks for session. -#[derive(Clone)] -pub enum SessionHook { - OnSessionRgba(fn(String, Vec) -> Vec), -} - -// #[repr(C)] -pub struct RustDeskApiTable { - pub add_session: AddSessionFunc, - pub remove_session: RemoveSessionFunc, - pub add_session_hook: AddSessionHookFunc, - pub remove_session_hook: RemoveSessionHookFunc, -} - -fn load_plugin(path: *const c_char) -> i32 { - PLUGIN_REGISTRAR.load_plugin(path) -} - -fn unload_plugin(path: *const c_char) -> i32 { - PLUGIN_REGISTRAR.unload_plugin(path) -} - -fn add_session(session_id: String) -> bool { - let mut sessions = SESSIONS.write().unwrap(); - // Create a dummy session in SESSIONS. - let mut session: Session = Session::default(); - session.id = session_id; - if sessions.contains_key(&session.id) { - return false; - } - let _ = sessions.insert(session.id.to_owned(), session); - // true - false -} - -fn remove_session(session_id: &String) -> bool { - let mut sessions = SESSIONS.write().unwrap(); - if !sessions.contains_key(session_id) { - return false; - } - let _ = sessions.remove(session_id); - true -} - -fn add_session_hook(session_id: String, key: String, hook: SessionHook) -> bool { - let sessions = SESSIONS.read().unwrap(); - if let Some(session) = sessions.get(&session_id) { - return session.add_session_hook(key, hook); - } - false -} - -fn remove_session_hook(session_id: String, key: &String) -> bool { - let sessions = SESSIONS.read().unwrap(); - if let Some(session) = sessions.get(&session_id) { - return session.remove_session_hook(key); - } - false -} - -impl Default for RustDeskApiTable { - fn default() -> Self { - Self { - add_session, - remove_session, - add_session_hook, - remove_session_hook, - } - } -} +pub trait Callable { + // Call + fn onCall(method_name: String) -> bool; +} \ No newline at end of file From 3774f8308f9a79ca1e5de27415e7378b1deb107d Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 27 Apr 2023 23:37:13 +0800 Subject: [PATCH 3/7] feat: add native session handlers --- src/plugin/api.rs | 14 -------------- src/plugin/mod.rs | 3 ++- src/plugin/native.rs | 16 +++++++++++++++ src/plugin/native_handlers/mod.rs | 24 +++++++++++++++++++++++ src/plugin/native_handlers/session.rs | 28 +++++++++++++++++++++++++++ src/plugin/plugins.rs | 12 +++++++++++- 6 files changed, 81 insertions(+), 16 deletions(-) delete mode 100644 src/plugin/api.rs create mode 100644 src/plugin/native.rs create mode 100644 src/plugin/native_handlers/mod.rs create mode 100644 src/plugin/native_handlers/session.rs diff --git a/src/plugin/api.rs b/src/plugin/api.rs deleted file mode 100644 index 744032e88..000000000 --- a/src/plugin/api.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::ffi::{c_char}; - -use lazy_static::lazy_static; - -use crate::{ - flutter::{FlutterHandler, SESSIONS}, - plugins::PLUGIN_REGISTRAR, - ui_session_interface::Session, -}; - -pub trait Callable { - // Call - fn onCall(method_name: String) -> bool; -} \ No newline at end of file diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index 09d0c63cb..dea7dbd2d 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -8,7 +8,8 @@ mod errno; pub mod ipc; mod plog; mod plugins; -pub mod api; +pub mod native; +mod native_handlers; pub use plugins::{ handle_client_event, handle_listen_event, handle_server_event, handle_ui_event, load_plugin, diff --git a/src/plugin/native.rs b/src/plugin/native.rs new file mode 100644 index 000000000..dad61099e --- /dev/null +++ b/src/plugin/native.rs @@ -0,0 +1,16 @@ +use std::{ffi::{c_char, c_void}, os::raw::c_uint}; + +/// The native returned value from librustdesk native. +/// +/// [Note] +/// The data is owned by librustdesk. +#[repr(C)] +pub struct NativeReturnValue{ + return_type: c_uint, + data: *const c_void +} + +pub(super) extern "C" fn cb_native_data(method: *const c_char, json: *const c_char, raw: *const c_void, raw_len: usize) -> NativeReturnValue { + // TODO: cb for native data. + return NativeReturnValue { return_type: 0, data: std::ptr::null() }; +} \ No newline at end of file diff --git a/src/plugin/native_handlers/mod.rs b/src/plugin/native_handlers/mod.rs new file mode 100644 index 000000000..9f7011cb2 --- /dev/null +++ b/src/plugin/native_handlers/mod.rs @@ -0,0 +1,24 @@ +use std::ffi::{c_void, c_ulonglong, c_ulong}; + +use serde_json::Map; + +pub mod session; + +pub type NR = super::native::NativeReturnValue; +pub type PluginNativeHandlerRegistrar = NativeHandlerRegistrar; + +pub struct NativeHandlerRegistrar{ + handlers: Vec +} + +pub(crate) trait PluginNativeHandler { + /// Try to handle the method with the given data. + /// + /// Returns: None for the message does not be handled by this handler. + fn on_message(method: &String, data: &Map) -> Option; + + /// Try to handle the method with the given data and extra void binary data. + /// + /// Returns: None for the message does not be handled by this handler. + fn on_message_raw(method: &String, data: &Map, raw: *const c_void, raw_len: usize) -> Option; +} \ No newline at end of file diff --git a/src/plugin/native_handlers/session.rs b/src/plugin/native_handlers/session.rs new file mode 100644 index 000000000..f8e8baa67 --- /dev/null +++ b/src/plugin/native_handlers/session.rs @@ -0,0 +1,28 @@ +use super::PluginNativeHandler; + + +/// Session related handler for librustdesk core. +pub struct PluginNativeSessionHandler; + + +impl PluginNativeHandler for PluginNativeSessionHandler { + fn on_message(method: &String, data: &serde_json::Map) -> Option { + None + } + + fn on_message_raw(method: &String, data: &serde_json::Map, raw: *const std::ffi::c_void, raw_len: usize) -> Option { + None + } + +} + +impl PluginNativeSessionHandler { + fn create_session() { + + } + + + fn add_session_hook() { + + } +} \ No newline at end of file diff --git a/src/plugin/plugins.rs b/src/plugin/plugins.rs index a17f24980..4441d314d 100644 --- a/src/plugin/plugins.rs +++ b/src/plugin/plugins.rs @@ -14,7 +14,7 @@ use std::{ collections::HashMap, ffi::{c_char, c_void}, path::PathBuf, - sync::{Arc, RwLock}, + sync::{Arc, RwLock}, os::raw::c_uint, }; const METHOD_HANDLE_UI: &[u8; 10] = b"handle_ui\0"; @@ -91,6 +91,14 @@ type CallbackGetId = extern "C" fn() -> *const c_char; /// level: "error", "warn", "info", "debug", "trace". /// msg: The message. type CallbackLog = extern "C" fn(level: *const c_char, msg: *const c_char); + +/// Callback to the librustdesk core. +/// +/// method: the method name of this callback. +/// json: the json data for the parameters. The argument *must* be non-null. +/// raw: the binary data for this call, nullable. +/// raw_len: the length of this binary data, only valid when we pass raw data to `raw`. +type CallbackNative = extern "C" fn(method: *const c_char, json: *const c_char, raw: *const c_void, raw_len: usize) -> super::native::NativeReturnValue; /// The main function of the plugin on the client(self) side. /// /// method: The method. "handle_ui" or "handle_peer" @@ -140,6 +148,7 @@ struct Callbacks { get_conf: CallbackGetConf, get_id: CallbackGetId, log: CallbackLog, + native: CallbackNative } /// The plugin initialize data. @@ -334,6 +343,7 @@ fn load_plugin_path(path: &str) -> ResultType<()> { get_conf: config::cb_get_conf, get_id: config::cb_get_local_peer_id, log: super::plog::plugin_log, + native: super::native::cb_native_data }, }; plugin.init(&init_data, path)?; From c140bcfed6ef16dea2c4170c0b3beea061129eac Mon Sep 17 00:00:00 2001 From: Kingtous Date: Fri, 28 Apr 2023 13:46:43 +0800 Subject: [PATCH 4/7] feat: add native call --- src/lib.rs | 7 -- src/plugin/native_handlers/macros.rs | 27 ++++++ src/plugin/native_handlers/mod.rs | 122 +++++++++++++++++++++++--- src/plugin/native_handlers/session.rs | 33 ++++--- 4 files changed, 159 insertions(+), 30 deletions(-) create mode 100644 src/plugin/native_handlers/macros.rs diff --git a/src/lib.rs b/src/lib.rs index ec70d1179..31ad83bca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,13 +48,6 @@ mod license; #[cfg(not(any(target_os = "android", target_os = "ios")))] mod port_forward; -#[cfg(not(any(target_os = "android", target_os = "ios")))] -#[cfg(any(feature = "flutter"))] -pub mod api; -#[cfg(not(any(target_os = "android", target_os = "ios")))] -#[cfg(any(feature = "flutter"))] -pub mod plugins; - #[cfg(all(feature = "flutter", feature = "plugin_framework"))] #[cfg(not(any(target_os = "android", target_os = "ios")))] pub mod plugin; diff --git a/src/plugin/native_handlers/macros.rs b/src/plugin/native_handlers/macros.rs new file mode 100644 index 000000000..82d7e10a6 --- /dev/null +++ b/src/plugin/native_handlers/macros.rs @@ -0,0 +1,27 @@ +#[macro_export] +macro_rules! return_if_not_method { + ($call: ident, $prefix: ident) => { + if $call.starts_with($prefix) { + return None; + } + }; +} + +#[macro_export] +macro_rules! call_if_method { + ($call: ident ,$method: literal, $block: block) => { + if ($call != $method) { + $block + } + }; +} + +#[macro_export] +macro_rules! define_method_prefix { + ($prefix: literal) => { + #[inline] + fn method_prefix(&self) -> &'static str { + $prefix + } + }; +} diff --git a/src/plugin/native_handlers/mod.rs b/src/plugin/native_handlers/mod.rs index 9f7011cb2..36fd2cebe 100644 --- a/src/plugin/native_handlers/mod.rs +++ b/src/plugin/native_handlers/mod.rs @@ -1,24 +1,126 @@ -use std::ffi::{c_void, c_ulonglong, c_ulong}; +use std::{ + ffi::c_void, + sync::{Arc, RwLock}, + vec, +}; +use hbb_common::libc::c_char; +use lazy_static::lazy_static; use serde_json::Map; +use crate::return_if_not_method; + +use self::session::PluginNativeSessionHandler; + +use super::cstr_to_string; + +mod macros; pub mod session; pub type NR = super::native::NativeReturnValue; -pub type PluginNativeHandlerRegistrar = NativeHandlerRegistrar; +pub type PluginNativeHandlerRegistrar = NativeHandlerRegistrar>; -pub struct NativeHandlerRegistrar{ - handlers: Vec +lazy_static! { + static ref NATIVE_HANDLERS_REGISTRAR: Arc = + Arc::new(PluginNativeHandlerRegistrar::default()); } -pub(crate) trait PluginNativeHandler { +#[derive(Clone)] +pub struct NativeHandlerRegistrar { + handlers: Arc>>, +} + +impl Default for PluginNativeHandlerRegistrar { + fn default() -> Self { + Self { + handlers: Arc::new(RwLock::new(vec![Box::new( + PluginNativeSessionHandler::default(), + )])), + } + } +} + +pub(self) trait PluginNativeHandler { + /// The method prefix handled by this handler.s + fn method_prefix(&self) -> &'static str; + /// Try to handle the method with the given data. - /// + /// /// Returns: None for the message does not be handled by this handler. - fn on_message(method: &String, data: &Map) -> Option; + fn on_message(&self, method: &str, data: &Map) -> Option; /// Try to handle the method with the given data and extra void binary data. - /// + /// /// Returns: None for the message does not be handled by this handler. - fn on_message_raw(method: &String, data: &Map, raw: *const c_void, raw_len: usize) -> Option; -} \ No newline at end of file + fn on_message_raw( + &self, + method: &str, + data: &Map, + raw: *const c_void, + raw_len: usize, + ) -> Option; +} + +pub(crate) trait Callable { + fn call( + &self, + method: &String, + json: *const c_char, + raw: *const c_void, + raw_len: usize, + ) -> Option { + None + } +} + +impl Callable for T +where + T: PluginNativeHandler + Send + Sync, +{ + fn call( + &self, + method: &String, + json: *const c_char, + raw: *const c_void, + raw_len: usize, + ) -> Option { + let prefix = self.method_prefix(); + return_if_not_method!(method, prefix); + match cstr_to_string(json) { + Ok(s) => { + if let Ok(json) = serde_json::from_str(s.as_str()) { + let method_suffix = &method[prefix.len()..]; + if raw != std::ptr::null() && raw_len > 0 { + return self.on_message_raw(method_suffix, &json, raw, raw_len); + } else { + return self.on_message(method_suffix, &json); + } + } else { + return None; + } + } + Err(_) => return None, + } + } +} + +impl Callable for NativeHandlerRegistrar +where + C: Callable, +{ + fn call( + &self, + method: &String, + json: *const c_char, + raw: *const c_void, + raw_len: usize, + ) -> Option { + for handler in self.handlers.read().unwrap().iter() { + let ret = handler.call(method, json, raw, raw_len); + if ret.is_some() { + return ret; + } + } + None + } +} diff --git a/src/plugin/native_handlers/session.rs b/src/plugin/native_handlers/session.rs index f8e8baa67..fc6f49014 100644 --- a/src/plugin/native_handlers/session.rs +++ b/src/plugin/native_handlers/session.rs @@ -1,28 +1,35 @@ +use crate::{call_if_method, define_method_prefix, return_if_not_method}; + use super::PluginNativeHandler; - +#[derive(Default)] /// Session related handler for librustdesk core. pub struct PluginNativeSessionHandler; - impl PluginNativeHandler for PluginNativeSessionHandler { - fn on_message(method: &String, data: &serde_json::Map) -> Option { + define_method_prefix!("session_"); + + fn on_message( + &self, + method: &str, + data: &serde_json::Map, + ) -> Option { None } - fn on_message_raw(method: &String, data: &serde_json::Map, raw: *const std::ffi::c_void, raw_len: usize) -> Option { + fn on_message_raw( + &self, + method: &str, + data: &serde_json::Map, + raw: *const std::ffi::c_void, + raw_len: usize, + ) -> Option { None } - } impl PluginNativeSessionHandler { - fn create_session() { + fn create_session() {} - } - - - fn add_session_hook() { - - } -} \ No newline at end of file + fn add_session_hook() {} +} From 952598af255146cf582aa7d2f82f55e989ce84b7 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Fri, 28 Apr 2023 14:55:40 +0800 Subject: [PATCH 5/7] feat: add session related function --- src/flutter.rs | 20 ++- src/plugin/native.rs | 4 +- src/plugin/native_handlers/mod.rs | 2 +- src/plugin/native_handlers/session.rs | 114 ++++++++++++++- src/plugins.rs | 201 -------------------------- 5 files changed, 130 insertions(+), 211 deletions(-) delete mode 100644 src/plugins.rs diff --git a/src/flutter.rs b/src/flutter.rs index f08b6a569..b955cc781 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -147,7 +147,7 @@ pub struct FlutterHandler { renderer: Arc>, peer_info: Arc>, #[cfg(not(any(target_os = "android", target_os = "ios")))] - hooks: Arc>>, + hooks: Arc>>, } #[cfg(not(feature = "flutter_texture_render"))] @@ -160,7 +160,7 @@ pub struct FlutterHandler { pub rgba_valid: Arc, peer_info: Arc>, #[cfg(not(any(target_os = "android", target_os = "ios")))] - hooks: Arc>>, + hooks: Arc>>, } #[cfg(feature = "flutter_texture_render")] @@ -294,7 +294,7 @@ impl FlutterHandler { } #[cfg(not(any(target_os = "android", target_os = "ios")))] - pub(crate) fn add_session_hook(&self, key: String, hook: crate::api::SessionHook) -> bool { + pub(crate) fn add_session_hook(&self, key: String, hook: SessionHook) -> bool { let mut hooks = self.hooks.write().unwrap(); if hooks.contains_key(&key) { // Already has the hook with this key. @@ -501,6 +501,14 @@ impl InvokeUiSession for FlutterHandler { #[inline] #[cfg(not(feature = "flutter_texture_render"))] fn on_rgba(&self, rgba: &mut scrap::ImageRgb) { + // Give a chance for plugins or etc to hook a rgba data. + for (key, hook) in self.hooks.read().unwrap().iter() { + match hook { + SessionHook::OnSessionRgba(cb) => { + cb(key.to_owned(), rgba); + }, + } + } // If the current rgba is not fetched by flutter, i.e., is valid. // We give up sending a new event to flutter. if self.rgba_valid.load(Ordering::Relaxed) { @@ -1056,3 +1064,9 @@ pub fn stop_global_event_stream(app_type: String) { #[no_mangle] unsafe extern "C" fn get_rgba() {} + +/// Hooks for session. +#[derive(Clone)] +pub enum SessionHook { + OnSessionRgba(fn(String, &mut scrap::ImageRgb)), +} \ No newline at end of file diff --git a/src/plugin/native.rs b/src/plugin/native.rs index dad61099e..3b5bcb2e4 100644 --- a/src/plugin/native.rs +++ b/src/plugin/native.rs @@ -6,8 +6,8 @@ use std::{ffi::{c_char, c_void}, os::raw::c_uint}; /// The data is owned by librustdesk. #[repr(C)] pub struct NativeReturnValue{ - return_type: c_uint, - data: *const c_void + pub return_type: c_uint, + pub data: *const c_void } pub(super) extern "C" fn cb_native_data(method: *const c_char, json: *const c_char, raw: *const c_void, raw_len: usize) -> NativeReturnValue { diff --git a/src/plugin/native_handlers/mod.rs b/src/plugin/native_handlers/mod.rs index 36fd2cebe..3aa0868e1 100644 --- a/src/plugin/native_handlers/mod.rs +++ b/src/plugin/native_handlers/mod.rs @@ -61,7 +61,7 @@ pub(self) trait PluginNativeHandler { ) -> Option; } -pub(crate) trait Callable { +pub trait Callable { fn call( &self, method: &String, diff --git a/src/plugin/native_handlers/session.rs b/src/plugin/native_handlers/session.rs index fc6f49014..94d00bf05 100644 --- a/src/plugin/native_handlers/session.rs +++ b/src/plugin/native_handlers/session.rs @@ -1,10 +1,22 @@ -use crate::{call_if_method, define_method_prefix, return_if_not_method}; +use std::sync::{atomic::AtomicU64, Arc, RwLock}; + +use crate::{ + call_if_method, define_method_prefix, flutter::FlutterHandler, return_if_not_method, + ui_session_interface::Session, +}; use super::PluginNativeHandler; #[derive(Default)] /// Session related handler for librustdesk core. -pub struct PluginNativeSessionHandler; +pub struct PluginNativeSessionHandler { + sessions: Arc>>>, + id: AtomicU64, +} + +lazy_static::lazy_static! { + pub static ref SESSION_HANDLER: Arc = Arc::new(PluginNativeSessionHandler::default()); +} impl PluginNativeHandler for PluginNativeSessionHandler { define_method_prefix!("session_"); @@ -14,6 +26,48 @@ impl PluginNativeHandler for PluginNativeSessionHandler { method: &str, data: &serde_json::Map, ) -> Option { + match method { + "create_session" => { + return Some(super::NR { + return_type: 1, + data: SESSION_HANDLER.create_session() as _, + }); + } + "add_session_hook" => { + if let Some(id) = data.get("id") { + if let Some(id) = id.as_u64() { + SESSION_HANDLER.add_session_hook(id); + return Some(super::NR { + return_type: 0, + data: std::ptr::null(), + }); + } + } + } + "remove_session_hook" => { + if let Some(id) = data.get("id") { + if let Some(id) = id.as_u64() { + SESSION_HANDLER.remove_session_hook(id); + return Some(super::NR { + return_type: 0, + data: std::ptr::null(), + }); + } + } + } + "remove_session" => { + if let Some(id) = data.get("id") { + if let Some(id) = id.as_u64() { + SESSION_HANDLER.remove_session(id); + return Some(super::NR { + return_type: 0, + data: std::ptr::null(), + }); + } + } + } + _ => {} + } None } @@ -29,7 +83,59 @@ impl PluginNativeHandler for PluginNativeSessionHandler { } impl PluginNativeSessionHandler { - fn create_session() {} + fn create_session(&self) -> u64 { + let mut sessions = self.sessions.write().unwrap(); + let unique_id = self.id.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + let mut session: Session = Session::default(); + session.id = self.get_hook_key(unique_id); + sessions.push(session); + return unique_id; + } - fn add_session_hook() {} + fn add_session_hook(&self, session_id: u64) { + let sessions = self.sessions.read().unwrap(); + let session_id = self.get_hook_key(session_id); + for session in sessions.iter() { + if session.id == session_id { + session.ui_handler.add_session_hook( + session_id.to_owned(), + crate::flutter::SessionHook::OnSessionRgba(session_rgba_cb), + ); + } + } + } + + fn remove_session_hook(&self, session_id: u64) { + let sessions = self.sessions.read().unwrap(); + let session_id = self.get_hook_key(session_id); + for session in sessions.iter() { + if session.id == session_id { + session.ui_handler.remove_session_hook(&session_id); + } + } + } + + fn remove_session(&self, session_id: u64) { + let mut sessions = self.sessions.write().unwrap(); + let session_id = self.get_hook_key(session_id); + for i in 0..sessions.len() { + if sessions[i].id == session_id { + sessions.remove(i); + } + } + } + + #[inline] + fn get_hook_key(&self, id: u64) -> String { + format!("{}_{}", self.method_prefix(), id) + } + + // The callback function for rgba data + fn session_rgba_cb(&self, key: String, rgb: &mut scrap::ImageRgb) { + todo!() + } +} + +fn session_rgba_cb(key: String, rgb: &mut scrap::ImageRgb) { + SESSION_HANDLER.session_rgba_cb(key, rgb); } diff --git a/src/plugins.rs b/src/plugins.rs deleted file mode 100644 index dfbdc7753..000000000 --- a/src/plugins.rs +++ /dev/null @@ -1,201 +0,0 @@ -use std::{ - collections::HashMap, - ffi::{c_char, CStr}, - sync::{Arc, RwLock}, -}; - -use hbb_common::{ - anyhow::Error, - log::{debug, error}, -}; -use lazy_static::lazy_static; -use libloading::{Library, Symbol}; - -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 PluginIdFunc = fn() -> *const c_char; -// API needed to be implemented by plugins. -pub type PluginNameFunc = fn() -> *const c_char; -// 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, // NonNull - pub dispose: Option, // NonNull -} - -pub struct PluginImpl { - vt: RustDeskPluginTable, - pub id: String, - pub name: String, - _inner: Option, -} - -impl Default for PluginImpl { - fn default() -> Self { - Self { - _inner: None, - vt: Default::default(), - id: Default::default(), - name: Default::default(), - } - } -} - -impl Plugin for PluginImpl { - fn plugin_id(&self) -> String { - self.id.to_owned() - } - - fn plugin_name(&self) -> String { - self.name.to_owned() - } - - fn plugin_vt(&self) -> &RustDeskPluginTable { - &self.vt - } -} - -#[derive(Default, Clone)] -pub struct PluginRegistar { - plugins: Arc>>, -} - -impl PluginRegistar

{ - pub fn load_plugin(&self, path: *const c_char) -> i32 { - let p = unsafe { CStr::from_ptr(path) }; - 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) => { - let plugin: PluginImpl = plugin; - // try to initialize this plugin - if let Some(init) = plugin.plugin_vt().init { - let init_ret = init(); - if init_ret != 0 { - error!( - "Error when initializing the plugin {} with error code {}.", - plugin.name, init_ret - ); - return init_ret; - } - } - 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 c_char) -> i32 { - let p = unsafe { CStr::from_ptr(path) }; - let lib_path = p.to_str().unwrap_or("").to_owned(); - match PLUGIN_REGISTRAR.plugins.write().unwrap().remove(&lib_path) { - Some(plugin) => { - if let Some(dispose) = plugin.plugin_vt().dispose { - return dispose(); - } - 0 - } - None => -1, - } - } -} - -impl TryFrom for PluginImpl { - type Error = Error; - - fn try_from(library: Library) -> Result { - let init: Symbol = unsafe { library.get(b"plugin_init")? }; - let dispose: Symbol = unsafe { library.get(b"plugin_dispose")? }; - let id_func: Symbol = unsafe { library.get(b"plugin_id")? }; - let id_string = unsafe { - std::ffi::CStr::from_ptr(id_func()) - .to_str() - .unwrap_or("") - .to_owned() - }; - let name_func: Symbol = unsafe { library.get(b"plugin_name")? }; - let name_string = unsafe { - std::ffi::CStr::from_ptr(name_func()) - .to_str() - .unwrap_or("") - .to_owned() - }; - debug!( - "Successfully loaded the plugin called {} with id {}.", - name_string, id_string - ); - Ok(Self { - vt: RustDeskPluginTable { - init: Some(*init), - dispose: Some(*dispose), - }, - id: id_string, - name: name_string, - _inner: Some(library), - }) - } -} - -#[test] -#[cfg(target_os = "linux")] -fn test_plugin() { - use std::io::Write; - let mut cmd = std::process::Command::new("cargo"); - cmd.current_dir("./examples/custom_plugin"); - // Strip this shared library. - cmd.env("RUSTFLAGS", "-C link-arg=-s"); - cmd.arg("build"); - // Spawn the compiler process. - let mut child = cmd.spawn().unwrap(); - // Wait for the compiler to finish. - let status = child.wait().unwrap(); - assert!(status.success()); - // Load the library. - let lib = unsafe { - Library::new("./examples/custom_plugin/target/debug/libcustom_plugin.so").unwrap() - }; - let plugin: PluginImpl = lib.try_into().unwrap(); - assert!(plugin._inner.is_some()); - assert!(plugin.name == "A Template Rust Plugin"); - assert!(plugin.id == "TemplatePlugin"); - println!( - "plugin vt size: {}", - std::mem::size_of::() - ); - assert!(PLUGIN_REGISTRAR - .plugins - .write() - .unwrap() - .insert("test".to_owned(), plugin) - .is_none()); -} From 5c0f2493902462445f8e718eda345e04366d101a Mon Sep 17 00:00:00 2001 From: Kingtous Date: Fri, 28 Apr 2023 15:09:45 +0800 Subject: [PATCH 6/7] feat: add cb for ffi --- src/plugin/errno.rs | 2 ++ src/plugin/native.rs | 42 ++++++++++++++++++++++++------- src/plugin/native_handlers/mod.rs | 8 +++--- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/plugin/errno.rs b/src/plugin/errno.rs index db580c0bd..f62a3daac 100644 --- a/src/plugin/errno.rs +++ b/src/plugin/errno.rs @@ -17,6 +17,8 @@ pub const ERR_CALL_NOT_SUPPORTED_METHOD: i32 = 10202; // failed on calling pub const ERR_CALL_INVALID_ARGS: i32 = 10301; pub const ERR_PEER_ID_MISMATCH: i32 = 10302; +// no handlers on calling +pub const ERR_NOT_HANDLED: i32 = 10401; // ====================================================== // errors that should be handled by the plugin diff --git a/src/plugin/native.rs b/src/plugin/native.rs index 3b5bcb2e4..ce885c77c 100644 --- a/src/plugin/native.rs +++ b/src/plugin/native.rs @@ -1,16 +1,40 @@ -use std::{ffi::{c_char, c_void}, os::raw::c_uint}; +use std::{ + ffi::{c_char, c_int, c_void}, + os::raw::c_uint, +}; +use hbb_common::log::error; + +use super::{ + cstr_to_string, + errno::ERR_NOT_HANDLED, + native_handlers::{Callable, NATIVE_HANDLERS_REGISTRAR}, +}; /// The native returned value from librustdesk native. -/// +/// /// [Note] /// The data is owned by librustdesk. #[repr(C)] -pub struct NativeReturnValue{ - pub return_type: c_uint, - pub data: *const c_void +pub struct NativeReturnValue { + pub return_type: c_int, + pub data: *const c_void, } -pub(super) extern "C" fn cb_native_data(method: *const c_char, json: *const c_char, raw: *const c_void, raw_len: usize) -> NativeReturnValue { - // TODO: cb for native data. - return NativeReturnValue { return_type: 0, data: std::ptr::null() }; -} \ No newline at end of file +pub(super) extern "C" fn cb_native_data( + method: *const c_char, + json: *const c_char, + raw: *const c_void, + raw_len: usize, +) -> NativeReturnValue { + let ret = match cstr_to_string(method) { + Ok(method) => NATIVE_HANDLERS_REGISTRAR.call(&method, json, raw, raw_len), + Err(err) => { + error!("cb_native_data error: {}", err); + None + } + }; + return ret.unwrap_or(NativeReturnValue { + return_type: ERR_NOT_HANDLED, + data: std::ptr::null(), + }); +} diff --git a/src/plugin/native_handlers/mod.rs b/src/plugin/native_handlers/mod.rs index 3aa0868e1..32b6627e2 100644 --- a/src/plugin/native_handlers/mod.rs +++ b/src/plugin/native_handlers/mod.rs @@ -21,7 +21,7 @@ pub type NR = super::native::NativeReturnValue; pub type PluginNativeHandlerRegistrar = NativeHandlerRegistrar>; lazy_static! { - static ref NATIVE_HANDLERS_REGISTRAR: Arc = + pub static ref NATIVE_HANDLERS_REGISTRAR: Arc = Arc::new(PluginNativeHandlerRegistrar::default()); } @@ -34,6 +34,7 @@ impl Default for PluginNativeHandlerRegistrar { fn default() -> Self { Self { handlers: Arc::new(RwLock::new(vec![Box::new( + // Add prebuilt native handlers here. PluginNativeSessionHandler::default(), )])), } @@ -104,10 +105,7 @@ where } } -impl Callable for NativeHandlerRegistrar -where - C: Callable, -{ +impl Callable for PluginNativeHandlerRegistrar { fn call( &self, method: &String, From 6da5bef064f47322705b84715d2e4799562c9196 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Fri, 28 Apr 2023 19:17:20 +0800 Subject: [PATCH 7/7] fix: ignore session hook on android/ios --- src/flutter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flutter.rs b/src/flutter.rs index b955cc781..6207eb4e3 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -502,6 +502,7 @@ impl InvokeUiSession for FlutterHandler { #[cfg(not(feature = "flutter_texture_render"))] fn on_rgba(&self, rgba: &mut scrap::ImageRgb) { // Give a chance for plugins or etc to hook a rgba data. + #[cfg(not(any(target_os = "android", target_os = "ios")))] for (key, hook) in self.hooks.read().unwrap().iter() { match hook { SessionHook::OnSessionRgba(cb) => {