2023-02-05 23:47:06 +08:00
use std ::{
collections ::HashMap ,
2024-01-02 16:58:10 +08:00
ffi ::c_void ,
2023-02-05 23:47:06 +08:00
net ::SocketAddr ,
2023-03-23 14:31:50 +08:00
ops ::Deref ,
2023-02-05 23:47:06 +08:00
str ::FromStr ,
2023-10-08 21:44:54 +08:00
sync ::{ mpsc , Arc , Mutex , RwLock } ,
2023-02-05 23:47:06 +08:00
} ;
2023-01-17 13:28:33 +08:00
use bytes ::Bytes ;
2022-04-23 02:17:33 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2021-03-29 15:59:14 +08:00
use cpal ::{
2023-02-13 16:40:24 +08:00
traits ::{ DeviceTrait , HostTrait , StreamTrait } ,
Device , Host , StreamConfig ,
2021-03-29 15:59:14 +08:00
} ;
2023-03-29 21:59:25 +08:00
use crossbeam_queue ::ArrayQueue ;
2022-05-08 21:01:03 +08:00
use magnum_opus ::{ Channels ::* , Decoder as AudioDecoder } ;
2023-03-29 16:59:50 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
use ringbuf ::{ ring_buffer ::RbBase , Rb } ;
2022-05-08 21:01:03 +08:00
use sha2 ::{ Digest , Sha256 } ;
use uuid ::Uuid ;
2022-07-01 11:26:32 +08:00
pub use file_trait ::FileManager ;
2023-07-20 21:16:38 +08:00
#[ cfg(windows) ]
use hbb_common ::tokio ;
2023-04-10 15:06:11 +08:00
#[ cfg(not(feature = " flutter " )) ]
2023-02-16 20:48:42 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
use hbb_common ::tokio ::sync ::mpsc ::UnboundedSender ;
2021-03-29 15:59:14 +08:00
use hbb_common ::{
allow_err ,
anyhow ::{ anyhow , Context } ,
bail ,
2023-05-17 23:19:20 +08:00
config ::{
2023-11-06 20:12:01 +08:00
Config , LocalConfig , PeerConfig , PeerInfoSerde , Resolution , CONNECT_TIMEOUT ,
PUBLIC_RS_PUB_KEY , READ_TIMEOUT , RELAY_PORT , RENDEZVOUS_PORT , RENDEZVOUS_SERVERS ,
2023-05-17 23:19:20 +08:00
} ,
2023-02-13 16:40:24 +08:00
get_version_number , log ,
2023-06-05 20:21:21 +08:00
message_proto ::{ option_message ::BoolOption , * } ,
2021-03-29 15:59:14 +08:00
protobuf ::Message as _ ,
2022-07-18 14:03:52 +08:00
rand ,
2021-03-29 15:59:14 +08:00
rendezvous_proto ::* ,
2022-01-02 22:55:33 +08:00
socket_client ,
2023-08-02 22:25:54 +08:00
sodiumoxide ::base64 ,
2024-01-07 19:01:35 +08:00
sodiumoxide ::crypto ::sign ,
2023-05-14 18:17:02 +08:00
tcp ::FramedStream ,
2023-02-13 16:40:24 +08:00
timeout ,
2023-02-16 20:48:42 +08:00
tokio ::time ::Duration ,
2023-02-13 16:40:24 +08:00
AddrMangle , ResultType , Stream ,
2021-03-29 15:59:14 +08:00
} ;
2023-02-13 16:40:24 +08:00
pub use helper ::* ;
2022-08-01 14:33:08 +08:00
use scrap ::{
2023-03-31 16:10:52 +08:00
codec ::Decoder ,
2022-09-15 17:31:28 +08:00
record ::{ Recorder , RecorderContext } ,
2024-01-22 20:01:17 +08:00
CodecFormat , ImageFormat , ImageRgb ,
2022-08-01 14:33:08 +08:00
} ;
2022-05-08 21:01:03 +08:00
2023-08-24 12:03:29 +08:00
use crate ::{
2023-11-06 20:12:01 +08:00
check_port ,
2023-08-27 10:28:16 +08:00
common ::input ::{ MOUSE_BUTTON_LEFT , MOUSE_BUTTON_RIGHT , MOUSE_TYPE_DOWN , MOUSE_TYPE_UP } ,
2024-01-07 19:01:35 +08:00
create_symmetric_key_msg , decode_id_pk , get_rs_pk , is_keyboard_mode_supported , secure_tcp ,
2023-10-08 21:44:54 +08:00
ui_session_interface ::{ InvokeUiSession , Session } ,
2023-08-24 12:03:29 +08:00
} ;
2023-02-05 23:47:06 +08:00
2023-04-10 15:06:11 +08:00
#[ cfg(not(feature = " flutter " )) ]
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
use crate ::ui_session_interface ::SessionPermissionConfig ;
2023-07-01 13:40:57 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
use crate ::{ check_clipboard , ClipboardContext , CLIPBOARD_INTERVAL } ;
2023-02-16 20:01:06 +08:00
2022-05-08 21:01:03 +08:00
pub use super ::lang ::* ;
2022-07-01 11:26:32 +08:00
2022-05-12 17:35:25 +08:00
pub mod file_trait ;
2022-05-20 00:11:48 +08:00
pub mod helper ;
2022-09-01 09:48:53 +08:00
pub mod io_loop ;
2023-02-05 23:47:06 +08:00
2022-09-01 09:48:53 +08:00
pub const MILLI1 : Duration = Duration ::from_millis ( 1 ) ;
2021-03-29 15:59:14 +08:00
pub const SEC30 : Duration = Duration ::from_secs ( 30 ) ;
2023-03-29 21:59:25 +08:00
pub const VIDEO_QUEUE_SIZE : usize = 120 ;
2024-01-22 20:01:17 +08:00
const MAX_DECODE_FAIL_COUNTER : usize = 10 ; // Currently, failed decode cause refresh_video, so make it small
2021-03-29 15:59:14 +08:00
2023-04-19 12:06:01 +08:00
#[ cfg(all(target_os = " linux " , feature = " linux_headless " )) ]
#[ cfg(not(any(feature = " flatpak " , feature = " appimage " ))) ]
2023-04-17 19:26:39 +08:00
pub const LOGIN_MSG_DESKTOP_NOT_INITED : & str = " Desktop env is not inited " ;
pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY : & str = " Desktop session not ready " ;
pub const LOGIN_MSG_DESKTOP_XSESSION_FAILED : & str = " Desktop xsession failed " ;
pub const LOGIN_MSG_DESKTOP_SESSION_ANOTHER_USER : & str = " Desktop session another user login " ;
pub const LOGIN_MSG_DESKTOP_XORG_NOT_FOUND : & str = " Desktop xorg not found " ;
// ls /usr/share/xsessions/
pub const LOGIN_MSG_DESKTOP_NO_DESKTOP : & str = " Desktop none " ;
pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY : & str =
" Desktop session not ready, password empty " ;
pub const LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG : & str =
" Desktop session not ready, password wrong " ;
pub const LOGIN_MSG_PASSWORD_EMPTY : & str = " Empty Password " ;
pub const LOGIN_MSG_PASSWORD_WRONG : & str = " Wrong Password " ;
2024-01-19 15:35:58 +08:00
pub const LOGIN_MSG_2FA_WRONG : & str = " Wrong 2FA Code " ;
pub const REQUIRE_2FA : & 'static str = " 2FA Required " ;
2023-04-17 19:26:39 +08:00
pub const LOGIN_MSG_NO_PASSWORD_ACCESS : & str = " No Password Access " ;
pub const LOGIN_MSG_OFFLINE : & str = " Offline " ;
2023-07-29 15:22:25 +08:00
pub const LOGIN_SCREEN_WAYLAND : & str = " Wayland login screen is not supported " ;
2023-07-29 14:02:13 +08:00
#[ cfg(target_os = " linux " ) ]
2023-04-17 19:26:39 +08:00
pub const SCRAP_UBUNTU_HIGHER_REQUIRED : & str = " Wayland requires Ubuntu 21.04 or higher version. " ;
2023-04-19 12:06:01 +08:00
#[ cfg(target_os = " linux " ) ]
2023-04-17 19:26:39 +08:00
pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED : & str =
" Wayland requires higher version of linux distro. Please try X11 desktop or change your OS. " ;
pub const SCRAP_X11_REQUIRED : & str = " x11 expected " ;
pub const SCRAP_X11_REF_URL : & str = " https://rustdesk.com/docs/en/manual/linux/#x11-required " ;
2023-05-13 21:40:53 +08:00
#[ cfg(feature = " flutter " ) ]
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
pub ( crate ) struct ClientClipboardContext ;
#[ cfg(not(feature = " flutter " )) ]
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
pub ( crate ) struct ClientClipboardContext {
pub cfg : SessionPermissionConfig ,
pub tx : UnboundedSender < Data > ,
}
2022-05-28 03:56:42 +08:00
/// Client of the remote desktop.
2021-03-29 15:59:14 +08:00
pub struct Client ;
2023-02-16 20:01:06 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
struct TextClipboardState {
is_required : bool ,
running : bool ,
}
2022-04-23 02:17:33 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2021-03-29 15:59:14 +08:00
lazy_static ::lazy_static! {
2022-09-01 18:23:06 +08:00
static ref AUDIO_HOST : Host = cpal ::default_host ( ) ;
2021-03-29 15:59:14 +08:00
}
2022-09-01 18:23:06 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
2022-08-31 22:24:57 +08:00
lazy_static ::lazy_static! {
2022-09-01 18:23:06 +08:00
static ref ENIGO : Arc < Mutex < enigo ::Enigo > > = Arc ::new ( Mutex ::new ( enigo ::Enigo ::new ( ) ) ) ;
2023-02-16 20:01:06 +08:00
static ref OLD_CLIPBOARD_TEXT : Arc < Mutex < String > > = Default ::default ( ) ;
static ref TEXT_CLIPBOARD_STATE : Arc < Mutex < TextClipboardState > > = Arc ::new ( Mutex ::new ( TextClipboardState ::new ( ) ) ) ;
2022-08-31 22:24:57 +08:00
}
2023-11-06 20:12:01 +08:00
const PUBLIC_SERVER : & str = " public " ;
2023-04-10 16:58:58 +08:00
#[ inline ]
2023-04-10 16:02:21 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
2023-04-10 16:58:58 +08:00
pub fn get_old_clipboard_text ( ) -> & 'static Arc < Mutex < String > > {
& OLD_CLIPBOARD_TEXT
2023-04-10 16:02:21 +08:00
}
2022-09-01 18:23:06 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
2022-08-31 22:24:57 +08:00
pub fn get_key_state ( key : enigo ::Key ) -> bool {
2022-09-01 18:23:06 +08:00
use enigo ::KeyboardControllable ;
2022-08-31 22:24:57 +08:00
#[ cfg(target_os = " macos " ) ]
if key = = enigo ::Key ::NumLock {
return true ;
}
ENIGO . lock ( ) . unwrap ( ) . get_key_state ( key )
2021-03-29 15:59:14 +08:00
}
cfg_if ::cfg_if! {
if #[ cfg(target_os = " android " ) ] {
2024-01-02 16:58:10 +08:00
use hbb_common ::libc ::{ c_float , c_int } ;
2021-03-29 15:59:14 +08:00
type Oboe = * mut c_void ;
extern " C " {
fn create_oboe_player ( channels : c_int , sample_rate : c_int ) -> Oboe ;
fn push_oboe_data ( oboe : Oboe , d : * const c_float , n : c_int ) ;
fn destroy_oboe_player ( oboe : Oboe ) ;
}
struct OboePlayer {
raw : Oboe ,
}
impl Default for OboePlayer {
fn default ( ) -> Self {
Self {
raw : std ::ptr ::null_mut ( ) ,
}
}
}
impl OboePlayer {
fn new ( channels : i32 , sample_rate : i32 ) -> Self {
unsafe {
Self {
raw : create_oboe_player ( channels , sample_rate ) ,
}
}
}
2023-04-20 13:36:44 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
2021-03-29 15:59:14 +08:00
fn is_null ( & self ) -> bool {
self . raw . is_null ( )
}
fn push ( & mut self , d : & [ f32 ] ) {
if self . raw . is_null ( ) {
return ;
}
unsafe {
push_oboe_data ( self . raw , d . as_ptr ( ) , d . len ( ) as _ ) ;
}
}
}
impl Drop for OboePlayer {
fn drop ( & mut self ) {
unsafe {
if ! self . raw . is_null ( ) {
destroy_oboe_player ( self . raw ) ;
}
}
}
}
}
}
impl Client {
2022-05-28 03:56:42 +08:00
/// Start a new connection.
2022-05-12 17:35:25 +08:00
pub async fn start (
peer : & str ,
key : & str ,
token : & str ,
conn_type : ConnType ,
2022-07-31 19:06:49 +08:00
interface : impl Interface ,
2023-04-19 14:39:22 +08:00
) -> ResultType < ( Stream , bool , Option < Vec < u8 > > ) > {
2023-11-06 20:12:01 +08:00
debug_assert! ( peer = = interface . get_id ( ) ) ;
2023-07-01 17:58:11 +08:00
interface . update_direct ( None ) ;
interface . update_received ( false ) ;
2022-07-31 19:06:49 +08:00
match Self ::_start ( peer , key , token , conn_type , interface ) . await {
2022-01-05 23:50:13 +08:00
Err ( err ) = > {
let err_str = err . to_string ( ) ;
if err_str . starts_with ( " Failed " ) {
bail! ( err_str + " : Please try later " ) ;
} else {
return Err ( err ) ;
}
}
2022-09-15 17:31:28 +08:00
Ok ( x ) = > Ok ( x ) ,
2022-01-05 23:50:13 +08:00
}
}
2022-05-28 03:56:42 +08:00
/// Start a new connection.
2022-05-12 17:35:25 +08:00
async fn _start (
peer : & str ,
key : & str ,
token : & str ,
conn_type : ConnType ,
2022-07-31 19:06:49 +08:00
interface : impl Interface ,
2023-04-19 14:39:22 +08:00
) -> ResultType < ( Stream , bool , Option < Vec < u8 > > ) > {
2021-03-29 15:59:14 +08:00
// to-do: remember the port for each peer, so that we can retry easier
2023-01-04 18:35:31 +08:00
if hbb_common ::is_ip_str ( peer ) {
2022-01-05 23:50:13 +08:00
return Ok ( (
2023-11-06 20:12:01 +08:00
socket_client ::connect_tcp ( check_port ( peer , RELAY_PORT + 1 ) , CONNECT_TIMEOUT )
. await ? ,
2022-01-05 23:50:13 +08:00
true ,
2023-04-19 14:39:22 +08:00
None ,
2022-01-05 23:50:13 +08:00
) ) ;
}
2023-01-18 14:08:46 +08:00
// Allow connect to {domain}:{port}
if hbb_common ::is_domain_port_str ( peer ) {
2023-01-17 22:46:11 +08:00
return Ok ( (
2023-05-14 18:17:02 +08:00
socket_client ::connect_tcp ( peer , CONNECT_TIMEOUT ) . await ? ,
2023-01-17 22:46:11 +08:00
true ,
2023-04-19 14:39:22 +08:00
None ,
2023-01-17 22:46:11 +08:00
) ) ;
}
2023-11-06 20:12:01 +08:00
let other_server = interface . get_lch ( ) . read ( ) . unwrap ( ) . other_server . clone ( ) ;
let ( peer , other_server , key , token ) = if let Some ( ( a , b , c ) ) = other_server . as_ref ( ) {
( a . as_ref ( ) , b . as_ref ( ) , c . as_ref ( ) , " " )
} else {
( peer , " " , key , token )
} ;
let ( mut rendezvous_server , servers , contained ) = if other_server . is_empty ( ) {
crate ::get_rendezvous_server ( 1_000 ) . await
} else {
if other_server = = PUBLIC_SERVER {
(
check_port ( RENDEZVOUS_SERVERS [ 0 ] , RENDEZVOUS_PORT ) ,
RENDEZVOUS_SERVERS [ 1 .. ]
. iter ( )
. map ( | x | x . to_string ( ) )
. collect ( ) ,
true ,
)
} else {
( check_port ( other_server , RENDEZVOUS_PORT ) , Vec ::new ( ) , true )
}
} ;
2023-05-14 18:17:02 +08:00
let mut socket = socket_client ::connect_tcp ( & * rendezvous_server , CONNECT_TIMEOUT ) . await ;
2022-07-14 15:21:26 +08:00
debug_assert! ( ! servers . contains ( & rendezvous_server ) ) ;
if socket . is_err ( ) & & ! servers . is_empty ( ) {
log ::info! ( " try the other servers: {:?} " , servers ) ;
for server in servers {
2023-11-06 20:12:01 +08:00
let server = check_port ( server , RENDEZVOUS_PORT ) ;
2023-05-14 18:17:02 +08:00
socket = socket_client ::connect_tcp ( & * server , CONNECT_TIMEOUT ) . await ;
2022-07-14 15:21:26 +08:00
if socket . is_ok ( ) {
rendezvous_server = server ;
break ;
}
}
crate ::refresh_rendezvous_server ( ) ;
} else if ! contained {
crate ::refresh_rendezvous_server ( ) ;
}
log ::info! ( " rendezvous server: {} " , rendezvous_server ) ;
let mut socket = socket ? ;
2022-01-02 22:55:33 +08:00
let my_addr = socket . local_addr ( ) ;
2022-03-20 20:20:32 +08:00
let mut signed_id_pk = Vec ::new ( ) ;
2021-03-29 15:59:14 +08:00
let mut relay_server = " " . to_owned ( ) ;
2023-05-14 18:17:02 +08:00
if ! key . is_empty ( ) & & ! token . is_empty ( ) {
// mainly for the security of token
2024-01-07 19:01:35 +08:00
allow_err! ( secure_tcp ( & mut socket , key ) . await ) ;
2023-05-14 18:17:02 +08:00
}
2021-03-29 15:59:14 +08:00
let start = std ::time ::Instant ::now ( ) ;
2022-12-28 13:52:13 +08:00
let mut peer_addr = Config ::get_any_listen_addr ( true ) ;
2021-03-29 15:59:14 +08:00
let mut peer_nat_type = NatType ::UNKNOWN_NAT ;
let my_nat_type = crate ::get_nat_type ( 100 ) . await ;
let mut is_local = false ;
for i in 1 ..= 3 {
log ::info! ( " #{} punch attempt with {}, id: {} " , i , my_addr , peer ) ;
let mut msg_out = RendezvousMessage ::new ( ) ;
2022-07-14 17:20:01 +08:00
use hbb_common ::protobuf ::Enum ;
2022-07-31 19:06:49 +08:00
let nat_type = if interface . is_force_relay ( ) {
NatType ::SYMMETRIC
} else {
NatType ::from_i32 ( my_nat_type ) . unwrap_or ( NatType ::UNKNOWN_NAT )
} ;
2021-03-29 15:59:14 +08:00
msg_out . set_punch_hole_request ( PunchHoleRequest {
id : peer . to_owned ( ) ,
2022-05-12 17:35:25 +08:00
token : token . to_owned ( ) ,
2021-03-29 15:59:14 +08:00
nat_type : nat_type . into ( ) ,
2022-05-12 17:35:25 +08:00
licence_key : key . to_owned ( ) ,
2021-07-27 23:53:12 +08:00
conn_type : conn_type . into ( ) ,
2021-03-29 15:59:14 +08:00
.. Default ::default ( )
} ) ;
socket . send ( & msg_out ) . await ? ;
2023-05-14 18:17:02 +08:00
if let Some ( msg_in ) =
2023-06-13 11:10:49 +08:00
crate ::get_next_nonkeyexchange_msg ( & mut socket , Some ( i * 6000 ) ) . await
2023-05-14 18:17:02 +08:00
{
match msg_in . union {
Some ( rendezvous_message ::Union ::PunchHoleResponse ( ph ) ) = > {
if ph . socket_addr . is_empty ( ) {
if ! ph . other_failure . is_empty ( ) {
bail! ( ph . other_failure ) ;
}
2023-07-22 14:16:41 +08:00
match ph . failure . enum_value ( ) {
Ok ( punch_hole_response ::Failure ::ID_NOT_EXIST ) = > {
2023-05-14 18:17:02 +08:00
bail! ( " ID does not exist " ) ;
2022-03-20 20:20:32 +08:00
}
2023-07-22 14:16:41 +08:00
Ok ( punch_hole_response ::Failure ::OFFLINE ) = > {
2023-05-14 18:17:02 +08:00
bail! ( " Remote desktop is offline " ) ;
}
2023-07-22 14:16:41 +08:00
Ok ( punch_hole_response ::Failure ::LICENSE_MISMATCH ) = > {
2023-05-14 18:17:02 +08:00
bail! ( " Key mismatch " ) ;
}
2023-07-22 14:16:41 +08:00
Ok ( punch_hole_response ::Failure ::LICENSE_OVERUSE ) = > {
2023-05-14 18:17:02 +08:00
bail! ( " Key overuse " ) ;
2021-03-29 15:59:14 +08:00
}
2023-07-22 14:16:41 +08:00
_ = > bail! ( " other punch hole failure " ) ,
2021-03-29 15:59:14 +08:00
}
2023-05-14 18:17:02 +08:00
} else {
peer_nat_type = ph . nat_type ( ) ;
is_local = ph . is_local ( ) ;
signed_id_pk = ph . pk . into ( ) ;
relay_server = ph . relay_server ;
peer_addr = AddrMangle ::decode ( & ph . socket_addr ) ;
log ::info! ( " Hole Punched {} = {} " , peer , peer_addr ) ;
break ;
2021-03-29 15:59:14 +08:00
}
}
2023-05-14 18:17:02 +08:00
Some ( rendezvous_message ::Union ::RelayResponse ( rr ) ) = > {
log ::info! (
" relay requested from peer, time used: {:?}, relay_server: {} " ,
start . elapsed ( ) ,
rr . relay_server
) ;
signed_id_pk = rr . pk ( ) . into ( ) ;
let mut conn = Self ::create_relay (
peer ,
rr . uuid ,
rr . relay_server ,
key ,
conn_type ,
my_addr . is_ipv4 ( ) ,
)
. await ? ;
2023-07-01 17:58:11 +08:00
let pk =
Self ::secure_connection ( peer , signed_id_pk , key , & mut conn ) . await ? ;
2023-05-14 18:17:02 +08:00
return Ok ( ( conn , false , pk ) ) ;
}
_ = > {
log ::error! ( " Unexpected protobuf msg received: {:?} " , msg_in ) ;
}
2021-03-29 15:59:14 +08:00
}
}
}
drop ( socket ) ;
if peer_addr . port ( ) = = 0 {
bail! ( " Failed to connect via rendezvous server " ) ;
}
let time_used = start . elapsed ( ) . as_millis ( ) as u64 ;
log ::info! (
" {} ms used to punch hole, relay_server: {}, {} " ,
time_used ,
relay_server ,
if is_local {
" is_local: true " . to_owned ( )
} else {
format! ( " nat_type: {:?} " , peer_nat_type )
}
) ;
Self ::connect (
my_addr ,
peer_addr ,
peer ,
2022-03-20 20:20:32 +08:00
signed_id_pk ,
2021-03-29 15:59:14 +08:00
& relay_server ,
2022-01-05 13:21:14 +08:00
& rendezvous_server ,
2021-03-29 15:59:14 +08:00
time_used ,
peer_nat_type ,
my_nat_type ,
is_local ,
2022-05-12 17:35:25 +08:00
key ,
token ,
2021-07-27 23:53:12 +08:00
conn_type ,
2022-07-31 19:06:49 +08:00
interface ,
2021-03-29 15:59:14 +08:00
)
. await
}
2022-05-28 03:56:42 +08:00
/// Connect to the peer.
2021-03-29 15:59:14 +08:00
async fn connect (
local_addr : SocketAddr ,
peer : SocketAddr ,
peer_id : & str ,
2022-03-20 20:20:32 +08:00
signed_id_pk : Vec < u8 > ,
2021-03-29 15:59:14 +08:00
relay_server : & str ,
2022-01-05 13:21:14 +08:00
rendezvous_server : & str ,
2021-03-29 15:59:14 +08:00
punch_time_used : u64 ,
peer_nat_type : NatType ,
my_nat_type : i32 ,
is_local : bool ,
2022-05-12 17:35:25 +08:00
key : & str ,
token : & str ,
2021-07-27 23:53:12 +08:00
conn_type : ConnType ,
2022-07-31 19:06:49 +08:00
interface : impl Interface ,
2023-04-19 14:39:22 +08:00
) -> ResultType < ( Stream , bool , Option < Vec < u8 > > ) > {
2023-11-06 20:12:01 +08:00
let direct_failures = interface . get_lch ( ) . read ( ) . unwrap ( ) . direct_failures ;
2021-03-29 15:59:14 +08:00
let mut connect_timeout = 0 ;
const MIN : u64 = 1000 ;
if is_local | | peer_nat_type = = NatType ::SYMMETRIC {
connect_timeout = MIN ;
} else {
if relay_server . is_empty ( ) {
connect_timeout = CONNECT_TIMEOUT ;
} else {
if peer_nat_type = = NatType ::ASYMMETRIC {
let mut my_nat_type = my_nat_type ;
if my_nat_type = = NatType ::UNKNOWN_NAT as i32 {
my_nat_type = crate ::get_nat_type ( 100 ) . await ;
}
if my_nat_type = = NatType ::ASYMMETRIC as i32 {
connect_timeout = CONNECT_TIMEOUT ;
2021-07-27 23:53:12 +08:00
if direct_failures > 0 {
connect_timeout = punch_time_used * 6 ;
}
2021-03-29 15:59:14 +08:00
} else if my_nat_type = = NatType ::SYMMETRIC as i32 {
connect_timeout = MIN ;
}
}
if connect_timeout = = 0 {
let n = if direct_failures > 0 { 3 } else { 6 } ;
connect_timeout = punch_time_used * ( n as u64 ) ;
}
}
if connect_timeout < MIN {
connect_timeout = MIN ;
}
}
log ::info! ( " peer address: {}, timeout: {} " , peer , connect_timeout ) ;
let start = std ::time ::Instant ::now ( ) ;
2022-01-02 22:55:33 +08:00
// NOTICE: Socks5 is be used event in intranet. Which may be not a good way.
2023-01-04 18:35:31 +08:00
let mut conn =
socket_client ::connect_tcp_local ( peer , Some ( local_addr ) , connect_timeout ) . await ;
2022-07-31 19:06:49 +08:00
let mut direct = ! conn . is_err ( ) ;
2023-07-01 17:58:11 +08:00
interface . update_direct ( Some ( direct ) ) ;
2022-07-31 19:06:49 +08:00
if interface . is_force_relay ( ) | | conn . is_err ( ) {
2021-03-29 15:59:14 +08:00
if ! relay_server . is_empty ( ) {
conn = Self ::request_relay (
peer_id ,
relay_server . to_owned ( ) ,
rendezvous_server ,
2022-03-20 20:20:32 +08:00
! signed_id_pk . is_empty ( ) ,
2022-05-12 17:35:25 +08:00
key ,
token ,
2021-07-27 23:53:12 +08:00
conn_type ,
2021-03-29 15:59:14 +08:00
)
. await ;
2023-07-01 17:58:11 +08:00
interface . update_direct ( Some ( false ) ) ;
2023-07-22 14:16:41 +08:00
if let Err ( e ) = conn {
bail! ( " Failed to connect via relay server: {} " , e ) ;
2021-03-29 15:59:14 +08:00
}
2022-07-31 19:06:49 +08:00
direct = false ;
2021-03-29 15:59:14 +08:00
} else {
bail! ( " Failed to make direct connection to remote desktop " ) ;
}
}
if ! relay_server . is_empty ( ) & & ( direct_failures = = 0 ) ! = direct {
2023-11-06 20:12:01 +08:00
let n = if direct { 0 } else { 1 } ;
log ::info! ( " direct_failures updated to {} " , n ) ;
interface . get_lch ( ) . write ( ) . unwrap ( ) . set_direct_failure ( n ) ;
2021-03-29 15:59:14 +08:00
}
let mut conn = conn ? ;
log ::info! ( " {:?} used to establish connection " , start . elapsed ( ) ) ;
2023-07-01 17:58:11 +08:00
let pk = Self ::secure_connection ( peer_id , signed_id_pk , key , & mut conn ) . await ? ;
2023-04-19 14:39:22 +08:00
Ok ( ( conn , direct , pk ) )
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Establish secure connection with the server.
2022-05-12 17:35:25 +08:00
async fn secure_connection (
peer_id : & str ,
signed_id_pk : Vec < u8 > ,
key : & str ,
conn : & mut Stream ,
2023-04-19 14:39:22 +08:00
) -> ResultType < Option < Vec < u8 > > > {
2022-05-12 17:35:25 +08:00
let rs_pk = get_rs_pk ( if key . is_empty ( ) {
2022-07-27 00:39:02 +08:00
hbb_common ::config ::RS_PUB_KEY
2022-05-12 17:35:25 +08:00
} else {
key
} ) ;
2022-03-20 20:20:32 +08:00
let mut sign_pk = None ;
2023-04-19 14:39:22 +08:00
let mut option_pk = None ;
2023-07-22 14:16:41 +08:00
if ! signed_id_pk . is_empty ( ) {
if let Some ( rs_pk ) = rs_pk {
if let Ok ( ( id , pk ) ) = decode_id_pk ( & signed_id_pk , & rs_pk ) {
if id = = peer_id {
sign_pk = Some ( sign ::PublicKey ( pk ) ) ;
option_pk = Some ( pk . to_vec ( ) ) ;
}
2022-03-20 20:20:32 +08:00
}
}
if sign_pk . is_none ( ) {
2021-12-28 18:33:36 +08:00
log ::error! ( " Handshake failed: invalid public key from rendezvous server " ) ;
}
}
2022-03-20 20:20:32 +08:00
let sign_pk = match sign_pk {
Some ( v ) = > v ,
None = > {
// send an empty message out in case server is setting up secure and waiting for first message
conn . send ( & Message ::new ( ) ) . await ? ;
2023-04-19 14:39:22 +08:00
return Ok ( option_pk ) ;
2022-03-20 20:20:32 +08:00
}
} ;
2022-07-31 19:06:49 +08:00
match timeout ( READ_TIMEOUT , conn . next ( ) ) . await ? {
2021-03-29 15:59:14 +08:00
Some ( res ) = > {
2023-07-01 17:58:11 +08:00
let bytes = res ? ;
2021-03-29 15:59:14 +08:00
if let Ok ( msg_in ) = Message ::parse_from_bytes ( & bytes ) {
2022-07-14 17:20:01 +08:00
if let Some ( message ::Union ::SignedId ( si ) ) = msg_in . union {
2022-03-26 00:06:06 +08:00
if let Ok ( ( id , their_pk_b ) ) = decode_id_pk ( & si . id , & sign_pk ) {
2021-12-28 18:33:36 +08:00
if id = = peer_id {
2023-05-14 18:17:02 +08:00
let ( asymmetric_value , symmetric_value , key ) =
create_symmetric_key_msg ( their_pk_b ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_public_key ( PublicKey {
asymmetric_value ,
symmetric_value ,
.. Default ::default ( )
} ) ;
timeout ( CONNECT_TIMEOUT , conn . send ( & msg_out ) ) . await ? ? ;
2021-03-29 15:59:14 +08:00
conn . set_key ( key ) ;
} else {
2021-12-28 18:33:36 +08:00
log ::error! ( " Handshake failed: sign failure " ) ;
conn . send ( & Message ::new ( ) ) . await ? ;
2021-03-29 15:59:14 +08:00
}
} else {
// fall back to non-secure connection in case pk mismatch
2021-07-27 23:53:12 +08:00
log ::info! ( " pk mismatch, fall back to non-secure " ) ;
2021-03-29 15:59:14 +08:00
let mut msg_out = Message ::new ( ) ;
msg_out . set_public_key ( PublicKey ::new ( ) ) ;
2022-03-26 00:06:06 +08:00
conn . send ( & msg_out ) . await ? ;
2021-03-29 15:59:14 +08:00
}
} else {
2021-12-28 18:33:36 +08:00
log ::error! ( " Handshake failed: invalid message type " ) ;
conn . send ( & Message ::new ( ) ) . await ? ;
2021-03-29 15:59:14 +08:00
}
} else {
2021-12-28 18:33:36 +08:00
log ::error! ( " Handshake failed: invalid message format " ) ;
conn . send ( & Message ::new ( ) ) . await ? ;
2021-03-29 15:59:14 +08:00
}
}
None = > {
bail! ( " Reset by the peer " ) ;
}
}
2023-04-19 14:39:22 +08:00
Ok ( option_pk )
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Request a relay connection to the server.
2021-03-29 15:59:14 +08:00
async fn request_relay (
peer : & str ,
relay_server : String ,
2022-01-05 13:21:14 +08:00
rendezvous_server : & str ,
2021-03-29 15:59:14 +08:00
secure : bool ,
2022-05-12 17:35:25 +08:00
key : & str ,
token : & str ,
2021-07-27 23:53:12 +08:00
conn_type : ConnType ,
2021-03-29 15:59:14 +08:00
) -> ResultType < Stream > {
let mut succeed = false ;
let mut uuid = " " . to_owned ( ) ;
2022-12-28 13:52:13 +08:00
let mut ipv4 = true ;
2023-06-30 13:37:51 +08:00
2021-03-29 15:59:14 +08:00
for i in 1 ..= 3 {
2023-06-30 13:37:51 +08:00
// use different socket due to current hbbs implementation requiring different nat address for each attempt
2023-05-14 18:17:02 +08:00
let mut socket = socket_client ::connect_tcp ( rendezvous_server , CONNECT_TIMEOUT )
2022-12-28 13:52:13 +08:00
. await
. with_context ( | | " Failed to connect to rendezvous server " ) ? ;
2022-01-02 22:55:33 +08:00
2023-06-30 13:37:51 +08:00
if ! key . is_empty ( ) & & ! token . is_empty ( ) {
// mainly for the security of token
2024-01-07 19:01:35 +08:00
allow_err! ( secure_tcp ( & mut socket , key ) . await ) ;
2023-06-30 13:37:51 +08:00
}
2022-12-28 13:52:13 +08:00
ipv4 = socket . local_addr ( ) . is_ipv4 ( ) ;
2021-03-29 15:59:14 +08:00
let mut msg_out = RendezvousMessage ::new ( ) ;
uuid = Uuid ::new_v4 ( ) . to_string ( ) ;
log ::info! (
" #{} request relay attempt, id: {}, uuid: {}, relay_server: {}, secure: {} " ,
i ,
peer ,
uuid ,
relay_server ,
secure ,
) ;
msg_out . set_request_relay ( RequestRelay {
id : peer . to_owned ( ) ,
2022-05-12 17:35:25 +08:00
token : token . to_owned ( ) ,
2021-03-29 15:59:14 +08:00
uuid : uuid . clone ( ) ,
relay_server : relay_server . clone ( ) ,
secure ,
.. Default ::default ( )
} ) ;
socket . send ( & msg_out ) . await ? ;
2023-06-30 13:08:34 +08:00
if let Some ( msg_in ) =
crate ::get_next_nonkeyexchange_msg ( & mut socket , Some ( CONNECT_TIMEOUT ) ) . await
{
if let Some ( rendezvous_message ::Union ::RelayResponse ( rs ) ) = msg_in . union {
if ! rs . refuse_reason . is_empty ( ) {
bail! ( rs . refuse_reason ) ;
2021-03-29 15:59:14 +08:00
}
2023-06-30 13:08:34 +08:00
succeed = true ;
break ;
2021-03-29 15:59:14 +08:00
}
}
}
if ! succeed {
2021-07-28 19:41:34 +08:00
bail! ( " Timeout " ) ;
2021-03-29 15:59:14 +08:00
}
2022-12-28 13:52:13 +08:00
Self ::create_relay ( peer , uuid , relay_server , key , conn_type , ipv4 ) . await
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Create a relay connection to the server.
2021-07-27 23:53:12 +08:00
async fn create_relay (
peer : & str ,
uuid : String ,
relay_server : String ,
2022-05-12 17:35:25 +08:00
key : & str ,
2021-07-27 23:53:12 +08:00
conn_type : ConnType ,
2022-12-28 13:52:13 +08:00
ipv4 : bool ,
2021-07-27 23:53:12 +08:00
) -> ResultType < Stream > {
2022-01-02 22:55:33 +08:00
let mut conn = socket_client ::connect_tcp (
2023-11-06 20:12:01 +08:00
socket_client ::ipv4_to_ipv6 ( check_port ( relay_server , RELAY_PORT ) , ipv4 ) ,
2021-03-29 15:59:14 +08:00
CONNECT_TIMEOUT ,
)
. await
. with_context ( | | " Failed to connect to relay server " ) ? ;
let mut msg_out = RendezvousMessage ::new ( ) ;
msg_out . set_request_relay ( RequestRelay {
2022-05-12 17:35:25 +08:00
licence_key : key . to_owned ( ) ,
2021-03-29 15:59:14 +08:00
id : peer . to_owned ( ) ,
uuid ,
2021-07-27 23:53:12 +08:00
conn_type : conn_type . into ( ) ,
2021-03-29 15:59:14 +08:00
.. Default ::default ( )
} ) ;
conn . send ( & msg_out ) . await ? ;
Ok ( conn )
}
2023-02-16 20:01:06 +08:00
#[ inline ]
#[ cfg(feature = " flutter " ) ]
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
pub fn set_is_text_clipboard_required ( b : bool ) {
TEXT_CLIPBOARD_STATE . lock ( ) . unwrap ( ) . is_required = b ;
}
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
2023-10-08 21:44:54 +08:00
fn try_stop_clipboard ( _self_id : & str ) {
2023-02-16 20:01:06 +08:00
#[ cfg(feature = " flutter " ) ]
2023-10-08 21:44:54 +08:00
if crate ::flutter ::sessions ::other_sessions_running (
_self_id . to_string ( ) ,
ConnType ::DEFAULT_CONN ,
) {
2023-02-16 20:01:06 +08:00
return ;
}
TEXT_CLIPBOARD_STATE . lock ( ) . unwrap ( ) . running = false ;
}
2023-04-10 17:11:17 +08:00
// `try_start_clipboard` is called by all session when connection is established. (When handling peer info).
// This function only create one thread with a loop, the loop is shared by all sessions.
// After all sessions are end, the loop exists.
2023-04-15 09:41:56 +08:00
//
2023-04-10 17:11:17 +08:00
// If clipboard update is detected, the text will be sent to all sessions by `send_text_clipboard_msg`.
2023-02-16 20:01:06 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
2023-04-10 16:16:09 +08:00
fn try_start_clipboard ( _ctx : Option < ClientClipboardContext > ) {
2023-02-16 20:01:06 +08:00
let mut clipboard_lock = TEXT_CLIPBOARD_STATE . lock ( ) . unwrap ( ) ;
if clipboard_lock . running {
return ;
}
match ClipboardContext ::new ( ) {
Ok ( mut ctx ) = > {
clipboard_lock . running = true ;
// ignore clipboard update before service start
check_clipboard ( & mut ctx , Some ( & OLD_CLIPBOARD_TEXT ) ) ;
std ::thread ::spawn ( move | | {
log ::info! ( " Start text clipboard loop " ) ;
loop {
std ::thread ::sleep ( Duration ::from_millis ( CLIPBOARD_INTERVAL ) ) ;
if ! TEXT_CLIPBOARD_STATE . lock ( ) . unwrap ( ) . running {
break ;
}
if ! TEXT_CLIPBOARD_STATE . lock ( ) . unwrap ( ) . is_required {
continue ;
}
if let Some ( msg ) = check_clipboard ( & mut ctx , Some ( & OLD_CLIPBOARD_TEXT ) ) {
#[ cfg(feature = " flutter " ) ]
2023-04-10 16:58:58 +08:00
crate ::flutter ::send_text_clipboard_msg ( msg ) ;
2023-02-16 20:01:06 +08:00
#[ cfg(not(feature = " flutter " )) ]
2023-04-10 14:30:38 +08:00
if let Some ( ctx ) = & _ctx {
2023-04-10 16:58:58 +08:00
if ctx . cfg . is_text_clipboard_required ( ) {
2023-04-10 14:30:38 +08:00
let _ = ctx . tx . send ( Data ::Message ( msg ) ) ;
2023-02-16 20:01:06 +08:00
}
}
}
}
log ::info! ( " Stop text clipboard loop " ) ;
} ) ;
}
Err ( err ) = > {
log ::error! ( " Failed to start clipboard service of client: {} " , err ) ;
}
}
}
2023-04-10 18:33:16 +08:00
#[ inline ]
2023-02-16 20:01:06 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
fn get_current_text_clipboard_msg ( ) -> Option < Message > {
let txt = & * OLD_CLIPBOARD_TEXT . lock ( ) . unwrap ( ) ;
if txt . is_empty ( ) {
None
} else {
Some ( crate ::create_clipboard_msg ( txt . clone ( ) ) )
}
}
}
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
impl TextClipboardState {
fn new ( ) -> Self {
Self {
is_required : true ,
running : false ,
}
}
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Audio handler for the [`Client`].
2021-03-29 15:59:14 +08:00
#[ derive(Default) ]
pub struct AudioHandler {
audio_decoder : Option < ( AudioDecoder , Vec < f32 > ) > ,
2022-04-23 02:17:33 +08:00
#[ cfg(target_os = " android " ) ]
oboe : Option < OboePlayer > ,
#[ cfg(target_os = " linux " ) ]
simple : Option < psimple ::Simple > ,
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2023-03-29 16:59:50 +08:00
audio_buffer : AudioBuffer ,
2021-03-29 15:59:14 +08:00
sample_rate : ( u32 , u32 ) ,
2022-04-23 02:17:33 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2021-03-29 15:59:14 +08:00
audio_stream : Option < Box < dyn StreamTrait > > ,
channels : u16 ,
2023-05-12 14:01:56 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2023-04-20 17:26:17 +08:00
device_channel : u16 ,
2023-03-29 07:32:35 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
ready : Arc < std ::sync ::Mutex < bool > > ,
2021-03-29 15:59:14 +08:00
}
2023-03-29 16:59:50 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
struct AudioBuffer ( pub Arc < std ::sync ::Mutex < ringbuf ::HeapRb < f32 > > > ) ;
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
impl Default for AudioBuffer {
fn default ( ) -> Self {
Self ( Arc ::new ( std ::sync ::Mutex ::new (
ringbuf ::HeapRb ::< f32 > ::new ( 48000 * 2 ) , // 48000hz, 2 channel, 1 second
) ) )
}
}
2021-03-29 15:59:14 +08:00
impl AudioHandler {
2022-05-28 03:56:42 +08:00
/// Start the audio playback.
2022-04-23 02:17:33 +08:00
#[ cfg(target_os = " linux " ) ]
2021-03-29 15:59:14 +08:00
fn start_audio ( & mut self , format0 : AudioFormat ) -> ResultType < ( ) > {
2022-04-23 02:17:33 +08:00
use psimple ::Simple ;
use pulse ::sample ::{ Format , Spec } ;
use pulse ::stream ::Direction ;
let spec = Spec {
format : Format ::F32le ,
channels : format0 . channels as _ ,
rate : format0 . sample_rate as _ ,
} ;
if ! spec . is_valid ( ) {
bail! ( " Invalid audio format " ) ;
}
self . simple = Some ( Simple ::new (
2022-05-13 14:46:37 +08:00
None , // Use the default server
& crate ::get_app_name ( ) , // Our application’ s name
Direction ::Playback , // We want a playback stream
None , // Use the default device
" playback " , // Description of our stream
& spec , // Our sample format
None , // Use default channel map
None , // Use default buffering attributes
2022-04-23 02:17:33 +08:00
) ? ) ;
self . sample_rate = ( format0 . sample_rate , format0 . sample_rate ) ;
Ok ( ( ) )
}
2022-05-28 03:56:42 +08:00
/// Start the audio playback.
2022-04-23 02:17:33 +08:00
#[ cfg(target_os = " android " ) ]
fn start_audio ( & mut self , format0 : AudioFormat ) -> ResultType < ( ) > {
self . oboe = Some ( OboePlayer ::new (
format0 . channels as _ ,
format0 . sample_rate as _ ,
) ) ;
2021-03-29 15:59:14 +08:00
self . sample_rate = ( format0 . sample_rate , format0 . sample_rate ) ;
Ok ( ( ) )
}
2022-05-28 03:56:42 +08:00
/// Start the audio playback.
2022-04-23 02:17:33 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2021-03-29 15:59:14 +08:00
fn start_audio ( & mut self , format0 : AudioFormat ) -> ResultType < ( ) > {
let device = AUDIO_HOST
. default_output_device ( )
. with_context ( | | " Failed to get default output device " ) ? ;
log ::info! (
" Using default output device: \" {} \" " ,
device . name ( ) . unwrap_or ( " " . to_owned ( ) )
) ;
let config = device . default_output_config ( ) . map_err ( | e | anyhow! ( e ) ) ? ;
let sample_format = config . sample_format ( ) ;
log ::info! ( " Default output format: {:?} " , config ) ;
log ::info! ( " Remote input format: {:?} " , format0 ) ;
2023-04-20 17:26:17 +08:00
let config : StreamConfig = config . into ( ) ;
2023-04-21 07:44:39 +08:00
self . sample_rate = ( format0 . sample_rate , config . sample_rate . 0 ) ;
let mut build_output_stream = | config : StreamConfig | match sample_format {
cpal ::SampleFormat ::I8 = > self . build_output_stream ::< i8 > ( & config , & device ) ,
cpal ::SampleFormat ::I16 = > self . build_output_stream ::< i16 > ( & config , & device ) ,
cpal ::SampleFormat ::I32 = > self . build_output_stream ::< i32 > ( & config , & device ) ,
cpal ::SampleFormat ::I64 = > self . build_output_stream ::< i64 > ( & config , & device ) ,
cpal ::SampleFormat ::U8 = > self . build_output_stream ::< u8 > ( & config , & device ) ,
cpal ::SampleFormat ::U16 = > self . build_output_stream ::< u16 > ( & config , & device ) ,
cpal ::SampleFormat ::U32 = > self . build_output_stream ::< u32 > ( & config , & device ) ,
cpal ::SampleFormat ::U64 = > self . build_output_stream ::< u64 > ( & config , & device ) ,
cpal ::SampleFormat ::F32 = > self . build_output_stream ::< f32 > ( & config , & device ) ,
cpal ::SampleFormat ::F64 = > self . build_output_stream ::< f64 > ( & config , & device ) ,
2023-04-15 09:41:56 +08:00
f = > bail! ( " unsupported audio format: {:?} " , f ) ,
2023-04-21 07:44:39 +08:00
} ;
if config . channels > format0 . channels as _ {
let no_rechannel_config = StreamConfig {
channels : format0 . channels as _ ,
.. config . clone ( )
} ;
if let Err ( _ ) = build_output_stream ( no_rechannel_config ) {
build_output_stream ( config ) ? ;
}
} else {
build_output_stream ( config ) ? ;
2021-03-29 15:59:14 +08:00
}
2023-04-21 07:44:39 +08:00
2021-03-29 15:59:14 +08:00
Ok ( ( ) )
}
2022-05-28 03:56:42 +08:00
/// Handle audio format and create an audio decoder.
2021-03-29 15:59:14 +08:00
pub fn handle_format ( & mut self , f : AudioFormat ) {
match AudioDecoder ::new ( f . sample_rate , if f . channels > 1 { Stereo } else { Mono } ) {
Ok ( d ) = > {
let buffer = vec! [ 0. ; f . sample_rate as usize * f . channels as usize ] ;
self . audio_decoder = Some ( ( d , buffer ) ) ;
self . channels = f . channels as _ ;
allow_err! ( self . start_audio ( f ) ) ;
}
Err ( err ) = > {
log ::error! ( " Failed to create audio decoder: {} " , err ) ;
}
}
}
2022-05-28 03:56:42 +08:00
/// Handle audio frame and play it.
2023-03-23 14:31:50 +08:00
#[ inline ]
2022-01-30 21:16:08 +08:00
pub fn handle_frame ( & mut self , frame : AudioFrame ) {
2022-04-23 02:17:33 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2023-03-29 07:32:35 +08:00
if self . audio_stream . is_none ( ) | | ! self . ready . lock ( ) . unwrap ( ) . clone ( ) {
2021-03-29 15:59:14 +08:00
return ;
}
2022-04-23 02:17:33 +08:00
#[ cfg(target_os = " linux " ) ]
if self . simple . is_none ( ) {
2023-01-29 14:10:06 +08:00
log ::debug! ( " PulseAudio simple binding does not exists " ) ;
2022-04-23 02:17:33 +08:00
return ;
2021-03-29 15:59:14 +08:00
}
2022-04-23 02:17:33 +08:00
#[ cfg(target_os = " android " ) ]
if self . oboe . is_none ( ) {
return ;
2021-03-29 15:59:14 +08:00
}
self . audio_decoder . as_mut ( ) . map ( | ( d , buffer ) | {
if let Ok ( n ) = d . decode_float ( & frame . data , buffer , false ) {
2022-04-23 02:17:33 +08:00
let channels = self . channels ;
2021-03-29 15:59:14 +08:00
let n = n * ( channels as usize ) ;
2022-04-23 02:17:33 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2021-03-29 15:59:14 +08:00
{
2022-04-23 02:17:33 +08:00
let sample_rate0 = self . sample_rate . 0 ;
let sample_rate = self . sample_rate . 1 ;
2023-03-29 16:59:50 +08:00
let audio_buffer = self . audio_buffer . 0. clone ( ) ;
2023-04-20 17:26:17 +08:00
let mut buffer = buffer [ 0 .. n ] . to_owned ( ) ;
2021-03-29 15:59:14 +08:00
if sample_rate ! = sample_rate0 {
2023-04-20 17:26:17 +08:00
buffer = crate ::audio_resample (
2021-03-29 15:59:14 +08:00
& buffer [ 0 .. n ] ,
sample_rate0 ,
sample_rate ,
channels ,
) ;
}
2023-04-20 17:26:17 +08:00
if self . channels ! = self . device_channel {
buffer = crate ::audio_rechannel (
buffer ,
sample_rate ,
sample_rate ,
self . channels ,
self . device_channel ,
) ;
}
audio_buffer . lock ( ) . unwrap ( ) . push_slice_overwrite ( & buffer ) ;
2021-03-29 15:59:14 +08:00
}
2022-04-23 02:17:33 +08:00
#[ cfg(target_os = " android " ) ]
{
self . oboe . as_mut ( ) . map ( | x | x . push ( & buffer [ 0 .. n ] ) ) ;
}
#[ cfg(target_os = " linux " ) ]
2021-03-29 15:59:14 +08:00
{
2022-04-23 02:17:33 +08:00
let data_u8 =
unsafe { std ::slice ::from_raw_parts ::< u8 > ( buffer . as_ptr ( ) as _ , n * 4 ) } ;
self . simple . as_mut ( ) . map ( | x | x . write ( data_u8 ) ) ;
2021-03-29 15:59:14 +08:00
}
}
} ) ;
}
2022-05-28 03:56:42 +08:00
/// Build audio output stream for current device.
2022-04-23 02:17:33 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " linux " ))) ]
2023-04-15 09:41:56 +08:00
fn build_output_stream < T : cpal ::Sample + cpal ::SizedSample + cpal ::FromSample < f32 > > (
2021-03-29 15:59:14 +08:00
& mut self ,
config : & StreamConfig ,
device : & Device ,
) -> ResultType < ( ) > {
2023-04-21 07:44:39 +08:00
self . device_channel = config . channels ;
2021-03-29 15:59:14 +08:00
let err_fn = move | err | {
2021-12-25 16:45:22 +08:00
// too many errors, will improve later
log ::trace! ( " an error occurred on stream: {} " , err ) ;
2021-03-29 15:59:14 +08:00
} ;
2023-03-29 16:59:50 +08:00
let audio_buffer = self . audio_buffer . 0. clone ( ) ;
2023-03-29 07:32:35 +08:00
let ready = self . ready . clone ( ) ;
2023-04-15 09:41:56 +08:00
let timeout = None ;
2021-03-29 15:59:14 +08:00
let stream = device . build_output_stream (
config ,
move | data : & mut [ T ] , _ : & _ | {
2023-03-29 07:32:35 +08:00
if ! * ready . lock ( ) . unwrap ( ) {
* ready . lock ( ) . unwrap ( ) = true ;
}
2021-03-29 15:59:14 +08:00
let mut lock = audio_buffer . lock ( ) . unwrap ( ) ;
2022-02-28 18:35:40 +08:00
let mut n = data . len ( ) ;
2023-03-29 16:59:50 +08:00
if lock . occupied_len ( ) < n {
n = lock . occupied_len ( ) ;
2021-03-29 15:59:14 +08:00
}
2023-03-29 16:59:50 +08:00
let mut elems = vec! [ 0.0 f32 ; n ] ;
lock . pop_slice ( & mut elems ) ;
drop ( lock ) ;
let mut input = elems . into_iter ( ) ;
2021-03-29 15:59:14 +08:00
for sample in data . iter_mut ( ) {
* sample = match input . next ( ) {
2023-04-15 09:41:56 +08:00
Some ( x ) = > T ::from_sample ( x ) ,
_ = > T ::from_sample ( 0. ) ,
2021-03-29 15:59:14 +08:00
} ;
}
} ,
err_fn ,
2023-04-15 09:41:56 +08:00
timeout ,
2021-03-29 15:59:14 +08:00
) ? ;
stream . play ( ) ? ;
self . audio_stream = Some ( Box ::new ( stream ) ) ;
Ok ( ( ) )
}
}
2022-05-28 03:56:42 +08:00
/// Video handler for the [`Client`].
2021-03-29 15:59:14 +08:00
pub struct VideoHandler {
decoder : Decoder ,
2023-04-28 11:44:52 +08:00
pub rgb : ImageRgb ,
2024-01-02 16:58:10 +08:00
pub texture : * mut c_void ,
2022-09-15 17:31:28 +08:00
recorder : Arc < Mutex < Option < Recorder > > > ,
record : bool ,
2023-10-18 22:39:28 +08:00
_display : usize , // useful for debug
2024-01-22 20:01:17 +08:00
fail_counter : usize ,
2021-03-29 15:59:14 +08:00
}
impl VideoHandler {
2022-05-28 03:56:42 +08:00
/// Create a new video handler.
2024-01-22 20:01:17 +08:00
pub fn new ( format : CodecFormat , _display : usize ) -> Self {
2024-01-02 16:58:10 +08:00
#[ cfg(all(feature = " gpucodec " , feature = " flutter " )) ]
let luid = crate ::flutter ::get_adapter_luid ( ) ;
#[ cfg(not(all(feature = " gpucodec " , feature = " flutter " ))) ]
let luid = Default ::default ( ) ;
2024-01-22 20:01:17 +08:00
log ::info! ( " new video handler for display #{_display}, format: {format:?}, luid: {luid:?} " ) ;
2021-03-29 15:59:14 +08:00
VideoHandler {
2024-01-22 20:01:17 +08:00
decoder : Decoder ::new ( format , luid ) ,
2023-04-28 11:44:52 +08:00
rgb : ImageRgb ::new ( ImageFormat ::ARGB , crate ::DST_STRIDE_RGBA ) ,
2024-01-02 16:58:10 +08:00
texture : std ::ptr ::null_mut ( ) ,
2022-09-15 17:31:28 +08:00
recorder : Default ::default ( ) ,
record : false ,
2023-10-18 22:39:28 +08:00
_display ,
2024-01-22 20:01:17 +08:00
fail_counter : 0 ,
2021-03-29 15:59:14 +08:00
}
}
2022-05-28 03:56:42 +08:00
/// Handle a new video frame.
2023-03-23 14:31:50 +08:00
#[ inline ]
2023-10-27 15:44:07 +08:00
pub fn handle_frame (
& mut self ,
vf : VideoFrame ,
2024-01-02 16:58:10 +08:00
pixelbuffer : & mut bool ,
2023-10-27 15:44:07 +08:00
chroma : & mut Option < Chroma > ,
) -> ResultType < bool > {
2024-01-22 20:01:17 +08:00
let format = CodecFormat ::from ( & vf ) ;
if format ! = self . decoder . format ( ) {
self . reset ( Some ( format ) ) ;
}
2022-05-19 21:45:25 +08:00
match & vf . union {
2022-09-15 17:31:28 +08:00
Some ( frame ) = > {
2024-01-02 16:58:10 +08:00
let res = self . decoder . handle_video_frame (
frame ,
& mut self . rgb ,
& mut self . texture ,
pixelbuffer ,
chroma ,
) ;
2024-01-22 20:01:17 +08:00
if res . as_ref ( ) . is_ok_and ( | x | * x ) {
self . fail_counter = 0 ;
} else {
if self . fail_counter < usize ::MAX {
self . fail_counter + = 1
}
}
2022-09-15 17:31:28 +08:00
if self . record {
self . recorder
. lock ( )
. unwrap ( )
. as_mut ( )
. map ( | r | r . write_frame ( frame ) ) ;
}
res
}
2022-05-19 21:45:25 +08:00
_ = > Ok ( false ) ,
}
}
2024-01-22 20:01:17 +08:00
/// Reset the decoder, change format if it is Some
pub fn reset ( & mut self , format : Option < CodecFormat > ) {
2024-01-02 16:58:10 +08:00
#[ cfg(all(feature = " flutter " , feature = " gpucodec " )) ]
let luid = crate ::flutter ::get_adapter_luid ( ) ;
#[ cfg(not(all(feature = " flutter " , feature = " gpucodec " ))) ]
let luid = None ;
2024-01-22 20:01:17 +08:00
let format = format . unwrap_or ( self . decoder . format ( ) ) ;
self . decoder = Decoder ::new ( format , luid ) ;
self . fail_counter = 0 ;
2021-03-29 15:59:14 +08:00
}
2022-09-15 17:31:28 +08:00
/// Start or stop screen record.
pub fn record_screen ( & mut self , start : bool , w : i32 , h : i32 , id : String ) {
self . record = false ;
if start {
self . recorder = Recorder ::new ( RecorderContext {
2022-12-07 16:30:44 +08:00
server : false ,
2022-09-15 17:31:28 +08:00
id ,
2022-10-12 16:06:15 +08:00
default_dir : crate ::ui_interface ::default_video_save_directory ( ) ,
2022-09-15 17:31:28 +08:00
filename : " " . to_owned ( ) ,
width : w as _ ,
height : h as _ ,
2023-03-31 16:10:52 +08:00
format : scrap ::CodecFormat ::VP9 ,
2022-12-07 16:30:44 +08:00
tx : None ,
2022-09-15 17:31:28 +08:00
} )
. map_or ( Default ::default ( ) , | r | Arc ::new ( Mutex ::new ( Some ( r ) ) ) ) ;
} else {
self . recorder = Default ::default ( ) ;
}
2023-03-23 14:31:50 +08:00
2022-09-15 17:31:28 +08:00
self . record = start ;
}
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Login config handler for [`Client`].
2021-03-29 15:59:14 +08:00
#[ derive(Default) ]
pub struct LoginConfigHandler {
id : String ,
2022-09-01 17:36:37 +08:00
pub conn_type : ConnType ,
2021-03-29 15:59:14 +08:00
hash : Hash ,
password : Vec < u8 > , // remember password for reconnect
pub remember : bool ,
config : PeerConfig ,
pub port_forward : ( String , i32 ) ,
2022-01-10 01:29:50 +08:00
pub version : i64 ,
2022-04-25 12:28:28 +08:00
features : Option < Features > ,
2023-07-01 16:21:36 +08:00
pub session_id : u64 , // used for local <-> server communication
2023-03-31 16:10:52 +08:00
pub supported_encoding : SupportedEncoding ,
2022-07-25 19:35:15 +08:00
pub restarting_remote_device : bool ,
2022-07-31 19:06:49 +08:00
pub force_relay : bool ,
2022-12-27 11:42:48 +08:00
pub direct : Option < bool > ,
pub received : bool ,
2023-01-17 13:28:33 +08:00
switch_uuid : Option < String > ,
2023-08-21 08:39:47 +08:00
pub save_ab_password_to_recent : bool , // true: connected with ab password
2023-11-06 20:12:01 +08:00
pub other_server : Option < ( String , String , String ) > ,
2023-11-13 19:29:16 +08:00
pub custom_fps : Arc < Mutex < Option < usize > > > ,
2024-01-02 16:58:10 +08:00
pub adapter_luid : Option < i64 > ,
2024-01-22 20:01:17 +08:00
pub mark_unsupported : Vec < CodecFormat > ,
2024-02-14 23:59:17 +08:00
pub selected_user_session_id : String ,
2021-03-29 15:59:14 +08:00
}
impl Deref for LoginConfigHandler {
type Target = PeerConfig ;
fn deref ( & self ) -> & Self ::Target {
& self . config
}
}
impl LoginConfigHandler {
2022-05-28 03:56:42 +08:00
/// Initialize the login config handler.
///
/// # Arguments
///
/// * `id` - id of peer
2022-09-01 17:36:37 +08:00
/// * `conn_type` - Connection type enum.
2023-02-13 16:40:24 +08:00
pub fn initialize (
& mut self ,
id : String ,
conn_type : ConnType ,
switch_uuid : Option < String > ,
2023-11-06 20:12:01 +08:00
mut force_relay : bool ,
2024-01-02 16:58:10 +08:00
adapter_luid : Option < i64 > ,
2023-02-13 16:40:24 +08:00
) {
2023-11-06 20:12:01 +08:00
let mut id = id ;
if id . contains ( " @ " ) {
let mut v = id . split ( " @ " ) ;
let raw_id : & str = v . next ( ) . unwrap_or_default ( ) ;
let mut server_key = v . next ( ) . unwrap_or_default ( ) . split ( '?' ) ;
let server = server_key . next ( ) . unwrap_or_default ( ) ;
let args = server_key . next ( ) . unwrap_or_default ( ) ;
let key = if server = = PUBLIC_SERVER {
PUBLIC_RS_PUB_KEY
} else {
let mut args_map : HashMap < & str , & str > = HashMap ::new ( ) ;
for arg in args . split ( '&' ) {
if let Some ( kv ) = arg . find ( '=' ) {
let k = & arg [ 0 .. kv ] ;
let v = & arg [ kv + 1 .. ] ;
args_map . insert ( k , v ) ;
}
}
let key = args_map . remove ( " key " ) . unwrap_or_default ( ) ;
key
} ;
// here we can check <id>/r@server
let real_id = crate ::ui_interface ::handle_relay_id ( raw_id ) . to_string ( ) ;
if real_id ! = raw_id {
force_relay = true ;
}
self . other_server = Some ( ( real_id . clone ( ) , server . to_owned ( ) , key . to_owned ( ) ) ) ;
id = format! ( " {real_id} @ {server} " ) ;
2023-11-09 21:58:03 +08:00
} else {
let real_id = crate ::ui_interface ::handle_relay_id ( & id ) ;
if real_id ! = id {
force_relay = true ;
id = real_id . to_owned ( ) ;
}
2023-11-06 20:12:01 +08:00
}
2021-03-29 15:59:14 +08:00
self . id = id ;
2022-09-01 17:36:37 +08:00
self . conn_type = conn_type ;
2021-03-29 15:59:14 +08:00
let config = self . load_config ( ) ;
self . remember = ! config . password . is_empty ( ) ;
self . config = config ;
2023-07-01 16:21:36 +08:00
let mut sid = rand ::random ( ) ;
2023-07-18 21:04:12 +08:00
if sid = = 0 {
// you won the lottery
2023-07-01 16:21:36 +08:00
sid = 1 ;
}
self . session_id = sid ;
2023-03-31 16:10:52 +08:00
self . supported_encoding = Default ::default ( ) ;
2022-07-25 19:35:15 +08:00
self . restarting_remote_device = false ;
2023-02-13 16:40:24 +08:00
self . force_relay = ! self . get_option ( " force-always-relay " ) . is_empty ( ) | | force_relay ;
2023-11-06 20:12:01 +08:00
if let Some ( ( real_id , server , key ) ) = & self . other_server {
let other_server_key = self . get_option ( " other-server-key " ) ;
if ! other_server_key . is_empty ( ) & & key . is_empty ( ) {
self . other_server = Some ( ( real_id . to_owned ( ) , server . to_owned ( ) , other_server_key ) ) ;
}
}
2022-12-27 11:42:48 +08:00
self . direct = None ;
self . received = false ;
2023-01-17 13:28:33 +08:00
self . switch_uuid = switch_uuid ;
2024-01-02 16:58:10 +08:00
self . adapter_luid = adapter_luid ;
2024-02-14 23:59:17 +08:00
self . selected_user_session_id = " " . to_owned ( ) ;
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Check if the client should auto login.
/// Return password if the client should auto login, otherwise return empty string.
2022-05-12 17:35:25 +08:00
pub fn should_auto_login ( & self ) -> String {
2023-02-02 09:39:14 +08:00
let l = self . lock_after_session_end . v ;
2022-05-12 17:35:25 +08:00
let a = ! self . get_option ( " auto-login " ) . is_empty ( ) ;
let p = self . get_option ( " os-password " ) ;
if ! p . is_empty ( ) & & l & & a {
p
} else {
" " . to_owned ( )
}
}
2022-05-28 03:56:42 +08:00
/// Load [`PeerConfig`].
2023-11-06 20:12:01 +08:00
pub fn load_config ( & self ) -> PeerConfig {
debug_assert! ( self . id . len ( ) > 0 ) ;
PeerConfig ::load ( & self . id )
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Save a [`PeerConfig`] into the handler.
///
/// # Arguments
///
/// * `config` - [`PeerConfig`] to save.
2021-03-29 15:59:14 +08:00
pub fn save_config ( & mut self , config : PeerConfig ) {
config . store ( & self . id ) ;
self . config = config ;
}
2022-05-28 03:56:42 +08:00
/// Set an option for handler's [`PeerConfig`].
///
/// # Arguments
///
/// * `k` - key of option
/// * `v` - value of option
2021-12-25 16:45:22 +08:00
pub fn set_option ( & mut self , k : String , v : String ) {
let mut config = self . load_config ( ) ;
config . options . insert ( k , v ) ;
self . save_config ( config ) ;
}
2022-11-17 18:52:27 +08:00
//to-do: too many dup code below.
2022-05-28 03:56:42 +08:00
/// Save view style to the current config.
///
/// # Arguments
///
/// * `value` - The view style to be saved.
2021-03-29 15:59:14 +08:00
pub fn save_view_style ( & mut self , value : String ) {
let mut config = self . load_config ( ) ;
config . view_style = value ;
self . save_config ( config ) ;
}
2022-11-16 15:09:29 +08:00
/// Save keyboard mode to the current config.
///
/// # Arguments
///
/// * `value` - The view style to be saved.
pub fn save_keyboard_mode ( & mut self , value : String ) {
let mut config = self . load_config ( ) ;
config . keyboard_mode = value ;
self . save_config ( config ) ;
}
2023-09-10 18:31:16 +08:00
/// Save reverse mouse wheel ("", "Y") to the current config.
2023-09-10 14:14:57 +08:00
///
/// # Arguments
///
2023-09-10 18:31:16 +08:00
/// * `value` - The reverse mouse wheel ("", "Y").
pub fn save_reverse_mouse_wheel ( & mut self , value : String ) {
2023-09-10 14:14:57 +08:00
let mut config = self . load_config ( ) ;
2023-09-10 18:31:16 +08:00
config . reverse_mouse_wheel = value ;
2023-09-10 14:14:57 +08:00
self . save_config ( config ) ;
}
2023-10-17 00:30:34 +08:00
/// Save "displays_as_individual_windows" ("", "Y") to the current config.
2023-10-09 17:22:22 +08:00
///
/// # Arguments
///
/// * `value` - The "displays_as_individual_windows" value ("", "Y").
pub fn save_displays_as_individual_windows ( & mut self , value : String ) {
let mut config = self . load_config ( ) ;
config . displays_as_individual_windows = value ;
self . save_config ( config ) ;
}
2023-10-17 13:57:06 +08:00
/// Save "use_all_my_displays_for_the_remote_session" ("", "Y") to the current config.
2023-10-17 00:30:34 +08:00
///
/// # Arguments
///
2023-10-17 13:57:06 +08:00
/// * `value` - The "use_all_my_displays_for_the_remote_session" value ("", "Y").
pub fn save_use_all_my_displays_for_the_remote_session ( & mut self , value : String ) {
2023-10-17 00:30:34 +08:00
let mut config = self . load_config ( ) ;
2023-10-17 13:57:06 +08:00
config . use_all_my_displays_for_the_remote_session = value ;
2023-10-17 00:30:34 +08:00
self . save_config ( config ) ;
}
2022-11-17 18:52:27 +08:00
/// Save scroll style to the current config.
///
/// # Arguments
///
/// * `value` - The view style to be saved.
pub fn save_scroll_style ( & mut self , value : String ) {
let mut config = self . load_config ( ) ;
config . scroll_style = value ;
self . save_config ( config ) ;
}
2022-11-10 21:25:12 +08:00
/// Set a ui config of flutter for handler's [`PeerConfig`].
///
/// # Arguments
///
/// * `k` - key of option
/// * `v` - value of option
2022-11-17 18:52:27 +08:00
pub fn save_ui_flutter ( & mut self , k : String , v : String ) {
2022-11-10 21:25:12 +08:00
let mut config = self . load_config ( ) ;
2023-08-10 19:48:26 +08:00
if v . is_empty ( ) {
config . ui_flutter . remove ( & k ) ;
} else {
config . ui_flutter . insert ( k , v ) ;
}
2022-11-10 21:25:12 +08:00
self . save_config ( config ) ;
}
2023-11-06 20:12:01 +08:00
pub fn set_direct_failure ( & mut self , value : i32 ) {
let mut config = self . load_config ( ) ;
config . direct_failures = value ;
self . save_config ( config ) ;
}
2022-11-10 21:25:12 +08:00
/// Get a ui config of flutter for handler's [`PeerConfig`].
/// Return String if the option is found, otherwise return "".
///
/// # Arguments
///
/// * `k` - key of option
pub fn get_ui_flutter ( & self , k : & str ) -> String {
if let Some ( v ) = self . config . ui_flutter . get ( k ) {
v . clone ( )
} else {
" " . to_owned ( )
}
}
2022-05-28 03:56:42 +08:00
/// Toggle an option in the handler.
///
/// # Arguments
///
/// * `name` - The name of the option to toggle.
2021-03-29 15:59:14 +08:00
pub fn toggle_option ( & mut self , name : String ) -> Option < Message > {
let mut option = OptionMessage ::default ( ) ;
let mut config = self . load_config ( ) ;
if name = = " show-remote-cursor " {
2023-02-02 09:39:14 +08:00
config . show_remote_cursor . v = ! config . show_remote_cursor . v ;
option . show_remote_cursor = ( if config . show_remote_cursor . v {
2021-03-29 15:59:14 +08:00
BoolOption ::Yes
} else {
BoolOption ::No
} )
. into ( ) ;
} else if name = = " disable-audio " {
2023-02-02 09:39:14 +08:00
config . disable_audio . v = ! config . disable_audio . v ;
option . disable_audio = ( if config . disable_audio . v {
2021-03-29 15:59:14 +08:00
BoolOption ::Yes
} else {
BoolOption ::No
} )
. into ( ) ;
} else if name = = " disable-clipboard " {
2023-02-02 09:39:14 +08:00
config . disable_clipboard . v = ! config . disable_clipboard . v ;
option . disable_clipboard = ( if config . disable_clipboard . v {
2021-03-29 15:59:14 +08:00
BoolOption ::Yes
} else {
BoolOption ::No
} )
. into ( ) ;
} else if name = = " lock-after-session-end " {
2023-02-02 09:39:14 +08:00
config . lock_after_session_end . v = ! config . lock_after_session_end . v ;
option . lock_after_session_end = ( if config . lock_after_session_end . v {
2021-03-29 15:59:14 +08:00
BoolOption ::Yes
} else {
BoolOption ::No
} )
. into ( ) ;
} else if name = = " privacy-mode " {
2022-04-25 12:28:28 +08:00
// try toggle privacy mode
2023-02-02 09:39:14 +08:00
option . privacy_mode = ( if config . privacy_mode . v {
2021-03-29 15:59:14 +08:00
BoolOption ::No
2022-04-25 12:28:28 +08:00
} else {
BoolOption ::Yes
2021-03-29 15:59:14 +08:00
} )
. into ( ) ;
2022-02-15 14:46:08 +08:00
} else if name = = " enable-file-transfer " {
2023-02-02 09:39:14 +08:00
config . enable_file_transfer . v = ! config . enable_file_transfer . v ;
option . enable_file_transfer = ( if config . enable_file_transfer . v {
2022-02-15 14:46:08 +08:00
BoolOption ::Yes
} else {
BoolOption ::No
} )
. into ( ) ;
2021-03-29 15:59:14 +08:00
} else if name = = " block-input " {
option . block_input = BoolOption ::Yes . into ( ) ;
} else if name = = " unblock-input " {
option . block_input = BoolOption ::No . into ( ) ;
2022-06-23 17:42:30 +08:00
} else if name = = " show-quality-monitor " {
2023-02-02 09:39:14 +08:00
config . show_quality_monitor . v = ! config . show_quality_monitor . v ;
2023-02-09 10:54:23 +08:00
} else if name = = " allow_swap_key " {
config . allow_swap_key . v = ! config . allow_swap_key . v ;
2023-03-17 11:27:22 +08:00
} else if name = = " view-only " {
config . view_only . v = ! config . view_only . v ;
let f = | b : bool | {
if b {
BoolOption ::Yes . into ( )
} else {
BoolOption ::No . into ( )
}
} ;
if config . view_only . v {
option . disable_keyboard = f ( true ) ;
option . disable_clipboard = f ( true ) ;
option . show_remote_cursor = f ( true ) ;
2023-12-25 21:49:34 +08:00
option . enable_file_transfer = f ( false ) ;
option . lock_after_session_end = f ( false ) ;
2023-03-17 11:27:22 +08:00
} else {
option . disable_keyboard = f ( false ) ;
option . disable_clipboard = f ( self . get_toggle_option ( " disable-clipboard " ) ) ;
option . show_remote_cursor = f ( self . get_toggle_option ( " show-remote-cursor " ) ) ;
2023-12-25 21:49:34 +08:00
option . enable_file_transfer = f ( self . config . enable_file_transfer . v ) ;
option . lock_after_session_end = f ( self . config . lock_after_session_end . v ) ;
2023-03-17 11:27:22 +08:00
}
2021-03-29 15:59:14 +08:00
} else {
2023-02-03 18:28:47 +08:00
let is_set = self
. options
. get ( & name )
. map ( | o | ! o . is_empty ( ) )
. unwrap_or ( false ) ;
if is_set {
2023-03-17 11:27:22 +08:00
if name = = " zoom-cursor " {
self . config . options . insert ( name , " " . to_owned ( ) ) ;
} else {
// Notice: When PeerConfig loads, the default value is taken when the option key does not exist.
self . config . options . remove ( & name ) ;
}
2021-03-29 15:59:14 +08:00
} else {
self . config . options . insert ( name , " Y " . to_owned ( ) ) ;
}
self . config . store ( & self . id ) ;
return None ;
}
2022-01-15 18:27:15 +08:00
if ! name . contains ( " block-input " ) {
self . save_config ( config ) ;
}
2021-03-29 15:59:14 +08:00
let mut misc = Misc ::new ( ) ;
misc . set_option ( option ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_misc ( misc ) ;
Some ( msg_out )
}
2022-08-08 22:00:01 +08:00
/// Get [`PeerConfig`] of the current [`LoginConfigHandler`].
///
/// # Arguments
pub fn get_config ( & mut self ) -> & mut PeerConfig {
& mut self . config
}
2022-05-28 03:56:42 +08:00
/// Get [`OptionMessage`] of the current [`LoginConfigHandler`].
/// Return `None` if there's no option, for example, when the session is only for file transfer.
///
/// # Arguments
///
/// * `ignore_default` - If `true`, ignore the default value of the option.
2021-03-29 15:59:14 +08:00
fn get_option_message ( & self , ignore_default : bool ) -> Option < OptionMessage > {
2024-02-14 23:59:17 +08:00
if self . conn_type . eq ( & ConnType ::PORT_FORWARD ) | | self . conn_type . eq ( & ConnType ::RDP ) {
2021-03-29 15:59:14 +08:00
return None ;
}
let mut n = 0 ;
let mut msg = OptionMessage ::new ( ) ;
2024-02-14 23:59:17 +08:00
msg . user_session = self . selected_user_session_id . clone ( ) ;
n + = 1 ;
if self . conn_type . eq ( & ConnType ::FILE_TRANSFER ) {
return Some ( msg ) ;
}
2021-03-29 15:59:14 +08:00
let q = self . image_quality . clone ( ) ;
if let Some ( q ) = self . get_image_quality_enum ( & q , ignore_default ) {
msg . image_quality = q . into ( ) ;
n + = 1 ;
} else if q = = " custom " {
2023-11-06 20:12:01 +08:00
let config = self . load_config ( ) ;
2023-11-13 19:29:16 +08:00
let allow_more =
! crate ::ui_interface ::using_public_server ( ) | | self . direct = = Some ( true ) ;
2022-10-19 10:19:49 +08:00
let quality = if config . custom_image_quality . is_empty ( ) {
50
} else {
2023-11-13 19:29:16 +08:00
let mut quality = config . custom_image_quality [ 0 ] ;
if ! allow_more & & quality > 100 {
quality = 50 ;
}
quality
2022-10-19 10:19:49 +08:00
} ;
msg . custom_image_quality = quality < < 8 ;
2023-11-09 15:24:57 +08:00
#[ cfg(feature = " flutter " ) ]
if let Some ( custom_fps ) = self . options . get ( " custom-fps " ) {
2023-11-13 19:29:16 +08:00
let mut custom_fps = custom_fps . parse ( ) . unwrap_or ( 30 ) ;
if ! allow_more & & custom_fps > 30 {
custom_fps = 30 ;
}
msg . custom_fps = custom_fps ;
* self . custom_fps . lock ( ) . unwrap ( ) = Some ( custom_fps as _ ) ;
2023-11-09 15:24:57 +08:00
}
2022-06-23 17:42:30 +08:00
n + = 1 ;
2021-03-29 15:59:14 +08:00
}
2023-03-16 09:37:35 +08:00
let view_only = self . get_toggle_option ( " view-only " ) ;
if view_only {
msg . disable_keyboard = BoolOption ::Yes . into ( ) ;
n + = 1 ;
}
if view_only | | self . get_toggle_option ( " show-remote-cursor " ) {
2021-03-29 15:59:14 +08:00
msg . show_remote_cursor = BoolOption ::Yes . into ( ) ;
n + = 1 ;
}
2023-12-25 21:49:34 +08:00
if ! view_only & & self . get_toggle_option ( " lock-after-session-end " ) {
2021-03-29 15:59:14 +08:00
msg . lock_after_session_end = BoolOption ::Yes . into ( ) ;
n + = 1 ;
}
2022-01-29 21:30:14 +08:00
if self . get_toggle_option ( " disable-audio " ) {
msg . disable_audio = BoolOption ::Yes . into ( ) ;
n + = 1 ;
}
2023-12-25 21:49:34 +08:00
if ! view_only & & self . get_toggle_option ( " enable-file-transfer " ) {
2022-02-15 14:46:08 +08:00
msg . enable_file_transfer = BoolOption ::Yes . into ( ) ;
n + = 1 ;
}
2023-03-16 09:37:35 +08:00
if view_only | | self . get_toggle_option ( " disable-clipboard " ) {
2022-01-29 21:30:14 +08:00
msg . disable_clipboard = BoolOption ::Yes . into ( ) ;
n + = 1 ;
}
2023-03-31 16:10:52 +08:00
msg . supported_decoding =
2024-01-02 16:58:10 +08:00
hbb_common ::protobuf ::MessageField ::some ( Decoder ::supported_decodings (
Some ( & self . id ) ,
cfg! ( feature = " flutter " ) ,
self . adapter_luid ,
2024-01-22 20:01:17 +08:00
& self . mark_unsupported ,
2024-01-02 16:58:10 +08:00
) ) ;
2022-05-29 17:23:14 +08:00
n + = 1 ;
2021-03-29 15:59:14 +08:00
if n > 0 {
Some ( msg )
} else {
None
}
}
2022-08-04 17:24:02 +08:00
pub fn get_option_message_after_login ( & self ) -> Option < OptionMessage > {
2023-06-05 18:01:43 +08:00
if self . conn_type . eq ( & ConnType ::FILE_TRANSFER )
| | self . conn_type . eq ( & ConnType ::PORT_FORWARD )
| | self . conn_type . eq ( & ConnType ::RDP )
2022-09-01 17:36:37 +08:00
{
2022-08-04 17:24:02 +08:00
return None ;
}
let mut n = 0 ;
let mut msg = OptionMessage ::new ( ) ;
2023-11-14 12:11:38 +08:00
if self . version < hbb_common ::get_version_number ( " 1.2.4 " ) {
if self . get_toggle_option ( " privacy-mode " ) {
msg . privacy_mode = BoolOption ::Yes . into ( ) ;
n + = 1 ;
}
2022-08-04 17:24:02 +08:00
}
if n > 0 {
Some ( msg )
} else {
None
}
}
2022-05-28 03:56:42 +08:00
/// Parse the image quality option.
/// Return [`ImageQuality`] if the option is valid, otherwise return `None`.
///
/// # Arguments
///
/// * `q` - The image quality option.
/// * `ignore_default` - Ignore the default value.
2021-03-29 15:59:14 +08:00
fn get_image_quality_enum ( & self , q : & str , ignore_default : bool ) -> Option < ImageQuality > {
if q = = " low " {
Some ( ImageQuality ::Low )
} else if q = = " best " {
Some ( ImageQuality ::Best )
} else if q = = " balanced " {
if ignore_default {
None
} else {
Some ( ImageQuality ::Balanced )
}
} else {
None
}
}
2022-05-28 03:56:42 +08:00
/// Get the status of a toggle option.
///
/// # Arguments
///
/// * `name` - The name of the toggle option.
2021-03-29 15:59:14 +08:00
pub fn get_toggle_option ( & self , name : & str ) -> bool {
if name = = " show-remote-cursor " {
2023-02-02 09:39:14 +08:00
self . config . show_remote_cursor . v
2021-03-29 15:59:14 +08:00
} else if name = = " lock-after-session-end " {
2023-02-02 09:39:14 +08:00
self . config . lock_after_session_end . v
2021-03-29 15:59:14 +08:00
} else if name = = " privacy-mode " {
2023-02-02 09:39:14 +08:00
self . config . privacy_mode . v
2022-02-15 15:35:19 +08:00
} else if name = = " enable-file-transfer " {
2023-02-02 09:39:14 +08:00
self . config . enable_file_transfer . v
2021-03-29 15:59:14 +08:00
} else if name = = " disable-audio " {
2023-02-02 09:39:14 +08:00
self . config . disable_audio . v
2021-03-29 15:59:14 +08:00
} else if name = = " disable-clipboard " {
2023-02-02 09:39:14 +08:00
self . config . disable_clipboard . v
2022-06-23 17:42:30 +08:00
} else if name = = " show-quality-monitor " {
2023-02-02 09:39:14 +08:00
self . config . show_quality_monitor . v
2023-02-09 10:54:23 +08:00
} else if name = = " allow_swap_key " {
self . config . allow_swap_key . v
2023-03-17 11:27:22 +08:00
} else if name = = " view-only " {
self . config . view_only . v
2021-03-29 15:59:14 +08:00
} else {
! self . get_option ( name ) . is_empty ( )
}
}
2022-04-25 12:28:28 +08:00
pub fn is_privacy_mode_supported ( & self ) -> bool {
if let Some ( features ) = & self . features {
features . privacy_mode
} else {
false
}
}
2022-05-28 03:56:42 +08:00
/// Create a [`Message`] for refreshing video.
2021-03-29 15:59:14 +08:00
pub fn refresh ( ) -> Message {
let mut misc = Misc ::new ( ) ;
misc . set_refresh_video ( true ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_misc ( misc ) ;
msg_out
}
2023-10-08 21:44:54 +08:00
/// Create a [`Message`] for refreshing video.
pub fn refresh_display ( display : usize ) -> Message {
let mut misc = Misc ::new ( ) ;
misc . set_refresh_video_display ( display as _ ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_misc ( misc ) ;
msg_out
}
2022-05-28 03:56:42 +08:00
/// Create a [`Message`] for saving custom image quality.
///
/// # Arguments
///
/// * `bitrate` - The given bitrate.
/// * `quantizer` - The given quantizer.
2022-06-27 22:24:56 +08:00
pub fn save_custom_image_quality ( & mut self , image_quality : i32 ) -> Message {
2021-03-29 15:59:14 +08:00
let mut misc = Misc ::new ( ) ;
misc . set_option ( OptionMessage {
2022-06-27 22:24:56 +08:00
custom_image_quality : image_quality < < 8 ,
2021-03-29 15:59:14 +08:00
.. Default ::default ( )
} ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_misc ( misc ) ;
let mut config = self . load_config ( ) ;
config . image_quality = " custom " . to_owned ( ) ;
2022-06-27 22:24:56 +08:00
config . custom_image_quality = vec! [ image_quality as _ ] ;
2021-03-29 15:59:14 +08:00
self . save_config ( config ) ;
msg_out
}
2022-05-28 03:56:42 +08:00
/// Save the given image quality to the config.
/// Return a [`Message`] that contains image quality, or `None` if the image quality is not valid.
/// # Arguments
///
/// * `value` - The image quality.
2021-03-29 15:59:14 +08:00
pub fn save_image_quality ( & mut self , value : String ) -> Option < Message > {
let mut res = None ;
if let Some ( q ) = self . get_image_quality_enum ( & value , false ) {
let mut misc = Misc ::new ( ) ;
misc . set_option ( OptionMessage {
image_quality : q . into ( ) ,
.. Default ::default ( )
} ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_misc ( misc ) ;
res = Some ( msg_out ) ;
}
let mut config = self . load_config ( ) ;
config . image_quality = value ;
self . save_config ( config ) ;
res
}
2023-11-09 15:24:57 +08:00
/// Create a [`Message`] for saving custom fps.
///
/// # Arguments
///
/// * `fps` - The given fps.
2023-11-13 19:29:16 +08:00
/// * `save_config` - Save the config.
pub fn set_custom_fps ( & mut self , fps : i32 , save_config : bool ) -> Message {
2023-11-09 15:24:57 +08:00
let mut misc = Misc ::new ( ) ;
misc . set_option ( OptionMessage {
custom_fps : fps ,
.. Default ::default ( )
} ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_misc ( misc ) ;
2023-11-13 19:29:16 +08:00
if save_config {
let mut config = self . load_config ( ) ;
config
. options
. insert ( " custom-fps " . to_owned ( ) , fps . to_string ( ) ) ;
self . save_config ( config ) ;
}
* self . custom_fps . lock ( ) . unwrap ( ) = Some ( fps as _ ) ;
2023-11-09 15:24:57 +08:00
msg_out
}
2021-03-29 15:59:14 +08:00
pub fn get_option ( & self , k : & str ) -> String {
if let Some ( v ) = self . config . options . get ( k ) {
v . clone ( )
} else {
" " . to_owned ( )
}
}
2023-05-17 23:19:20 +08:00
#[ inline ]
2023-06-05 18:01:43 +08:00
pub fn get_custom_resolution ( & self , display : i32 ) -> Option < ( i32 , i32 ) > {
self . config
. custom_resolutions
2023-06-05 19:50:24 +08:00
. get ( & display . to_string ( ) )
2023-06-05 18:01:43 +08:00
. map ( | r | ( r . w , r . h ) )
2023-05-17 23:19:20 +08:00
}
#[ inline ]
2023-06-05 18:01:43 +08:00
pub fn set_custom_resolution ( & mut self , display : i32 , wh : Option < ( i32 , i32 ) > ) {
2023-06-05 19:50:24 +08:00
let display = display . to_string ( ) ;
2023-05-17 23:19:20 +08:00
let mut config = self . load_config ( ) ;
2023-06-05 18:01:43 +08:00
match wh {
Some ( ( w , h ) ) = > {
config
. custom_resolutions
. insert ( display , Resolution { w , h } ) ;
}
None = > {
config . custom_resolutions . remove ( & display ) ;
}
}
2023-05-17 23:19:20 +08:00
self . save_config ( config ) ;
}
2022-05-28 03:56:42 +08:00
/// Get user name.
/// Return the name of the given peer. If the peer has no name, return the name in the config.
///
/// # Arguments
///
/// * `pi` - peer info.
2021-03-29 15:59:14 +08:00
pub fn get_username ( & self , pi : & PeerInfo ) -> String {
return if pi . username . is_empty ( ) {
self . info . username . clone ( )
} else {
pi . username . clone ( )
} ;
}
2022-05-28 03:56:42 +08:00
/// Handle peer info.
///
/// # Arguments
///
/// * `username` - The name of the peer.
/// * `pi` - The peer info.
2022-09-01 21:18:29 +08:00
pub fn handle_peer_info ( & mut self , pi : & PeerInfo ) {
2021-03-29 15:59:14 +08:00
if ! pi . version . is_empty ( ) {
2022-01-15 02:16:00 +08:00
self . version = hbb_common ::get_version_number ( & pi . version ) ;
2021-03-29 15:59:14 +08:00
}
2022-09-01 21:18:29 +08:00
self . features = pi . features . clone ( ) . into_option ( ) ;
2021-03-29 15:59:14 +08:00
let serde = PeerInfoSerde {
2022-09-01 16:21:41 +08:00
username : pi . username . clone ( ) ,
2021-03-29 15:59:14 +08:00
hostname : pi . hostname . clone ( ) ,
platform : pi . platform . clone ( ) ,
} ;
let mut config = self . load_config ( ) ;
config . info = serde ;
let password = self . password . clone ( ) ;
let password0 = config . password . clone ( ) ;
let remember = self . remember ;
if remember {
if ! password . is_empty ( ) & & password ! = password0 {
config . password = password ;
log ::debug! ( " remember password of {} " , self . id ) ;
}
} else {
2023-08-20 15:49:00 +08:00
if self . save_ab_password_to_recent {
config . password = password ;
log ::debug! ( " save ab password of {} to recent " , self . id ) ;
} else if ! password0 . is_empty ( ) {
2021-03-29 15:59:14 +08:00
config . password = Default ::default ( ) ;
log ::debug! ( " remove password of {} " , self . id ) ;
}
}
2023-11-06 20:12:01 +08:00
if let Some ( ( _ , b , c ) ) = self . other_server . as_ref ( ) {
if b ! = PUBLIC_SERVER {
config
. options
. insert ( " other-server-key " . to_owned ( ) , c . clone ( ) ) ;
}
}
if self . force_relay {
config
. options
. insert ( " force-always-relay " . to_owned ( ) , " Y " . to_owned ( ) ) ;
}
2023-08-21 08:39:47 +08:00
#[ cfg(feature = " flutter " ) ]
{
// sync ab password with PeerConfig password
let password = base64 ::encode ( config . password . clone ( ) , base64 ::Variant ::Original ) ;
let evt : HashMap < & str , String > = HashMap ::from ( [
( " name " , " sync_peer_password_to_ab " . to_string ( ) ) ,
( " id " , self . id . clone ( ) ) ,
( " password " , password ) ,
] ) ;
let evt = serde_json ::ser ::to_string ( & evt ) . unwrap_or ( " " . to_owned ( ) ) ;
crate ::flutter ::push_global_event ( crate ::flutter ::APP_TYPE_MAIN , evt ) ;
}
2022-12-20 17:11:52 +08:00
if config . keyboard_mode . is_empty ( ) {
2023-11-09 22:40:15 +08:00
if is_keyboard_mode_supported (
& KeyboardMode ::Map ,
get_version_number ( & pi . version ) ,
& pi . platform ,
) {
2022-12-20 17:11:52 +08:00
config . keyboard_mode = KeyboardMode ::Map . to_string ( ) ;
2022-11-16 15:09:29 +08:00
} else {
2022-12-20 17:11:52 +08:00
config . keyboard_mode = KeyboardMode ::Legacy . to_string ( ) ;
2022-11-16 15:09:29 +08:00
}
2023-01-11 23:38:05 +08:00
} else {
let keyboard_modes =
2023-10-30 15:34:01 +08:00
crate ::get_supported_keyboard_modes ( get_version_number ( & pi . version ) , & pi . platform ) ;
2023-01-11 23:38:05 +08:00
let current_mode = & KeyboardMode ::from_str ( & config . keyboard_mode ) . unwrap_or_default ( ) ;
if ! keyboard_modes . contains ( current_mode ) {
config . keyboard_mode = KeyboardMode ::Legacy . to_string ( ) ;
}
2022-11-16 15:09:29 +08:00
}
2021-03-29 15:59:14 +08:00
// no matter if change, for update file time
self . save_config ( config ) ;
2023-03-31 16:10:52 +08:00
self . supported_encoding = pi . encoding . clone ( ) . unwrap_or_default ( ) ;
2024-01-02 16:58:10 +08:00
log ::info! ( " peer info supported_encoding:{:?} " , self . supported_encoding ) ;
2021-03-29 15:59:14 +08:00
}
2022-05-12 17:35:25 +08:00
pub fn get_remote_dir ( & self ) -> String {
2022-04-07 22:13:30 +08:00
serde_json ::from_str ::< HashMap < String , String > > ( & self . get_option ( " remote_dir " ) )
. unwrap_or_default ( )
. remove ( & self . info . username )
. unwrap_or_default ( )
}
pub fn get_all_remote_dir ( & self , path : String ) -> String {
let d = self . get_option ( " remote_dir " ) ;
let user = self . info . username . clone ( ) ;
let mut x = serde_json ::from_str ::< HashMap < String , String > > ( & d ) . unwrap_or_default ( ) ;
if path . is_empty ( ) {
x . remove ( & user ) ;
} else {
x . insert ( user , path ) ;
}
serde_json ::to_string ::< HashMap < String , String > > ( & x ) . unwrap_or_default ( )
}
2022-05-28 03:56:42 +08:00
/// Create a [`Message`] for login.
2023-03-22 17:01:11 +08:00
fn create_login_msg (
& self ,
os_username : String ,
os_password : String ,
password : Vec < u8 > ,
) -> Message {
2021-03-29 15:59:14 +08:00
#[ cfg(any(target_os = " android " , target_os = " ios " )) ]
2023-06-13 11:10:49 +08:00
let my_id = Config ::get_id_or ( crate ::DEVICE_ID . lock ( ) . unwrap ( ) . clone ( ) ) ;
2021-03-29 15:59:14 +08:00
#[ cfg(not(any(target_os = " android " , target_os = " ios " ))) ]
let my_id = Config ::get_id ( ) ;
2023-11-06 20:12:01 +08:00
let ( my_id , pure_id ) = if let Some ( ( id , _ , _ ) ) = self . other_server . as_ref ( ) {
let server = Config ::get_rendezvous_server ( ) ;
( format! ( " {my_id} @ {server} " ) , id . clone ( ) )
} else {
( my_id , self . id . clone ( ) )
} ;
2021-03-29 15:59:14 +08:00
let mut lr = LoginRequest {
2023-11-06 20:12:01 +08:00
username : pure_id ,
2022-07-25 19:35:15 +08:00
password : password . into ( ) ,
2021-03-29 15:59:14 +08:00
my_id ,
2022-11-20 15:53:08 +08:00
my_name : crate ::username ( ) ,
2021-03-29 15:59:14 +08:00
option : self . get_option_message ( true ) . into ( ) ,
2022-07-18 14:03:52 +08:00
session_id : self . session_id ,
2022-08-04 17:24:02 +08:00
version : crate ::VERSION . to_string ( ) ,
2023-03-22 17:01:11 +08:00
os_login : Some ( OSLogin {
username : os_username ,
password : os_password ,
.. Default ::default ( )
} )
. into ( ) ,
2021-03-29 15:59:14 +08:00
.. Default ::default ( )
} ;
2022-09-01 17:36:37 +08:00
match self . conn_type {
ConnType ::FILE_TRANSFER = > lr . set_file_transfer ( FileTransfer {
2022-04-07 22:13:30 +08:00
dir : self . get_remote_dir ( ) ,
2021-03-29 15:59:14 +08:00
show_hidden : ! self . get_option ( " remote_show_hidden " ) . is_empty ( ) ,
.. Default ::default ( )
2022-09-01 17:36:37 +08:00
} ) ,
2023-05-18 19:49:36 +08:00
ConnType ::PORT_FORWARD | ConnType ::RDP = > lr . set_port_forward ( PortForward {
2021-03-29 15:59:14 +08:00
host : self . port_forward . 0. clone ( ) ,
port : self . port_forward . 1 ,
.. Default ::default ( )
2022-09-01 17:36:37 +08:00
} ) ,
_ = > { }
2021-03-29 15:59:14 +08:00
}
2022-09-01 17:36:37 +08:00
2021-03-29 15:59:14 +08:00
let mut msg_out = Message ::new ( ) ;
msg_out . set_login_request ( lr ) ;
msg_out
}
2022-07-09 20:17:10 +08:00
2024-01-02 16:58:10 +08:00
pub fn update_supported_decodings ( & self ) -> Message {
let decoding = scrap ::codec ::Decoder ::supported_decodings (
Some ( & self . id ) ,
cfg! ( feature = " flutter " ) ,
self . adapter_luid ,
2024-01-22 20:01:17 +08:00
& self . mark_unsupported ,
2024-01-02 16:58:10 +08:00
) ;
2022-07-09 20:17:10 +08:00
let mut misc = Misc ::new ( ) ;
misc . set_option ( OptionMessage {
2023-03-31 16:10:52 +08:00
supported_decoding : hbb_common ::protobuf ::MessageField ::some ( decoding ) ,
2022-07-09 20:17:10 +08:00
.. Default ::default ( )
} ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_misc ( misc ) ;
msg_out
}
2022-07-25 19:35:15 +08:00
pub fn restart_remote_device ( & self ) -> Message {
let mut misc = Misc ::new ( ) ;
misc . set_restart_remote_device ( true ) ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_misc ( misc ) ;
msg_out
}
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Media data.
2022-01-30 21:16:08 +08:00
pub enum MediaData {
2023-10-08 21:44:54 +08:00
VideoQueue ( usize ) ,
2023-03-30 11:47:08 +08:00
VideoFrame ( Box < VideoFrame > ) ,
AudioFrame ( Box < AudioFrame > ) ,
2022-01-30 21:16:08 +08:00
AudioFormat ( AudioFormat ) ,
2023-10-08 21:44:54 +08:00
Reset ( usize ) ,
RecordScreen ( bool , usize , i32 , i32 , String ) ,
2022-01-30 21:16:08 +08:00
}
pub type MediaSender = mpsc ::Sender < MediaData > ;
2023-10-08 21:44:54 +08:00
struct VideoHandlerController {
handler : VideoHandler ,
count : u128 ,
duration : std ::time ::Duration ,
skip_beginning : u32 ,
}
2022-05-28 03:56:42 +08:00
/// Start video and audio thread.
/// Return two [`MediaSender`], they should be given to the media producer.
///
/// # Arguments
///
/// * `video_callback` - The callback for video frame. Being called when a video frame is ready.
2023-10-08 21:44:54 +08:00
pub fn start_video_audio_threads < F , T > (
session : Session < T > ,
2023-03-29 21:59:25 +08:00
video_callback : F ,
2023-04-06 21:36:37 +08:00
) -> (
MediaSender ,
MediaSender ,
2023-10-08 21:44:54 +08:00
Arc < RwLock < HashMap < usize , ArrayQueue < VideoFrame > > > > ,
Arc < RwLock < HashMap < usize , usize > > > ,
2023-10-27 15:44:07 +08:00
Arc < RwLock < Option < Chroma > > > ,
2023-04-06 21:36:37 +08:00
)
2022-01-30 21:16:08 +08:00
where
2024-01-02 16:58:10 +08:00
F : 'static + FnMut ( usize , & mut scrap ::ImageRgb , * mut c_void , bool ) + Send ,
2023-10-08 21:44:54 +08:00
T : InvokeUiSession ,
2022-01-30 21:16:08 +08:00
{
let ( video_sender , video_receiver ) = mpsc ::channel ::< MediaData > ( ) ;
2023-10-08 21:44:54 +08:00
let video_queue_map : Arc < RwLock < HashMap < usize , ArrayQueue < VideoFrame > > > > = Default ::default ( ) ;
let video_queue_map_cloned = video_queue_map . clone ( ) ;
2022-01-30 21:16:08 +08:00
let mut video_callback = video_callback ;
2024-01-02 16:58:10 +08:00
2023-10-08 21:44:54 +08:00
let fps_map = Arc ::new ( RwLock ::new ( HashMap ::new ( ) ) ) ;
let decode_fps_map = fps_map . clone ( ) ;
2023-10-27 15:44:07 +08:00
let chroma = Arc ::new ( RwLock ::new ( None ) ) ;
let chroma_cloned = chroma . clone ( ) ;
let mut last_chroma = None ;
2022-01-30 21:16:08 +08:00
std ::thread ::spawn ( move | | {
2023-07-20 21:16:38 +08:00
#[ cfg(windows) ]
sync_cpu_usage ( ) ;
2023-10-08 21:44:54 +08:00
let mut handler_controller_map = Vec ::new ( ) ;
// let mut count = Vec::new();
// let mut duration = std::time::Duration::ZERO;
// let mut skip_beginning = Vec::new();
2022-01-30 21:16:08 +08:00
loop {
if let Ok ( data ) = video_receiver . recv ( ) {
match data {
2023-10-08 21:44:54 +08:00
MediaData ::VideoFrame ( _ ) | MediaData ::VideoQueue ( _ ) = > {
let vf = match data {
MediaData ::VideoFrame ( vf ) = > * vf ,
MediaData ::VideoQueue ( display ) = > {
if let Some ( video_queue ) =
video_queue_map . read ( ) . unwrap ( ) . get ( & display )
{
if let Some ( vf ) = video_queue . pop ( ) {
vf
} else {
continue ;
}
} else {
continue ;
}
}
_ = > {
// unreachable!();
2023-04-06 21:36:37 +08:00
continue ;
}
} ;
2023-10-08 21:44:54 +08:00
let display = vf . display as usize ;
2023-04-06 21:36:37 +08:00
let start = std ::time ::Instant ::now ( ) ;
2024-01-22 20:01:17 +08:00
let format = CodecFormat ::from ( & vf ) ;
2023-10-08 21:44:54 +08:00
if handler_controller_map . len ( ) < = display {
for _i in handler_controller_map . len ( ) ..= display {
handler_controller_map . push ( VideoHandlerController {
2024-01-22 20:01:17 +08:00
handler : VideoHandler ::new ( format , _i ) ,
2023-10-08 21:44:54 +08:00
count : 0 ,
duration : std ::time ::Duration ::ZERO ,
skip_beginning : 0 ,
} ) ;
2023-04-06 21:36:37 +08:00
}
2023-10-08 21:44:54 +08:00
}
if let Some ( handler_controller ) = handler_controller_map . get_mut ( display ) {
2024-01-02 16:58:10 +08:00
let mut pixelbuffer = true ;
2023-10-27 15:44:07 +08:00
let mut tmp_chroma = None ;
2024-01-02 16:58:10 +08:00
match handler_controller . handler . handle_frame (
vf ,
& mut pixelbuffer ,
& mut tmp_chroma ,
) {
2023-10-08 21:44:54 +08:00
Ok ( true ) = > {
2024-01-02 16:58:10 +08:00
video_callback (
display ,
& mut handler_controller . handler . rgb ,
handler_controller . handler . texture ,
pixelbuffer ,
) ;
2023-10-08 21:44:54 +08:00
2023-10-27 15:44:07 +08:00
// chroma
if tmp_chroma . is_some ( ) & & last_chroma ! = tmp_chroma {
last_chroma = tmp_chroma ;
* chroma . write ( ) . unwrap ( ) = tmp_chroma ;
}
2023-10-08 21:44:54 +08:00
// fps calculation
// The first frame will be very slow
if handler_controller . skip_beginning < 5 {
handler_controller . skip_beginning + = 1 ;
continue ;
}
handler_controller . duration + = start . elapsed ( ) ;
handler_controller . count + = 1 ;
if handler_controller . count % 10 = = 0 {
fps_map . write ( ) . unwrap ( ) . insert (
display ,
( handler_controller . count * 1000
/ handler_controller . duration . as_millis ( ) )
as usize ,
) ;
}
// Clear to get real-time fps
if handler_controller . count > 150 {
handler_controller . count = 0 ;
handler_controller . duration = Duration ::ZERO ;
}
}
Err ( e ) = > {
// This is a simple workaround.
//
// I only see the following error:
// FailedCall("errcode=1 scrap::common::vpxcodec:libs\\scrap\\src\\common\\vpxcodec.rs:433:9")
// When switching from all displays to one display, the error occurs.
// eg:
// 1. Connect to a device with two displays (A and B).
// 2. Switch to display A. The error occurs.
// 3. If the error does not occur. Switch from A to display B. The error occurs.
//
// to-do: fix the error
log ::error! ( " handle video frame error, {} " , e ) ;
2023-10-08 23:32:11 +08:00
session . refresh_video ( display as _ ) ;
2023-10-08 21:44:54 +08:00
}
_ = > { }
2023-03-29 21:59:25 +08:00
}
2022-01-30 21:16:08 +08:00
}
2024-01-22 20:01:17 +08:00
// check invalid decoders
let mut should_update_supported = false ;
handler_controller_map
. iter ( )
. map ( | h | {
if ! h . handler . decoder . valid ( ) | | h . handler . fail_counter > = MAX_DECODE_FAIL_COUNTER {
let mut lc = session . lc . write ( ) . unwrap ( ) ;
let format = h . handler . decoder . format ( ) ;
if ! lc . mark_unsupported . contains ( & format ) {
lc . mark_unsupported . push ( format ) ;
should_update_supported = true ;
log ::info! ( " mark {format:?} decoder as unsupported, valid:{}, fail_counter:{}, all unsupported:{:?} " , h . handler . decoder . valid ( ) , h . handler . fail_counter , lc . mark_unsupported ) ;
}
}
} )
. count ( ) ;
if should_update_supported {
session . send ( Data ::Message (
session . lc . read ( ) . unwrap ( ) . update_supported_decodings ( ) ,
) ) ;
}
2022-01-30 21:16:08 +08:00
}
2023-10-08 21:44:54 +08:00
MediaData ::Reset ( display ) = > {
if let Some ( handler_controler ) = handler_controller_map . get_mut ( display ) {
2024-01-22 20:01:17 +08:00
handler_controler . handler . reset ( None ) ;
2023-10-08 21:44:54 +08:00
}
2022-01-30 21:16:08 +08:00
}
2023-10-08 21:44:54 +08:00
MediaData ::RecordScreen ( start , display , w , h , id ) = > {
2023-11-18 09:47:08 +08:00
log ::info! ( " record screen command: start: {start}, display: {display} " ) ;
2023-10-08 21:44:54 +08:00
if handler_controller_map . len ( ) = = 1 {
// Compatible with the sciter version(single ui session).
// For the sciter version, there're no multi-ui-sessions for one connection.
// The display is always 0, video_handler_controllers.len() is always 1. So we use the first video handler.
handler_controller_map [ 0 ]
. handler
. record_screen ( start , w , h , id ) ;
} else {
if let Some ( handler_controler ) = handler_controller_map . get_mut ( display )
{
handler_controler . handler . record_screen ( start , w , h , id ) ;
}
}
2022-09-15 17:31:28 +08:00
}
2022-01-30 21:16:08 +08:00
_ = > { }
}
} else {
break ;
}
}
log ::info! ( " Video decoder loop exits " ) ;
} ) ;
2023-03-23 14:31:50 +08:00
let audio_sender = start_audio_thread ( ) ;
2023-10-08 21:44:54 +08:00
return (
video_sender ,
audio_sender ,
video_queue_map_cloned ,
decode_fps_map ,
2023-10-27 15:44:07 +08:00
chroma_cloned ,
2023-10-08 21:44:54 +08:00
) ;
2022-11-04 12:02:17 +08:00
}
/// Start an audio thread
/// Return a audio [`MediaSender`]
2023-03-23 14:31:50 +08:00
pub fn start_audio_thread ( ) -> MediaSender {
2022-11-04 12:02:17 +08:00
let ( audio_sender , audio_receiver ) = mpsc ::channel ::< MediaData > ( ) ;
2022-01-30 21:16:08 +08:00
std ::thread ::spawn ( move | | {
2023-03-23 14:31:50 +08:00
let mut audio_handler = AudioHandler ::default ( ) ;
2022-01-30 21:16:08 +08:00
loop {
if let Ok ( data ) = audio_receiver . recv ( ) {
match data {
MediaData ::AudioFrame ( af ) = > {
2023-03-30 11:47:08 +08:00
audio_handler . handle_frame ( * af ) ;
2022-01-30 21:16:08 +08:00
}
MediaData ::AudioFormat ( f ) = > {
2023-01-29 14:10:06 +08:00
log ::debug! ( " recved audio format, sample rate={} " , f . sample_rate ) ;
2022-01-30 21:16:08 +08:00
audio_handler . handle_format ( f ) ;
}
_ = > { }
}
} else {
break ;
}
}
log ::info! ( " Audio decoder loop exits " ) ;
} ) ;
2022-11-04 12:02:17 +08:00
audio_sender
2022-01-30 21:16:08 +08:00
}
2023-07-20 21:16:38 +08:00
#[ cfg(windows) ]
fn sync_cpu_usage ( ) {
use std ::sync ::Once ;
static ONCE : Once = Once ::new ( ) ;
ONCE . call_once ( | | {
let t = std ::thread ::spawn ( do_sync_cpu_usage ) ;
t . join ( ) . ok ( ) ;
} ) ;
}
#[ cfg(windows) ]
#[ tokio::main(flavor = " current_thread " ) ]
async fn do_sync_cpu_usage ( ) {
use crate ::ipc ::{ connect , Data } ;
let start = std ::time ::Instant ::now ( ) ;
match connect ( 50 , " " ) . await {
Ok ( mut conn ) = > {
if conn . send ( & & Data ::SyncWinCpuUsage ( None ) ) . await . is_ok ( ) {
if let Ok ( Some ( data ) ) = conn . next_timeout ( 50 ) . await {
match data {
Data ::SyncWinCpuUsage ( cpu_usage ) = > {
hbb_common ::platform ::windows ::sync_cpu_usage ( cpu_usage ) ;
}
_ = > { }
}
}
}
}
_ = > { }
}
log ::info! ( " {:?} used to sync cpu usage " , start . elapsed ( ) ) ;
}
2022-05-28 03:56:42 +08:00
/// Handle latency test.
///
/// # Arguments
///
/// * `t` - The latency test message.
/// * `peer` - The peer.
2021-03-29 15:59:14 +08:00
pub async fn handle_test_delay ( t : TestDelay , peer : & mut Stream ) {
if ! t . from_client {
let mut msg_out = Message ::new ( ) ;
msg_out . set_test_delay ( t ) ;
allow_err! ( peer . send ( & msg_out ) . await ) ;
}
}
2022-11-20 22:46:27 +08:00
/// Whether is track pad scrolling.
2022-11-07 01:25:36 +08:00
#[ inline ]
2023-06-17 00:17:56 +08:00
#[ cfg(all(target_os = " macos " , not(feature = " flutter " ))) ]
2022-11-07 01:25:36 +08:00
fn check_scroll_on_mac ( mask : i32 , x : i32 , y : i32 ) -> bool {
2022-11-20 22:46:27 +08:00
// flutter version we set mask type bit to 4 when track pad scrolling.
2023-06-13 11:10:49 +08:00
if mask & 7 = = crate ::input ::MOUSE_TYPE_TRACKPAD {
2022-11-20 22:46:27 +08:00
return true ;
}
2023-06-13 11:10:49 +08:00
if mask & 3 ! = crate ::input ::MOUSE_TYPE_WHEEL {
2022-11-07 01:25:36 +08:00
return false ;
}
let btn = mask > > 3 ;
if y = = - 1 {
btn ! = 0xff88 & & btn ! = - 0x780000
} else if y = = 1 {
btn ! = 0x78 & & btn ! = 0x780000
} else if x ! = 0 {
// No mouse support horizontal scrolling.
true
} else {
false
}
}
2022-05-28 03:56:42 +08:00
/// Send mouse data.
///
/// # Arguments
///
/// * `mask` - Mouse event.
/// * mask = buttons << 3 | type
2022-11-20 22:46:27 +08:00
/// * type, 1: down, 2: up, 3: wheel, 4: trackpad
2022-05-28 03:56:42 +08:00
/// * buttons, 1: left, 2: right, 4: middle
/// * `x` - X coordinate.
/// * `y` - Y coordinate.
/// * `alt` - Whether the alt key is pressed.
/// * `ctrl` - Whether the ctrl key is pressed.
/// * `shift` - Whether the shift key is pressed.
/// * `command` - Whether the command key is pressed.
/// * `interface` - The interface for sending data.
2022-05-12 17:35:25 +08:00
#[ inline ]
pub fn send_mouse (
mask : i32 ,
x : i32 ,
y : i32 ,
alt : bool ,
ctrl : bool ,
shift : bool ,
command : bool ,
interface : & impl Interface ,
) {
let mut msg_out = Message ::new ( ) ;
let mut mouse_event = MouseEvent {
mask ,
x ,
y ,
.. Default ::default ( )
} ;
if alt {
mouse_event . modifiers . push ( ControlKey ::Alt . into ( ) ) ;
}
if shift {
mouse_event . modifiers . push ( ControlKey ::Shift . into ( ) ) ;
}
if ctrl {
mouse_event . modifiers . push ( ControlKey ::Control . into ( ) ) ;
}
if command {
mouse_event . modifiers . push ( ControlKey ::Meta . into ( ) ) ;
}
2023-06-11 15:56:09 +08:00
#[ cfg(all(target_os = " macos " , not(feature = " flutter " ))) ]
2022-11-07 01:25:36 +08:00
if check_scroll_on_mac ( mask , x , y ) {
2023-06-11 15:56:09 +08:00
let factor = 3 ;
2023-06-13 11:10:49 +08:00
mouse_event . mask = crate ::input ::MOUSE_TYPE_TRACKPAD ;
2023-06-11 15:56:09 +08:00
mouse_event . x * = factor ;
mouse_event . y * = factor ;
2022-11-07 01:25:36 +08:00
}
2023-02-11 09:41:06 +08:00
interface . swap_modifier_mouse ( & mut mouse_event ) ;
2022-05-12 17:35:25 +08:00
msg_out . set_mouse_event ( mouse_event ) ;
interface . send ( Data ::Message ( msg_out ) ) ;
}
2023-07-19 01:18:10 +08:00
#[ inline ]
2023-07-19 07:33:35 +08:00
pub fn send_pointer_device_event (
mut evt : PointerDeviceEvent ,
2023-07-19 01:18:10 +08:00
alt : bool ,
ctrl : bool ,
shift : bool ,
command : bool ,
interface : & impl Interface ,
) {
let mut msg_out = Message ::new ( ) ;
if alt {
evt . modifiers . push ( ControlKey ::Alt . into ( ) ) ;
}
if shift {
evt . modifiers . push ( ControlKey ::Shift . into ( ) ) ;
}
if ctrl {
evt . modifiers . push ( ControlKey ::Control . into ( ) ) ;
}
if command {
evt . modifiers . push ( ControlKey ::Meta . into ( ) ) ;
}
2023-07-19 07:33:35 +08:00
msg_out . set_pointer_device_event ( evt ) ;
2023-07-19 01:18:10 +08:00
interface . send ( Data ::Message ( msg_out ) ) ;
}
2023-01-09 15:30:19 +08:00
/// Activate OS by sending mouse movement.
2022-06-27 11:18:53 +08:00
///
2022-05-28 03:56:42 +08:00
/// # Arguments
2022-06-27 11:18:53 +08:00
///
2022-05-28 03:56:42 +08:00
/// * `interface` - The interface for sending data.
2023-08-27 10:28:16 +08:00
/// * `send_left_click` - Whether to send a click event.
fn activate_os ( interface : & impl Interface , send_left_click : bool ) {
2023-08-24 12:03:29 +08:00
let left_down = MOUSE_BUTTON_LEFT < < 3 | MOUSE_TYPE_DOWN ;
let left_up = MOUSE_BUTTON_LEFT < < 3 | MOUSE_TYPE_UP ;
2023-08-27 10:28:16 +08:00
let right_down = MOUSE_BUTTON_RIGHT < < 3 | MOUSE_TYPE_DOWN ;
let right_up = MOUSE_BUTTON_RIGHT < < 3 | MOUSE_TYPE_UP ;
2023-08-24 12:03:29 +08:00
send_mouse ( left_up , 0 , 0 , false , false , false , false , interface ) ;
std ::thread ::sleep ( Duration ::from_millis ( 50 ) ) ;
2023-07-19 01:18:10 +08:00
send_mouse ( 0 , 0 , 0 , false , false , false , false , interface ) ;
2022-05-12 17:35:25 +08:00
std ::thread ::sleep ( Duration ::from_millis ( 50 ) ) ;
2023-07-19 01:18:10 +08:00
send_mouse ( 0 , 3 , 3 , false , false , false , false , interface ) ;
2023-08-27 10:28:16 +08:00
let ( click_down , click_up ) = if send_left_click {
( left_down , left_up )
} else {
( right_down , right_up )
} ;
std ::thread ::sleep ( Duration ::from_millis ( 50 ) ) ;
send_mouse ( click_down , 0 , 0 , false , false , false , false , interface ) ;
send_mouse ( click_up , 0 , 0 , false , false , false , false , interface ) ;
2022-05-12 17:35:25 +08:00
/*
let mut key_event = KeyEvent ::new ( ) ;
// do not use Esc, which has problem with Linux
key_event . set_control_key ( ControlKey ::RightArrow ) ;
key_event . press = true ;
let mut msg_out = Message ::new ( ) ;
msg_out . set_key_event ( key_event . clone ( ) ) ;
interface . send ( Data ::Message ( msg_out . clone ( ) ) ) ;
* /
}
2022-05-28 03:56:42 +08:00
/// Input the OS's password.
2022-06-27 11:18:53 +08:00
///
2022-05-28 03:56:42 +08:00
/// # Arguments
2022-06-27 11:18:53 +08:00
///
2022-05-28 03:56:42 +08:00
/// * `p` - The password.
2023-01-09 15:30:19 +08:00
/// * `activate` - Whether to activate OS.
2022-05-28 03:56:42 +08:00
/// * `interface` - The interface for sending data.
2022-05-12 17:35:25 +08:00
pub fn input_os_password ( p : String , activate : bool , interface : impl Interface ) {
std ::thread ::spawn ( move | | {
_input_os_password ( p , activate , interface ) ;
} ) ;
}
2022-05-28 03:56:42 +08:00
/// Input the OS's password.
2022-06-27 11:18:53 +08:00
///
2022-05-28 03:56:42 +08:00
/// # Arguments
2022-06-27 11:18:53 +08:00
///
2022-05-28 03:56:42 +08:00
/// * `p` - The password.
2023-01-09 15:30:19 +08:00
/// * `activate` - Whether to activate OS.
2022-05-28 03:56:42 +08:00
/// * `interface` - The interface for sending data.
2022-05-12 17:35:25 +08:00
fn _input_os_password ( p : String , activate : bool , interface : impl Interface ) {
2023-08-24 12:03:29 +08:00
let input_password = ! p . is_empty ( ) ;
2022-05-12 17:35:25 +08:00
if activate {
2023-08-24 12:03:29 +08:00
// Click event is used to bring up the password input box.
activate_os ( & interface , input_password ) ;
2022-05-12 17:35:25 +08:00
std ::thread ::sleep ( Duration ::from_millis ( 1200 ) ) ;
}
2023-08-24 12:03:29 +08:00
if ! input_password {
2023-08-23 23:29:15 +08:00
return ;
}
2022-05-12 17:35:25 +08:00
let mut key_event = KeyEvent ::new ( ) ;
key_event . press = true ;
let mut msg_out = Message ::new ( ) ;
key_event . set_seq ( p ) ;
msg_out . set_key_event ( key_event . clone ( ) ) ;
interface . send ( Data ::Message ( msg_out . clone ( ) ) ) ;
key_event . set_control_key ( ControlKey ::Return ) ;
msg_out . set_key_event ( key_event ) ;
interface . send ( Data ::Message ( msg_out ) ) ;
}
2023-04-01 00:28:56 +08:00
#[ derive(Copy, Clone) ]
struct LoginErrorMsgBox {
msgtype : & 'static str ,
title : & 'static str ,
text : & 'static str ,
link : & 'static str ,
try_again : bool ,
}
lazy_static ::lazy_static! {
static ref LOGIN_ERROR_MAP : Arc < HashMap < & 'static str , LoginErrorMsgBox > > = {
use hbb_common ::config ::LINK_HEADLESS_LINUX_SUPPORT ;
2023-07-29 14:02:13 +08:00
let map = HashMap ::from ( [ ( LOGIN_SCREEN_WAYLAND , LoginErrorMsgBox {
msgtype : " error " ,
2023-07-29 18:02:12 +08:00
title : " Login Error " ,
text : " Login screen using Wayland is not supported " ,
2023-07-29 14:02:13 +08:00
link : " https://rustdesk.com/docs/en/manual/linux/#login-screen " ,
try_again : true ,
} ) , ( LOGIN_MSG_DESKTOP_SESSION_NOT_READY , LoginErrorMsgBox {
2023-04-01 00:28:56 +08:00
msgtype : " session-login " ,
2023-04-03 14:24:17 +08:00
title : " " ,
text : " " ,
2023-04-01 00:28:56 +08:00
link : " " ,
try_again : true ,
2023-04-17 19:26:39 +08:00
} ) , ( LOGIN_MSG_DESKTOP_XSESSION_FAILED , LoginErrorMsgBox {
2023-04-01 00:28:56 +08:00
msgtype : " session-re-login " ,
2023-04-03 14:46:28 +08:00
title : " " ,
text : " " ,
2023-04-01 00:28:56 +08:00
link : " " ,
try_again : true ,
2023-04-17 19:26:39 +08:00
} ) , ( LOGIN_MSG_DESKTOP_SESSION_ANOTHER_USER , LoginErrorMsgBox {
2023-04-03 14:24:17 +08:00
msgtype : " info-nocancel " ,
2023-04-01 00:28:56 +08:00
title : " another_user_login_title_tip " ,
text : " another_user_login_text_tip " ,
link : " " ,
try_again : false ,
2023-04-17 19:26:39 +08:00
} ) , ( LOGIN_MSG_DESKTOP_XORG_NOT_FOUND , LoginErrorMsgBox {
2023-04-03 14:24:17 +08:00
msgtype : " info-nocancel " ,
2023-04-01 00:28:56 +08:00
title : " xorg_not_found_title_tip " ,
text : " xorg_not_found_text_tip " ,
link : LINK_HEADLESS_LINUX_SUPPORT ,
try_again : true ,
2023-04-17 19:26:39 +08:00
} ) , ( LOGIN_MSG_DESKTOP_NO_DESKTOP , LoginErrorMsgBox {
2023-04-03 14:24:17 +08:00
msgtype : " info-nocancel " ,
2023-04-01 00:28:56 +08:00
title : " no_desktop_title_tip " ,
text : " no_desktop_text_tip " ,
link : LINK_HEADLESS_LINUX_SUPPORT ,
try_again : true ,
2023-04-17 19:26:39 +08:00
} ) , ( LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY , LoginErrorMsgBox {
2023-04-01 00:28:56 +08:00
msgtype : " session-login-password " ,
2023-04-03 14:46:28 +08:00
title : " " ,
text : " " ,
2023-04-01 00:28:56 +08:00
link : " " ,
try_again : true ,
2023-04-17 19:26:39 +08:00
} ) , ( LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG , LoginErrorMsgBox {
2023-04-01 00:28:56 +08:00
msgtype : " session-login-re-password " ,
2023-04-03 14:46:28 +08:00
title : " " ,
text : " " ,
2023-04-01 00:28:56 +08:00
link : " " ,
try_again : true ,
2023-04-17 19:26:39 +08:00
} ) , ( LOGIN_MSG_NO_PASSWORD_ACCESS , LoginErrorMsgBox {
2023-04-01 00:28:56 +08:00
msgtype : " wait-remote-accept-nook " ,
title : " Prompt " ,
2023-04-01 22:47:57 +08:00
text : " Please wait for the remote side to accept your session request... " ,
2023-04-01 00:28:56 +08:00
link : " " ,
try_again : true ,
} ) ] ) ;
Arc ::new ( map )
} ;
}
2022-12-27 11:42:48 +08:00
/// Handle login error.
/// Return true if the password is wrong, return false if there's an actual error.
pub fn handle_login_error (
lc : Arc < RwLock < LoginConfigHandler > > ,
err : & str ,
interface : & impl Interface ,
) -> bool {
2023-08-20 15:49:00 +08:00
lc . write ( ) . unwrap ( ) . save_ab_password_to_recent = false ;
2023-04-17 19:26:39 +08:00
if err = = LOGIN_MSG_PASSWORD_EMPTY {
2022-12-27 11:42:48 +08:00
lc . write ( ) . unwrap ( ) . password = Default ::default ( ) ;
2023-03-22 17:01:11 +08:00
interface . msgbox ( " input-password " , " Password Required " , " " , " " ) ;
2022-12-27 11:42:48 +08:00
true
2023-04-17 19:26:39 +08:00
} else if err = = LOGIN_MSG_PASSWORD_WRONG {
2022-12-27 11:42:48 +08:00
lc . write ( ) . unwrap ( ) . password = Default ::default ( ) ;
interface . msgbox ( " re-input-password " , err , " Do you want to enter again? " , " " ) ;
true
2024-01-19 15:35:58 +08:00
} else if err = = LOGIN_MSG_2FA_WRONG | | err = = REQUIRE_2FA {
interface . msgbox ( " input-2fa " , err , " " , " " ) ;
true
2023-04-01 00:28:56 +08:00
} else if LOGIN_ERROR_MAP . contains_key ( err ) {
if let Some ( msgbox_info ) = LOGIN_ERROR_MAP . get ( err ) {
interface . msgbox (
msgbox_info . msgtype ,
msgbox_info . title ,
msgbox_info . text ,
msgbox_info . link ,
) ;
msgbox_info . try_again
} else {
// unreachable!
false
}
2022-12-27 11:42:48 +08:00
} else {
if err . contains ( SCRAP_X11_REQUIRED ) {
interface . msgbox ( " error " , " Login Error " , err , SCRAP_X11_REF_URL ) ;
} else {
interface . msgbox ( " error " , " Login Error " , err , " " ) ;
}
false
}
}
2022-05-28 03:56:42 +08:00
/// Handle hash message sent by peer.
/// Hash will be used for login.
///
/// # Arguments
///
/// * `lc` - Login config.
/// * `hash` - Hash sent by peer.
/// * `interface` - [`Interface`] for sending data.
/// * `peer` - [`Stream`] for communicating with peer.
2021-03-29 15:59:14 +08:00
pub async fn handle_hash (
lc : Arc < RwLock < LoginConfigHandler > > ,
2022-07-27 00:31:20 +08:00
password_preset : & str ,
2021-03-29 15:59:14 +08:00
hash : Hash ,
interface : & impl Interface ,
peer : & mut Stream ,
) {
2023-01-17 13:28:33 +08:00
lc . write ( ) . unwrap ( ) . hash = hash . clone ( ) ;
let uuid = lc . read ( ) . unwrap ( ) . switch_uuid . clone ( ) ;
if let Some ( uuid ) = uuid {
if let Ok ( uuid ) = uuid ::Uuid ::from_str ( & uuid ) {
send_switch_login_request ( lc . clone ( ) , peer , uuid ) . await ;
return ;
}
}
2021-03-29 15:59:14 +08:00
let mut password = lc . read ( ) . unwrap ( ) . password . clone ( ) ;
2022-07-27 00:31:20 +08:00
if password . is_empty ( ) {
if ! password_preset . is_empty ( ) {
let mut hasher = Sha256 ::new ( ) ;
hasher . update ( password_preset ) ;
hasher . update ( & hash . salt ) ;
let res = hasher . finalize ( ) ;
password = res [ .. ] . into ( ) ;
}
}
2021-03-29 15:59:14 +08:00
if password . is_empty ( ) {
password = lc . read ( ) . unwrap ( ) . config . password . clone ( ) ;
}
2023-08-02 22:25:54 +08:00
if password . is_empty ( ) {
let access_token = LocalConfig ::get_option ( " access_token " ) ;
let ab = hbb_common ::config ::Ab ::load ( ) ;
if ! access_token . is_empty ( ) & & access_token = = ab . access_token {
let id = lc . read ( ) . unwrap ( ) . id . clone ( ) ;
if let Some ( p ) = ab
. peers
. iter ( )
. find_map ( | p | if p . id = = id { Some ( p ) } else { None } )
{
if let Ok ( hash ) = base64 ::decode ( p . hash . clone ( ) , base64 ::Variant ::Original ) {
2023-08-20 15:49:00 +08:00
if ! hash . is_empty ( ) {
password = hash ;
lc . write ( ) . unwrap ( ) . save_ab_password_to_recent = true ;
}
2023-08-02 22:25:54 +08:00
}
}
}
}
2023-08-21 08:39:47 +08:00
lc . write ( ) . unwrap ( ) . password = password . clone ( ) ;
2023-03-30 15:36:03 +08:00
let password = if password . is_empty ( ) {
2021-03-29 15:59:14 +08:00
// login without password, the remote side can click accept
2022-10-14 11:19:49 +08:00
interface . msgbox ( " input-password " , " Password Required " , " " , " " ) ;
2023-03-30 15:36:03 +08:00
Vec ::new ( )
2021-03-29 15:59:14 +08:00
} else {
let mut hasher = Sha256 ::new ( ) ;
hasher . update ( & password ) ;
hasher . update ( & hash . challenge ) ;
2023-03-30 15:36:03 +08:00
hasher . finalize ( ) [ .. ] . into ( )
} ;
let os_username = lc . read ( ) . unwrap ( ) . get_option ( " os-username " ) ;
let os_password = lc . read ( ) . unwrap ( ) . get_option ( " os-password " ) ;
send_login ( lc . clone ( ) , os_username , os_password , password , peer ) . await ;
2021-03-29 15:59:14 +08:00
lc . write ( ) . unwrap ( ) . hash = hash ;
}
2022-05-28 03:56:42 +08:00
/// Send login message to peer.
///
/// # Arguments
///
/// * `lc` - Login config.
2023-03-22 17:01:11 +08:00
/// * `os_username` - OS username.
/// * `os_password` - OS password.
2022-05-28 03:56:42 +08:00
/// * `password` - Password.
/// * `peer` - [`Stream`] for communicating with peer.
2023-03-22 17:01:11 +08:00
async fn send_login (
lc : Arc < RwLock < LoginConfigHandler > > ,
os_username : String ,
os_password : String ,
password : Vec < u8 > ,
peer : & mut Stream ,
) {
let msg_out = lc
. read ( )
. unwrap ( )
. create_login_msg ( os_username , os_password , password ) ;
2021-03-29 15:59:14 +08:00
allow_err! ( peer . send ( & msg_out ) . await ) ;
}
2022-05-28 03:56:42 +08:00
/// Handle login request made from ui.
///
/// # Arguments
///
/// * `lc` - Login config.
2023-03-22 17:01:11 +08:00
/// * `os_username` - OS username.
/// * `os_password` - OS password.
2022-05-28 03:56:42 +08:00
/// * `password` - Password.
/// * `remember` - Whether to remember password.
/// * `peer` - [`Stream`] for communicating with peer.
2021-03-29 15:59:14 +08:00
pub async fn handle_login_from_ui (
lc : Arc < RwLock < LoginConfigHandler > > ,
2023-03-22 17:01:11 +08:00
os_username : String ,
os_password : String ,
2021-03-29 15:59:14 +08:00
password : String ,
remember : bool ,
peer : & mut Stream ,
) {
2023-03-22 17:01:11 +08:00
let mut hash_password = if password . is_empty ( ) {
let mut password2 = lc . read ( ) . unwrap ( ) . password . clone ( ) ;
if password2 . is_empty ( ) {
password2 = lc . read ( ) . unwrap ( ) . config . password . clone ( ) ;
}
password2
} else {
let mut hasher = Sha256 ::new ( ) ;
hasher . update ( password ) ;
hasher . update ( & lc . read ( ) . unwrap ( ) . hash . salt ) ;
let res = hasher . finalize ( ) ;
lc . write ( ) . unwrap ( ) . remember = remember ;
res [ .. ] . into ( )
} ;
2023-08-21 08:39:47 +08:00
lc . write ( ) . unwrap ( ) . password = hash_password . clone ( ) ;
2021-03-29 15:59:14 +08:00
let mut hasher2 = Sha256 ::new ( ) ;
2023-03-22 17:01:11 +08:00
hasher2 . update ( & hash_password [ .. ] ) ;
2021-03-29 15:59:14 +08:00
hasher2 . update ( & lc . read ( ) . unwrap ( ) . hash . challenge ) ;
2023-03-22 17:01:11 +08:00
hash_password = hasher2 . finalize ( ) [ .. ] . to_vec ( ) ;
send_login ( lc . clone ( ) , os_username , os_password , hash_password , peer ) . await ;
2021-03-29 15:59:14 +08:00
}
2023-01-17 13:28:33 +08:00
async fn send_switch_login_request (
lc : Arc < RwLock < LoginConfigHandler > > ,
peer : & mut Stream ,
uuid : Uuid ,
) {
let mut msg_out = Message ::new ( ) ;
msg_out . set_switch_sides_response ( SwitchSidesResponse {
uuid : Bytes ::from ( uuid . as_bytes ( ) . to_vec ( ) ) ,
lr : hbb_common ::protobuf ::MessageField ::some (
lc . read ( )
. unwrap ( )
2023-03-22 17:01:11 +08:00
. create_login_msg ( " " . to_owned ( ) , " " . to_owned ( ) , vec! [ ] )
2023-01-17 13:28:33 +08:00
. login_request ( )
. to_owned ( ) ,
) ,
.. Default ::default ( )
} ) ;
allow_err! ( peer . send ( & msg_out ) . await ) ;
}
2022-05-28 03:56:42 +08:00
/// Interface for client to send data and commands.
2021-03-29 15:59:14 +08:00
pub trait Interface : Send + Clone + 'static + Sized {
2022-09-06 19:08:45 +08:00
/// Send message data to remote peer.
2022-05-12 17:35:25 +08:00
fn send ( & self , data : Data ) ;
2022-10-14 11:19:49 +08:00
fn msgbox ( & self , msgtype : & str , title : & str , text : & str , link : & str ) ;
2023-10-03 09:51:21 +08:00
fn handle_login_error ( & self , err : & str ) -> bool ;
fn handle_peer_info ( & self , pi : PeerInfo ) ;
2024-02-14 23:59:17 +08:00
fn set_multiple_user_sessions ( & self , sessions : Vec < hbb_common ::message_proto ::RdpUserSession > ) ;
2022-08-31 16:31:31 +08:00
fn on_error ( & self , err : & str ) {
2022-10-14 11:19:49 +08:00
self . msgbox ( " error " , " Error " , err , " " ) ;
2022-08-31 16:31:31 +08:00
}
2023-10-03 09:51:21 +08:00
async fn handle_hash ( & self , pass : & str , hash : Hash , peer : & mut Stream ) ;
2023-03-22 17:01:11 +08:00
async fn handle_login_from_ui (
2023-10-03 09:51:21 +08:00
& self ,
2023-03-22 17:01:11 +08:00
os_username : String ,
os_password : String ,
password : String ,
remember : bool ,
peer : & mut Stream ,
) ;
2023-10-03 09:51:21 +08:00
async fn handle_test_delay ( & self , t : TestDelay , peer : & mut Stream ) ;
2022-12-29 00:02:31 +08:00
2023-11-06 20:12:01 +08:00
fn get_lch ( & self ) -> Arc < RwLock < LoginConfigHandler > > ;
fn get_id ( & self ) -> String {
self . get_lch ( ) . read ( ) . unwrap ( ) . id . clone ( )
}
2023-07-01 17:58:11 +08:00
2022-12-29 00:02:31 +08:00
fn is_force_relay ( & self ) -> bool {
2023-11-06 20:12:01 +08:00
self . get_lch ( ) . read ( ) . unwrap ( ) . force_relay
2022-12-29 00:02:31 +08:00
}
2023-11-06 20:12:01 +08:00
2023-03-03 14:02:49 +08:00
fn swap_modifier_mouse ( & self , _msg : & mut hbb_common ::protos ::message ::MouseEvent ) { }
2023-07-01 17:58:11 +08:00
fn update_direct ( & self , direct : Option < bool > ) {
2023-11-06 20:12:01 +08:00
self . get_lch ( ) . write ( ) . unwrap ( ) . direct = direct ;
2023-07-01 17:58:11 +08:00
}
fn update_received ( & self , received : bool ) {
2023-11-06 20:12:01 +08:00
self . get_lch ( ) . write ( ) . unwrap ( ) . received = received ;
2023-07-01 17:58:11 +08:00
}
fn on_establish_connection_error ( & self , err : String ) {
let title = " Connection Error " ;
let text = err . to_string ( ) ;
2023-11-06 20:12:01 +08:00
let lc = self . get_lch ( ) ;
2023-07-01 17:58:11 +08:00
let direct = lc . read ( ) . unwrap ( ) . direct ;
let received = lc . read ( ) . unwrap ( ) . received ;
2023-11-09 22:40:15 +08:00
let mut relay_hint = false ;
let mut relay_hint_type = " relay-hint " ;
2023-07-01 17:58:11 +08:00
// force relay
let errno = errno ::errno ( ) . 0 ;
2023-11-06 20:12:01 +08:00
log ::error! ( " Connection closed: {err}({errno}) " ) ;
2023-11-09 22:40:15 +08:00
if direct = = Some ( true )
& & ( ( cfg! ( windows ) & & ( errno = = 10054 | | err . contains ( " 10054 " ) ) )
| | ( ! cfg! ( windows ) & & ( errno = = 104 | | err . contains ( " 104 " ) ) ) )
2023-07-01 17:58:11 +08:00
{
2023-11-09 22:40:15 +08:00
relay_hint = true ;
if ! received {
relay_hint_type = " relay-hint2 "
}
2023-07-01 17:58:11 +08:00
}
// relay-hint
2023-11-09 22:40:15 +08:00
if cfg! ( feature = " flutter " ) & & relay_hint {
self . msgbox ( relay_hint_type , title , & text , " " ) ;
2023-07-01 17:58:11 +08:00
} else {
self . msgbox ( " error " , title , & text , " " ) ;
}
}
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Data used by the client interface.
2021-03-29 15:59:14 +08:00
#[ derive(Clone) ]
pub enum Data {
Close ,
2023-03-22 17:01:11 +08:00
Login ( ( String , String , String , bool ) ) ,
2021-03-29 15:59:14 +08:00
Message ( Message ) ,
2022-05-13 11:23:30 +08:00
SendFiles ( ( i32 , String , String , i32 , bool , bool ) ) ,
2022-07-01 11:26:32 +08:00
RemoveDirAll ( ( i32 , String , bool , bool ) ) ,
2021-03-29 15:59:14 +08:00
ConfirmDeleteFiles ( ( i32 , i32 ) ) ,
SetNoConfirm ( i32 ) ,
RemoveDir ( ( i32 , String ) ) ,
RemoveFile ( ( i32 , String , i32 , bool ) ) ,
CreateDir ( ( i32 , String , bool ) ) ,
CancelJob ( i32 ) ,
RemovePortForward ( i32 ) ,
AddPortForward ( ( i32 , String , i32 ) ) ,
2023-06-18 20:23:54 +08:00
#[ cfg(not(feature = " flutter " )) ]
2022-02-15 15:35:19 +08:00
ToggleClipboardFile ,
2021-03-29 15:59:14 +08:00
NewRDP ,
2022-04-28 17:42:22 +08:00
SetConfirmOverrideFile ( ( i32 , i32 , bool , bool , bool ) ) ,
2022-05-14 11:58:47 +08:00
AddJob ( ( i32 , String , String , i32 , bool , bool ) ) ,
ResumeJob ( ( i32 , bool ) ) ,
2023-10-08 21:44:54 +08:00
RecordScreen ( bool , usize , i32 , i32 , String ) ,
2023-01-12 21:03:05 +08:00
ElevateDirect ,
ElevateWithLogon ( String , String ) ,
2023-02-05 23:47:06 +08:00
NewVoiceCall ,
CloseVoiceCall ,
2021-03-29 15:59:14 +08:00
}
2022-05-28 03:56:42 +08:00
/// Keycode for key events.
2022-08-27 09:29:46 +08:00
#[ derive(Clone, Debug) ]
2021-03-29 15:59:14 +08:00
pub enum Key {
ControlKey ( ControlKey ) ,
Chr ( u32 ) ,
_Raw ( u32 ) ,
}
lazy_static ::lazy_static! {
pub static ref KEY_MAP : HashMap < & 'static str , Key > =
[
( " VK_A " , Key ::Chr ( 'a' as _ ) ) ,
( " VK_B " , Key ::Chr ( 'b' as _ ) ) ,
( " VK_C " , Key ::Chr ( 'c' as _ ) ) ,
( " VK_D " , Key ::Chr ( 'd' as _ ) ) ,
( " VK_E " , Key ::Chr ( 'e' as _ ) ) ,
( " VK_F " , Key ::Chr ( 'f' as _ ) ) ,
( " VK_G " , Key ::Chr ( 'g' as _ ) ) ,
( " VK_H " , Key ::Chr ( 'h' as _ ) ) ,
( " VK_I " , Key ::Chr ( 'i' as _ ) ) ,
( " VK_J " , Key ::Chr ( 'j' as _ ) ) ,
( " VK_K " , Key ::Chr ( 'k' as _ ) ) ,
( " VK_L " , Key ::Chr ( 'l' as _ ) ) ,
( " VK_M " , Key ::Chr ( 'm' as _ ) ) ,
( " VK_N " , Key ::Chr ( 'n' as _ ) ) ,
( " VK_O " , Key ::Chr ( 'o' as _ ) ) ,
( " VK_P " , Key ::Chr ( 'p' as _ ) ) ,
( " VK_Q " , Key ::Chr ( 'q' as _ ) ) ,
( " VK_R " , Key ::Chr ( 'r' as _ ) ) ,
( " VK_S " , Key ::Chr ( 's' as _ ) ) ,
( " VK_T " , Key ::Chr ( 't' as _ ) ) ,
( " VK_U " , Key ::Chr ( 'u' as _ ) ) ,
( " VK_V " , Key ::Chr ( 'v' as _ ) ) ,
( " VK_W " , Key ::Chr ( 'w' as _ ) ) ,
( " VK_X " , Key ::Chr ( 'x' as _ ) ) ,
( " VK_Y " , Key ::Chr ( 'y' as _ ) ) ,
( " VK_Z " , Key ::Chr ( 'z' as _ ) ) ,
( " VK_0 " , Key ::Chr ( '0' as _ ) ) ,
( " VK_1 " , Key ::Chr ( '1' as _ ) ) ,
( " VK_2 " , Key ::Chr ( '2' as _ ) ) ,
( " VK_3 " , Key ::Chr ( '3' as _ ) ) ,
( " VK_4 " , Key ::Chr ( '4' as _ ) ) ,
( " VK_5 " , Key ::Chr ( '5' as _ ) ) ,
( " VK_6 " , Key ::Chr ( '6' as _ ) ) ,
( " VK_7 " , Key ::Chr ( '7' as _ ) ) ,
( " VK_8 " , Key ::Chr ( '8' as _ ) ) ,
( " VK_9 " , Key ::Chr ( '9' as _ ) ) ,
( " VK_COMMA " , Key ::Chr ( ',' as _ ) ) ,
( " VK_SLASH " , Key ::Chr ( '/' as _ ) ) ,
( " VK_SEMICOLON " , Key ::Chr ( ';' as _ ) ) ,
( " VK_QUOTE " , Key ::Chr ( '\'' as _ ) ) ,
( " VK_LBRACKET " , Key ::Chr ( '[' as _ ) ) ,
( " VK_RBRACKET " , Key ::Chr ( ']' as _ ) ) ,
( " VK_BACKSLASH " , Key ::Chr ( '\\' as _ ) ) ,
( " VK_MINUS " , Key ::Chr ( '-' as _ ) ) ,
( " VK_PLUS " , Key ::Chr ( '=' as _ ) ) , // it is =, but sciter return VK_PLUS
( " VK_DIVIDE " , Key ::ControlKey ( ControlKey ::Divide ) ) , // numpad
( " VK_MULTIPLY " , Key ::ControlKey ( ControlKey ::Multiply ) ) , // numpad
( " VK_SUBTRACT " , Key ::ControlKey ( ControlKey ::Subtract ) ) , // numpad
( " VK_ADD " , Key ::ControlKey ( ControlKey ::Add ) ) , // numpad
( " VK_DECIMAL " , Key ::ControlKey ( ControlKey ::Decimal ) ) , // numpad
( " VK_F1 " , Key ::ControlKey ( ControlKey ::F1 ) ) ,
( " VK_F2 " , Key ::ControlKey ( ControlKey ::F2 ) ) ,
( " VK_F3 " , Key ::ControlKey ( ControlKey ::F3 ) ) ,
( " VK_F4 " , Key ::ControlKey ( ControlKey ::F4 ) ) ,
( " VK_F5 " , Key ::ControlKey ( ControlKey ::F5 ) ) ,
( " VK_F6 " , Key ::ControlKey ( ControlKey ::F6 ) ) ,
( " VK_F7 " , Key ::ControlKey ( ControlKey ::F7 ) ) ,
( " VK_F8 " , Key ::ControlKey ( ControlKey ::F8 ) ) ,
( " VK_F9 " , Key ::ControlKey ( ControlKey ::F9 ) ) ,
( " VK_F10 " , Key ::ControlKey ( ControlKey ::F10 ) ) ,
( " VK_F11 " , Key ::ControlKey ( ControlKey ::F11 ) ) ,
( " VK_F12 " , Key ::ControlKey ( ControlKey ::F12 ) ) ,
( " VK_ENTER " , Key ::ControlKey ( ControlKey ::Return ) ) ,
( " VK_CANCEL " , Key ::ControlKey ( ControlKey ::Cancel ) ) ,
( " VK_BACK " , Key ::ControlKey ( ControlKey ::Backspace ) ) ,
( " VK_TAB " , Key ::ControlKey ( ControlKey ::Tab ) ) ,
( " VK_CLEAR " , Key ::ControlKey ( ControlKey ::Clear ) ) ,
( " VK_RETURN " , Key ::ControlKey ( ControlKey ::Return ) ) ,
( " VK_SHIFT " , Key ::ControlKey ( ControlKey ::Shift ) ) ,
( " VK_CONTROL " , Key ::ControlKey ( ControlKey ::Control ) ) ,
2021-05-26 12:42:21 +08:00
( " VK_MENU " , Key ::ControlKey ( ControlKey ::Alt ) ) ,
2021-03-29 15:59:14 +08:00
( " VK_PAUSE " , Key ::ControlKey ( ControlKey ::Pause ) ) ,
( " VK_CAPITAL " , Key ::ControlKey ( ControlKey ::CapsLock ) ) ,
( " VK_KANA " , Key ::ControlKey ( ControlKey ::Kana ) ) ,
( " VK_HANGUL " , Key ::ControlKey ( ControlKey ::Hangul ) ) ,
( " VK_JUNJA " , Key ::ControlKey ( ControlKey ::Junja ) ) ,
( " VK_FINAL " , Key ::ControlKey ( ControlKey ::Final ) ) ,
( " VK_HANJA " , Key ::ControlKey ( ControlKey ::Hanja ) ) ,
( " VK_KANJI " , Key ::ControlKey ( ControlKey ::Kanji ) ) ,
( " VK_ESCAPE " , Key ::ControlKey ( ControlKey ::Escape ) ) ,
( " VK_CONVERT " , Key ::ControlKey ( ControlKey ::Convert ) ) ,
( " VK_SPACE " , Key ::ControlKey ( ControlKey ::Space ) ) ,
( " VK_PRIOR " , Key ::ControlKey ( ControlKey ::PageUp ) ) ,
( " VK_NEXT " , Key ::ControlKey ( ControlKey ::PageDown ) ) ,
( " VK_END " , Key ::ControlKey ( ControlKey ::End ) ) ,
( " VK_HOME " , Key ::ControlKey ( ControlKey ::Home ) ) ,
( " VK_LEFT " , Key ::ControlKey ( ControlKey ::LeftArrow ) ) ,
( " VK_UP " , Key ::ControlKey ( ControlKey ::UpArrow ) ) ,
( " VK_RIGHT " , Key ::ControlKey ( ControlKey ::RightArrow ) ) ,
( " VK_DOWN " , Key ::ControlKey ( ControlKey ::DownArrow ) ) ,
( " VK_SELECT " , Key ::ControlKey ( ControlKey ::Select ) ) ,
( " VK_PRINT " , Key ::ControlKey ( ControlKey ::Print ) ) ,
( " VK_EXECUTE " , Key ::ControlKey ( ControlKey ::Execute ) ) ,
( " VK_SNAPSHOT " , Key ::ControlKey ( ControlKey ::Snapshot ) ) ,
( " VK_INSERT " , Key ::ControlKey ( ControlKey ::Insert ) ) ,
( " VK_DELETE " , Key ::ControlKey ( ControlKey ::Delete ) ) ,
( " VK_HELP " , Key ::ControlKey ( ControlKey ::Help ) ) ,
( " VK_SLEEP " , Key ::ControlKey ( ControlKey ::Sleep ) ) ,
( " VK_SEPARATOR " , Key ::ControlKey ( ControlKey ::Separator ) ) ,
( " VK_NUMPAD0 " , Key ::ControlKey ( ControlKey ::Numpad0 ) ) ,
( " VK_NUMPAD1 " , Key ::ControlKey ( ControlKey ::Numpad1 ) ) ,
( " VK_NUMPAD2 " , Key ::ControlKey ( ControlKey ::Numpad2 ) ) ,
( " VK_NUMPAD3 " , Key ::ControlKey ( ControlKey ::Numpad3 ) ) ,
( " VK_NUMPAD4 " , Key ::ControlKey ( ControlKey ::Numpad4 ) ) ,
( " VK_NUMPAD5 " , Key ::ControlKey ( ControlKey ::Numpad5 ) ) ,
( " VK_NUMPAD6 " , Key ::ControlKey ( ControlKey ::Numpad6 ) ) ,
( " VK_NUMPAD7 " , Key ::ControlKey ( ControlKey ::Numpad7 ) ) ,
( " VK_NUMPAD8 " , Key ::ControlKey ( ControlKey ::Numpad8 ) ) ,
( " VK_NUMPAD9 " , Key ::ControlKey ( ControlKey ::Numpad9 ) ) ,
2021-08-10 12:18:10 +08:00
( " Apps " , Key ::ControlKey ( ControlKey ::Apps ) ) ,
( " Meta " , Key ::ControlKey ( ControlKey ::Meta ) ) ,
2021-05-26 12:42:21 +08:00
( " RAlt " , Key ::ControlKey ( ControlKey ::RAlt ) ) ,
( " RWin " , Key ::ControlKey ( ControlKey ::RWin ) ) ,
( " RControl " , Key ::ControlKey ( ControlKey ::RControl ) ) ,
( " RShift " , Key ::ControlKey ( ControlKey ::RShift ) ) ,
2021-03-29 15:59:14 +08:00
( " CTRL_ALT_DEL " , Key ::ControlKey ( ControlKey ::CtrlAltDel ) ) ,
( " LOCK_SCREEN " , Key ::ControlKey ( ControlKey ::LockScreen ) ) ,
] . iter ( ) . cloned ( ) . collect ( ) ;
}
2021-08-11 01:28:53 +08:00
2022-05-28 03:56:42 +08:00
/// Check if the given message is an error and can be retried.
2022-06-27 11:18:53 +08:00
///
2022-05-28 03:56:42 +08:00
/// # Arguments
2022-06-27 11:18:53 +08:00
///
2022-05-28 03:56:42 +08:00
/// * `msgtype` - The message type.
/// * `title` - The title of the message.
/// * `text` - The text of the message.
2021-08-11 01:28:53 +08:00
#[ inline ]
2022-12-27 11:42:48 +08:00
pub fn check_if_retry ( msgtype : & str , title : & str , text : & str , retry_for_relay : bool ) -> bool {
2021-08-11 01:28:53 +08:00
msgtype = = " error "
& & title = = " Connection Error "
2022-12-27 11:42:48 +08:00
& & ( ( text . contains ( " 10054 " ) | | text . contains ( " 104 " ) ) & & retry_for_relay
2022-07-31 19:06:49 +08:00
| | ( ! text . to_lowercase ( ) . contains ( " offline " )
& & ! text . to_lowercase ( ) . contains ( " exist " )
& & ! text . to_lowercase ( ) . contains ( " handshake " )
& & ! text . to_lowercase ( ) . contains ( " failed " )
& & ! text . to_lowercase ( ) . contains ( " resolve " )
& & ! text . to_lowercase ( ) . contains ( " mismatch " )
& & ! text . to_lowercase ( ) . contains ( " manually " )
2023-02-20 16:12:11 +08:00
& & ! text . to_lowercase ( ) . contains ( " not allowed " ) ) )
2022-03-26 00:06:06 +08:00
}