From 34314e50f7ecbf3d569d61c8ba6519416b6368cd Mon Sep 17 00:00:00 2001 From: Kingtous Date: Thu, 4 May 2023 13:18:19 +0800 Subject: [PATCH] feat: callbacks and flutter msg bridge --- libs/scrap/src/common/mod.rs | 7 +- src/flutter.rs | 6 +- src/flutter_ffi.rs | 7 ++ src/plugin/mod.rs | 2 +- src/plugin/native_handlers/session.rs | 161 +++++++++++++++++++------- 5 files changed, 133 insertions(+), 50 deletions(-) diff --git a/libs/scrap/src/common/mod.rs b/libs/scrap/src/common/mod.rs index 80b4e7813..9e73c9e20 100644 --- a/libs/scrap/src/common/mod.rs +++ b/libs/scrap/src/common/mod.rs @@ -44,19 +44,20 @@ pub const HW_STRIDE_ALIGN: usize = 0; // recommended by av_frame_get_buffer pub mod record; mod vpx; +#[repr(usize)] #[derive(Copy, Clone)] pub enum ImageFormat { Raw, ABGR, ARGB, } - +#[repr(C)] pub struct ImageRgb { pub raw: Vec, pub w: usize, pub h: usize, - fmt: ImageFormat, - stride: usize, + pub fmt: ImageFormat, + pub stride: usize, } impl ImageRgb { diff --git a/src/flutter.rs b/src/flutter.rs index cc774ebf3..9062b5031 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -691,7 +691,7 @@ pub fn session_add( switch_uuid: &str, force_relay: bool, password: String, -) -> ResultType<()> { +) -> ResultType> { let session_id = get_session_id(id.to_owned()); LocalConfig::set_remote_id(&session_id); @@ -725,11 +725,11 @@ pub fn session_add( .unwrap() .initialize(session_id, conn_type, switch_uuid, force_relay); - if let Some(same_id_session) = SESSIONS.write().unwrap().insert(id.to_owned(), session) { + if let Some(same_id_session) = SESSIONS.write().unwrap().insert(id.to_owned(), session.clone()) { same_id_session.close(); } - Ok(()) + Ok(session) } /// start a session with the given id. diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index a2e3bdd9a..92dfc3b23 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1405,6 +1405,13 @@ pub fn plugin_event(_id: String, _peer: String, _event: Vec) { } } +pub fn plugin_register_event_stream(id: String, event2ui: StreamSink) { + #[cfg(feature = "plugin_framework")] + { + crate::plugin::native_handlers::session::session_register_event_stream(id, event2ui); + } +} + #[inline] pub fn plugin_get_session_option( _id: String, diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index dea7dbd2d..ce4383ce5 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -9,7 +9,7 @@ pub mod ipc; mod plog; mod plugins; pub mod native; -mod native_handlers; +pub 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_handlers/session.rs b/src/plugin/native_handlers/session.rs index 94d00bf05..6a4f5edec 100644 --- a/src/plugin/native_handlers/session.rs +++ b/src/plugin/native_handlers/session.rs @@ -1,17 +1,36 @@ -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 std::{ + collections::HashMap, + ffi::{c_char, c_void}, + ptr::addr_of_mut, + sync::{Arc, RwLock}, }; +use flutter_rust_bridge::StreamSink; + +use crate::{ + define_method_prefix, + flutter::{FlutterHandler}, + ui_session_interface::Session, plugin::MSG_TO_UI_TYPE_PLUGIN_EVENT, flutter_ffi::EventToUI, +}; + +const MSG_TO_UI_TYPE_SESSION_CREATED: &str = "session_created"; + use super::PluginNativeHandler; +pub type OnSessionRgbaCallback = unsafe extern "C" fn( + *const c_char, // Session ID + *mut c_void, // raw data + *mut usize, // width + *mut usize, // height, + *mut usize, // stride, + *mut scrap::ImageFormat, // ImageFormat +); + #[derive(Default)] /// Session related handler for librustdesk core. pub struct PluginNativeSessionHandler { sessions: Arc>>>, - id: AtomicU64, + cbs: Arc>>, } lazy_static::lazy_static! { @@ -28,26 +47,31 @@ impl PluginNativeHandler for PluginNativeSessionHandler { ) -> 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); + if let Some(id) = id.as_str() { return Some(super::NR { - return_type: 0, - data: std::ptr::null(), + return_type: 1, + data: SESSION_HANDLER.create_session(id.to_string()).as_ptr() as _, }); } } } + "start_session" => { + if let Some(id) = data.get("id") { + if let Some(id) = id.as_str() { + let sessions = SESSION_HANDLER.sessions.read().unwrap(); + for session in sessions.iter() { + if session.id == id { + crate::ui_session_interface::io_loop(session.clone()); + } + } + } + } + } "remove_session_hook" => { if let Some(id) = data.get("id") { - if let Some(id) = id.as_u64() { - SESSION_HANDLER.remove_session_hook(id); + if let Some(id) = id.as_str() { + SESSION_HANDLER.remove_session_hook(id.to_string()); return Some(super::NR { return_type: 0, data: std::ptr::null(), @@ -57,8 +81,8 @@ impl PluginNativeHandler for PluginNativeSessionHandler { } "remove_session" => { if let Some(id) = data.get("id") { - if let Some(id) = id.as_u64() { - SESSION_HANDLER.remove_session(id); + if let Some(id) = id.as_str() { + SESSION_HANDLER.remove_session(id.to_owned()); return Some(super::NR { return_type: 0, data: std::ptr::null(), @@ -76,38 +100,61 @@ impl PluginNativeHandler for PluginNativeSessionHandler { method: &str, data: &serde_json::Map, raw: *const std::ffi::c_void, - raw_len: usize, + _raw_len: usize, ) -> Option { + match method { + "add_session_hook" => { + if let Some(id) = data.get("id") { + if let Some(id) = id.as_str() { + let cb: OnSessionRgbaCallback = unsafe { std::mem::transmute(raw) }; + SESSION_HANDLER.add_session_hook(id.to_string(), cb); + return Some(super::NR { + return_type: 0, + data: std::ptr::null(), + }); + } + } + } + _ => {} + } None } } impl PluginNativeSessionHandler { - 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 create_session(&self, session_id: String) -> String { + let session = + crate::flutter::session_add(&session_id, false, false, "", false, "".to_owned()); + if let Ok(session) = session { + let mut sessions = self.sessions.write().unwrap(); + sessions.push(session); + // push a event to notify flutter to bind a event stream for this session. + let mut m = HashMap::new(); + m.insert("name", MSG_TO_UI_TYPE_SESSION_CREATED); + m.insert("session_id", &session_id); + crate::flutter::push_global_event(crate::flutter::APP_TYPE_DESKTOP_REMOTE, serde_json::to_string(&m).unwrap_or("".to_string())); + return session_id; + } else { + return "".to_string(); + } } - fn add_session_hook(&self, session_id: u64) { + fn add_session_hook(&self, session_id: String, cb: OnSessionRgbaCallback) { 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 { + self.cbs.write().unwrap().insert(session_id.to_owned(), cb); session.ui_handler.add_session_hook( - session_id.to_owned(), + session_id, crate::flutter::SessionHook::OnSessionRgba(session_rgba_cb), ); + break; } } } - fn remove_session_hook(&self, session_id: u64) { + fn remove_session_hook(&self, session_id: String) { 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); @@ -115,27 +162,55 @@ impl PluginNativeSessionHandler { } } - fn remove_session(&self, session_id: u64) { + fn remove_session(&self, session_id: String) { + let _ = self.cbs.write().unwrap().remove(&session_id); 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[i].close_event_stream(); + sessions[i].close(); 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(&self, session_id: String, rgb: &mut scrap::ImageRgb) { + let cbs = self.cbs.read().unwrap(); + if let Some(cb) = cbs.get(&session_id) { + unsafe { + cb( + session_id.as_ptr() as _, + rgb.raw.as_mut_ptr() as _, + addr_of_mut!(rgb.w), + addr_of_mut!(rgb.h), + addr_of_mut!(rgb.stride), + addr_of_mut!(rgb.fmt), + ); + } + } + } + + #[inline] + // The callback function for rgba data + fn session_register_event_stream(&self, session_id: String, stream: StreamSink) { + let sessions = self.sessions.read().unwrap(); + for session in sessions.iter() { + if session.id == session_id { + *session.event_stream.write().unwrap() = Some(stream); + break; + } + } } } -fn session_rgba_cb(key: String, rgb: &mut scrap::ImageRgb) { - SESSION_HANDLER.session_rgba_cb(key, rgb); +#[inline] +fn session_rgba_cb(id: String, rgb: &mut scrap::ImageRgb) { + SESSION_HANDLER.session_rgba_cb(id, rgb); +} + +#[inline] +pub fn session_register_event_stream(id: String, stream: StreamSink) { + SESSION_HANDLER.session_register_event_stream(id, stream); }