2023-02-09 16:54:26 +08:00
use crate ::{
client ::* ,
flutter_ffi ::EventToUI ,
ui_session_interface ::{ io_loop , InvokeUiSession , Session } ,
} ;
2023-02-22 22:33:17 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
use dlopen ::{
symbor ::{ Library , Symbol } ,
Error as LibError ,
} ;
2023-02-13 16:40:24 +08:00
use flutter_rust_bridge ::StreamSink ;
2023-02-23 13:40:08 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
use hbb_common ::libc ::c_void ;
2022-09-05 10:27:33 +08:00
use hbb_common ::{
2023-02-23 13:40:08 +08:00
bail , config ::LocalConfig , get_version_number , log , message_proto ::* ,
rendezvous_proto ::ConnType , ResultType ,
2022-09-05 10:27:33 +08:00
} ;
use serde_json ::json ;
2023-02-21 21:56:46 +08:00
2023-02-22 09:43:57 +08:00
#[ cfg(not(feature = " flutter_texture_render " )) ]
2023-02-13 16:40:24 +08:00
use std ::sync ::atomic ::{ AtomicBool , Ordering } ;
2023-01-17 13:28:33 +08:00
use std ::{
collections ::HashMap ,
ffi ::CString ,
os ::raw ::{ c_char , c_int } ,
sync ::{ Arc , RwLock } ,
} ;
2022-05-12 17:35:25 +08:00
2023-03-07 10:08:41 +08:00
/// tag "main" for [Desktop Main Page] and [Mobile (Client and Server)] (the mobile don't need multiple windows, only one global event stream is needed)
/// tag "cm" only for [Desktop CM Page]
2022-08-03 22:03:31 +08:00
pub ( super ) const APP_TYPE_MAIN : & str = " main " ;
2023-03-07 10:08:41 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
2023-02-07 15:39:46 +08:00
pub ( super ) const APP_TYPE_CM : & str = " cm " ;
2023-03-07 10:08:41 +08:00
#[ cfg(any(target_os = " android " , target_os = " ios " )) ]
pub ( super ) const APP_TYPE_CM : & str = " main " ;
2022-08-03 22:03:31 +08:00
pub ( super ) const APP_TYPE_DESKTOP_REMOTE : & str = " remote " ;
pub ( super ) const APP_TYPE_DESKTOP_FILE_TRANSFER : & str = " file transfer " ;
2022-09-07 18:57:49 +08:00
pub ( super ) const APP_TYPE_DESKTOP_PORT_FORWARD : & str = " port forward " ;
2022-08-03 22:03:31 +08:00
2022-05-12 17:35:25 +08:00
lazy_static ::lazy_static! {
2023-01-20 21:03:30 +08:00
pub static ref CUR_SESSION_ID : RwLock < String > = Default ::default ( ) ;
2022-10-25 22:07:29 +08:00
pub static ref SESSIONS : RwLock < HashMap < String , Session < FlutterHandler > > > = Default ::default ( ) ;
2022-08-03 22:03:31 +08:00
pub static ref GLOBAL_EVENT_STREAM : RwLock < HashMap < String , StreamSink < String > > > = Default ::default ( ) ; // rust to dart event channel
2023-02-22 09:43:57 +08:00
}
2023-02-23 10:21:31 +08:00
#[ cfg(all(target_os = " windows " , feature = " flutter_texture_render " )) ]
2023-02-22 09:43:57 +08:00
lazy_static ::lazy_static! {
2023-02-23 10:21:31 +08:00
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN : Result < Library , LibError > = Library ::open ( " texture_rgba_renderer_plugin.dll " ) ;
}
#[ cfg(all(target_os = " linux " , feature = " flutter_texture_render " )) ]
lazy_static ::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN : Result < Library , LibError > = Library ::open ( " libtexture_rgba_renderer_plugin.so " ) ;
}
#[ cfg(all(target_os = " macos " , feature = " flutter_texture_render " )) ]
lazy_static ::lazy_static! {
pub static ref TEXTURE_RGBA_RENDERER_PLUGIN : Result < Library , LibError > = Library ::open_self ( ) ;
2022-05-12 17:35:25 +08:00
}
2022-10-09 21:10:41 +08:00
/// FFI for rustdesk core's main entry.
/// Return true if the app should continue running with UI(possibly Flutter), false if the app should exit.
#[ cfg(not(windows)) ]
#[ no_mangle ]
pub extern " C " fn rustdesk_core_main ( ) -> bool {
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
return crate ::core_main ::core_main ( ) . is_some ( ) ;
#[ cfg(any(target_os = " android " , target_os = " ios " )) ]
false
}
2023-01-20 01:25:15 +08:00
#[ cfg(target_os = " macos " ) ]
#[ no_mangle ]
pub extern " C " fn handle_applicationShouldOpenUntitledFile ( ) {
2023-02-09 21:28:42 +08:00
crate ::platform ::macos ::handle_application_should_open_untitled_file ( ) ;
2023-01-20 01:25:15 +08:00
}
2022-10-09 21:10:41 +08:00
#[ cfg(windows) ]
#[ no_mangle ]
2022-11-29 22:00:27 +08:00
pub extern " C " fn rustdesk_core_main_args ( args_len : * mut c_int ) -> * mut * mut c_char {
2022-10-09 21:10:41 +08:00
unsafe { std ::ptr ::write ( args_len , 0 ) } ;
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
{
if let Some ( args ) = crate ::core_main ::core_main ( ) {
return rust_args_to_c_args ( args , args_len ) ;
}
return std ::ptr ::null_mut ( ) as _ ;
}
#[ cfg(any(target_os = " android " , target_os = " ios " )) ]
return std ::ptr ::null_mut ( ) as _ ;
}
// https://gist.github.com/iskakaushik/1c5b8aa75c77479c33c4320913eebef6
2022-11-10 23:26:09 +08:00
#[ cfg(windows) ]
2022-10-09 21:10:41 +08:00
fn rust_args_to_c_args ( args : Vec < String > , outlen : * mut c_int ) -> * mut * mut c_char {
let mut v = vec! [ ] ;
// Let's fill a vector with null-terminated strings
for s in args {
v . push ( CString ::new ( s ) . unwrap ( ) ) ;
}
// Turning each null-terminated string into a pointer.
// `into_raw` takes ownershop, gives us the pointer and does NOT drop the data.
let mut out = v . into_iter ( ) . map ( | s | s . into_raw ( ) ) . collect ::< Vec < _ > > ( ) ;
// Make sure we're not wasting space.
out . shrink_to_fit ( ) ;
assert! ( out . len ( ) = = out . capacity ( ) ) ;
// Get the pointer to our vector.
let len = out . len ( ) ;
let ptr = out . as_mut_ptr ( ) ;
std ::mem ::forget ( out ) ;
// Let's write back the length the caller can expect
unsafe { std ::ptr ::write ( outlen , len as c_int ) } ;
// Finally return the data
ptr
}
#[ no_mangle ]
pub unsafe extern " C " fn free_c_args ( ptr : * mut * mut c_char , len : c_int ) {
let len = len as usize ;
// Get back our vector.
// Previously we shrank to fit, so capacity == length.
let v = Vec ::from_raw_parts ( ptr , len , len ) ;
// Now drop one string at a time.
for elem in v {
let s = CString ::from_raw ( elem ) ;
std ::mem ::drop ( s ) ;
}
// Afterwards the vector will be dropped and thus freed.
}
2023-02-23 10:21:31 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
#[ derive(Default, Clone) ]
pub struct FlutterHandler {
pub event_stream : Arc < RwLock < Option < StreamSink < EventToUI > > > > ,
notify_rendered : Arc < RwLock < bool > > ,
renderer : Arc < RwLock < VideoRenderer > > ,
peer_info : Arc < RwLock < PeerInfo > > ,
}
#[ cfg(not(feature = " flutter_texture_render " )) ]
2022-08-31 20:46:30 +08:00
#[ derive(Default, Clone) ]
pub struct FlutterHandler {
pub event_stream : Arc < RwLock < Option < StreamSink < EventToUI > > > > ,
2023-02-12 10:28:04 +08:00
// SAFETY: [rgba] is guarded by [rgba_valid], and it's safe to reach [rgba] with `rgba_valid == true`.
// We must check the `rgba_valid` before reading [rgba].
2023-02-12 01:52:11 +08:00
pub rgba : Arc < RwLock < Vec < u8 > > > ,
2023-02-13 16:40:24 +08:00
pub rgba_valid : Arc < AtomicBool > ,
2023-02-21 21:56:46 +08:00
peer_info : Arc < RwLock < PeerInfo > > ,
2023-02-18 11:16:07 +08:00
}
2023-02-23 10:21:31 +08:00
2023-02-21 23:46:13 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
2023-03-03 14:02:49 +08:00
pub type FlutterRgbaRendererPluginOnRgba = unsafe extern " C " fn (
texture_rgba : * mut c_void ,
buffer : * const u8 ,
2023-03-03 16:03:06 +08:00
len : c_int ,
2023-03-03 14:02:49 +08:00
width : c_int ,
height : c_int ,
dst_rgba_stride : c_int ,
) ;
2023-02-18 11:16:07 +08:00
// Video Texture Renderer in Flutter
2023-02-21 23:46:13 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
2023-02-18 11:47:18 +08:00
#[ derive(Clone) ]
2023-02-21 21:56:46 +08:00
struct VideoRenderer {
2023-02-18 11:16:07 +08:00
// TextureRgba pointer in flutter native.
ptr : usize ,
width : i32 ,
height : i32 ,
2023-02-22 22:33:17 +08:00
on_rgba_func : Option < Symbol < 'static , FlutterRgbaRendererPluginOnRgba > > ,
2023-02-18 11:16:07 +08:00
}
2023-02-21 23:46:13 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
2023-02-18 11:47:18 +08:00
impl Default for VideoRenderer {
fn default ( ) -> Self {
2023-02-22 22:33:17 +08:00
let on_rgba_func = match & * TEXTURE_RGBA_RENDERER_PLUGIN {
Ok ( lib ) = > {
let find_sym_res = unsafe {
lib . symbol ::< FlutterRgbaRendererPluginOnRgba > ( " FlutterRgbaRendererPluginOnRgba " )
} ;
match find_sym_res {
Ok ( sym ) = > Some ( sym ) ,
Err ( e ) = > {
log ::error! ( " Failed to find symbol FlutterRgbaRendererPluginOnRgba, {e} " ) ;
None
}
}
}
Err ( e ) = > {
log ::error! ( " Failed to load texture rgba renderer plugin, {e} " ) ;
None
2023-02-18 11:47:18 +08:00
}
2023-02-22 22:33:17 +08:00
} ;
Self {
ptr : 0 ,
width : 0 ,
height : 0 ,
on_rgba_func ,
2023-02-18 11:47:18 +08:00
}
}
}
2023-02-18 11:16:07 +08:00
2023-02-21 23:46:13 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
2023-02-18 11:16:07 +08:00
impl VideoRenderer {
2023-02-21 21:56:46 +08:00
#[ inline ]
2023-02-18 11:16:07 +08:00
pub fn set_size ( & mut self , width : i32 , height : i32 ) {
self . width = width ;
self . height = height ;
}
2023-02-21 21:56:46 +08:00
pub fn on_rgba ( & self , rgba : & Vec < u8 > ) {
2023-04-02 14:31:30 +08:00
if self . ptr = = usize ::default ( ) | | self . width = = 0 | | self . height = = 0 {
2023-02-18 11:16:07 +08:00
return ;
}
2023-02-22 22:33:17 +08:00
if let Some ( func ) = & self . on_rgba_func {
unsafe {
func (
self . ptr as _ ,
rgba . as_ptr ( ) as _ ,
2023-03-03 16:03:06 +08:00
rgba . len ( ) as _ ,
2023-02-22 22:33:17 +08:00
self . width as _ ,
self . height as _ ,
2023-03-03 14:02:49 +08:00
crate ::DST_STRIDE_RGBA as _ ,
2023-02-22 22:33:17 +08:00
)
} ;
}
2023-02-18 11:16:07 +08:00
}
2022-05-12 17:35:25 +08:00
}
2022-08-31 20:46:30 +08:00
impl FlutterHandler {
2022-05-28 03:56:42 +08:00
/// Push an event to the event queue.
/// An event is stored as json in the event queue.
///
/// # Arguments
///
/// * `name` - The name of the event.
/// * `event` - Fields of the event content.
2022-05-12 17:35:25 +08:00
fn push_event ( & self , name : & str , event : Vec < ( & str , & str ) > ) {
let mut h : HashMap < & str , & str > = event . iter ( ) . cloned ( ) . collect ( ) ;
assert! ( h . get ( " name " ) . is_none ( ) ) ;
h . insert ( " name " , name ) ;
2022-05-31 22:09:36 +08:00
let out = serde_json ::ser ::to_string ( & h ) . unwrap_or ( " " . to_owned ( ) ) ;
2022-08-31 20:46:30 +08:00
if let Some ( stream ) = & * self . event_stream . read ( ) . unwrap ( ) {
2022-08-30 21:15:35 +08:00
stream . add ( EventToUI ::Event ( out ) ) ;
2022-08-27 16:03:44 +08:00
}
2022-05-12 17:35:25 +08:00
}
2023-02-15 21:27:50 +08:00
pub 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 ( ) ) ) ;
}
* stream_lock = None ;
}
2023-02-17 13:32:17 +08:00
fn make_displays_msg ( displays : & Vec < DisplayInfo > ) -> String {
let mut msg_vec = Vec ::new ( ) ;
for ref d in displays . iter ( ) {
let mut h : HashMap < & str , i32 > = Default ::default ( ) ;
h . insert ( " x " , d . x ) ;
h . insert ( " y " , d . y ) ;
h . insert ( " width " , d . width ) ;
h . insert ( " height " , d . height ) ;
h . insert ( " cursor_embedded " , if d . cursor_embedded { 1 } else { 0 } ) ;
msg_vec . push ( h ) ;
}
serde_json ::ser ::to_string ( & msg_vec ) . unwrap_or ( " " . to_owned ( ) )
}
2023-02-18 11:16:07 +08:00
2023-02-21 21:56:46 +08:00
#[ inline ]
2023-02-21 23:46:13 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
2023-02-18 11:47:18 +08:00
pub fn register_texture ( & mut self , ptr : usize ) {
2023-02-19 15:25:30 +08:00
self . renderer . write ( ) . unwrap ( ) . ptr = ptr ;
2023-02-18 11:16:07 +08:00
}
2023-02-21 21:56:46 +08:00
#[ inline ]
2023-02-21 23:46:13 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
2023-02-21 21:56:46 +08:00
pub fn set_size ( & mut self , width : i32 , height : i32 ) {
* self . notify_rendered . write ( ) . unwrap ( ) = false ;
self . renderer . write ( ) . unwrap ( ) . set_size ( width , height ) ;
}
2022-08-31 20:46:30 +08:00
}
2022-05-12 17:35:25 +08:00
2022-09-05 19:41:09 +08:00
impl InvokeUiSession for FlutterHandler {
2022-08-31 20:46:30 +08:00
fn set_cursor_data ( & self , cd : CursorData ) {
let colors = hbb_common ::compress ::decompress ( & cd . colors ) ;
self . push_event (
" cursor_data " ,
vec! [
( " id " , & cd . id . to_string ( ) ) ,
( " hotx " , & cd . hotx . to_string ( ) ) ,
( " hoty " , & cd . hoty . to_string ( ) ) ,
( " width " , & cd . width . to_string ( ) ) ,
( " height " , & cd . height . to_string ( ) ) ,
(
" colors " ,
& serde_json ::ser ::to_string ( & colors ) . unwrap_or ( " " . to_owned ( ) ) ,
) ,
] ,
) ;
2022-05-12 17:35:25 +08:00
}
2022-08-31 20:46:30 +08:00
fn set_cursor_id ( & self , id : String ) {
self . push_event ( " cursor_id " , vec! [ ( " id " , & id . to_string ( ) ) ] ) ;
2022-05-12 17:35:25 +08:00
}
2022-08-31 20:46:30 +08:00
fn set_cursor_position ( & self , cp : CursorPosition ) {
self . push_event (
" cursor_position " ,
vec! [ ( " x " , & cp . x . to_string ( ) ) , ( " y " , & cp . y . to_string ( ) ) ] ,
) ;
2022-05-12 17:35:25 +08:00
}
2022-07-11 16:07:49 +08:00
2022-09-01 17:36:37 +08:00
/// unused in flutter, use switch_display or set_peer_info
2022-12-31 21:41:16 +08:00
fn set_display ( & self , _x : i32 , _y : i32 , _w : i32 , _h : i32 , _cursor_embedded : bool ) { }
2022-07-11 16:07:49 +08:00
2022-08-31 20:46:30 +08:00
fn update_privacy_mode ( & self ) {
self . push_event ( " update_privacy_mode " , [ ] . into ( ) ) ;
2022-07-11 18:23:58 +08:00
}
2022-08-31 20:46:30 +08:00
fn set_permission ( & self , name : & str , value : bool ) {
2022-09-01 09:48:53 +08:00
self . push_event ( " permission " , vec! [ ( name , & value . to_string ( ) ) ] ) ;
2022-07-11 16:07:49 +08:00
}
2022-09-05 10:27:33 +08:00
// unused in flutter
2022-09-01 17:36:37 +08:00
fn close_success ( & self ) { }
2022-08-04 17:24:02 +08:00
fn update_quality_status ( & self , status : QualityStatus ) {
const NULL : String = String ::new ( ) ;
self . push_event (
" update_quality_status " ,
vec! [
( " speed " , & status . speed . map_or ( NULL , | it | it ) ) ,
( " fps " , & status . fps . map_or ( NULL , | it | it . to_string ( ) ) ) ,
( " delay " , & status . delay . map_or ( NULL , | it | it . to_string ( ) ) ) ,
(
" target_bitrate " ,
& status . target_bitrate . map_or ( NULL , | it | it . to_string ( ) ) ,
) ,
(
" codec_format " ,
& status . codec_format . map_or ( NULL , | it | it . to_string ( ) ) ,
) ,
] ,
) ;
}
2022-05-12 17:35:25 +08:00
2022-08-31 20:46:30 +08:00
fn set_connection_type ( & self , is_secured : bool , direct : bool ) {
2022-05-12 17:35:25 +08:00
self . push_event (
2022-08-31 20:46:30 +08:00
" connection_ready " ,
2022-05-12 17:35:25 +08:00
vec! [
2022-08-31 20:46:30 +08:00
( " secure " , & is_secured . to_string ( ) ) ,
( " direct " , & direct . to_string ( ) ) ,
2022-05-12 17:35:25 +08:00
] ,
) ;
}
2022-08-31 20:46:30 +08:00
fn job_error ( & self , id : i32 , err : String , file_num : i32 ) {
2022-09-05 10:27:33 +08:00
self . push_event (
" job_error " ,
vec! [
( " id " , & id . to_string ( ) ) ,
( " err " , & err ) ,
( " file_num " , & file_num . to_string ( ) ) ,
] ,
) ;
2022-05-12 17:35:25 +08:00
}
2022-08-31 20:46:30 +08:00
fn job_done ( & self , id : i32 , file_num : i32 ) {
2022-05-12 17:35:25 +08:00
self . push_event (
2022-09-01 09:48:53 +08:00
" job_done " ,
vec! [ ( " id " , & id . to_string ( ) ) , ( " file_num " , & file_num . to_string ( ) ) ] ,
2022-05-12 17:35:25 +08:00
) ;
}
2022-09-05 10:27:33 +08:00
// unused in flutter
fn clear_all_jobs ( & self ) { }
fn load_last_job ( & self , _cnt : i32 , job_json : & str ) {
self . push_event ( " load_last_job " , vec! [ ( " value " , job_json ) ] ) ;
2022-08-25 11:50:30 +08:00
}
2022-09-05 10:27:33 +08:00
fn update_folder_files (
2022-08-31 20:46:30 +08:00
& self ,
id : i32 ,
2022-09-05 10:27:33 +08:00
entries : & Vec < FileEntry > ,
2022-08-31 20:46:30 +08:00
path : String ,
2022-11-15 16:49:55 +08:00
#[ allow(unused_variables) ] is_local : bool ,
2022-09-05 10:27:33 +08:00
only_count : bool ,
2022-08-31 20:46:30 +08:00
) {
2022-09-05 10:27:33 +08:00
// TODO opt
if only_count {
self . push_event (
" update_folder_files " ,
vec! [ ( " info " , & make_fd_flutter ( id , entries , only_count ) ) ] ,
) ;
} else {
self . push_event (
" file_dir " ,
vec! [
2022-12-29 00:02:31 +08:00
( " value " , & crate ::common ::make_fd_to_json ( id , path , entries ) ) ,
2022-09-05 10:27:33 +08:00
( " is_local " , " false " ) ,
] ,
) ;
}
2022-08-25 11:50:30 +08:00
}
2022-09-05 10:27:33 +08:00
// unused in flutter
fn update_transfer_list ( & self ) { }
2022-05-12 17:35:25 +08:00
2022-09-05 10:27:33 +08:00
// unused in flutter // TEST flutter
fn confirm_delete_files ( & self , _id : i32 , _i : i32 , _name : String ) { }
2022-05-12 17:35:25 +08:00
2023-03-20 00:16:06 +08:00
fn override_file_confirm (
& self ,
id : i32 ,
file_num : i32 ,
to : String ,
is_upload : bool ,
is_identical : bool ,
) {
2022-09-01 09:48:53 +08:00
self . push_event (
" override_file_confirm " ,
vec! [
( " id " , & id . to_string ( ) ) ,
( " file_num " , & file_num . to_string ( ) ) ,
( " read_path " , & to ) ,
( " is_upload " , & is_upload . to_string ( ) ) ,
2023-03-20 00:16:06 +08:00
( " is_identical " , & is_identical . to_string ( ) ) ,
2022-09-01 09:48:53 +08:00
] ,
) ;
2022-05-12 17:35:25 +08:00
}
2022-08-31 20:46:30 +08:00
fn job_progress ( & self , id : i32 , file_num : i32 , speed : f64 , finished_size : f64 ) {
2022-09-01 09:48:53 +08:00
self . push_event (
" job_progress " ,
vec! [
( " id " , & id . to_string ( ) ) ,
( " file_num " , & file_num . to_string ( ) ) ,
( " speed " , & speed . to_string ( ) ) ,
( " finished_size " , & finished_size . to_string ( ) ) ,
] ,
) ;
2022-08-08 17:03:28 +08:00
}
2022-09-05 10:27:33 +08:00
// unused in flutter
2022-09-01 17:36:37 +08:00
fn adapt_size ( & self ) { }
2022-08-08 17:03:28 +08:00
2023-02-19 15:25:30 +08:00
#[ inline ]
2023-02-21 23:46:13 +08:00
#[ cfg(not(feature = " flutter_texture_render " )) ]
2023-02-12 10:28:04 +08:00
fn on_rgba ( & self , data : & mut Vec < u8 > ) {
2023-02-12 01:52:11 +08:00
// If the current rgba is not fetched by flutter, i.e., is valid.
// We give up sending a new event to flutter.
2023-02-12 10:28:04 +08:00
if self . rgba_valid . load ( Ordering ::Relaxed ) {
2023-02-12 01:52:11 +08:00
return ;
}
2023-02-12 10:28:04 +08:00
self . rgba_valid . store ( true , Ordering ::Relaxed ) ;
2023-02-12 01:52:11 +08:00
// Return the rgba buffer to the video handler for reusing allocated rgba buffer.
2023-02-12 10:28:04 +08:00
std ::mem ::swap ::< Vec < u8 > > ( data , & mut * self . rgba . write ( ) . unwrap ( ) ) ;
2022-08-31 20:46:30 +08:00
if let Some ( stream ) = & * self . event_stream . read ( ) . unwrap ( ) {
2023-02-12 01:52:11 +08:00
stream . add ( EventToUI ::Rgba ) ;
2022-08-08 17:03:28 +08:00
}
2023-02-21 21:56:46 +08:00
}
#[ inline ]
2023-02-21 23:46:13 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
2023-02-21 21:56:46 +08:00
fn on_rgba ( & self , data : & mut Vec < u8 > ) {
self . renderer . read ( ) . unwrap ( ) . on_rgba ( data ) ;
if * self . notify_rendered . read ( ) . unwrap ( ) {
return ;
}
if let Some ( stream ) = & * self . event_stream . read ( ) . unwrap ( ) {
stream . add ( EventToUI ::Rgba ) ;
* self . notify_rendered . write ( ) . unwrap ( ) = true ;
2023-02-19 15:25:30 +08:00
}
2022-05-12 17:35:25 +08:00
}
2022-09-01 16:21:41 +08:00
fn set_peer_info ( & self , pi : & PeerInfo ) {
2023-02-17 13:32:17 +08:00
let displays = Self ::make_displays_msg ( & pi . displays ) ;
2022-12-02 21:34:20 +08:00
let mut features : HashMap < & str , i32 > = Default ::default ( ) ;
for ref f in pi . features . iter ( ) {
features . insert ( " privacy_mode " , if f . privacy_mode { 1 } else { 0 } ) ;
}
// compatible with 1.1.9
if get_version_number ( & pi . version ) < get_version_number ( " 1.2.0 " ) {
features . insert ( " privacy_mode " , 0 ) ;
}
let features = serde_json ::ser ::to_string ( & features ) . unwrap_or ( " " . to_owned ( ) ) ;
2023-02-09 15:53:51 +08:00
let resolutions = serialize_resolutions ( & pi . resolutions . resolutions ) ;
2023-02-19 15:25:30 +08:00
* self . peer_info . write ( ) . unwrap ( ) = pi . clone ( ) ;
2022-08-31 20:46:30 +08:00
self . push_event (
" peer_info " ,
2022-05-12 17:35:25 +08:00
vec! [
2022-09-01 16:21:41 +08:00
( " username " , & pi . username ) ,
( " hostname " , & pi . hostname ) ,
( " platform " , & pi . platform ) ,
( " sas_enabled " , & pi . sas_enabled . to_string ( ) ) ,
2022-08-31 20:46:30 +08:00
( " displays " , & displays ) ,
2022-09-01 16:21:41 +08:00
( " version " , & pi . version ) ,
2022-12-02 21:34:20 +08:00
( " features " , & features ) ,
2022-09-01 16:21:41 +08:00
( " current_display " , & pi . current_display . to_string ( ) ) ,
2023-02-09 15:53:51 +08:00
( " resolutions " , & resolutions ) ,
2023-03-21 12:25:47 +08:00
( " platform_additions " , & pi . platform_additions ) ,
2022-05-12 17:35:25 +08:00
] ,
2022-08-08 22:00:01 +08:00
) ;
}
2023-02-17 13:32:17 +08:00
fn set_displays ( & self , displays : & Vec < DisplayInfo > ) {
2023-02-19 15:25:30 +08:00
self . peer_info . write ( ) . unwrap ( ) . displays = displays . clone ( ) ;
2023-02-17 13:32:17 +08:00
self . push_event (
" sync_peer_info " ,
vec! [ ( " displays " , & Self ::make_displays_msg ( displays ) ) ] ,
) ;
}
2022-12-09 21:16:09 +08:00
fn on_connected ( & self , _conn_type : ConnType ) { }
2022-10-14 11:19:49 +08:00
fn msgbox ( & self , msgtype : & str , title : & str , text : & str , link : & str , retry : bool ) {
2022-08-31 20:46:30 +08:00
let has_retry = if retry { " true " } else { " " } ;
self . push_event (
" msgbox " ,
2022-05-19 21:45:25 +08:00
vec! [
2022-08-31 20:46:30 +08:00
( " type " , msgtype ) ,
( " title " , title ) ,
( " text " , text ) ,
2022-10-14 11:19:49 +08:00
( " link " , link ) ,
2022-08-31 20:46:30 +08:00
( " hasRetry " , has_retry ) ,
2022-05-19 21:45:25 +08:00
] ,
2022-05-17 20:56:36 +08:00
) ;
2022-08-08 22:00:01 +08:00
}
2022-11-15 16:49:55 +08:00
fn cancel_msgbox ( & self , tag : & str ) {
self . push_event ( " cancel_msgbox " , vec! [ ( " tag " , tag ) ] ) ;
}
2022-09-01 09:48:53 +08:00
fn new_message ( & self , msg : String ) {
self . push_event ( " chat_client_mode " , vec! [ ( " text " , & msg ) ] ) ;
2022-08-08 22:00:01 +08:00
}
2022-09-01 09:48:53 +08:00
fn switch_display ( & self , display : & SwitchDisplay ) {
2023-02-09 15:53:51 +08:00
let resolutions = serialize_resolutions ( & display . resolutions . resolutions ) ;
2022-09-01 09:48:53 +08:00
self . push_event (
" switch_display " ,
2022-05-12 17:35:25 +08:00
vec! [
2022-09-21 16:03:08 +08:00
( " display " , & display . display . to_string ( ) ) ,
2022-09-01 09:48:53 +08:00
( " x " , & display . x . to_string ( ) ) ,
( " y " , & display . y . to_string ( ) ) ,
( " width " , & display . width . to_string ( ) ) ,
( " height " , & display . height . to_string ( ) ) ,
2023-01-17 13:28:33 +08:00
(
" cursor_embedded " ,
& {
if display . cursor_embedded {
1
} else {
0
}
}
. to_string ( ) ,
) ,
2023-02-09 15:53:51 +08:00
( " resolutions " , & resolutions ) ,
2022-05-12 17:35:25 +08:00
] ,
) ;
}
2022-09-01 09:48:53 +08:00
fn update_block_input_state ( & self , on : bool ) {
self . push_event (
" update_block_input_state " ,
[ ( " input_state " , if on { " on " } else { " off " } ) ] . into ( ) ,
) ;
2022-05-12 17:35:25 +08:00
}
2022-09-01 09:48:53 +08:00
#[ cfg(any(target_os = " android " , target_os = " ios " )) ]
fn clipboard ( & self , content : String ) {
self . push_event ( " clipboard " , vec! [ ( " content " , & content ) ] ) ;
2022-05-12 17:35:25 +08:00
}
2023-01-17 13:28:33 +08:00
fn switch_back ( & self , peer_id : & str ) {
self . push_event ( " switch_back " , [ ( " peer_id " , peer_id ) ] . into ( ) ) ;
}
2023-02-06 11:42:25 +08:00
2023-02-24 15:51:13 +08:00
fn portable_service_running ( & self , running : bool ) {
self . push_event (
" portable_service_running " ,
[ ( " running " , running . to_string ( ) . as_str ( ) ) ] . into ( ) ,
) ;
}
2023-02-06 15:36:36 +08:00
fn on_voice_call_started ( & self ) {
self . push_event ( " on_voice_call_started " , [ ] . into ( ) ) ;
2023-02-06 11:42:25 +08:00
}
2023-02-06 12:14:20 +08:00
fn on_voice_call_closed ( & self , reason : & str ) {
self . push_event ( " on_voice_call_closed " , [ ( " reason " , reason ) ] . into ( ) )
2023-02-06 11:42:25 +08:00
}
fn on_voice_call_waiting ( & self ) {
self . push_event ( " on_voice_call_waiting " , [ ] . into ( ) ) ;
}
fn on_voice_call_incoming ( & self ) {
self . push_event ( " on_voice_call_incoming " , [ ] . into ( ) ) ;
}
2023-02-11 09:57:27 +08:00
2023-02-12 10:28:04 +08:00
#[ inline ]
fn get_rgba ( & self ) -> * const u8 {
2023-02-22 09:43:57 +08:00
#[ cfg(not(feature = " flutter_texture_render " )) ]
2023-02-12 10:28:04 +08:00
if self . rgba_valid . load ( Ordering ::Relaxed ) {
return self . rgba . read ( ) . unwrap ( ) . as_ptr ( ) ;
}
std ::ptr ::null_mut ( )
}
#[ inline ]
2023-02-19 15:25:30 +08:00
fn next_rgba ( & self ) {
2023-02-22 09:43:57 +08:00
#[ cfg(not(feature = " flutter_texture_render " )) ]
2023-02-12 10:28:04 +08:00
self . rgba_valid . store ( false , Ordering ::Relaxed ) ;
2023-02-11 09:57:27 +08:00
}
2022-08-31 20:46:30 +08:00
}
2022-05-17 20:56:36 +08:00
2022-08-31 20:46:30 +08:00
/// Create a new remote session with the given id.
///
/// # Arguments
///
/// * `id` - The identifier of the remote session with prefix. Regex: [\w]*[\_]*[\d]+
/// * `is_file_transfer` - If the session is used for file transfer.
/// * `is_port_forward` - If the session is used for port forward.
2023-01-17 13:28:33 +08:00
pub fn session_add (
id : & str ,
is_file_transfer : bool ,
is_port_forward : bool ,
switch_uuid : & str ,
2023-02-13 16:40:24 +08:00
force_relay : bool ,
2023-03-20 00:16:06 +08:00
password : String ,
2023-01-17 13:28:33 +08:00
) -> ResultType < ( ) > {
2022-08-31 20:46:30 +08:00
let session_id = get_session_id ( id . to_owned ( ) ) ;
LocalConfig ::set_remote_id ( & session_id ) ;
let session : Session < FlutterHandler > = Session {
id : session_id . clone ( ) ,
2023-03-20 00:16:06 +08:00
password ,
2023-02-16 20:01:06 +08:00
server_keyboard_enabled : Arc ::new ( RwLock ::new ( true ) ) ,
server_file_transfer_enabled : Arc ::new ( RwLock ::new ( true ) ) ,
server_clipboard_enabled : Arc ::new ( RwLock ::new ( true ) ) ,
2022-08-31 20:46:30 +08:00
.. Default ::default ( )
} ;
2022-09-01 17:36:37 +08:00
// TODO rdp
let conn_type = if is_file_transfer {
ConnType ::FILE_TRANSFER
} else if is_port_forward {
ConnType ::PORT_FORWARD
} else {
ConnType ::DEFAULT_CONN
} ;
2023-01-17 13:28:33 +08:00
let switch_uuid = if switch_uuid . is_empty ( ) {
None
} else {
Some ( switch_uuid . to_string ( ) )
} ;
2022-08-31 20:46:30 +08:00
session
. lc
. write ( )
. unwrap ( )
2023-02-13 16:40:24 +08:00
. initialize ( session_id , conn_type , switch_uuid , force_relay ) ;
2022-09-01 17:36:37 +08:00
2022-09-05 10:27:33 +08:00
if let Some ( same_id_session ) = SESSIONS . write ( ) . unwrap ( ) . insert ( id . to_owned ( ) , session ) {
2022-09-01 17:36:37 +08:00
same_id_session . close ( ) ;
2022-05-17 20:56:36 +08:00
}
2022-07-11 18:23:58 +08:00
2022-08-31 20:46:30 +08:00
Ok ( ( ) )
}
/// start a session with the given id.
///
/// # Arguments
///
/// * `id` - The identifier of the remote session with prefix. Regex: [\w]*[\_]*[\d]+
/// * `events2ui` - The events channel to ui.
pub fn session_start_ ( id : & str , event_stream : StreamSink < EventToUI > ) -> ResultType < ( ) > {
if let Some ( session ) = SESSIONS . write ( ) . unwrap ( ) . get_mut ( id ) {
2023-02-23 14:02:16 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
log ::info! (
" Session {} start, render by flutter texture rgba plugin " ,
id
) ;
#[ cfg(not(feature = " flutter_texture_render " )) ]
log ::info! ( " Session {} start, render by flutter paint widget " , id ) ;
2022-08-31 20:46:30 +08:00
* session . event_stream . write ( ) . unwrap ( ) = Some ( event_stream ) ;
let session = session . clone ( ) ;
std ::thread ::spawn ( move | | {
io_loop ( session ) ;
} ) ;
Ok ( ( ) )
} else {
bail! ( " No session with peer id {} " , id )
2022-07-11 18:23:58 +08:00
}
2022-05-12 17:35:25 +08:00
}
2023-02-16 20:01:06 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
pub fn update_text_clipboard_required ( ) {
let is_required = SESSIONS
. read ( )
. unwrap ( )
. iter ( )
. any ( | ( _id , session ) | session . is_text_clipboard_required ( ) ) ;
Client ::set_is_text_clipboard_required ( is_required ) ;
}
#[ inline ]
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
pub fn other_sessions_running ( id : & str ) -> bool {
SESSIONS . read ( ) . unwrap ( ) . keys ( ) . filter ( | k | * k ! = id ) . count ( ) ! = 0
}
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
pub fn send_text_clipboard_msg ( msg : Message ) {
for ( _id , session ) in SESSIONS . read ( ) . unwrap ( ) . iter ( ) {
if session . is_text_clipboard_required ( ) {
session . send ( Data ::Message ( msg . clone ( ) ) ) ;
}
}
}
2022-05-12 17:35:25 +08:00
// Server Side
2022-05-25 00:28:59 +08:00
#[ cfg(not(any(target_os = " ios " ))) ]
2022-05-12 17:35:25 +08:00
pub mod connection_manager {
2022-09-05 19:41:09 +08:00
use std ::collections ::HashMap ;
2022-05-12 17:35:25 +08:00
2022-10-31 10:18:22 +08:00
#[ cfg(any(target_os = " android " )) ]
2022-09-05 20:05:23 +08:00
use hbb_common ::log ;
2022-05-25 00:28:59 +08:00
#[ cfg(any(target_os = " android " )) ]
2022-05-12 17:35:25 +08:00
use scrap ::android ::call_main_service_set_by_name ;
2022-07-01 11:26:32 +08:00
2022-09-05 19:41:09 +08:00
use crate ::ui_cm_interface ::InvokeUiCM ;
2022-05-12 17:35:25 +08:00
2022-05-31 22:09:36 +08:00
use super ::GLOBAL_EVENT_STREAM ;
2022-05-17 19:59:37 +08:00
2022-09-05 19:41:09 +08:00
#[ derive(Clone) ]
struct FlutterHandler { }
2022-08-17 17:23:55 +08:00
2022-09-05 19:41:09 +08:00
impl InvokeUiCM for FlutterHandler {
//TODO port_forward
fn add_connection ( & self , client : & crate ::ui_cm_interface ::Client ) {
2022-08-17 17:23:55 +08:00
let client_json = serde_json ::to_string ( & client ) . unwrap_or ( " " . into ( ) ) ;
// send to Android service, active notification no matter UI is shown or not.
#[ cfg(any(target_os = " android " )) ]
if let Err ( e ) =
2022-09-05 19:41:09 +08:00
call_main_service_set_by_name ( " add_connection " , Some ( & client_json ) , None )
2022-08-17 17:23:55 +08:00
{
log ::debug! ( " call_service_set_by_name fail,{} " , e ) ;
}
// send to UI, refresh widget
2022-09-13 22:37:16 +08:00
self . push_event ( " add_connection " , vec! [ ( " client " , & client_json ) ] ) ;
2022-08-17 17:23:55 +08:00
}
2022-05-17 19:59:37 +08:00
2022-10-08 20:15:02 +08:00
fn remove_connection ( & self , id : i32 , close : bool ) {
self . push_event (
" on_client_remove " ,
vec! [ ( " id " , & id . to_string ( ) ) , ( " close " , & close . to_string ( ) ) ] ,
) ;
2022-05-12 17:35:25 +08:00
}
2022-09-05 19:41:09 +08:00
fn new_message ( & self , id : i32 , text : String ) {
self . push_event (
" chat_server_mode " ,
vec! [ ( " id " , & id . to_string ( ) ) , ( " text " , & text ) ] ,
) ;
2022-05-12 17:35:25 +08:00
}
2022-09-07 18:57:49 +08:00
2022-09-21 23:32:59 +08:00
fn change_theme ( & self , dark : String ) {
self . push_event ( " theme " , vec! [ ( " dark " , & dark ) ] ) ;
2022-09-07 18:57:49 +08:00
}
2022-09-08 08:52:56 +08:00
fn change_language ( & self ) {
self . push_event ( " language " , vec! [ ] ) ;
}
2022-11-10 10:27:13 +08:00
fn show_elevation ( & self , show : bool ) {
self . push_event ( " show_elevation " , vec! [ ( " show " , & show . to_string ( ) ) ] ) ;
}
2023-02-06 12:53:57 +08:00
2023-02-07 16:11:55 +08:00
fn update_voice_call_state ( & self , client : & crate ::ui_cm_interface ::Client ) {
let client_json = serde_json ::to_string ( & client ) . unwrap_or ( " " . into ( ) ) ;
self . push_event ( " update_voice_call_state " , vec! [ ( " client " , & client_json ) ] ) ;
2023-02-06 12:53:57 +08:00
}
2022-05-12 17:35:25 +08:00
}
2022-09-05 19:41:09 +08:00
impl FlutterHandler {
fn push_event ( & self , name : & str , event : Vec < ( & str , & str ) > ) {
let mut h : HashMap < & str , & str > = event . iter ( ) . cloned ( ) . collect ( ) ;
assert! ( h . get ( " name " ) . is_none ( ) ) ;
h . insert ( " name " , name ) ;
2023-02-09 16:54:26 +08:00
2023-02-07 15:39:46 +08:00
if let Some ( s ) = GLOBAL_EVENT_STREAM . read ( ) . unwrap ( ) . get ( super ::APP_TYPE_CM ) {
2022-09-05 19:41:09 +08:00
s . add ( serde_json ::ser ::to_string ( & h ) . unwrap_or ( " " . to_owned ( ) ) ) ;
2023-02-07 19:33:58 +08:00
} else {
2023-02-09 16:54:26 +08:00
println! (
" Push event {} failed. No {} event stream found. " ,
name ,
super ::APP_TYPE_CM
) ;
2022-09-05 19:41:09 +08:00
} ;
2022-05-12 17:35:25 +08:00
}
}
2023-03-30 18:16:48 +08:00
#[ inline ]
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
pub fn start_cm_no_ui ( ) {
start_listen_ipc ( false ) ;
}
#[ inline ]
2022-09-05 19:41:09 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
pub fn start_listen_ipc_thread ( ) {
2023-03-30 18:16:48 +08:00
start_listen_ipc ( true ) ;
}
2023-03-31 09:49:00 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
2023-03-30 18:16:48 +08:00
fn start_listen_ipc ( new_thread : bool ) {
2022-09-05 20:32:21 +08:00
use crate ::ui_cm_interface ::{ start_ipc , ConnectionManager } ;
2022-05-12 17:35:25 +08:00
2022-09-05 19:41:09 +08:00
#[ cfg(target_os = " linux " ) ]
2022-09-05 20:32:21 +08:00
std ::thread ::spawn ( crate ::ipc ::start_pa ) ;
2022-05-12 17:35:25 +08:00
2022-09-05 19:41:09 +08:00
let cm = ConnectionManager {
ui_handler : FlutterHandler { } ,
} ;
2023-03-30 18:16:48 +08:00
if new_thread {
std ::thread ::spawn ( move | | start_ipc ( cm ) ) ;
} else {
start_ipc ( cm ) ;
}
2022-05-12 17:35:25 +08:00
}
2022-09-05 19:41:09 +08:00
#[ cfg(target_os = " android " ) ]
2022-09-05 20:32:21 +08:00
use hbb_common ::tokio ::sync ::mpsc ::{ UnboundedReceiver , UnboundedSender } ;
2022-05-12 17:35:25 +08:00
2022-09-05 20:05:23 +08:00
#[ cfg(target_os = " android " ) ]
pub fn start_channel (
rx : UnboundedReceiver < crate ::ipc ::Data > ,
tx : UnboundedSender < crate ::ipc ::Data > ,
) {
2022-09-05 19:41:09 +08:00
use crate ::ui_cm_interface ::start_listen ;
2022-09-05 20:05:23 +08:00
let cm = crate ::ui_cm_interface ::ConnectionManager {
ui_handler : FlutterHandler { } ,
} ;
std ::thread ::spawn ( move | | start_listen ( cm , rx , tx ) ) ;
2022-05-12 17:35:25 +08:00
}
}
2022-06-28 22:15:00 +08:00
#[ inline ]
pub fn get_session_id ( id : String ) -> String {
return if let Some ( index ) = id . find ( '_' ) {
id [ index + 1 .. ] . to_string ( )
} else {
id
} ;
}
2022-08-29 13:08:42 +08:00
2022-09-05 10:27:33 +08:00
pub fn make_fd_flutter ( id : i32 , entries : & Vec < FileEntry > , only_count : bool ) -> String {
let mut m = serde_json ::Map ::new ( ) ;
m . insert ( " id " . into ( ) , json! ( id ) ) ;
let mut a = vec! [ ] ;
let mut n : u64 = 0 ;
for entry in entries {
n + = entry . size ;
if only_count {
continue ;
}
let mut e = serde_json ::Map ::new ( ) ;
e . insert ( " name " . into ( ) , json! ( entry . name . to_owned ( ) ) ) ;
let tmp = entry . entry_type . value ( ) ;
e . insert ( " type " . into ( ) , json! ( if tmp = = 0 { 1 } else { tmp } ) ) ;
e . insert ( " time " . into ( ) , json! ( entry . modified_time as f64 ) ) ;
e . insert ( " size " . into ( ) , json! ( entry . size as f64 ) ) ;
a . push ( e ) ;
}
if only_count {
m . insert ( " num_entries " . into ( ) , json! ( entries . len ( ) as i32 ) ) ;
} else {
m . insert ( " entries " . into ( ) , json! ( a ) ) ;
}
m . insert ( " total_size " . into ( ) , json! ( n as f64 ) ) ;
serde_json ::to_string ( & m ) . unwrap_or ( " " . into ( ) )
2022-09-21 16:03:08 +08:00
}
2022-10-26 19:42:14 +08:00
pub fn get_cur_session_id ( ) -> String {
2022-10-27 10:56:14 +08:00
CUR_SESSION_ID . read ( ) . unwrap ( ) . clone ( )
2022-10-26 19:42:14 +08:00
}
pub fn set_cur_session_id ( id : String ) {
if get_cur_session_id ( ) ! = id {
* CUR_SESSION_ID . write ( ) . unwrap ( ) = id ;
}
}
2023-02-12 01:52:11 +08:00
2023-02-09 15:53:51 +08:00
#[ inline ]
fn serialize_resolutions ( resolutions : & Vec < Resolution > ) -> String {
#[ derive(Debug, serde::Serialize) ]
struct ResolutionSerde {
width : i32 ,
height : i32 ,
}
let mut v = vec! [ ] ;
resolutions
. iter ( )
. map ( | r | {
v . push ( ResolutionSerde {
width : r . width ,
height : r . height ,
} )
} )
. count ( ) ;
serde_json ::ser ::to_string ( & v ) . unwrap_or ( " " . to_string ( ) )
}
2023-02-12 01:52:11 +08:00
#[ no_mangle ]
2023-02-22 09:43:57 +08:00
#[ cfg(not(feature = " flutter_texture_render " )) ]
pub fn session_get_rgba_size ( id : * const char ) -> usize {
let id = unsafe { std ::ffi ::CStr ::from_ptr ( id as _ ) } ;
2023-02-12 01:52:11 +08:00
if let Ok ( id ) = id . to_str ( ) {
2023-02-22 09:43:57 +08:00
if let Some ( session ) = SESSIONS . read ( ) . unwrap ( ) . get ( id ) {
2023-02-13 16:40:24 +08:00
return session . rgba . read ( ) . unwrap ( ) . len ( ) ;
2023-02-12 01:52:11 +08:00
}
}
0
}
2023-02-22 09:43:57 +08:00
#[ no_mangle ]
#[ cfg(feature = " flutter_texture_render " ) ]
pub fn session_get_rgba_size ( _id : * const char ) -> usize {
0
}
2023-02-12 01:52:11 +08:00
#[ no_mangle ]
2023-02-12 10:28:04 +08:00
pub fn session_get_rgba ( id : * const char ) -> * const u8 {
let id = unsafe { std ::ffi ::CStr ::from_ptr ( id as _ ) } ;
if let Ok ( id ) = id . to_str ( ) {
2023-02-22 09:43:57 +08:00
if let Some ( session ) = SESSIONS . read ( ) . unwrap ( ) . get ( id ) {
2023-02-12 10:28:04 +08:00
return session . get_rgba ( ) ;
}
}
std ::ptr ::null ( )
}
#[ no_mangle ]
pub fn session_next_rgba ( id : * const char ) {
2023-02-12 01:52:11 +08:00
let id = unsafe { std ::ffi ::CStr ::from_ptr ( id as _ ) } ;
if let Ok ( id ) = id . to_str ( ) {
2023-02-22 09:43:57 +08:00
if let Some ( session ) = SESSIONS . read ( ) . unwrap ( ) . get ( id ) {
2023-02-12 10:28:04 +08:00
return session . next_rgba ( ) ;
2023-02-12 01:52:11 +08:00
}
}
2023-02-13 16:40:24 +08:00
}
2023-02-18 11:16:07 +08:00
#[ no_mangle ]
2023-02-22 09:43:57 +08:00
#[ cfg(feature = " flutter_texture_render " ) ]
2023-02-18 11:16:07 +08:00
pub fn session_register_texture ( id : * const char , ptr : usize ) {
let id = unsafe { std ::ffi ::CStr ::from_ptr ( id as _ ) } ;
if let Ok ( id ) = id . to_str ( ) {
2023-02-22 11:03:40 +08:00
if let Some ( session ) = SESSIONS . write ( ) . unwrap ( ) . get_mut ( id ) {
2023-02-18 11:16:07 +08:00
return session . register_texture ( ptr ) ;
}
}
2023-02-18 11:47:18 +08:00
}
2023-02-22 09:43:57 +08:00
#[ no_mangle ]
#[ cfg(not(feature = " flutter_texture_render " )) ]
pub fn session_register_texture ( _id : * const char , _ptr : usize ) { }