feat: callbacks and flutter msg bridge

This commit is contained in:
Kingtous 2023-05-04 13:18:19 +08:00
parent 0ed209b4d2
commit 34314e50f7
5 changed files with 133 additions and 50 deletions

View File

@ -44,19 +44,20 @@ pub const HW_STRIDE_ALIGN: usize = 0; // recommended by av_frame_get_buffer
pub mod record; pub mod record;
mod vpx; mod vpx;
#[repr(usize)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ImageFormat { pub enum ImageFormat {
Raw, Raw,
ABGR, ABGR,
ARGB, ARGB,
} }
#[repr(C)]
pub struct ImageRgb { pub struct ImageRgb {
pub raw: Vec<u8>, pub raw: Vec<u8>,
pub w: usize, pub w: usize,
pub h: usize, pub h: usize,
fmt: ImageFormat, pub fmt: ImageFormat,
stride: usize, pub stride: usize,
} }
impl ImageRgb { impl ImageRgb {

View File

@ -691,7 +691,7 @@ pub fn session_add(
switch_uuid: &str, switch_uuid: &str,
force_relay: bool, force_relay: bool,
password: String, password: String,
) -> ResultType<()> { ) -> ResultType<Session<FlutterHandler>> {
let session_id = get_session_id(id.to_owned()); let session_id = get_session_id(id.to_owned());
LocalConfig::set_remote_id(&session_id); LocalConfig::set_remote_id(&session_id);
@ -725,11 +725,11 @@ pub fn session_add(
.unwrap() .unwrap()
.initialize(session_id, conn_type, switch_uuid, force_relay); .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(); same_id_session.close();
} }
Ok(()) Ok(session)
} }
/// start a session with the given id. /// start a session with the given id.

View File

