From 952598af255146cf582aa7d2f82f55e989ce84b7 Mon Sep 17 00:00:00 2001 From: Kingtous Date: Fri, 28 Apr 2023 14:55:40 +0800 Subject: [PATCH] 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()); -}