From 75590af0d7be6165ba531ea26cc8f2496e04ef0d Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 11 Oct 2022 20:34:58 -0700 Subject: [PATCH 01/11] build: trivial changes build.py Signed-off-by: fufesou --- build.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.py b/build.py index 3e9fe813d..7780ecfd0 100755 --- a/build.py +++ b/build.py @@ -144,7 +144,9 @@ Description: A remote control software. file.close() def build_flutter_deb(version): - os.system('cargo build --features flutter --lib --release') + os.system('cargo build --features default,flutter --lib --release') + # workaround ffigen + os.system('sed -i "s/ffi.NativeFunction Date: Tue, 11 Oct 2022 20:35:30 -0700 Subject: [PATCH 02/11] flutter: msgbox selectable Signed-off-by: fufesou --- flutter/lib/common.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 6e32ad09c..686ef3144 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -656,7 +656,8 @@ void msgBox( } dialogManager.show((setState, close) => CustomAlertDialog( title: _msgBoxTitle(title), - content: Text(translate(text), style: const TextStyle(fontSize: 15)), + content: SelectableText(translate(text), + style: const TextStyle(fontSize: 15)), actions: buttons, onSubmit: hasOk ? submit : null, onCancel: hasCancel == true ? cancel : null, From 2da5401fd48664d40a984d7a9839849877e169db Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 11 Oct 2022 20:36:19 -0700 Subject: [PATCH 03/11] add global init and update wayland error map Signed-off-by: fufesou --- libs/hbb_common/src/platform/linux.rs | 31 +++++++++++++- libs/scrap/src/common/mod.rs | 1 + libs/scrap/src/common/wayland.rs | 16 ++++++- src/common.rs | 35 ++++++++++++++- src/main.rs | 12 ++++++ src/server.rs | 2 +- src/server/connection.rs | 2 +- src/server/wayland.rs | 62 +++++++++++++++++++++++++-- src/ui_interface.rs | 2 +- 9 files changed, 151 insertions(+), 12 deletions(-) diff --git a/libs/hbb_common/src/platform/linux.rs b/libs/hbb_common/src/platform/linux.rs index 08e091337..0473a3bbc 100644 --- a/libs/hbb_common/src/platform/linux.rs +++ b/libs/hbb_common/src/platform/linux.rs @@ -1,5 +1,31 @@ use crate::ResultType; +lazy_static::lazy_static! { + pub static ref DISTRO: Disto = Disto::new(); +} + +pub struct Disto { + pub name: String, + pub version_id: String, +} + +impl Disto { + fn new() -> Self { + let name = run_cmds("awk -F'=' '/^NAME=/ {print $2}' /etc/os-release".to_owned()) + .unwrap_or_default() + .trim() + .trim_matches('"') + .to_string(); + let version_id = + run_cmds("awk -F'=' '/^VERSION_ID=/ {print $2}' /etc/os-release".to_owned()) + .unwrap_or_default() + .trim() + .trim_matches('"') + .to_string(); + Self { name, version_id } + } +} + pub fn get_display_server() -> String { let session = get_value_of_seat0(0); get_display_server_of_session(&session) @@ -81,8 +107,9 @@ pub fn get_value_of_seat0(i: usize) -> String { } // loginctl has not given the expected output. try something else. - if let Ok(sid) = std::env::var("XDG_SESSION_ID") { // could also execute "cat /proc/self/sessionid" - return sid.to_owned(); + if let Ok(sid) = std::env::var("XDG_SESSION_ID") { + // could also execute "cat /proc/self/sessionid" + return sid.to_owned(); } return "".to_owned(); diff --git a/libs/scrap/src/common/mod.rs b/libs/scrap/src/common/mod.rs index fe817c00a..468efb88e 100644 --- a/libs/scrap/src/common/mod.rs +++ b/libs/scrap/src/common/mod.rs @@ -12,6 +12,7 @@ cfg_if! { mod x11; pub use self::linux::*; pub use self::x11::Frame; + pub use self::wayland::set_map_err; } else { mod x11; pub use self::x11::*; diff --git a/libs/scrap/src/common/wayland.rs b/libs/scrap/src/common/wayland.rs index e33cbe745..6ad2d84cb 100644 --- a/libs/scrap/src/common/wayland.rs +++ b/libs/scrap/src/common/wayland.rs @@ -1,11 +1,23 @@ use crate::common::{x11::Frame, TraitCapturer}; use crate::wayland::{capturable::*, *}; -use std::{io, time::Duration}; +use std::{io, sync::RwLock, time::Duration}; pub struct Capturer(Display, Box, bool, Vec); +lazy_static::lazy_static! { + static ref MAP_ERR: RwLock io::Error>> = Default::default(); +} + +pub fn set_map_err(f: fn(err: String) -> io::Error) { + *MAP_ERR.write().unwrap() = Some(f); +} + fn map_err(err: E) -> io::Error { - io::Error::new(io::ErrorKind::Other, err.to_string()) + if let Some(f) = *MAP_ERR.read().unwrap() { + f(err.to_string()) + } else { + io::Error::new(io::ErrorKind::Other, err.to_string()) + } } impl Capturer { diff --git a/src/common.rs b/src/common.rs index 129e948cf..9beed2e90 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,4 +1,7 @@ -use std::sync::{Arc, Mutex}; +use std::{ + collections::HashMap, + sync::{Arc, Mutex}, +}; #[cfg(not(any(target_os = "android", target_os = "ios")))] pub use arboard::Clipboard as ClipboardContext; @@ -31,6 +34,36 @@ lazy_static::lazy_static! { pub static ref DEVICE_NAME: Arc> = Default::default(); } +lazy_static::lazy_static! { + static ref GLOBAL_INIT_FUNCS: Mutex bool>> = Default::default(); + static ref GLOBAL_CLEAN_FUNCS: Mutex> = Default::default(); +} + +pub fn reg_global_init(key: String, f: fn() -> bool) { + GLOBAL_INIT_FUNCS.lock().unwrap().insert(key, f); +} + +pub fn reg_global_clean(key: String, f: fn()) { + GLOBAL_CLEAN_FUNCS.lock().unwrap().insert(key, f); +} + +pub fn global_init() -> bool { + for (k, f) in GLOBAL_INIT_FUNCS.lock().unwrap().iter() { + println!("Init {}", k); + if !f() { + return false; + } + } + true +} + +pub fn global_clean() { + for (k, f) in GLOBAL_CLEAN_FUNCS.lock().unwrap().iter() { + println!("Clean {}", k); + f(); + } +} + #[inline] pub fn valid_for_numlock(evt: &KeyEvent) -> bool { if let Some(key_event::Union::ControlKey(ck)) = evt.union { diff --git a/src/main.rs b/src/main.rs index 23559ed8a..ac8fd5219 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,21 +6,32 @@ use librustdesk::*; #[cfg(any(target_os = "android", target_os = "ios"))] fn main() { + if !common::global_init() { + return; + } common::test_rendezvous_server(); common::test_nat_type(); #[cfg(target_os = "android")] crate::common::check_software_update(); + common::global_clean(); } #[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))] fn main() { + if !common::global_init() { + return; + } if let Some(args) = crate::core_main::core_main().as_mut() { ui::start(args); } + common::global_clean(); } #[cfg(feature = "cli")] fn main() { + if !common::global_init() { + return; + } use hbb_common::log; use clap::App; let args = format!( @@ -64,4 +75,5 @@ fn main() { let token = LocalConfig::get_option("access_token"); cli::start_one_port_forward(options[0].clone(), port, remote_host, remote_port, key, token); } + common::global_clean(); } \ No newline at end of file diff --git a/src/server.rs b/src/server.rs index cb3fd7c9d..58aab8fd1 100644 --- a/src/server.rs +++ b/src/server.rs @@ -27,7 +27,7 @@ cfg_if::cfg_if! { if #[cfg(not(any(target_os = "android", target_os = "ios")))] { mod clipboard_service; #[cfg(target_os = "linux")] -mod wayland; +pub(crate) mod wayland; #[cfg(target_os = "linux")] pub mod uinput; #[cfg(target_os = "linux")] diff --git a/src/server/connection.rs b/src/server/connection.rs index d111757bf..8e3f80bb9 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -745,7 +745,7 @@ impl Connection { try_activate_screen(); match super::video_service::get_displays().await { Err(err) => { - res.set_error(format!("X11 error: {}", err)); + res.set_error(format!("Error: {}", err)); } Ok((current, displays)) => { pi.displays = displays.into(); diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 1ac2c18be..c12d1e8da 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -1,10 +1,53 @@ use super::*; -use hbb_common::allow_err; -use scrap::{Capturer, Display, Frame, TraitCapturer}; -use std::io::Result; +use hbb_common::{allow_err, platform::linux::DISTRO}; +use scrap::{set_map_err, Capturer, Display, Frame, TraitCapturer}; +use std::io; + +pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; +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 is required"; +pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required"; lazy_static::lazy_static! { static ref CAP_DISPLAY_INFO: RwLock = RwLock::new(0); + static ref LOG_SCRAP_COUNT: Mutex = Mutex::new(0); + static ref GLOBAL_INIT_REG_HELPER: u8 = { + set_map_err(map_err_scrap); + 0u8 + }; +} + +pub fn map_err_scrap(err: String) -> io::Error { + if DISTRO.name.to_uppercase() == "Ubuntu".to_uppercase() { + if DISTRO.version_id < "21".to_owned() { + io::Error::new(io::ErrorKind::Other, SCRAP_UBUNTU_HIGHER_REQUIRED) + } else { + try_log(&err); + io::Error::new(io::ErrorKind::Other, err) + } + } else { + try_log(&err); + if err.contains("org.freedesktop.portal") + || err.contains("pipewire") + || err.contains("dbus") + { + io::Error::new(io::ErrorKind::Other, SCRAP_OTHER_VERSION_OR_X11_REQUIRED) + } else { + io::Error::new(io::ErrorKind::Other, SCRAP_X11_REQUIRED) + } + } +} + +fn try_log(err: &String) { + let mut lock_count = LOG_SCRAP_COUNT.lock().unwrap(); + if *lock_count >= 1000000 { + return; + } + if *lock_count % 10000 == 0 { + log::error!("Failed scrap {}", err); + } + *lock_count += 1; } struct CapturerPtr(*mut Capturer); @@ -16,7 +59,7 @@ impl Clone for CapturerPtr { } impl TraitCapturer for CapturerPtr { - fn frame<'a>(&'a mut self, timeout: Duration) -> Result> { + fn frame<'a>(&'a mut self, timeout: Duration) -> io::Result> { unsafe { (*self.0).frame(timeout) } } @@ -187,3 +230,14 @@ pub(super) fn get_capturer() -> ResultType { bail!("Failed to get capturer display info"); } } + +pub fn common_get_error() -> String { + if DISTRO.name.to_uppercase() == "Ubuntu".to_uppercase() { + if DISTRO.version_id < "21".to_owned() { + return "".to_owned(); + } + } else { + // to-do: check other distros + } + return "".to_owned(); +} diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 9952a5b35..9ef512fd7 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -547,7 +547,7 @@ pub fn get_error() -> String { { let dtype = crate::platform::linux::get_display_server(); if "wayland" == dtype { - return "".to_owned(); + return crate::server::wayland::common_get_error(); } if dtype != "x11" { return format!( From 3c9ac9e4d77e374e282b9d7aacfb6f53ee5ef6d8 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 12 Oct 2022 20:05:30 -0700 Subject: [PATCH 04/11] wayland: fix enigo init Signed-off-by: fufesou --- libs/enigo/src/linux/nix_impl.rs | 73 ++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/libs/enigo/src/linux/nix_impl.rs b/libs/enigo/src/linux/nix_impl.rs index 5fb67c5ee..e09f826dc 100644 --- a/libs/enigo/src/linux/nix_impl.rs +++ b/libs/enigo/src/linux/nix_impl.rs @@ -8,7 +8,7 @@ use tfc::{traits::*, Context as TFC_Context, Key as TFC_Key}; pub struct Enigo { xdo: EnigoXdo, is_x11: bool, - tfc: TFC_Context, + tfc: Option, uinput_keyboard: Option>, uinput_mouse: Option>, } @@ -35,46 +35,55 @@ impl Enigo { } fn tfc_key_down_or_up(&mut self, key: Key, down: bool, up: bool) -> bool { - if let Key::Layout(chr) = key { - if down { - if let Err(_) = self.tfc.unicode_char_down(chr) { - return false; + match &mut self.tfc { + None => false, + Some(tfc) => { + if let Key::Layout(chr) = key { + if down { + if let Err(_) = tfc.unicode_char_down(chr) { + return false; + } + } + if up { + if let Err(_) = tfc.unicode_char_up(chr) { + return false; + } + } + return true; } + let key = match convert_to_tfc_key(key) { + Some(key) => key, + None => { + return false; + } + }; + + if down { + if let Err(_) = tfc.key_down(key) { + return false; + } + }; + if up { + if let Err(_) = tfc.key_up(key) { + return false; + } + }; + return true; } - if up { - if let Err(_) = self.tfc.unicode_char_up(chr) { - return false; - } - } - return true; } - - let key = match convert_to_tfc_key(key) { - Some(key) => key, - None => { - return false; - } - }; - - if down { - if let Err(_) = self.tfc.key_down(key) { - return false; - } - }; - if up { - if let Err(_) = self.tfc.key_up(key) { - return false; - } - }; - return true; } } impl Default for Enigo { fn default() -> Self { + let is_x11 = "x11" == hbb_common::platform::linux::get_display_server(); Self { - is_x11: "x11" == hbb_common::platform::linux::get_display_server(), - tfc: TFC_Context::new().expect("kbd context error"), + is_x11, + tfc: if is_x11 { + Some(TFC_Context::new().expect("kbd context error")) + } else { + None + }, uinput_keyboard: None, uinput_mouse: None, xdo: EnigoXdo::default(), From 5ddb10366e5fe0c66187a44a45f07e43e1dfa0d9 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 13 Oct 2022 06:34:50 -0700 Subject: [PATCH 05/11] wayland: fix enigo crash & mid commit Signed-off-by: fufesou --- build.py | 1 + res/DEBIAN/postinst | 2 +- src/common.rs | 25 ++++-------------------- src/server/connection.rs | 1 - src/server/input_service.rs | 3 ++- src/server/video_service.rs | 26 ++++++++++++++++++++++--- src/server/wayland.rs | 39 ++++++++++++++++++++++++++++++++----- 7 files changed, 65 insertions(+), 32 deletions(-) diff --git a/build.py b/build.py index 7780ecfd0..dbc4f6255 100755 --- a/build.py +++ b/build.py @@ -342,6 +342,7 @@ def main(): os.system('cp -a res/DEBIAN/* tmpdeb/DEBIAN/') os.system('strip tmpdeb/usr/bin/rustdesk') os.system('mkdir -p tmpdeb/usr/lib/rustdesk') + os.system('mv tmpdeb/usr/bin/rustdesk tmpdeb/usr/lib/rustdesk/') os.system('cp libsciter-gtk.so tmpdeb/usr/lib/rustdesk/') md5_file('usr/share/rustdesk/files/systemd/rustdesk.service') md5_file('usr/share/rustdesk/files/systemd/rustdesk.service.user') diff --git a/res/DEBIAN/postinst b/res/DEBIAN/postinst index 44cb88c33..95222564d 100755 --- a/res/DEBIAN/postinst +++ b/res/DEBIAN/postinst @@ -14,7 +14,7 @@ if [ "$1" = configure ]; then fi version=$(python3 -V 2>&1 | grep -Po '(?<=Python )(.+)') parsedVersion=$(echo "${version//./}") - mkdir -p /usr/lib/systemd/system/ + mkdir -p /usr/lib/systemd/system/ cp /usr/share/rustdesk/files/systemd/rustdesk.service /usr/lib/systemd/system/rustdesk.service systemctl daemon-reload systemctl enable rustdesk diff --git a/src/common.rs b/src/common.rs index 9beed2e90..26903eacf 100644 --- a/src/common.rs +++ b/src/common.rs @@ -34,34 +34,17 @@ lazy_static::lazy_static! { pub static ref DEVICE_NAME: Arc> = Default::default(); } -lazy_static::lazy_static! { - static ref GLOBAL_INIT_FUNCS: Mutex bool>> = Default::default(); - static ref GLOBAL_CLEAN_FUNCS: Mutex> = Default::default(); -} - -pub fn reg_global_init(key: String, f: fn() -> bool) { - GLOBAL_INIT_FUNCS.lock().unwrap().insert(key, f); -} - -pub fn reg_global_clean(key: String, f: fn()) { - GLOBAL_CLEAN_FUNCS.lock().unwrap().insert(key, f); -} - pub fn global_init() -> bool { - for (k, f) in GLOBAL_INIT_FUNCS.lock().unwrap().iter() { - println!("Init {}", k); - if !f() { - return false; + #[cfg(target_os = "linux")] + { + if !scrap::is_x11() { + crate::server::wayland::set_wayland_scrap_map_err(); } } true } pub fn global_clean() { - for (k, f) in GLOBAL_CLEAN_FUNCS.lock().unwrap().iter() { - println!("Clean {}", k); - f(); - } } #[inline] diff --git a/src/server/connection.rs b/src/server/connection.rs index 8e3f80bb9..c451d5a1c 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -666,7 +666,6 @@ impl Connection { #[allow(unused_mut)] let mut username = crate::platform::get_active_username(); let mut res = LoginResponse::new(); - let mut pi = PeerInfo { username: username.clone(), conn_id: self.inner.id, diff --git a/src/server/input_service.rs b/src/server/input_service.rs index f36f2c50e..7dbba0e05 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -190,7 +190,8 @@ pub async fn set_uinput() -> ResultType<()> { let mouse = super::uinput::client::UInputMouse::new().await?; log::info!("UInput mouse created"); - let mut en = ENIGO.lock().unwrap(); + let xxx = ENIGO.lock(); + let mut en = xxx.unwrap(); en.set_uinput_keyboard(Some(Box::new(keyboard))); en.set_uinput_mouse(Some(Box::new(mouse))); Ok(()) diff --git a/src/server/video_service.rs b/src/server/video_service.rs index fad66ffb4..2b94077be 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -379,6 +379,10 @@ fn run(sp: GenericService) -> ResultType<()> { #[cfg(windows)] ensure_close_virtual_device()?; + // ensure_inited() is needed because release_resouce() may be called. + #[cfg(target_os = "linux")] + super::wayland::ensure_inited()?; + let mut c = get_capturer(true)?; let mut video_qos = VIDEO_QOS.lock().unwrap(); @@ -458,6 +462,8 @@ fn run(sp: GenericService) -> ResultType<()> { #[cfg(windows)] start_uac_elevation_check(); + let mut would_block_count = 0u32; + while sp.ok() { #[cfg(windows)] check_uac_switch(c.privacy_mode_id, c._captuerer_privacy_mode_id)?; @@ -547,8 +553,7 @@ fn run(sp: GenericService) -> ResultType<()> { }; match res { - Err(ref e) if e.kind() == WouldBlock => - { + Err(ref e) if e.kind() == WouldBlock => { #[cfg(windows)] if try_gdi > 0 && !c.is_gdi() { if try_gdi > 3 { @@ -558,6 +563,19 @@ fn run(sp: GenericService) -> ResultType<()> { } try_gdi += 1; } + + would_block_count += 1; + #[cfg(target_os = "linux")] + { + if !scrap::is_x11() { + if would_block_count >= 100 { + // For now, the user should choose and agree screen sharing agiain. + // to-do: Remember choice, attendless... + super::wayland::release_resouce(); + bail!("Wayland capturer none 100 times, try restart captuere"); + } + } + } } Err(err) => { if check_display_changed(c.ndisplay, c.current, c.width, c.height) { @@ -575,7 +593,9 @@ fn run(sp: GenericService) -> ResultType<()> { return Err(err.into()); } - _ => {} + _ => { + would_block_count = 0; + } } let mut fetched_conn_ids = HashSet::new(); diff --git a/src/server/wayland.rs b/src/server/wayland.rs index c12d1e8da..6d4a85399 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -12,13 +12,22 @@ pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/# lazy_static::lazy_static! { static ref CAP_DISPLAY_INFO: RwLock = RwLock::new(0); static ref LOG_SCRAP_COUNT: Mutex = Mutex::new(0); - static ref GLOBAL_INIT_REG_HELPER: u8 = { - set_map_err(map_err_scrap); - 0u8 - }; } -pub fn map_err_scrap(err: String) -> io::Error { +pub fn set_wayland_scrap_map_err() { + set_map_err(map_err_scrap); +} + +fn map_err_scrap(err: String) -> io::Error { + // REMOVE ME ===================================== uncomment to handle error + // // to-do: Handle error better, do not restart server + // if err.starts_with("Did not receive a reply") { + // log::error!("Fatal pipewire error, {}", &err); + // std::process::exit(-1); + // } + + log::error!("REMOVE ME ===================================== wayland scrap error {}", &err); + if DISTRO.name.to_uppercase() == "Ubuntu".to_uppercase() { if DISTRO.version_id < "21".to_owned() { io::Error::new(io::ErrorKind::Other, SCRAP_UBUNTU_HIGHER_REQUIRED) @@ -79,6 +88,11 @@ struct CapDisplayInfo { capturer: CapturerPtr, } +#[tokio::main(flavor = "current_thread")] +pub(super) async fn ensure_inited() -> ResultType<()> { + check_init().await +} + async fn check_init() -> ResultType<()> { if !scrap::is_x11() { let mut minx = 0; @@ -205,6 +219,21 @@ pub(super) fn get_display_num() -> ResultType { } } +pub(super) fn release_resouce() { + if scrap::is_x11() { + return; + } + let mut write_lock = CAP_DISPLAY_INFO.write().unwrap(); + if *write_lock != 0 { + let cap_display_info: *mut CapDisplayInfo = *write_lock as _; + unsafe { + let box_capturer = Box::from_raw((*cap_display_info).capturer.0); + let box_cap_display_info = Box::from_raw(cap_display_info); + *write_lock = 0; + } + } +} + pub(super) fn get_capturer() -> ResultType { if scrap::is_x11() { bail!("Do not call this function if not wayland"); From 77de0d05f95d45d3f84e28df8b43fb2fd1328f1f Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 14 Oct 2022 11:19:49 +0800 Subject: [PATCH 06/11] msgbox & translations Signed-off-by: fufesou --- flutter/lib/common.dart | 14 ++++- .../lib/desktop/pages/desktop_home_page.dart | 2 +- flutter/lib/mobile/widgets/dialog.dart | 2 +- flutter/lib/models/model.dart | 17 +++--- libs/hbb_common/protos/message.proto | 14 +++++ libs/hbb_common/src/config.rs | 10 +++- src/client.rs | 19 ++++-- src/client/io_loop.rs | 59 ++++++++++++------- src/common.rs | 6 +- src/flutter.rs | 3 +- src/lang/cn.rs | 4 ++ src/lang/cs.rs | 4 ++ src/lang/da.rs | 4 ++ src/lang/de.rs | 4 ++ src/lang/en.rs | 1 + src/lang/eo.rs | 4 ++ src/lang/es.rs | 4 ++ src/lang/fr.rs | 4 ++ src/lang/hu.rs | 4 ++ src/lang/id.rs | 4 ++ src/lang/it.rs | 4 ++ src/lang/ja.rs | 4 ++ src/lang/ko.rs | 4 ++ src/lang/kz.rs | 4 ++ src/lang/pl.rs | 4 ++ src/lang/pt_PT.rs | 4 ++ src/lang/ptbr.rs | 4 ++ src/lang/ru.rs | 4 ++ src/lang/sk.rs | 4 ++ src/lang/template.rs | 4 ++ src/lang/tr.rs | 4 ++ src/lang/tw.rs | 4 ++ src/lang/ua.rs | 4 ++ src/lang/vn.rs | 4 ++ src/port_forward.rs | 4 +- src/server/connection.rs | 4 ++ src/server/video_service.rs | 16 ++++- src/server/wayland.rs | 34 +++++++++-- src/ui/common.tis | 12 ++-- src/ui/msgbox.tis | 12 ++++ src/ui/remote.rs | 4 +- src/ui_session_interface.rs | 10 ++-- 42 files changed, 271 insertions(+), 64 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 686ef3144..caa143632 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -18,6 +18,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:window_manager/window_manager.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:window_size/window_size.dart' as window_size; +import 'package:url_launcher/url_launcher.dart'; import 'common/widgets/overlay.dart'; import 'mobile/pages/file_manager_page.dart'; @@ -618,8 +619,8 @@ class CustomAlertDialog extends StatelessWidget { } } -void msgBox( - String type, String title, String text, OverlayDialogManager dialogManager, +void msgBox(String type, String title, String text, String link, + OverlayDialogManager dialogManager, {bool? hasCancel}) { dialogManager.dismissAll(); List buttons = []; @@ -636,6 +637,12 @@ void msgBox( dialogManager.dismissAll(); } + jumplink() { + if (link.startsWith('http')) { + launchUrl(Uri.parse(link)); + } + } + if (type != "connecting" && type != "success" && !type.contains("nook")) { hasOk = true; buttons.insert(0, msgBoxButton(translate('OK'), submit)); @@ -654,6 +661,9 @@ void msgBox( dialogManager.dismissAll(); })); } + if (link.isNotEmpty) { + buttons.insert(0, msgBoxButton(translate('JumpLink'), jumplink)); + } dialogManager.show((setState, close) => CustomAlertDialog( title: _msgBoxTitle(title), content: SelectableText(translate(text), diff --git a/flutter/lib/desktop/pages/desktop_home_page.dart b/flutter/lib/desktop/pages/desktop_home_page.dart index 4bdbbbaac..a31a71802 100644 --- a/flutter/lib/desktop/pages/desktop_home_page.dart +++ b/flutter/lib/desktop/pages/desktop_home_page.dart @@ -414,7 +414,7 @@ class _DesktopHomePageState extends State final root = await bind.mainIsRoot(); final release = await bind.mainIsRelease(); if (Platform.isWindows && release && !installed && !root) { - msgBox('custom-elevation-nocancel', 'Prompt', 'elevation_prompt', + msgBox('custom-elevation-nocancel', 'Prompt', 'elevation_prompt', '', gFFI.dialogManager); } }); diff --git a/flutter/lib/mobile/widgets/dialog.dart b/flutter/lib/mobile/widgets/dialog.dart index 455922e34..ca82cbed9 100644 --- a/flutter/lib/mobile/widgets/dialog.dart +++ b/flutter/lib/mobile/widgets/dialog.dart @@ -6,7 +6,7 @@ import '../../models/model.dart'; import '../../models/platform_model.dart'; void clientClose(OverlayDialogManager dialogManager) { - msgBox('', 'Close', 'Are you sure to close the connection?', dialogManager); + msgBox('', 'Close', 'Are you sure to close the connection?', '', dialogManager); } void showSuccess() { diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 1fd33bc77..79cd7ad54 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -222,26 +222,27 @@ class FfiModel with ChangeNotifier { handleMsgBox(Map evt, String id) { if (parent.target == null) return; final dialogManager = parent.target!.dialogManager; - var type = evt['type']; - var title = evt['title']; - var text = evt['text']; + final type = evt['type']; + final title = evt['title']; + final text = evt['text']; + final link = evt['link']; if (type == 're-input-password') { wrongPasswordDialog(id, dialogManager); } else if (type == 'input-password') { enterPasswordDialog(id, dialogManager); } else if (type == 'restarting') { - showMsgBox(id, type, title, text, false, dialogManager, hasCancel: false); + showMsgBox(id, type, title, text, link, false, dialogManager, hasCancel: false); } else { var hasRetry = evt['hasRetry'] == 'true'; - showMsgBox(id, type, title, text, hasRetry, dialogManager); + showMsgBox(id, type, title, text, link, hasRetry, dialogManager); } } /// Show a message box with [type], [title] and [text]. - showMsgBox(String id, String type, String title, String text, bool hasRetry, - OverlayDialogManager dialogManager, + showMsgBox(String id, String type, String title, String text, String link, + bool hasRetry, OverlayDialogManager dialogManager, {bool? hasCancel}) { - msgBox(type, title, text, dialogManager, hasCancel: hasCancel); + msgBox(type, title, text, link, dialogManager, hasCancel: hasCancel); _timer?.cancel(); if (hasRetry) { _timer = Timer(Duration(seconds: _reconnects), () { diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index 1f3d24157..a48ec9d14 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -506,6 +506,19 @@ message AudioFrame { int64 timestamp = 2; } +// Notify peer to show message box. +message MessageBox { + // Message type. Refer to flutter/lib/commom.dart/msgBox(). + string msgtype = 1; + string title = 2; + // English + string text = 3; + // If not empty, msgbox provides a button to following the link. + // The link here can't be directly http url. + // It must be the key of http url configed in peer side or "rustdesk://*" (jump in app). + string link = 4; +} + message BackNotification { // no need to consider block input by someone else enum BlockInputState { @@ -581,5 +594,6 @@ message Message { FileResponse file_response = 18; Misc misc = 19; Cliprdr cliprdr = 20; + MessageBox message_box = 21; } } diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 0ef507a13..ad0585549 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -53,11 +53,19 @@ lazy_static::lazy_static! { static ref HW_CODEC_CONFIG: Arc> = Arc::new(RwLock::new(HwCodecConfig::load())); } -// #[cfg(any(target_os = "android", target_os = "ios"))] lazy_static::lazy_static! { pub static ref APP_DIR: Arc> = Default::default(); pub static ref APP_HOME_DIR: Arc> = Default::default(); } + +// #[cfg(any(target_os = "android", target_os = "ios"))] +lazy_static::lazy_static! { + pub static ref HELPER_URL: HashMap<&'static str, &'static str> = HashMap::from([ + ("rustdesk docs home", "https://rustdesk.com/docs/en/"), + ("rustdesk docs x11-required", "https://rustdesk.com/docs/en/manual/linux/#x11-required"), + ]); +} + const CHARS: &'static [char] = &[ '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', diff --git a/src/client.rs b/src/client.rs index 8723480f3..6b3917790 100644 --- a/src/client.rs +++ b/src/client.rs @@ -48,7 +48,10 @@ pub use super::lang::*; pub mod file_trait; pub mod helper; pub mod io_loop; -use crate::ui_session_interface::global_save_keyboard_mode; +use crate::{ + server::video_service::{SCRAP_X11_REF_URL, SCRAP_X11_REQUIRED}, + ui_session_interface::global_save_keyboard_mode, +}; pub static SERVER_KEYBOARD_ENABLED: AtomicBool = AtomicBool::new(true); pub static SERVER_FILE_TRANSFER_ENABLED: AtomicBool = AtomicBool::new(true); pub static SERVER_CLIPBOARD_ENABLED: AtomicBool = AtomicBool::new(true); @@ -1263,10 +1266,14 @@ impl LoginConfigHandler { pub fn handle_login_error(&mut self, err: &str, interface: &impl Interface) -> bool { if err == "Wrong Password" { self.password = Default::default(); - interface.msgbox("re-input-password", err, "Do you want to enter again?"); + interface.msgbox("re-input-password", err, "Do you want to enter again?", ""); true } else { - interface.msgbox("error", "Login Error", err); + if err.contains(SCRAP_X11_REQUIRED) { + interface.msgbox("error", "Login Error", err, SCRAP_X11_REF_URL); + } else { + interface.msgbox("error", "Login Error", err, ""); + } false } } @@ -1636,7 +1643,7 @@ pub async fn handle_hash( if password.is_empty() { // login without password, the remote side can click accept send_login(lc.clone(), Vec::new(), peer).await; - interface.msgbox("input-password", "Password Required", ""); + interface.msgbox("input-password", "Password Required", "", ""); } else { let mut hasher = Sha256::new(); hasher.update(&password); @@ -1689,7 +1696,7 @@ pub async fn handle_login_from_ui( pub trait Interface: Send + Clone + 'static + Sized { /// Send message data to remote peer. fn send(&self, data: Data); - fn msgbox(&self, msgtype: &str, title: &str, text: &str); + fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str); fn handle_login_error(&mut self, err: &str) -> bool; fn handle_peer_info(&mut self, pi: PeerInfo); fn set_force_relay(&mut self, direct: bool, received: bool); @@ -1697,7 +1704,7 @@ pub trait Interface: Send + Clone + 'static + Sized { fn is_port_forward(&self) -> bool; fn is_rdp(&self) -> bool; fn on_error(&self, err: &str) { - self.msgbox("error", "Error", err); + self.msgbox("error", "Error", err, ""); } fn is_force_relay(&self) -> bool; async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream); diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 7e3bbb3dc..a415576c8 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -119,7 +119,7 @@ impl Remote { Err(err) => { log::error!("Connection closed: {}", err); self.handler.set_force_relay(direct, received); - self.handler.msgbox("error", "Connection Error", &err.to_string()); + self.handler.msgbox("error", "Connection Error", &err.to_string(), ""); break; } Ok(ref bytes) => { @@ -134,10 +134,10 @@ impl Remote { } else { if self.handler.is_restarting_remote_device() { log::info!("Restart remote device"); - self.handler.msgbox("restarting", "Restarting Remote Device", "remote_restarting_tip"); + self.handler.msgbox("restarting", "Restarting Remote Device", "remote_restarting_tip", ""); } else { log::info!("Reset by the peer"); - self.handler.msgbox("error", "Connection Error", "Reset by the peer"); + self.handler.msgbox("error", "Connection Error", "Reset by the peer", ""); } break; } @@ -162,12 +162,12 @@ impl Remote { } _ = self.timer.tick() => { if last_recv_time.elapsed() >= SEC30 { - self.handler.msgbox("error", "Connection Error", "Timeout"); + self.handler.msgbox("error", "Connection Error", "Timeout", ""); break; } if !self.read_jobs.is_empty() { if let Err(err) = fs::handle_read_jobs(&mut self.read_jobs, &mut peer).await { - self.handler.msgbox("error", "Connection Error", &err.to_string()); + self.handler.msgbox("error", "Connection Error", &err.to_string(), ""); break; } self.update_jobs_status(); @@ -191,7 +191,7 @@ impl Remote { } Err(err) => { self.handler - .msgbox("error", "Connection Error", &err.to_string()); + .msgbox("error", "Connection Error", &err.to_string(), ""); } } if let Some(stop) = stop_clipboard { @@ -971,7 +971,7 @@ impl Remote { } } Some(misc::Union::CloseReason(c)) => { - self.handler.msgbox("error", "Connection Error", &c); + self.handler.msgbox("error", "Connection Error", &c, ""); return false; } Some(misc::Union::BackNotification(notification)) => { @@ -981,8 +981,12 @@ impl Remote { } Some(misc::Union::Uac(uac)) => { if uac { - self.handler - .msgbox("custom-uac-nocancel", "Warning", "uac_warning"); + self.handler.msgbox( + "custom-uac-nocancel", + "Warning", + "uac_warning", + "", + ); } } Some(misc::Union::ForegroundWindowElevated(elevated)) => { @@ -991,6 +995,7 @@ impl Remote { "custom-elevated-foreground-nocancel", "Warning", "elevated_foreground_window_warning", + "", ); } } @@ -1012,6 +1017,19 @@ impl Remote { } _ => {} }, + Some(message::Union::MessageBox(msgbox)) => { + let mut link = msgbox.link; + if !link.starts_with("rustdesk://") { + if let Some(v) = hbb_common::config::HELPER_URL.get(&link as &str) { + link = v.to_string(); + } else { + log::warn!("Message box ignore link {} for security", &link); + link = "".to_string(); + } + } + self.handler + .msgbox(&msgbox.msgtype, &msgbox.title, &msgbox.text, &link); + } _ => {} } } @@ -1053,7 +1071,7 @@ impl Remote { } back_notification::BlockInputState::BlkOnFailed => { self.handler - .msgbox("custom-error", "Block user input", "Failed"); + .msgbox("custom-error", "Block user input", "Failed", ""); self.update_block_input_state(false); } back_notification::BlockInputState::BlkOffSucceeded => { @@ -1061,7 +1079,7 @@ impl Remote { } back_notification::BlockInputState::BlkOffFailed => { self.handler - .msgbox("custom-error", "Unblock user input", "Failed"); + .msgbox("custom-error", "Unblock user input", "Failed", ""); } _ => {} } @@ -1086,51 +1104,52 @@ impl Remote { "error", "Connecting...", "Someone turns on privacy mode, exit", + "", ); return false; } back_notification::PrivacyModeState::PrvNotSupported => { self.handler - .msgbox("custom-error", "Privacy mode", "Unsupported"); + .msgbox("custom-error", "Privacy mode", "Unsupported", ""); self.update_privacy_mode(false); } back_notification::PrivacyModeState::PrvOnSucceeded => { self.handler - .msgbox("custom-nocancel", "Privacy mode", "In privacy mode"); + .msgbox("custom-nocancel", "Privacy mode", "In privacy mode", ""); self.update_privacy_mode(true); } back_notification::PrivacyModeState::PrvOnFailedDenied => { self.handler - .msgbox("custom-error", "Privacy mode", "Peer denied"); + .msgbox("custom-error", "Privacy mode", "Peer denied", ""); self.update_privacy_mode(false); } back_notification::PrivacyModeState::PrvOnFailedPlugin => { self.handler - .msgbox("custom-error", "Privacy mode", "Please install plugins"); + .msgbox("custom-error", "Privacy mode", "Please install plugins", ""); self.update_privacy_mode(false); } back_notification::PrivacyModeState::PrvOnFailed => { self.handler - .msgbox("custom-error", "Privacy mode", "Failed"); + .msgbox("custom-error", "Privacy mode", "Failed", ""); self.update_privacy_mode(false); } back_notification::PrivacyModeState::PrvOffSucceeded => { self.handler - .msgbox("custom-nocancel", "Privacy mode", "Out privacy mode"); + .msgbox("custom-nocancel", "Privacy mode", "Out privacy mode", ""); self.update_privacy_mode(false); } back_notification::PrivacyModeState::PrvOffByPeer => { self.handler - .msgbox("custom-error", "Privacy mode", "Peer exit"); + .msgbox("custom-error", "Privacy mode", "Peer exit", ""); self.update_privacy_mode(false); } back_notification::PrivacyModeState::PrvOffFailed => { self.handler - .msgbox("custom-error", "Privacy mode", "Failed to turn off"); + .msgbox("custom-error", "Privacy mode", "Failed to turn off", ""); } back_notification::PrivacyModeState::PrvOffUnknown => { self.handler - .msgbox("custom-error", "Privacy mode", "Turned off"); + .msgbox("custom-error", "Privacy mode", "Turned off", ""); // log::error!("Privacy mode is turned off with unknown reason"); self.update_privacy_mode(false); } diff --git a/src/common.rs b/src/common.rs index 26903eacf..3022e5b56 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,5 +1,6 @@ use std::{ collections::HashMap, + future::Future, sync::{Arc, Mutex}, }; @@ -21,6 +22,8 @@ use hbb_common::{ // #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))] use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all}; +pub type NotifyMessageBox = fn(String, String, String, String) -> dyn Future; + pub const CLIPBOARD_NAME: &'static str = "clipboard"; pub const CLIPBOARD_INTERVAL: u64 = 333; @@ -44,8 +47,7 @@ pub fn global_init() -> bool { true } -pub fn global_clean() { -} +pub fn global_clean() {} #[inline] pub fn valid_for_numlock(evt: &KeyEvent) -> bool { diff --git a/src/flutter.rs b/src/flutter.rs index b65ce4412..2b95f9cfb 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -310,7 +310,7 @@ impl InvokeUiSession for FlutterHandler { ); } - fn msgbox(&self, msgtype: &str, title: &str, text: &str, retry: bool) { + fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) { let has_retry = if retry { "true" } else { "" }; self.push_event( "msgbox", @@ -318,6 +318,7 @@ impl InvokeUiSession for FlutterHandler { ("type", msgtype), ("title", title), ("text", text), + ("link", link), ("hasRetry", has_retry), ], ); diff --git a/src/lang/cn.rs b/src/lang/cn.rs index c88b0182c..cf2575a7f 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", "自定义"), ("Full Access", "完全访问"), ("Screen Share", "仅共享屏幕"), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland 需要 Ubuntu 21.04 或更高版本。"), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland 需要更高版本的 linux 发行版。 请尝试 X11 桌面或更改您的操作系统。"), + ("JumpLink", "查看"), + ("Please Select the screen to be shared(Operate on the peer side).", "请选择要分享的画面(对端操作)。"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index f616d518b..162fdc1ed 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland vyžaduje Ubuntu 21.04 nebo vyšší verzi."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland vyžaduje vyšší verzi linuxové distribuce. Zkuste prosím X11 desktop nebo změňte OS."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Vyberte prosím obrazovku, kterou chcete sdílet (Ovládejte na straně protějšku)."), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 3fe49d051..df9929d1f 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland kræver Ubuntu 21.04 eller nyere version."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland kræver en højere version af linux distro. Prøv venligst X11 desktop eller skift dit OS."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Vælg venligst den skærm, der skal deles (Betjen på peer-siden)."), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 4942b3171..b0f6d0ba3 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland erfordert Ubuntu 21.04 oder eine höhere Version."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland erfordert eine höhere Version der Linux-Distribution. Bitte versuchen Sie den X11-Desktop oder ändern Sie Ihr Betriebssystem."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Bitte wählen Sie den Bildschirm aus, der freigegeben werden soll (auf der Peer-Seite arbeiten)."), ].iter().cloned().collect(); } diff --git a/src/lang/en.rs b/src/lang/en.rs index 279f26cd1..7c95f8abb 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -33,5 +33,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevation_prompt", "Running software without privilege elevation may cause problems when remote users operate certain windows."), ("uac_warning", "Temporarily denied access due to elevation request, please wait for the remote user to accept the UAC dialog. To avoid this problem, it is recommended to install the software on the remote device or run it with administrator privileges."), ("elevated_foreground_window_warning", "Temporarily unable to use the mouse and keyboard, because the current window of the remote desktop requires higher privilege to operate, you can request the remote user to minimize the current window. To avoid this problem, it is recommended to install the software on the remote device or run it with administrator privileges."), + ("JumpLink", "View"), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 9bfea5440..ca0f12bcd 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland postulas Ubuntu 21.04 aŭ pli altan version."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland postulas pli altan version de linuksa distro. Bonvolu provi X11-labortablon aŭ ŝanĝi vian OS."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Bonvolu Elekti la ekranon por esti dividita (Funkciu ĉe la sama flanko)."), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 3b6419572..3be5f920e 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requiere Ubuntu 21.04 o una versión superior."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requiere una versión superior de la distribución de Linux. Pruebe el escritorio X11 o cambie su sistema operativo."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Seleccione la pantalla que se compartirá (Operar en el lado del compañero)."), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index b7dbd5636..484c415fc 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland nécessite Ubuntu 21.04 ou une version supérieure."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland nécessite une version supérieure de la distribution Linux. Veuillez essayer le bureau X11 ou changer votre système d'exploitation."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Veuillez sélectionner l'écran à partager (opérer du côté pair)."), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index aa5e34d09..c2d5903e1 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "A Waylandhoz Ubuntu 21.04 vagy újabb verzió szükséges."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "A Wayland a Linux disztró magasabb verzióját igényli. Próbálja ki az X11 desktopot, vagy változtassa meg az operációs rendszert."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Kérjük, válassza ki a megosztani kívánt képernyőt (a társoldalon működjön)."), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 1ab7fd134..33aae1579 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland membutuhkan Ubuntu 21.04 atau versi yang lebih tinggi."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland membutuhkan versi distro linux yang lebih tinggi. Silakan coba desktop X11 atau ubah OS Anda."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Silakan Pilih layar yang akan dibagikan (Operasi di sisi rekan)."), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 65c16567c..5b37e9291 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland richiede Ubuntu 21.04 o versione successiva."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland richiede una versione superiore della distribuzione Linux. Prova X11 desktop o cambia il tuo sistema operativo."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Seleziona lo schermo da condividere (opera sul lato peer)."), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 75a9c0c9b..593ef0186 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland には、Ubuntu 21.04 以降のバージョンが必要です。"), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland には、より高いバージョンの Linux ディストリビューションが必要です。 X11 デスクトップを試すか、OS を変更してください。"), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "共有する画面を選択してください(ピア側で操作)。"), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index eccb4d836..1b668462e 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland는 Ubuntu 21.04 이상 버전이 필요합니다."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland에는 더 높은 버전의 Linux 배포판이 필요합니다. X11 데스크탑을 시도하거나 OS를 변경하십시오."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "공유할 화면을 선택하십시오(피어 측에서 작동)."), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 9a1e23c23..e55b0a3e3 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland Ubuntu 21.04 немесе одан жоғары нұсқасын қажет етеді."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland linux дистрибутивінің жоғарырақ нұсқасын қажет етеді. X11 жұмыс үстелін қолданып көріңіз немесе операциялық жүйеңізді өзгертіңіз."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Бөлісетін экранды таңдаңыз (бірдей жағынан жұмыс жасаңыз)."), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index e96061729..16f1a5ff3 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland wymaga Ubuntu 21.04 lub nowszego."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland wymaga wyższej wersji dystrybucji Linuksa. Wypróbuj pulpit X11 lub zmień system operacyjny."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Wybierz ekran do udostępnienia (działaj po stronie równorzędnej)."), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index e17967998..ea90329a5 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland requer Ubuntu 21.04 ou versão superior."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland requer uma versão superior da distribuição linux. Por favor, tente o desktop X11 ou mude seu sistema operacional."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Por favor, selecione a tela a ser compartilhada (operar no lado do peer)."), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index c2965405d..8a6280aed 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", ""), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", ""), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 95c59dede..5fe9c89ec 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland требует Ubuntu 21.04 или более позднюю версию."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Для Wayland требуется более поздняя версия дистрибутива Linux. Пожалуйста, попробуйте рабочий стол X11 или смените ОС."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Пожалуйста, выберите экран для совместного использования (работайте на одноранговой стороне)."), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 5064e1069..23c8b7220 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland vyžaduje Ubuntu 21.04 alebo vyššiu verziu."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland vyžaduje vyššiu verziu linuxovej distribúcie. Skúste X11 desktop alebo zmeňte OS."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Vyberte obrazovku, ktorú chcete zdieľať (Ovládajte na strane partnera)."), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index e08a2ba76..6d549b02a 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", ""), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", ""), + ("JumpLink", ""), + ("Please Select the screen to be shared(Operate on the peer side).", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 117a5683b..1cf50b2ca 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland, Ubuntu 21.04 veya daha yüksek bir sürüm gerektirir."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland, linux dağıtımının daha yüksek bir sürümünü gerektirir. Lütfen X11 masaüstünü deneyin veya işletim sisteminizi değiştirin."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Lütfen paylaşılacak ekranı seçiniz (Ekran tarafında çalıştırın)."), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index d0bce5d77..91d0ab169 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", "自定義"), ("Full Access", "完全訪問"), ("Screen Share", "僅共享屏幕"), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland 需要 Ubuntu 21.04 或更高版本。"), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland 需要更高版本的 linux 發行版。 請嘗試 X11 桌面或更改您的操作系統。"), + ("JumpLink", "查看"), + ("Please Select the screen to be shared(Operate on the peer side).", "請選擇要分享的畫面(在對端操作)。"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index f17e17a93..528b919b8 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland потребує Ubuntu 21.04 або новішої версії."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Для Wayland потрібна новіша версія дистрибутива Linux. Будь ласка, спробуйте робочий стіл X11 або змініть свою ОС."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Будь ласка, виберіть екран, до якого потрібно надати доступ (працюйте на стороні однорангового пристрою)."), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 30e32a82c..7f368126f 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -377,5 +377,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Custom", ""), ("Full Access", ""), ("Screen Share", ""), + ("Wayland requires Ubuntu 21.04 or higher version.", "Wayland yêu cầu phiên bản Ubuntu 21.04 trở lên."), + ("Wayland requires higher version of linux distro. Please try X11 desktop or change your OS.", "Wayland yêu cầu phiên bản distro linux cao hơn. Vui lòng thử máy tính để bàn X11 hoặc thay đổi hệ điều hành của bạn."), + ("JumpLink", "View"), + ("Please Select the screen to be shared(Operate on the peer side).", "Vui lòng Chọn màn hình để chia sẻ (Hoạt động ở phía ngang hàng)."), ].iter().cloned().collect(); } diff --git a/src/port_forward.rs b/src/port_forward.rs index 934743edc..f50f40db8 100644 --- a/src/port_forward.rs +++ b/src/port_forward.rs @@ -75,13 +75,13 @@ pub async fn listen( let interface = interface.clone(); tokio::spawn(async move { if let Err(err) = run_forward(forward, stream).await { - interface.msgbox("error", "Error", &err.to_string()); + interface.msgbox("error", "Error", &err.to_string(), ""); } log::info!("connection from {:?} closed", addr); }); } Err(err) => { - interface.msgbox("error", "Error", &err.to_string()); + interface.msgbox("error", "Error", &err.to_string(), ""); } _ => {} } diff --git a/src/server/connection.rs b/src/server/connection.rs index c451d5a1c..dca05e088 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -742,6 +742,10 @@ impl Connection { res.set_peer_info(pi); } else { try_activate_screen(); + if let Some(msg_out) = super::video_service::is_inited_msg() { + self.send(msg_out).await; + } + match super::video_service::get_displays().await { Err(err) => { res.set_error(format!("Error: {}", err)); diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 2b94077be..d43996559 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -39,6 +39,12 @@ use std::{ #[cfg(windows)] use virtual_display; +pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; +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"; + pub const NAME: &'static str = "video"; lazy_static::lazy_static! { @@ -569,7 +575,7 @@ fn run(sp: GenericService) -> ResultType<()> { { if !scrap::is_x11() { if would_block_count >= 100 { - // For now, the user should choose and agree screen sharing agiain. + // For now, the user should choose and agree screen sharing agiain. // to-do: Remember choice, attendless... super::wayland::release_resouce(); bail!("Wayland capturer none 100 times, try restart captuere"); @@ -747,6 +753,14 @@ pub(super) fn get_displays_2(all: &Vec) -> (usize, Vec) { (*lock, displays) } +pub fn is_inited_msg() -> Option { + #[cfg(target_os = "linux")] + if !scrap::is_x11() { + return super::wayland::is_inited(); + } + None +} + pub async fn get_displays() -> ResultType<(usize, Vec)> { #[cfg(target_os = "linux")] { diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 6d4a85399..8cf1623c5 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -3,11 +3,9 @@ use hbb_common::{allow_err, platform::linux::DISTRO}; use scrap::{set_map_err, Capturer, Display, Frame, TraitCapturer}; use std::io; -pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "Wayland requires Ubuntu 21.04 or higher version."; -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 is required"; -pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required"; +use super::video_service::{ + SCRAP_OTHER_VERSION_OR_X11_REQUIRED, SCRAP_UBUNTU_HIGHER_REQUIRED, SCRAP_X11_REQUIRED, +}; lazy_static::lazy_static! { static ref CAP_DISPLAY_INFO: RwLock = RwLock::new(0); @@ -26,7 +24,10 @@ fn map_err_scrap(err: String) -> io::Error { // std::process::exit(-1); // } - log::error!("REMOVE ME ===================================== wayland scrap error {}", &err); + log::error!( + "REMOVE ME ===================================== wayland scrap error {}", + &err + ); if DISTRO.name.to_uppercase() == "Ubuntu".to_uppercase() { if DISTRO.version_id < "21".to_owned() { @@ -93,6 +94,27 @@ pub(super) async fn ensure_inited() -> ResultType<()> { check_init().await } +pub(super) fn is_inited() -> Option { + if scrap::is_x11() { + None + } else { + if *CAP_DISPLAY_INFO.read().unwrap() == 0 { + let mut msg_out = Message::new(); + let res = MessageBox { + msgtype: "nook-nocancel-hasclose".to_owned(), + title: "Wayland".to_owned(), + text: "Please Select the screen to be shared(Operate on the peer side).".to_owned(), + link: "".to_owned(), + ..Default::default() + }; + msg_out.set_message_box(res); + Some(msg_out) + } else { + None + } + } +} + async fn check_init() -> ResultType<()> { if !scrap::is_x11() { let mut minx = 0; diff --git a/src/ui/common.tis b/src/ui/common.tis index 69e5565f0..e591f45a3 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -232,7 +232,7 @@ class ChatBox: Reactor.Component { /******************** start of msgbox ****************************************/ var remember_password = false; -function msgbox(type, title, content, callback=null, height=180, width=500, hasRetry=false, contentStyle="") { +function msgbox(type, title, content, link, callback=null, height=180, width=500, hasRetry=false, contentStyle="") { $(body).scrollTo(0, 0); if (!type) { closeMsgbox(); @@ -264,21 +264,21 @@ function msgbox(type, title, content, callback=null, height=180, width=500, hasR } else if (type.indexOf("custom") < 0 && !is_port_forward && !callback) { callback = function() { view.close(); } } - $(#msgbox).content(); + $(#msgbox).content(); } function connecting() { handler.msgbox("connecting", "Connecting...", "Connection in progress. Please wait."); } -handler.msgbox = function(type, title, text, hasRetry=false) { +handler.msgbox = function(type, title, text, link = "", hasRetry=false) { // crash somehow (when input wrong password), even with small time, for example, 1ms - self.timer(60ms, function() { msgbox(type, title, text, null, 180, 500, hasRetry); }); + self.timer(60ms, function() { msgbox(type, title, text, link, null, 180, 500, hasRetry); }); } var reconnectTimeout = 1000; -handler.msgbox_retry = function(type, title, text, hasRetry) { - handler.msgbox(type, title, text, hasRetry); +handler.msgbox_retry = function(type, title, text, link, hasRetry) { + handler.msgbox(type, title, text, link, hasRetry); if (hasRetry) { self.timer(0, retryConnect); self.timer(reconnectTimeout, retryConnect); diff --git a/src/ui/msgbox.tis b/src/ui/msgbox.tis index 7d1430cb0..3f40c367d 100644 --- a/src/ui/msgbox.tis +++ b/src/ui/msgbox.tis @@ -1,3 +1,5 @@ +import * as env from "@env"; + function translate_text(text) { if (text.indexOf('Failed') == 0 && text.indexOf(': ') > 0) { var fds = text.split(': '); @@ -22,6 +24,7 @@ class MsgboxComponent: Reactor.Component { this.type = params.type; this.title = params.title; this.content = params.content; + this.link = params.link; this.remember = params.remember; this.callback = params.callback; this.hasRetry = params.hasRetry; @@ -93,6 +96,7 @@ class MsgboxComponent: Reactor.Component { var content = this.getContent(); var hasCancel = this.type.indexOf("error") < 0 && this.type.indexOf("nocancel") < 0 && this.type != "restarting"; var hasOk = this.type != "connecting" && this.type != "success" && this.type.indexOf("nook") < 0; + var hasLink = this.link != ""; var hasClose = this.type.indexOf("hasclose") >= 0; var show_progress = this.type == "connecting"; var me = this; @@ -121,6 +125,7 @@ class MsgboxComponent: Reactor.Component { {hasCancel || this.hasRetry ? : ""} {this.hasSkip() ? : ""} {hasOk || this.hasRetry ? : ""} + {hasLink ? : ""} {hasClose ? : ""} @@ -155,6 +160,13 @@ class MsgboxComponent: Reactor.Component { if (this.callback) this.callback(values); if (this.close) this.close(); } + + event click $(button#jumplink) { + stdout.println("REMOVE ME ================================= jump link" + this.link); + if (this.link.indexOf("http") == 0) { + env.launch(this.link); + } + } event click $(button#submit) { if (this.type == "error") { diff --git a/src/ui/remote.rs b/src/ui/remote.rs index b3f443dda..dfd6394a5 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -238,8 +238,8 @@ impl InvokeUiSession for SciterHandler { self.call("updatePi", &make_args!(pi_sciter)); } - fn msgbox(&self, msgtype: &str, title: &str, text: &str, retry: bool) { - self.call2("msgbox_retry", &make_args!(msgtype, title, text, retry)); + fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool) { + self.call2("msgbox_retry", &make_args!(msgtype, title, text, link, retry)); } fn new_message(&self, msg: String) { diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index f5cc0499d..cf550ed63 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -1088,7 +1088,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default { fn job_progress(&self, id: i32, file_num: i32, speed: f64, finished_size: f64); fn adapt_size(&self); fn on_rgba(&self, data: &[u8]); - fn msgbox(&self, msgtype: &str, title: &str, text: &str, retry: bool); + fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str, retry: bool); #[cfg(any(target_os = "android", target_os = "ios"))] fn clipboard(&self, content: String); } @@ -1137,9 +1137,9 @@ impl Interface for Session { self.lc.read().unwrap().conn_type.eq(&ConnType::RDP) } - fn msgbox(&self, msgtype: &str, title: &str, text: &str) { + fn msgbox(&self, msgtype: &str, title: &str, text: &str, link: &str) { let retry = check_if_retry(msgtype, title, text); - self.ui_handler.msgbox(msgtype, title, text, retry); + self.ui_handler.msgbox(msgtype, title, text, link, retry); } fn handle_login_error(&mut self, err: &str) -> bool { @@ -1164,7 +1164,7 @@ impl Interface for Session { if pi.displays.is_empty() { self.lc.write().unwrap().handle_peer_info(&pi); self.update_privacy_mode(); - self.msgbox("error", "Remote Error", "No Display"); + self.msgbox("error", "Remote Error", "No Display", ""); return; } let p = self.lc.read().unwrap().should_auto_login(); @@ -1181,7 +1181,7 @@ impl Interface for Session { if self.is_file_transfer() { self.close_success(); } else if !self.is_port_forward() { - self.msgbox("success", "Successful", "Connected, waiting for image..."); + self.msgbox("success", "Successful", "Connected, waiting for image...", ""); } #[cfg(windows)] { From 9385e95b4eb653581184ae81e4cce92a4505363c Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Oct 2022 09:41:02 +0800 Subject: [PATCH 07/11] debug msgbox in sciter ui Signed-off-by: fufesou --- src/server/connection.rs | 2 +- src/ui/ab.tis | 50 ++++++++++++++++++++++------------------ src/ui/common.tis | 2 +- src/ui/file_transfer.tis | 8 +++---- src/ui/header.tis | 20 ++++++++++------ src/ui/index.tis | 18 +++++++-------- src/ui/msgbox.tis | 5 +--- 7 files changed, 57 insertions(+), 48 deletions(-) diff --git a/src/server/connection.rs b/src/server/connection.rs index dca05e088..e865a8b4f 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -748,7 +748,7 @@ impl Connection { match super::video_service::get_displays().await { Err(err) => { - res.set_error(format!("Error: {}", err)); + res.set_error(format!("{}", err)); } Ok((current, displays)) => { pi.displays = displays.into(); diff --git a/src/ui/ab.tis b/src/ui/ab.tis index ac2efb7dd..acee472a8 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -76,28 +76,34 @@ class AddressBook: Reactor.Component event click $(#add-id) (_, __) { var me = this; - msgbox("custom-add-id", translate("Add ID"),
+ msgbox( + "custom-add-id", + translate("Add ID"), +
{translate("whitelist_sep")}
-
, function(res=null) { - if (!res) return; - var value = (res.text || "").trim(); - var values = value.split(/[\s,;\n]+/g); - if (values.length == 0) return; - for (var v in values) { - var found; - for (var i = 0; i < ab.peers.length; ++i) { - if (ab.peers[i].id == v) { - found = true; - break; +
, + "", + function(res=null) { + if (!res) return; + var value = (res.text || "").trim(); + var values = value.split(/[\s,;\n]+/g); + if (values.length == 0) return; + for (var v in values) { + var found; + for (var i = 0; i < ab.peers.length; ++i) { + if (ab.peers[i].id == v) { + found = true; + break; + } } + if (found) continue; + ab.peers.push({ id: v }); } - if (found) continue; - ab.peers.push({ id: v }); - } - updateAb(); - me.update(); - }, 300); + updateAb(); + me.update(); + }, + 300); } event click $(#add-tag) (_, __) { @@ -105,7 +111,7 @@ class AddressBook: Reactor.Component msgbox("custom-add-tag", translate("Add Tag"),
{translate("whitelist_sep")}
-
, function(res=null) { + , "", function(res=null) { if (!res) return; var value = (res.text || "").trim(); var values = value.split(/[\s,;\n]+/g); @@ -483,7 +489,7 @@ class SessionList: Reactor.Component { msgbox("custom-rename", "Rename", "
\
\
\ - ", function(res=null) { + ", "", function(res=null) { if (!res) return; var name = (res.name || "").trim(); if (name != old_name) { @@ -506,7 +512,7 @@ class SessionList: Reactor.Component { } } if (!peer) return; - msgbox("custom-edit-tag", "Edit Tag", , function(res=null) { + msgbox("custom-edit-tag", "Edit Tag", , "", function(res=null) { if (!res) return; peer.tags = selectTags.tags; updateAb(); @@ -738,7 +744,7 @@ function editRdpPort() {
{translate('Port')}:{port}
{translate('Username')}:
{translate('Password')}:
- , function(res=null) { + , "", function(res=null) { if (!res) return; var p = (res.port || '').trim(); if (p != p0) { diff --git a/src/ui/common.tis b/src/ui/common.tis index e591f45a3..76e0fb84e 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -232,7 +232,7 @@ class ChatBox: Reactor.Component { /******************** start of msgbox ****************************************/ var remember_password = false; -function msgbox(type, title, content, link, callback=null, height=180, width=500, hasRetry=false, contentStyle="") { +function msgbox(type, title, content, link="", callback=null, height=180, width=500, hasRetry=false, contentStyle="") { $(body).scrollTo(0, 0); if (!type) { closeMsgbox(); diff --git a/src/ui/file_transfer.tis b/src/ui/file_transfer.tis index 38c6321dc..451117403 100644 --- a/src/ui/file_transfer.tis +++ b/src/ui/file_transfer.tis @@ -535,7 +535,7 @@ class FolderView : Reactor.Component { msgbox("custom", translate("Create Folder"), "
\
" + translate("Please enter the folder name") + ":
\
\ -
", function(res=null) { + ", "", function(res=null) { if (!res) return; if (!res.name) return; var name = res.name.trim(); @@ -716,7 +716,7 @@ function confirmDelete(id ,path, is_remote) { msgbox("custom-skip", "Confirm Delete", "
\
" + translate('Are you sure you want to delete this file?') + "
\ " + path + "
\ - ", function(res=null) { + ", "", function(res=null) { if (!res) { file_transfer.job_table.updateJobStatus(id, -1, "cancel"); file_transfer.job_table.cancelDeletePolling(); @@ -746,7 +746,7 @@ handler.confirmDeleteFiles = function(id, i, name) {
" + translate('Are you sure you want to delete this file?') + "
\ " + file_path + " \
" + translate('Do this for all conflicts') + "
\ - ", function(res=null) { + ", "", function(res=null) { if (!res) { jt.updateJobStatus(id, i - 1, "cancel"); file_transfer.job_table.cancelDeletePolling(); @@ -778,7 +778,7 @@ handler.overrideFileConfirm = function(id, file_num, to, is_upload) {
" + translate('This file exists, skip or overwrite this file?') + "
\ " + to + " \
" + translate('Do this for all conflicts') + "
\ - ", function(res=null) { + ", "", function(res=null) { if (!res) { jt.updateJobStatus(id, -1, "cancel"); handler.cancel_job(id); diff --git a/src/ui/header.tis b/src/ui/header.tis index 8f9fa8a32..01699a583 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -78,7 +78,7 @@ class EditOsPassword: Reactor.Component { function editOSPassword(login=false) { var p0 = handler.get_option('os-password'); - msgbox("custom-os-password", 'OS Password', p0, function(res=null) { + msgbox("custom-os-password", 'OS Password', p0, "", function(res=null) { if (!res) return; var a0 = handler.get_option('auto-login') != ''; var p = (res.password || '').trim(); @@ -320,7 +320,7 @@ class Header: Reactor.Component { var self = this; msgbox("custom", "Note",
-
, function(res=null) { + , "", function(res=null) { if (!res) return; if (!res.text) return; self.conn_note = res.text; @@ -333,9 +333,15 @@ class Header: Reactor.Component { } event click $(#restart_remote_device) { - msgbox("restart-confirmation", translate("Restart Remote Device"), translate("Are you sure you want to restart") + " " + pi.username + "@" + pi.hostname + "(" + get_id() + ") ?", function(res=null) { - if (res != null) handler.restart_remote_device(); - }); + msgbox( + "restart-confirmation", + translate("Restart Remote Device"), + translate("Are you sure you want to restart") + " " + pi.username + "@" + pi.hostname + "(" + get_id() + ") ?", + "", + function(res=null) { + if (res != null) handler.restart_remote_device(); + } + ); } event click $(#lock-screen) { @@ -400,7 +406,7 @@ function handle_custom_image_quality() { var bitrate = (tmp[0] || 50); msgbox("custom", "Custom Image Quality", "
\
x% Bitrate
\ -
", function(res=null) { + ", "", function(res=null) { if (!res) return; if (!res.bitrate) return; handler.save_custom_image_quality(res.bitrate); @@ -489,7 +495,7 @@ handler.updatePrivacyMode = updatePrivacyMode; function togglePrivacyMode(privacy_id) { var supported = handler.is_privacy_mode_supported(); if (!supported) { - msgbox("nocancel", translate("Privacy mode"), translate("Unsupported"), function() { }); + msgbox("nocancel", translate("Privacy mode"), translate("Unsupported"), "", function() { }); } else { handler.toggle_option(privacy_id); } diff --git a/src/ui/index.tis b/src/ui/index.tis index a2d895733..45e881096 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -247,7 +247,7 @@ class Enhancements: Reactor.Component {
- , function(res=null) { + , "", function(res=null) { if (!res) return; handler.set_option("enable-record-session", res.enable_record_session ? '' : 'N'); handler.set_option("allow-auto-record-incoming", res.auto_record_incoming ? 'Y' : ''); @@ -369,7 +369,7 @@ class MyIdMenu: Reactor.Component {
" + handler.get_license() + " \

Made with heart in this chaotic world!

\ \ - ", function(el) { + ", "", function(el) { if (el && el.attributes) { handler.open_url(el.attributes['url']); }; @@ -389,7 +389,7 @@ class MyIdMenu: Reactor.Component {
" + translate("whitelist_sep") + "
\ \ \ - ", function(res=null) { + ", "", function(res=null) { if (!res) return; var value = (res.text || "").trim(); if (value) { @@ -417,7 +417,7 @@ class MyIdMenu: Reactor.Component {
" + translate("API Server") + ":
\
" + translate("Key") + ":
\ \ - ", function(res=null) { + ", "", function(res=null) { if (!res) return; var id = (res.id || "").trim(); var relay = (res.relay || "").trim(); @@ -453,7 +453,7 @@ class MyIdMenu: Reactor.Component {
{translate("Username")}:
{translate("Password")}:
- , function(res=null) { + , "", function(res=null) { if (!res) return; var proxy = (res.proxy || "").trim(); var username = (res.username || "").trim(); @@ -474,7 +474,7 @@ class MyIdMenu: Reactor.Component {
" + translate('id_change_tip') + "
\
ID:
\ \ - ", function(res=null, show_progress) { + ", "", function(res=null, show_progress) { if (!res) return; show_progress(); var id = (res.id || "").trim(); @@ -520,7 +520,7 @@ function editDirectAccessPort() { ; msgbox("custom-direct-access-port", translate('Direct IP Access Settings'),
{translate('Port')}:{port}
-
, function(res=null) { + , "", function(res=null) { if (!res) return; var p = (res.port || '').trim(); if (p) { @@ -934,7 +934,7 @@ class PasswordArea: Reactor.Component {
" + translate('Password') + ":
\
" + translate('Confirmation') + ":
\ \ - ", function(res=null) { + ", "", function(res=null) { if (!res) return; var p0 = (res.password || "").trim(); var p1 = (res.confirmation || "").trim(); @@ -1161,7 +1161,7 @@ function login() { msgbox("custom-login", translate('Login'),
{translate('Username')}:
{translate('Password')}:
-
, function(res=null, show_progress) { + , "", function(res=null, show_progress) { if (!res) return; show_progress(); var name = (res.username || '').trim(); diff --git a/src/ui/msgbox.tis b/src/ui/msgbox.tis index 3f40c367d..d5c60d95c 100644 --- a/src/ui/msgbox.tis +++ b/src/ui/msgbox.tis @@ -1,5 +1,3 @@ -import * as env from "@env"; - function translate_text(text) { if (text.indexOf('Failed') == 0 && text.indexOf(': ') > 0) { var fds = text.split(': '); @@ -162,9 +160,8 @@ class MsgboxComponent: Reactor.Component { } event click $(button#jumplink) { - stdout.println("REMOVE ME ================================= jump link" + this.link); if (this.link.indexOf("http") == 0) { - env.launch(this.link); + Sciter.launch(this.link); } } From c48ed06d93b0ca072e9f4db605c2a849fcbb37fd Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Oct 2022 03:06:06 -0700 Subject: [PATCH 08/11] wayland: remove user service Signed-off-by: fufesou --- build.py | 6 - res/DEBIAN/postinst | 9 -- res/DEBIAN/preinst | 7 -- res/DEBIAN/prerm | 5 +- res/rustdesk.service.user | 15 --- src/platform/linux.rs | 229 +++++++++++++++++++------------------- 6 files changed, 117 insertions(+), 154 deletions(-) delete mode 100644 res/rustdesk.service.user diff --git a/build.py b/build.py index dbc4f6255..0cf62daf1 100755 --- a/build.py +++ b/build.py @@ -161,8 +161,6 @@ def build_flutter_deb(version): 'cp -r build/linux/x64/release/bundle/* tmpdeb/usr/lib/rustdesk/') os.system( 'cp ../res/rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/') - os.system( - 'cp ../res/rustdesk.service.user tmpdeb/usr/share/rustdesk/files/systemd/') os.system( 'cp ../res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png') os.system( @@ -177,7 +175,6 @@ def build_flutter_deb(version): generate_control_file(version) os.system('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/') md5_file('usr/share/rustdesk/files/systemd/rustdesk.service') - md5_file('usr/share/rustdesk/files/systemd/rustdesk.service.user') os.system('dpkg-deb -b tmpdeb rustdesk.deb;') os.system('/bin/rm -rf tmpdeb/') @@ -331,8 +328,6 @@ def main(): os.system('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/') os.system( 'cp res/rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/') - os.system( - 'cp res/rustdesk.service.user tmpdeb/usr/share/rustdesk/files/systemd/') os.system( 'cp res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png') os.system( @@ -345,7 +340,6 @@ def main(): os.system('mv tmpdeb/usr/bin/rustdesk tmpdeb/usr/lib/rustdesk/') os.system('cp libsciter-gtk.so tmpdeb/usr/lib/rustdesk/') md5_file('usr/share/rustdesk/files/systemd/rustdesk.service') - md5_file('usr/share/rustdesk/files/systemd/rustdesk.service.user') md5_file('usr/lib/rustdesk/libsciter-gtk.so') os.system('dpkg-deb -b tmpdeb rustdesk.deb; /bin/rm -rf tmpdeb/') os.rename('rustdesk.deb', 'rustdesk-%s.deb' % version) diff --git a/res/DEBIAN/postinst b/res/DEBIAN/postinst index 95222564d..5b37e2f51 100755 --- a/res/DEBIAN/postinst +++ b/res/DEBIAN/postinst @@ -19,14 +19,5 @@ if [ "$1" = configure ]; then systemctl daemon-reload systemctl enable rustdesk systemctl start rustdesk - - cp /usr/share/rustdesk/files/systemd/rustdesk.service.user /usr/lib/systemd/user/rustdesk.service - ubuntuVersion=$(grep -oP 'VERSION_ID="\K[\d]+' /etc/os-release | bc -l) - waylandSupportVersion=21 - if [ "$ubuntuVersion" -ge "$waylandSupportVersion" ] - then - curUser=$(who | awk '{print $1}' | head -1) - systemctl --machine=${curUser}@.host --user daemon-reload - fi fi fi diff --git a/res/DEBIAN/preinst b/res/DEBIAN/preinst index 7fbedca4a..8b73e9962 100755 --- a/res/DEBIAN/preinst +++ b/res/DEBIAN/preinst @@ -7,13 +7,6 @@ case $1 in INITSYS=$(ls -al /proc/1/exe | awk -F' ' '{print $NF}' | awk -F'/' '{print $NF}') if [ "systemd" == "${INITSYS}" ]; then service rustdesk stop || true - - serverUser=$(ps -ef | grep -E 'rustdesk +--server' | awk '{print $1}' | head -1) - if [ "$serverUser" != "" ] && [ "$serverUser" != "root" ] - then - systemctl --machine=${serverUser}@.host --user stop rustdesk || true - fi - sleep 1 rm -rf /usr/bin/libsciter-gtk.so fi diff --git a/res/DEBIAN/prerm b/res/DEBIAN/prerm index e9e3931ac..6d5026991 100755 --- a/res/DEBIAN/prerm +++ b/res/DEBIAN/prerm @@ -11,7 +11,9 @@ case $1 in systemctl stop rustdesk || true systemctl disable rustdesk || true + rm /etc/systemd/system/rustdesk.service /usr/lib/systemd/system/rustdesk.service || true + # workaround temp dev build between 1.1.9 and 1.2.0 serverUser=$(ps -ef | grep -E 'rustdesk +--server' | awk '{print $1}' | head -1) ubuntuVersion=$(grep -oP 'VERSION_ID="\K[\d]+' /etc/os-release | bc -l) waylandSupportVersion=21 @@ -19,8 +21,7 @@ case $1 in then systemctl --machine=${serverUser}@.host --user stop rustdesk || true fi - - rm /etc/systemd/system/rustdesk.service /usr/lib/systemd/system/rustdesk.service /usr/lib/systemd/user/rustdesk.service || true + rm /usr/lib/systemd/user/rustdesk.service >/dev/null 2>/dev/null || true fi ;; esac diff --git a/res/rustdesk.service.user b/res/rustdesk.service.user deleted file mode 100644 index f6c7454c9..000000000 --- a/res/rustdesk.service.user +++ /dev/null @@ -1,15 +0,0 @@ -[Unit] -Description=RustDesk user service (--server) - -[Service] -Type=simple -ExecStart=/usr/bin/rustdesk --server -PIDFile=/run/rustdesk.user.pid -KillMode=mixed -TimeoutStopSec=30 -LimitNOFILE=100000 -Restart=on-failure -RestartSec=3 - -[Install] -WantedBy=multi-user.target diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 5ff69d732..2efe06faf 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -161,45 +161,6 @@ fn start_uinput_service() { }); } -fn try_start_user_service(username: &str) { - if username == "" || username == "root" { - return; - } - - if let Ok(mut cur_username) = - run_cmds("ps -ef | grep -E 'rustdesk +--server' | awk '{print $1}' | head -1".to_owned()) - { - cur_username = cur_username.trim().to_owned(); - if cur_username != "root" && cur_username != username { - let _ = run_cmds(format!( - "systemctl --machine={}@.host --user stop rustdesk", - &cur_username - )); - } else if cur_username == username { - return; - } - } - - let _ = run_cmds(format!( - "systemctl --machine={}@.host --user start rustdesk", - username - )); -} - -fn try_stop_user_service() { - if let Ok(mut username) = - run_cmds("ps -ef | grep -E 'rustdesk +--server' | awk '{print $1}' | head -1".to_owned()) - { - username = username.trim().to_owned(); - if username != "root" { - let _ = run_cmds(format!( - "systemctl --machine={}@.host --user stop rustdesk", - &username - )); - } - } -} - fn stop_server(server: &mut Option) { if let Some(mut ps) = server.take() { allow_err!(ps.kill()); @@ -214,13 +175,106 @@ fn stop_server(server: &mut Option) { } } +fn set_x11_env(uid: &str) { + log::info!("uid of seat0: {}", uid); + let gdm = format!("/run/user/{}/gdm/Xauthority", uid); + let mut auth = get_env_tries("XAUTHORITY", uid, 10); + if auth.is_empty() { + auth = if std::path::Path::new(&gdm).exists() { + gdm + } else { + let username = get_active_username(); + if username == "root" { + format!("/{}/.Xauthority", username) + } else { + let tmp = format!("/home/{}/.Xauthority", username); + if std::path::Path::new(&tmp).exists() { + tmp + } else { + format!("/var/lib/{}/.Xauthority", username) + } + } + }; + } + let mut d = get_env("DISPLAY", uid); + if d.is_empty() { + d = get_display(); + } + if d.is_empty() { + d = ":0".to_owned(); + } + d = d.replace(&whoami::hostname(), "").replace("localhost", ""); + log::info!("DISPLAY: {}", d); + log::info!("XAUTHORITY: {}", auth); + std::env::set_var("XAUTHORITY", auth); + std::env::set_var("DISPLAY", d); +} + +fn stop_rustdesk_servers() { + let _ = run_cmds(format!( + r##"ps -ef | grep -E 'rustdesk +--server' | awk '{{printf("kill -9 %d\n", $2)}}' | bash"##, + )); +} + +fn should_start_server( + try_x11: bool, + uid: &mut String, + cm0: &mut bool, + last_restart: &mut std::time::Instant, + server: &mut Option, +) -> bool { + let cm = get_cm(); + let tmp = get_active_userid(); + let mut start_new = false; + if tmp != *uid && !tmp.is_empty() { + *uid = tmp; + if try_x11 { + set_x11_env(&uid); + } + if let Some(ps) = server.as_mut() { + allow_err!(ps.kill()); + std::thread::sleep(std::time::Duration::from_millis(30)); + *last_restart = std::time::Instant::now(); + } + } else if !cm + && ((*cm0 && last_restart.elapsed().as_secs() > 60) + || last_restart.elapsed().as_secs() > 3600) + { + // restart server if new connections all closed, or every one hour, + // as a workaround to resolve "SpotUdp" (dns resolve) + // and x server get displays failure issue + if let Some(ps) = server.as_mut() { + allow_err!(ps.kill()); + std::thread::sleep(std::time::Duration::from_millis(30)); + *last_restart = std::time::Instant::now(); + log::info!("restart server"); + } + } + if let Some(ps) = server.as_mut() { + match ps.try_wait() { + Ok(Some(_)) => { + *server = None; + start_new = true; + } + _ => {} + } + } else { + start_new = true; + } + *cm0 = cm; + start_new +} + pub fn start_os_service() { + stop_rustdesk_servers(); + start_uinput_service(); let running = Arc::new(AtomicBool::new(true)); let r = running.clone(); let mut uid = "".to_owned(); let mut server: Option = None; + let mut user_server: Option = None; if let Err(err) = ctrlc::set_handler(move || { r.store(false, Ordering::SeqCst); }) { @@ -234,78 +288,9 @@ pub fn start_os_service() { let is_wayland = current_is_wayland(); if username == "root" || !is_wayland { - // try stop user service - try_stop_user_service(); - + stop_server(&mut user_server); // try start subprocess "--server" - let cm = get_cm(); - let tmp = get_active_userid(); - let mut start_new = false; - if tmp != uid && !tmp.is_empty() { - uid = tmp; - log::info!("uid of seat0: {}", uid); - let gdm = format!("/run/user/{}/gdm/Xauthority", uid); - let mut auth = get_env_tries("XAUTHORITY", &uid, 10); - if auth.is_empty() { - auth = if std::path::Path::new(&gdm).exists() { - gdm - } else { - let username = get_active_username(); - if username == "root" { - format!("/{}/.Xauthority", username) - } else { - let tmp = format!("/home/{}/.Xauthority", username); - if std::path::Path::new(&tmp).exists() { - tmp - } else { - format!("/var/lib/{}/.Xauthority", username) - } - } - }; - } - let mut d = get_env("DISPLAY", &uid); - if d.is_empty() { - d = get_display(); - } - if d.is_empty() { - d = ":0".to_owned(); - } - d = d.replace(&whoami::hostname(), "").replace("localhost", ""); - log::info!("DISPLAY: {}", d); - log::info!("XAUTHORITY: {}", auth); - std::env::set_var("XAUTHORITY", auth); - std::env::set_var("DISPLAY", d); - if let Some(ps) = server.as_mut() { - allow_err!(ps.kill()); - std::thread::sleep(std::time::Duration::from_millis(30)); - last_restart = std::time::Instant::now(); - } - } else if !cm - && ((cm0 && last_restart.elapsed().as_secs() > 60) - || last_restart.elapsed().as_secs() > 3600) - { - // restart server if new connections all closed, or every one hour, - // as a workaround to resolve "SpotUdp" (dns resolve) - // and x server get displays failure issue - if let Some(ps) = server.as_mut() { - allow_err!(ps.kill()); - std::thread::sleep(std::time::Duration::from_millis(30)); - last_restart = std::time::Instant::now(); - log::info!("restart server"); - } - } - if let Some(ps) = server.as_mut() { - match ps.try_wait() { - Ok(Some(_)) => { - server = None; - start_new = true; - } - _ => {} - } - } else { - start_new = true; - } - if start_new { + if should_start_server(true, &mut uid, &mut cm0, &mut last_restart, &mut server) { match crate::run_me(vec!["--server"]) { Ok(ps) => server = Some(ps), Err(err) => { @@ -313,23 +298,37 @@ pub fn start_os_service() { } } } - cm0 = cm; } else if username != "" { if username != "gdm" { // try kill subprocess "--server" stop_server(&mut server); - // try start user service - try_start_user_service(&username); + // try start subprocess "--server" + if should_start_server( + false, + &mut uid, + &mut cm0, + &mut last_restart, + &mut user_server, + ) { + match run_as_user("--server") { + Ok(ps) => user_server = ps, + Err(err) => { + log::error!("Failed to start server: {}", err); + } + } + } } } else { - try_stop_user_service(); + stop_server(&mut user_server); stop_server(&mut server); } std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL)); } - try_stop_user_service(); + if let Some(ps) = user_server.take().as_mut() { + allow_err!(ps.kill()); + } if let Some(ps) = server.take().as_mut() { allow_err!(ps.kill()); } From 9a9a8197aec79ba97229127bfb3310c38d414da6 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Oct 2022 07:55:14 -0700 Subject: [PATCH 09/11] fix linux uid username mismatch Signed-off-by: fufesou --- libs/hbb_common/src/platform/linux.rs | 40 ++++++++++++++-------- src/platform/linux.rs | 49 ++++++++++++++++++--------- src/server/connection.rs | 9 ++++- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/libs/hbb_common/src/platform/linux.rs b/libs/hbb_common/src/platform/linux.rs index 0473a3bbc..1a20ed0e1 100644 --- a/libs/hbb_common/src/platform/linux.rs +++ b/libs/hbb_common/src/platform/linux.rs @@ -27,7 +27,18 @@ impl Disto { } pub fn get_display_server() -> String { - let session = get_value_of_seat0(0); + let mut session = get_values_of_seat0([0].to_vec())[0].clone(); + if session.is_empty() { + // loginctl has not given the expected output. try something else. + if let Ok(sid) = std::env::var("XDG_SESSION_ID") { + // could also execute "cat /proc/self/sessionid" + session = sid.to_owned(); + } + if session.is_empty() { + session = run_cmds("cat /proc/self/sessionid".to_owned()).unwrap_or_default(); + } + } + get_display_server_of_session(&session) } @@ -77,15 +88,16 @@ fn get_display_server_of_session(session: &str) -> String { } } -pub fn get_value_of_seat0(i: usize) -> String { +pub fn get_values_of_seat0(indices: Vec) -> Vec { if let Ok(output) = run_loginctl(None) { for line in String::from_utf8_lossy(&output.stdout).lines() { if line.contains("seat0") { if let Some(sid) = line.split_whitespace().nth(0) { if is_active(sid) { - if let Some(uid) = line.split_whitespace().nth(i) { - return uid.to_owned(); - } + return indices + .into_iter() + .map(|idx| line.split_whitespace().nth(idx).unwrap_or("").to_owned()) + .collect::>(); } } } @@ -98,21 +110,19 @@ pub fn get_value_of_seat0(i: usize) -> String { if let Some(sid) = line.split_whitespace().nth(0) { let d = get_display_server_of_session(sid); if is_active(sid) && d != "tty" { - if let Some(uid) = line.split_whitespace().nth(i) { - return uid.to_owned(); - } + return indices + .into_iter() + .map(|idx| line.split_whitespace().nth(idx).unwrap_or("").to_owned()) + .collect::>(); } } } } - // loginctl has not given the expected output. try something else. - if let Ok(sid) = std::env::var("XDG_SESSION_ID") { - // could also execute "cat /proc/self/sessionid" - return sid.to_owned(); - } - - return "".to_owned(); + return indices + .iter() + .map(|_x| "".to_owned()) + .collect::>(); } fn is_active(sid: &str) -> bool { diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 2efe06faf..b72c15f54 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -219,15 +219,15 @@ fn stop_rustdesk_servers() { fn should_start_server( try_x11: bool, uid: &mut String, + cur_uid: String, cm0: &mut bool, last_restart: &mut std::time::Instant, server: &mut Option, ) -> bool { let cm = get_cm(); - let tmp = get_active_userid(); let mut start_new = false; - if tmp != *uid && !tmp.is_empty() { - *uid = tmp; + if cur_uid != *uid && !cur_uid.is_empty() { + *uid = cur_uid; if try_x11 { set_x11_env(&uid); } @@ -267,7 +267,6 @@ fn should_start_server( pub fn start_os_service() { stop_rustdesk_servers(); - start_uinput_service(); let running = Arc::new(AtomicBool::new(true)); @@ -284,13 +283,20 @@ pub fn start_os_service() { let mut cm0 = false; let mut last_restart = std::time::Instant::now(); while running.load(Ordering::SeqCst) { - let username = get_active_username(); + let (cur_uid, cur_user) = get_active_user_id_name(); let is_wayland = current_is_wayland(); - if username == "root" || !is_wayland { + if cur_user == "root" || !is_wayland { stop_server(&mut user_server); // try start subprocess "--server" - if should_start_server(true, &mut uid, &mut cm0, &mut last_restart, &mut server) { + if should_start_server( + true, + &mut uid, + cur_uid, + &mut cm0, + &mut last_restart, + &mut server, + ) { match crate::run_me(vec!["--server"]) { Ok(ps) => server = Some(ps), Err(err) => { @@ -298,8 +304,8 @@ pub fn start_os_service() { } } } - } else if username != "" { - if username != "gdm" { + } else if cur_user != "" { + if cur_user != "gdm" { // try kill subprocess "--server" stop_server(&mut server); @@ -307,11 +313,12 @@ pub fn start_os_service() { if should_start_server( false, &mut uid, + cur_uid.clone(), &mut cm0, &mut last_restart, &mut user_server, ) { - match run_as_user("--server") { + match run_as_user("--server", Some((cur_uid, cur_user))) { Ok(ps) => user_server = ps, Err(err) => { log::error!("Failed to start server: {}", err); @@ -335,8 +342,13 @@ pub fn start_os_service() { log::info!("Exit"); } +pub fn get_active_user_id_name() -> (String, String) { + let vec_id_name = get_values_of_seat0([1, 2].to_vec()); + (vec_id_name[0].clone(), vec_id_name[1].clone()) +} + pub fn get_active_userid() -> String { - get_value_of_seat0(1) + get_values_of_seat0([1].to_vec())[0].clone() } fn get_cm() -> bool { @@ -513,7 +525,7 @@ fn _get_display_manager() -> String { } pub fn get_active_username() -> String { - get_value_of_seat0(2) + get_values_of_seat0([2].to_vec())[0].clone() } pub fn get_active_user_home() -> Option { @@ -545,12 +557,17 @@ fn is_opensuse() -> bool { false } -pub fn run_as_user(arg: &str) -> ResultType> { - let uid = get_active_userid(); +pub fn run_as_user( + arg: &str, + user: Option<(String, String)>, +) -> ResultType> { + let (uid, username) = match user { + Some(id_name) => id_name, + None => get_active_user_id_name(), + }; let cmd = std::env::current_exe()?; let xdg = &format!("XDG_RUNTIME_DIR=/run/user/{}", uid) as &str; - let username = &get_active_username(); - let mut args = vec![xdg, "-u", username, cmd.to_str().unwrap_or(""), arg]; + let mut args = vec![xdg, "-u", &username, cmd.to_str().unwrap_or(""), arg]; // -E required for opensuse if is_opensuse() { args.insert(0, "-E"); diff --git a/src/server/connection.rs b/src/server/connection.rs index e865a8b4f..4f122b59d 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1514,7 +1514,14 @@ async fn start_ipc( if crate::platform::is_root() { let mut res = Ok(None); for _ in 0..10 { - res = crate::platform::run_as_user("--cm"); + #[cfg(not(target_os = "linux"))] + { + res = crate::platform::run_as_user("--cm"); + } + #[cfg(target_os = "linux")] + { + res = crate::platform::run_as_user("--cm", None); + } if res.is_ok() { break; } From b2688da10f71878eabc9b8753912cf6e1bdbf742 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Oct 2022 08:17:03 -0700 Subject: [PATCH 10/11] workaround of handle subprocess from run_as_user Signed-off-by: fufesou --- src/platform/linux.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/platform/linux.rs b/src/platform/linux.rs index b72c15f54..508ad456c 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -297,6 +297,10 @@ pub fn start_os_service() { &mut last_restart, &mut server, ) { + // to-do: stop_server(&mut user_server); may not stop child correctly + // stop_rustdesk_servers() is just a temp solution here. + stop_rustdesk_servers(); + std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL)); match crate::run_me(vec!["--server"]) { Ok(ps) => server = Some(ps), Err(err) => { @@ -327,6 +331,7 @@ pub fn start_os_service() { } } } else { + stop_rustdesk_servers(); stop_server(&mut user_server); stop_server(&mut server); } From 2f33e9dfac4817c0072c77a104e47e51f2756080 Mon Sep 17 00:00:00 2001 From: fufesou Date: Mon, 17 Oct 2022 08:45:58 -0700 Subject: [PATCH 11/11] linux workaround --server orphan Signed-off-by: fufesou --- src/platform/linux.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 508ad456c..a02c4618b 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -322,6 +322,8 @@ pub fn start_os_service() { &mut last_restart, &mut user_server, ) { + stop_rustdesk_servers(); + std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL)); match run_as_user("--server", Some((cur_uid, cur_user))) { Ok(ps) => user_server = ps, Err(err) => { @@ -332,6 +334,7 @@ pub fn start_os_service() { } } else { stop_rustdesk_servers(); + std::thread::sleep(std::time::Duration::from_millis(super::SERVICE_INTERVAL)); stop_server(&mut user_server); stop_server(&mut server); }