@ -1405,6 +1405,13 @@ pub fn plugin_event(_id: String, _peer: String, _event: Vec<u8>) {
} }
} }
pub fn plugin_register_event_stream(id: String, event2ui: StreamSink<EventToUI>) {
#[cfg(feature = "plugin_framework")]
{
crate::plugin::native_handlers::session::session_register_event_stream(id, event2ui);
}
}
#[inline] #[inline]
pub fn plugin_get_session_option( pub fn plugin_get_session_option(
_id: String, _id: String,

View File

@ -9,7 +9,7 @@ pub mod ipc;
mod plog; mod plog;
mod plugins; mod plugins;
pub mod native; pub mod native;
mod native_handlers; pub mod native_handlers;
pub use plugins::{ pub use plugins::{
handle_client_event, handle_listen_event, handle_server_event, handle_ui_event, load_plugin, handle_client_event, handle_listen_event, handle_server_event, handle_ui_event, load_plugin,

View File

@ -1,17 +1,36 @@
use std::sync::{atomic::AtomicU64, Arc, RwLock}; use std::{
collections::HashMap,
use crate::{ ffi::{c_char, c_void},
call_if_method, define_method_prefix, flutter::FlutterHandler, return_if_not_method, ptr::addr_of_mut,
ui_session_interface::Session, 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; 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)] #[derive(Default)]
/// Session related handler for librustdesk core. /// Session related handler for librustdesk core.
pub struct PluginNativeSessionHandler { pub struct PluginNativeSessionHandler {
sessions: Arc<RwLock<Vec<Session<FlutterHandler>>>>, sessions: Arc<RwLock<Vec<Session<FlutterHandler>>>>,
id: AtomicU64, cbs: Arc<RwLock<HashMap<String, OnSessionRgbaCallback>>>,
} }
lazy_static::lazy_static! { lazy_static::lazy_static! {
@ -28,26 +47,31 @@ impl PluginNativeHandler for PluginNativeSessionHandler {
) -> Option<super::NR> { ) -> Option<super::NR> {
match method { match method {
"create_session" => { "create_session" => {
if let Some(id) = data.get("id") {
if let Some(id) = id.as_str() {
return Some(super::NR { return Some(super::NR {
return_type: 1, return_type: 1,
data: SESSION_HANDLER.create_session() as _, data: SESSION_HANDLER.create_session(id.to_string()).as_ptr() as _,
}); });
} }
"add_session_hook" => { }
}
"start_session" => {
if let Some(id) = data.get("id") { if let Some(id) = data.get("id") {
if let Some(id) = id.as_u64() { if let Some(id) = id.as_str() {
SESSION_HANDLER.add_session_hook(id); let sessions = SESSION_HANDLER.sessions.read().unwrap();
return Some(super::NR { for session in sessions.iter() {
return_type: 0, if session.id == id {
data: std::ptr::null(), crate::ui_session_interface::io_loop(session.clone());
}); }
}
} }
} }
} }
"remove_session_hook" => { "remove_session_hook" => {
if let Some(id) = data.get("id") { if let Some(id) = data.get("id") {
if let Some(id) = id.as_u64() { if let Some(id) = id.as_str() {
SESSION_HANDLER.remove_session_hook(id); SESSION_HANDLER.remove_session_hook(id.to_string());
return Some(super::NR { return Some(super::NR {
return_type: 0, return_type: 0,
data: std::ptr::null(), data: std::ptr::null(),
@ -57,8 +81,8 @@ impl PluginNativeHandler for PluginNativeSessionHandler {
} }
"remove_session" => { "remove_session" => {
if let Some(id) = data.get("id") { if let Some(id) = data.get("id") {
if let Some(id) = id.as_u64() { if let Some(id) = id.as_str() {
SESSION_HANDLER.remove_session(id); SESSION_HANDLER.remove_session(id.to_owned());
return Some(super::NR { return Some(super::NR {
return_type: 0, return_type: 0,
data: std::ptr::null(), data: std::ptr::null(),
@ -76,38 +100,61 @@ impl PluginNativeHandler for PluginNativeSessionHandler {
method: &str, method: &str,
data: &serde_json::Map<String, serde_json::Value>, data: &serde_json::Map<String, serde_json::Value>,
raw: *const std::ffi::c_void, raw: *const std::ffi::c_void,
raw_len: usize, _raw_len: usize,
) -> Option<super::NR> { ) -> Option<super::NR> {
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 None
} }
} }
impl PluginNativeSessionHandler { impl PluginNativeSessionHandler {
fn create_session(&self) -> u64 { 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(); let mut sessions = self.sessions.write().unwrap();
let unique_id = self.id.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let mut session: Session<FlutterHandler> = Session::default();
session.id = self.get_hook_key(unique_id);
sessions.push(session); sessions.push(session);
return unique_id; // 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 sessions = self.sessions.read().unwrap();
let session_id = self.get_hook_key(session_id);
for session in sessions.iter() { for session in sessions.iter() {
if session.id == session_id { if session.id == session_id {
self.cbs.write().unwrap().insert(session_id.to_owned(), cb);
session.ui_handler.add_session_hook( session.ui_handler.add_session_hook(
session_id.to_owned(), session_id,
crate::flutter::SessionHook::OnSessionRgba(session_rgba_cb), 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 sessions = self.sessions.read().unwrap();
let session_id = self.get_hook_key(session_id);
for session in sessions.iter() { for session in sessions.iter() {
if session.id == session_id { if session.id == session_id {
session.ui_handler.remove_session_hook(&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 mut sessions = self.sessions.write().unwrap();
let session_id = self.get_hook_key(session_id);
for i in 0..sessions.len() { for i in 0..sessions.len() {
if sessions[i].id == session_id { if sessions[i].id == session_id {
sessions[i].close_event_stream();
sessions[i].close();
sessions.remove(i); sessions.remove(i);
} }
} }
} }
#[inline] #[inline]
fn get_hook_key(&self, id: u64) -> String {
format!("{}_{}", self.method_prefix(), id)
}
// The callback function for rgba data // The callback function for rgba data
fn session_rgba_cb(&self, key: String, rgb: &mut scrap::ImageRgb) { fn session_rgba_cb(&self, session_id: String, rgb: &mut scrap::ImageRgb) {
todo!() 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<EventToUI>) {
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) { #[inline]
SESSION_HANDLER.session_rgba_cb(key, rgb); 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<EventToUI>) {
SESSION_HANDLER.session_register_event_stream(id, stream);
} }