diff --git a/examples/custom_plugin/src/lib.rs b/examples/custom_plugin/src/lib.rs index 860e0366a..0b21f3fc8 100644 --- a/examples/custom_plugin/src/lib.rs +++ b/examples/custom_plugin/src/lib.rs @@ -1,4 +1,4 @@ -use librustdesk::{api::RustDeskApiTable}; +use librustdesk::api::RustDeskApiTable; /// This file demonstrates how to write a custom plugin for RustDesk. use std::ffi::{c_char, c_int, CString}; @@ -9,8 +9,6 @@ lazy_static::lazy_static! { pub static ref API: RustDeskApiTable = RustDeskApiTable::default(); } - - #[no_mangle] fn plugin_name() -> *const c_char { return PLUGIN_NAME.as_ptr(); diff --git a/src/api.rs b/src/api.rs index 1c993a5ee..187c396d0 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,32 +1,87 @@ use std::ffi::c_char; -use crate::plugins::PLUGIN_REGISTRAR; +use crate::{ + flutter::{FlutterHandler, SESSIONS}, + plugins::PLUGIN_REGISTRAR, + ui_session_interface::Session, +}; // 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: Session) -> 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. +#[repr(usize)] +#[derive(Clone)] +pub enum SessionHook { + OnSessionRgba(fn(&Session, Vec) -> Vec) = 1, +} #[repr(C)] pub struct RustDeskApiTable { - pub(crate) register_plugin: LoadPluginFunc, + pub(crate) load_plugin: LoadPluginFunc, pub(crate) unload_plugin: UnloadPluginFunc, + pub add_session: AddSessionFunc, + pub remove_session: RemoveSessionFunc, + pub add_session_hook: AddSessionHookFunc, + pub remove_session_hook: RemoveSessionHookFunc, } -#[no_mangle] fn load_plugin(path: *const c_char) -> i32 { PLUGIN_REGISTRAR.load_plugin(path) } -#[no_mangle] fn unload_plugin(path: *const c_char) -> i32 { PLUGIN_REGISTRAR.unload_plugin(path) } +fn add_session(session: Session) -> bool { + let mut sessions = SESSIONS.write().unwrap(); + if sessions.contains_key(&session.id) { + return false; + } + let _ = sessions.insert(session.id.to_owned(), session); + true +} + +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 { - register_plugin: load_plugin, - unload_plugin: unload_plugin, + load_plugin, + unload_plugin, + add_session, + remove_session, + add_session_hook, + remove_session_hook, } } } diff --git a/src/flutter.rs b/src/flutter.rs index 8c4522e47..94c5e52e7 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -1,4 +1,5 @@ use crate::{ + api::SessionHook, client::*, flutter_ffi::EventToUI, ui_session_interface::{io_loop, InvokeUiSession, Session}, @@ -40,9 +41,9 @@ pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer"; pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward"; lazy_static::lazy_static! { - pub static ref CUR_SESSION_ID: RwLock = Default::default(); - pub static ref SESSIONS: RwLock>> = Default::default(); - pub static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel + pub(crate) static ref CUR_SESSION_ID: RwLock = Default::default(); + pub(crate) static ref SESSIONS: RwLock>> = Default::default(); + pub(crate) static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel } #[cfg(all(target_os = "windows", feature = "flutter_texture_render"))] @@ -146,6 +147,7 @@ pub struct FlutterHandler { notify_rendered: Arc>, renderer: Arc>, peer_info: Arc>, + hooks: Arc>>, } #[cfg(not(feature = "flutter_texture_render"))] @@ -157,6 +159,7 @@ pub struct FlutterHandler { pub rgba: Arc>>, pub rgba_valid: Arc, peer_info: Arc>, + hooks: Arc>>, } #[cfg(feature = "flutter_texture_render")] @@ -255,7 +258,7 @@ impl FlutterHandler { } } - pub fn close_event_stream(&mut self) { + pub(crate) fn close_event_stream(&mut self) { let mut stream_lock = self.event_stream.write().unwrap(); if let Some(stream) = &*stream_lock { stream.add(EventToUI::Event("close".to_owned())); @@ -277,6 +280,26 @@ impl FlutterHandler { serde_json::ser::to_string(&msg_vec).unwrap_or("".to_owned()) } + pub(crate) fn add_session_hook(&self, key: String, hook: crate::api::SessionHook) -> bool { + let mut hooks = self.hooks.write().unwrap(); + if hooks.contains_key(&key) { + // Already has the hook with this key. + return false; + } + let _ = hooks.insert(key, hook); + true + } + + pub(crate) fn remove_session_hook(&self, key: &String) -> bool { + let mut hooks = self.hooks.write().unwrap(); + if !hooks.contains_key(key) { + // The hook with this key does not found. + return false; + } + let _ = hooks.remove(key); + true + } + #[inline] #[cfg(feature = "flutter_texture_render")] pub fn register_texture(&mut self, ptr: usize) {