From 5f190297a96486c6c554509388728c79fd24f093 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 21 Dec 2021 16:35:18 +0800 Subject: [PATCH 01/77] adjust #[warn(unreachable_code)] position --- libs/hbb_common/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index bf4dfb7da..cf80cd49b 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -274,8 +274,8 @@ impl Config { return "".into(); } + #[allow(unreachable_code)] pub fn log_path() -> PathBuf { - #[allow(unreachable_code)] #[cfg(target_os = "macos")] { if let Some(path) = dirs_next::home_dir().as_mut() { From 334c94ceb32fe0714c4b816f85883472014548e9 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 22 Dec 2021 14:28:08 +0800 Subject: [PATCH 02/77] https://github.com/rustdesk/rustdesk/issues/210 --- src/ui/common.tis | 7 +++++++ src/ui/index.tis | 6 +++--- src/ui/remote.tis | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/ui/common.tis b/src/ui/common.tis index 6af29ab02..679744439 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -311,3 +311,10 @@ function Progress() this.value = ""; } + +function isReasonableSize(r) { + var x = r[0]; + var y = r[1]; + return !(x < -3200 || x > 3200 || y < -3200 || y > 3200); +} + diff --git a/src/ui/index.tis b/src/ui/index.tis index 55fcf6f7c..5bffff322 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -708,10 +708,10 @@ function self.closing() { function self.ready() { var r = handler.get_size(); - if (r[2] == 0) { - centerize(800, 600); - } else { + if (isReasonableSize(r) && r[2] > 0) { view.move(r[0], r[1], r[2], r[3]); + } else { + centerize(800, 600); } if (!handler.get_remote_id()) { view.focus = $(#remote_id); diff --git a/src/ui/remote.tis b/src/ui/remote.tis index f78d8ec65..061fb5241 100644 --- a/src/ui/remote.tis +++ b/src/ui/remote.tis @@ -396,7 +396,7 @@ function self.ready() { var h = 640; if (is_file_transfer || is_port_forward) { var r = handler.get_size(); - if (r[0] > 0) { + if (isReasonableSize(r) && r[2] > 0) { view.move(r[0], r[1], r[2], r[3]); } else { centerize(w, h); @@ -418,7 +418,7 @@ handler.adaptSize = function() { var (fx, fy, fw, fh) = view.screenBox(#frame, #rectw); if (is_osx) workarea_offset = sy; var r = handler.get_size(); - if (r[2] > 0) { + if (isReasonableSize(r) && r[2] > 0) { if (r[2] >= fw && r[3] >= fh && !is_linux) { view.windowState = View.WINDOW_FULL_SCREEN; stdout.println("Initialize to full screen"); From dc724a30e7637060ac902310a3a215ec7c093db8 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 22 Dec 2021 14:56:10 +0800 Subject: [PATCH 03/77] https://github.com/rustdesk/rustdesk/issues/298 --- src/ui/common.css | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ui/common.css b/src/ui/common.css index 22fb9dc6d..94b16642b 100644 --- a/src/ui/common.css +++ b/src/ui/common.css @@ -156,9 +156,7 @@ header caption { top: 0; padding: 0 10px; width: 22px; - height: *; position: absolute; - margin: 0; color: black; border: none; background: none; From 26a4b1f3ebe9a8f4aa5eb95c5cb0400984364749 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 22 Dec 2021 16:51:33 +0800 Subject: [PATCH 04/77] comment on bias --- src/server/connection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/connection.rs b/src/server/connection.rs index 6ee09ca11..0782338e6 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -146,7 +146,7 @@ impl Connection { loop { tokio::select! { - biased; + biased; // video has higher priority Some(data) = rx_from_cm.recv() => { match data { From 252d3cb797311e73b2c552f3f49851fad8d5b930 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 23 Dec 2021 11:11:48 +0800 Subject: [PATCH 05/77] refactor --- src/server/connection.rs | 21 ++++++++++++--------- src/server/input_service.rs | 2 -- src/server/service.rs | 9 ++++----- src/server/video_service.rs | 7 +++---- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/server/connection.rs b/src/server/connection.rs index 0782338e6..0cebac601 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -62,15 +62,18 @@ impl Subscriber for ConnInner { #[inline] fn send(&mut self, msg: Arc) { - self.tx.as_mut().map(|tx| { - allow_err!(tx.send((Instant::now(), msg))); - }); - } - - fn send_video_frame(&mut self, tm: std::time::Instant, msg: Arc) { - self.tx_video.as_mut().map(|tx| { - allow_err!(tx.send((tm.into(), msg))); - }); + match &msg.union { + Some(message::Union::video_frame(_)) => { + self.tx_video.as_mut().map(|tx| { + allow_err!(tx.send((Instant::now(), msg))); + }); + } + _ => { + self.tx.as_mut().map(|tx| { + allow_err!(tx.send((Instant::now(), msg))); + }); + } + } } } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index aee13304b..056267c5b 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -79,8 +79,6 @@ impl Subscriber for MouseCursorSub { self.inner.send(msg); } } - - fn send_video_frame(&mut self, _: std::time::Instant, _: Arc) {} } pub const NAME_CURSOR: &'static str = "mouse_cursor"; diff --git a/src/server/service.rs b/src/server/service.rs index 7f280130f..9c146b047 100644 --- a/src/server/service.rs +++ b/src/server/service.rs @@ -16,7 +16,6 @@ pub trait Service: Send + Sync { pub trait Subscriber: Default + Send + Sync + 'static { fn id(&self) -> i32; fn send(&mut self, msg: Arc); - fn send_video_frame(&mut self, tm: time::Instant, msg: Arc); } #[derive(Default)] @@ -145,15 +144,15 @@ impl> ServiceTmpl { } } - pub fn send_video_frame(&self, tm: time::Instant, msg: Message) -> HashSet { - self.send_video_frame_shared(tm, Arc::new(msg)) + pub fn send_video_frame(&self, msg: Message) -> HashSet { + self.send_video_frame_shared(Arc::new(msg)) } - pub fn send_video_frame_shared(&self, tm: time::Instant, msg: Arc) -> HashSet { + pub fn send_video_frame_shared(&self, msg: Arc) -> HashSet { let mut conn_ids = HashSet::new(); let mut lock = self.0.write().unwrap(); for s in lock.subscribes.values_mut() { - s.send_video_frame(tm, msg.clone()); + s.send(msg.clone()); conn_ids.insert(s.id()); } conn_ids diff --git a/src/server/video_service.rs b/src/server/video_service.rs index f087cc30b..9ec5f9849 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -108,7 +108,7 @@ impl VideoFrameController { fetched_conn_ids.insert(id); // break if all connections have received current frame - if fetched_conn_ids.is_superset(&send_conn_ids) { + if fetched_conn_ids.len() >= send_conn_ids.len() { break; } } @@ -257,7 +257,7 @@ fn run(sp: GenericService) -> ResultType<()> { Ok(frame) => { let time = now - start; let ms = (time.as_secs() * 1000 + time.subsec_millis() as u64) as i64; - let send_conn_ids = handle_one_frame(&sp, now, &frame, ms, &mut crc, &mut vpx)?; + let send_conn_ids = handle_one_frame(&sp, &frame, ms, &mut crc, &mut vpx)?; frame_controller.set_send(now, send_conn_ids); #[cfg(windows)] { @@ -327,7 +327,6 @@ fn create_frame(frame: &EncodeFrame) -> VP9 { #[inline] fn handle_one_frame( sp: &GenericService, - now: Instant, frame: &[u8], ms: i64, crc: &mut (u32, u32), @@ -365,7 +364,7 @@ fn handle_one_frame( // to-do: flush periodically, e.g. 1 second if frames.len() > 0 { - send_conn_ids = sp.send_video_frame(now, create_msg(frames)); + send_conn_ids = sp.send_video_frame(create_msg(frames)); } } Ok(send_conn_ids) From a30aaebc72fc6e8eeb1d711477dfb9133698f8de Mon Sep 17 00:00:00 2001 From: open-trade Date: Thu, 23 Dec 2021 17:44:44 +0800 Subject: [PATCH 06/77] fix clipboard crash and https://github.com/rustdesk/rustdesk/issues/302 --- libs/scrap/src/common/convert.rs | 4 +- libs/scrap/src/dxgi/mod.rs | 92 +++++++++++++++++++------------- src/common.rs | 8 ++- src/server/clipboard_service.rs | 8 ++- src/server/video_service.rs | 15 +++--- 5 files changed, 79 insertions(+), 48 deletions(-) diff --git a/libs/scrap/src/common/convert.rs b/libs/scrap/src/common/convert.rs index 2cf9a4eca..fdc90a806 100644 --- a/libs/scrap/src/common/convert.rs +++ b/libs/scrap/src/common/convert.rs @@ -9,8 +9,8 @@ extern "C" { src_stride_argb: c_int, dst_argb: *mut u8, dst_stride_argb: c_int, - width: c_int, - height: c_int, + src_width: c_int, + src_height: c_int, mode: c_int, ) -> c_int; diff --git a/libs/scrap/src/dxgi/mod.rs b/libs/scrap/src/dxgi/mod.rs index f6bc704a9..677811b93 100644 --- a/libs/scrap/src/dxgi/mod.rs +++ b/libs/scrap/src/dxgi/mod.rs @@ -3,32 +3,20 @@ pub mod gdi; pub use gdi::CapturerGDI; use winapi::{ - shared::dxgi::{ - CreateDXGIFactory1, IDXGIAdapter1, IDXGIFactory1, IDXGIResource, IDXGISurface, - IID_IDXGIFactory1, IID_IDXGISurface, DXGI_MAP_READ, DXGI_OUTPUT_DESC, - DXGI_RESOURCE_PRIORITY_MAXIMUM, + shared::{ + dxgi::*, + dxgi1_2::*, + dxgitype::*, + minwindef::{DWORD, FALSE, TRUE, UINT}, + ntdef::LONG, + windef::HMONITOR, + winerror::*, + // dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE}, }, - shared::dxgi1_2::IDXGIOutputDuplication, - // shared::dxgiformat::{DXGI_FORMAT, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_420_OPAQUE}, - shared::dxgi1_2::{IDXGIOutput1, IID_IDXGIOutput1}, - shared::dxgitype::DXGI_MODE_ROTATION, - shared::minwindef::{DWORD, FALSE, TRUE, UINT}, - shared::ntdef::LONG, - shared::windef::HMONITOR, - shared::winerror::{ - DXGI_ERROR_ACCESS_LOST, DXGI_ERROR_INVALID_CALL, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE, - DXGI_ERROR_SESSION_DISCONNECTED, DXGI_ERROR_UNSUPPORTED, DXGI_ERROR_WAIT_TIMEOUT, - E_ACCESSDENIED, E_INVALIDARG, S_OK, + um::{ + d3d11::*, d3dcommon::D3D_DRIVER_TYPE_UNKNOWN, unknwnbase::IUnknown, wingdi::*, + winnt::HRESULT, winuser::*, }, - um::d3d11::{ - D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext, ID3D11Texture2D, IID_ID3D11Texture2D, - D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_USAGE_STAGING, - }, - um::d3dcommon::D3D_DRIVER_TYPE_UNKNOWN, - um::unknwnbase::IUnknown, - um::wingdi::*, - um::winnt::HRESULT, - um::winuser::*, }; pub struct ComPtr(*mut T); @@ -54,12 +42,11 @@ pub struct Capturer { duplication: ComPtr, fastlane: bool, surface: ComPtr, - data: *const u8, - len: usize, width: usize, height: usize, use_yuv: bool, yuv: Vec, + rotated: Vec, gdi_capturer: Option, gdi_buffer: Vec, } @@ -158,10 +145,9 @@ impl Capturer { width: display.width() as usize, height: display.height() as usize, display, - data: ptr::null(), - len: 0, use_yuv, yuv: Vec::new(), + rotated: Vec::new(), gdi_capturer, gdi_buffer: Vec::new(), }) @@ -181,10 +167,9 @@ impl Capturer { self.gdi_capturer.take(); } - unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<()> { + unsafe fn load_frame(&mut self, timeout: UINT) -> io::Result<(*const u8, i32)> { let mut frame = ptr::null_mut(); let mut info = mem::MaybeUninit::uninit().assume_init(); - self.data = ptr::null(); wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?; let frame = ComPtr(frame); @@ -200,9 +185,7 @@ impl Capturer { self.surface = ComPtr(self.ohgodwhat(frame.0)?); wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?; } - self.data = rect.pBits; - self.len = self.height * rect.Pitch as usize; - Ok(()) + Ok((rect.pBits, rect.Pitch)) } // copy from GPU memory to system memory @@ -257,8 +240,42 @@ impl Capturer { } } else { self.unmap(); - self.load_frame(timeout)?; - slice::from_raw_parts(self.data, self.len) + let r = self.load_frame(timeout)?; + let rotate = match self.display.rotation() { + DXGI_MODE_ROTATION_IDENTITY | DXGI_MODE_ROTATION_UNSPECIFIED => 0, + DXGI_MODE_ROTATION_ROTATE90 => 90, + DXGI_MODE_ROTATION_ROTATE180 => 180, + DXGI_MODE_ROTATION_ROTATE270 => 270, + _ => { + return Err(io::Error::new( + io::ErrorKind::Other, + "Unknown roration".to_string(), + )); + } + }; + if rotate == 0 { + slice::from_raw_parts(r.0, r.1 as usize * self.height) + } else { + self.rotated.resize(self.width * self.height * 4, 0); + crate::common::ARGBRotate( + r.0, + r.1, + self.rotated.as_mut_ptr(), + 4 * self.width as i32, + if rotate == 180 { + self.width + } else { + self.height + } as _, + if rotate != 180 { + self.width + } else { + self.height + } as _, + rotate, + ); + &self.rotated[..] + } } }; Ok({ @@ -478,7 +495,10 @@ pub struct Display { gdi: bool, } -// https://github.com/dchapyshev/aspia/blob/59233c5d01a4d03ed6de19b03ce77d61a6facf79/source/base/desktop/win/screen_capture_utils.cc +// optimized for updated region +// https://github.com/dchapyshev/aspia/blob/master/source/base/desktop/win/dxgi_output_duplicator.cc +// rotation +// https://github.com/bryal/dxgcap-rs/blob/master/src/lib.rs impl Display { pub fn width(&self) -> LONG { diff --git a/src/common.rs b/src/common.rs index e5a7e4f99..921516311 100644 --- a/src/common.rs +++ b/src/common.rs @@ -95,7 +95,10 @@ pub fn update_clipboard(clipboard: Clipboard, old: Option<&Arc>>) let side = if old.is_none() { "host" } else { "client" }; let old = if let Some(old) = old { old } else { &CONTENT }; *old.lock().unwrap() = content.clone(); - allow_err!(ctx.set_text(content)); + if !content.is_empty() { + // empty content make ctx.set_text crash + allow_err!(ctx.set_text(content)); + } log::debug!("{} updated on {}", CLIPBOARD_NAME, side); } Err(err) => { @@ -240,7 +243,8 @@ async fn test_nat_type_() -> ResultType { let rendezvous_server = get_rendezvous_server(100).await; let server1 = rendezvous_server; let mut server2 = server1; - if server1.port() == 0 { // offline + if server1.port() == 0 { + // offline // avoid overflow crash bail!("Offline"); } diff --git a/src/server/clipboard_service.rs b/src/server/clipboard_service.rs index be496c859..0a1745fcb 100644 --- a/src/server/clipboard_service.rs +++ b/src/server/clipboard_service.rs @@ -97,8 +97,12 @@ mod listen { fn trigger(ctx: &mut ClipboardContext) { let _ = match ctx.get_text() { - Ok(text) => ctx.set_text(text), - Err(_) => ctx.set_text(Default::default()), + Ok(text) => { + if !text.is_empty() { + ctx.set_text(text).ok(); + } + } + Err(_) => {} }; } } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 9ec5f9849..4d8f6dbe4 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -220,7 +220,7 @@ fn run(sp: GenericService) -> ResultType<()> { let start = time::Instant::now(); let mut last_check_displays = time::Instant::now(); #[cfg(windows)] - let mut try_gdi = true; + let mut try_gdi = 1; #[cfg(windows)] log::info!("gdi: {}", c.is_gdi()); while sp.ok() { @@ -261,7 +261,7 @@ fn run(sp: GenericService) -> ResultType<()> { frame_controller.set_send(now, send_conn_ids); #[cfg(windows)] { - try_gdi = false; + try_gdi = 0; } } Err(ref e) if e.kind() == WouldBlock => { @@ -271,10 +271,13 @@ fn run(sp: GenericService) -> ResultType<()> { wait = 0 } #[cfg(windows)] - if try_gdi && !c.is_gdi() { - c.set_gdi(); - try_gdi = false; - log::info!("No image, fall back to gdi"); + if try_gdi > 0 && !c.is_gdi() { + if try_gdi > 3 { + c.set_gdi(); + try_gdi = 0; + log::info!("No image, fall back to gdi"); + } + try_gdi += 1; } continue; } From 96afb885186ece78f6a2872d45be2cab097ef3c4 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 23 Dec 2021 21:41:53 +0800 Subject: [PATCH 07/77] change line-through style from grey to red --- src/ui/common.css | 2 +- src/ui/index.tis | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/common.css b/src/ui/common.css index 94b16642b..574fbb1a5 100644 --- a/src/ui/common.css +++ b/src/ui/common.css @@ -319,5 +319,5 @@ menu li.selected span { menu li.line-through { text-decoration-line: line-through; - color: grey; + color: red; } diff --git a/src/ui/index.tis b/src/ui/index.tis index 5bffff322..09339a75e 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -209,7 +209,7 @@ class MyIdMenu: Reactor.Component {
  • IP Whitelisting
  • ID/Relay Server
  • -
  • {svg_checkmark}Enable service
  • +
  • {svg_checkmark}Enable Service
  • Forum
  • About {handler.get_app_name()}
  • From 0e8fc4a8157ff6374e43320b74d2a2bce892272d Mon Sep 17 00:00:00 2001 From: rustdesk Date: Thu, 23 Dec 2021 23:03:43 +0800 Subject: [PATCH 08/77] 65515 -> Meta(win) on Linux --- src/ui/remote.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 8c82ce4d5..a9759cbf4 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -753,6 +753,7 @@ impl Handler { 65300 => key_event.set_control_key(ControlKey::Scroll), 65421 => key_event.set_control_key(ControlKey::NumpadEnter), // numpad enter 65407 => key_event.set_control_key(ControlKey::NumLock), + 65515 => key_event.set_control_key(ControlKey::Meta), 65516 => key_event.set_control_key(ControlKey::RWin), 65513 => key_event.set_control_key(ControlKey::Alt), 65514 => key_event.set_control_key(ControlKey::RAlt), From 885d8a45864c2756e209354abe0ae82f8d6539f6 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 24 Dec 2021 00:27:27 +0800 Subject: [PATCH 09/77] https://github.com/rustdesk/rustdesk/issues/332 --- src/server/input_service.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 056267c5b..ba34772a5 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -195,15 +195,20 @@ fn modifier_sleep() { std::thread::sleep(std::time::Duration::from_nanos(1)); } -#[cfg(not(target_os = "macos"))] #[inline] fn get_modifier_state(key: Key, en: &mut Enigo) -> bool { + // on Linux, if RightAlt is down, RightAlt status is false, Alt status is true + // but on Windows, both are true let x = en.get_key_state(key.clone()); match key { Key::Shift => x || en.get_key_state(Key::RightShift), Key::Control => x || en.get_key_state(Key::RightControl), Key::Alt => x || en.get_key_state(Key::RightAlt), Key::Meta => x || en.get_key_state(Key::RWin), + Key::RightShift => x || en.get_key_state(Key::Shift), + Key::RightControl => x || en.get_key_state(Key::Control), + Key::RightAlt => x || en.get_key_state(Key::Alt), + Key::RWin => x || en.get_key_state(Key::Meta), _ => x, } } @@ -262,7 +267,7 @@ fn fix_key_down_timeout(force: bool) { if let Some(key) = key { let func = move || { let mut en = ENIGO.lock().unwrap(); - if en.get_key_state(key) { + if get_modifier_state(key, &mut en) { en.key_up(key); log::debug!("Fixed {:?} timeout", key); } @@ -284,7 +289,7 @@ fn fix_modifier( key1: Key, en: &mut Enigo, ) { - if en.get_key_state(key1) && !modifiers.contains(&ProtobufEnumOrUnknown::new(key0)) { + if get_modifier_state(key1, en) && !modifiers.contains(&ProtobufEnumOrUnknown::new(key0)) { en.key_up(key1); log::debug!("Fixed {:?}", key1); } From 8d90c5a93b662ea27916635b534812996d84281c Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 24 Dec 2021 12:40:47 +0800 Subject: [PATCH 10/77] change codec cpu usage to 0 --- src/client.rs | 2 +- src/server/video_service.rs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/client.rs b/src/client.rs index b4116a945..1001d1e9a 100644 --- a/src/client.rs +++ b/src/client.rs @@ -582,7 +582,7 @@ pub struct VideoHandler { impl VideoHandler { pub fn new() -> Self { VideoHandler { - decoder: Decoder::new(VideoCodecId::VP9, 1).unwrap(), + decoder: Decoder::new(VideoCodecId::VP9, 0).unwrap(), rgb: Default::default(), } } diff --git a/src/server/video_service.rs b/src/server/video_service.rs index 4d8f6dbe4..1fb549242 100644 --- a/src/server/video_service.rs +++ b/src/server/video_service.rs @@ -188,11 +188,7 @@ fn run(sp: GenericService) -> ResultType<()> { speed, }; let mut vpx; - let mut n = ((width * height) as f64 / (1920 * 1080) as f64).round() as u32; - if n < 1 { - n = 1; - } - match Encoder::new(&cfg, n) { + match Encoder::new(&cfg, 0) { Ok(x) => vpx = x, Err(err) => bail!("Failed to create encoder: {}", err), } From 4703a7d332eccdebfab62c126de067d128e0a94c Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 24 Dec 2021 19:13:11 +0800 Subject: [PATCH 11/77] https://github.com/rustdesk/rustdesk/issues/327 --- libs/enigo/examples/key.rs | 2 +- libs/enigo/examples/keyboard.rs | 2 +- libs/enigo/examples/mouse.rs | 2 +- libs/enigo/examples/timer.rs | 2 +- libs/hbb_common/src/tcp.rs | 19 ++++++-- libs/scrap/examples/record-screen.rs | 1 - src/server/connection.rs | 73 +++++++++++++--------------- 7 files changed, 52 insertions(+), 49 deletions(-) diff --git a/libs/enigo/examples/key.rs b/libs/enigo/examples/key.rs index c806451ef..472f377b9 100644 --- a/libs/enigo/examples/key.rs +++ b/libs/enigo/examples/key.rs @@ -6,7 +6,7 @@ fn main() { thread::sleep(Duration::from_secs(2)); let mut enigo = Enigo::new(); - enigo.key_down(Key::Layout('a')); + enigo.key_down(Key::Layout('a')).ok(); thread::sleep(Duration::from_secs(1)); enigo.key_up(Key::Layout('a')); } diff --git a/libs/enigo/examples/keyboard.rs b/libs/enigo/examples/keyboard.rs index f2c290356..c9a12cd3a 100644 --- a/libs/enigo/examples/keyboard.rs +++ b/libs/enigo/examples/keyboard.rs @@ -10,7 +10,7 @@ fn main() { enigo.key_sequence("Hello World! here is a lot of text ❤️"); // select all - enigo.key_down(Key::Control); + enigo.key_down(Key::Control).ok(); enigo.key_click(Key::Layout('a')); enigo.key_up(Key::Control); } diff --git a/libs/enigo/examples/mouse.rs b/libs/enigo/examples/mouse.rs index 7026b9af7..50a3506cf 100644 --- a/libs/enigo/examples/mouse.rs +++ b/libs/enigo/examples/mouse.rs @@ -11,7 +11,7 @@ fn main() { enigo.mouse_move_to(500, 200); thread::sleep(wait_time); - enigo.mouse_down(MouseButton::Left); + enigo.mouse_down(MouseButton::Left).ok(); thread::sleep(wait_time); enigo.mouse_move_relative(100, 100); diff --git a/libs/enigo/examples/timer.rs b/libs/enigo/examples/timer.rs index 5e451f3a8..92ded3dbb 100644 --- a/libs/enigo/examples/timer.rs +++ b/libs/enigo/examples/timer.rs @@ -16,7 +16,7 @@ fn main() { println!("{:?}", time); // select all - enigo.key_down(Key::Control); + enigo.key_down(Key::Control).ok(); enigo.key_click(Key::Layout('a')); enigo.key_up(Key::Control); } diff --git a/libs/hbb_common/src/tcp.rs b/libs/hbb_common/src/tcp.rs index 0789c87f0..4189963ba 100644 --- a/libs/hbb_common/src/tcp.rs +++ b/libs/hbb_common/src/tcp.rs @@ -10,7 +10,7 @@ use std::{ use tokio::net::{lookup_host, TcpListener, TcpSocket, TcpStream, ToSocketAddrs}; use tokio_util::codec::Framed; -pub struct FramedStream(Framed, Option<(Key, u64, u64)>); +pub struct FramedStream(Framed, Option<(Key, u64, u64)>, u64); impl Deref for FramedStream { type Target = Framed; @@ -56,14 +56,18 @@ impl FramedStream { new_socket(local_addr, true)?.connect(remote_addr), ) .await??; - return Ok(Self(Framed::new(stream, BytesCodec::new()), None)); + return Ok(Self(Framed::new(stream, BytesCodec::new()), None, 0)); } } bail!("could not resolve to any address"); } + pub fn set_send_timeout(&mut self, ms: u64) { + self.2 = ms; + } + pub fn from(stream: TcpStream) -> Self { - Self(Framed::new(stream, BytesCodec::new()), None) + Self(Framed::new(stream, BytesCodec::new()), None, 0) } pub fn set_raw(&mut self) { @@ -88,12 +92,17 @@ impl FramedStream { let nonce = Self::get_nonce(key.1); msg = secretbox::seal(&msg, &nonce, &key.0); } - self.0.send(bytes::Bytes::from(msg)).await?; + self.send_bytes(bytes::Bytes::from(msg)).await?; Ok(()) } + #[inline] pub async fn send_bytes(&mut self, bytes: Bytes) -> ResultType<()> { - self.0.send(bytes).await?; + if self.2 > 0 { + super::timeout(self.2, self.0.send(bytes)).await??; + } else { + self.0.send(bytes).await?; + } Ok(()) } diff --git a/libs/scrap/examples/record-screen.rs b/libs/scrap/examples/record-screen.rs index bd8291d27..2a56c0dcd 100644 --- a/libs/scrap/examples/record-screen.rs +++ b/libs/scrap/examples/record-screen.rs @@ -43,7 +43,6 @@ struct Args { flag_time: Option, flag_fps: u64, flag_bv: u32, - flag_ba: u32, } #[derive(Debug, serde::Deserialize)] diff --git a/src/server/connection.rs b/src/server/connection.rs index 0cebac601..482a9f654 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -81,6 +81,8 @@ const TEST_DELAY_TIMEOUT: Duration = Duration::from_secs(3); const SEC30: Duration = Duration::from_secs(30); const H1: Duration = Duration::from_secs(3600); const MILLI1: Duration = Duration::from_millis(1); +const SEND_TIMEOUT_VIDEO: u64 = 12_000; +const SEND_TIMEOUT_OTHER: u64 = SEND_TIMEOUT_VIDEO * 10; impl Connection { pub async fn start( @@ -147,6 +149,14 @@ impl Connection { time::interval_at(Instant::now() + TEST_DELAY_TIMEOUT, TEST_DELAY_TIMEOUT); let mut last_recv_time = Instant::now(); + conn.stream.set_send_timeout( + if conn.file_transfer.is_some() || conn.port_forward_socket.is_some() { + SEND_TIMEOUT_OTHER + } else { + SEND_TIMEOUT_VIDEO + }, + ); + loop { tokio::select! { biased; // video has higher priority @@ -286,73 +296,58 @@ impl Connection { } } } - video_service::notify_video_frame_feched(id, None); + video_service::notify_video_frame_feched(id, None); super::video_service::update_test_latency(id, 0); super::video_service::update_image_quality(id, None); - if let Some(forward) = conn.port_forward_socket.as_mut() { + if let Err(err) = conn.try_port_forward_loop(&mut rx_from_cm).await { + conn.on_close(&err.to_string(), false); + } + } + + async fn try_port_forward_loop( + &mut self, + rx_from_cm: &mut mpsc::UnboundedReceiver, + ) -> ResultType<()> { + let mut last_recv_time = Instant::now(); + if let Some(forward) = self.port_forward_socket.as_mut() { log::info!("Running port forwarding loop"); - conn.stream.set_raw(); + self.stream.set_raw(); loop { tokio::select! { Some(data) = rx_from_cm.recv() => { match data { ipc::Data::Close => { - conn.on_close("Close requested from connection manager", false); - break; + bail!("Close requested from selfection manager"); } _ => {} } } res = forward.next() => { if let Some(res) = res { - match res { - Err(err) => { - conn.on_close(&err.to_string(), false); - break; - }, - Ok(bytes) => { - last_recv_time = Instant::now(); - if let Err(err) = conn.stream.send_bytes(bytes.into()).await { - conn.on_close(&err.to_string(), false); - break; - } - } - } + last_recv_time = Instant::now(); + self.stream.send_bytes(res?.into()).await?; } else { - conn.on_close("Forward reset by the peer", false); - break; + bail!("Forward reset by the peer"); } }, - res = conn.stream.next() => { + res = self.stream.next() => { if let Some(res) = res { - match res { - Err(err) => { - conn.on_close(&err.to_string(), false); - break; - }, - Ok(bytes) => { - last_recv_time = Instant::now(); - if let Err(err) = forward.send(bytes.into()).await { - conn.on_close(&err.to_string(), false); - break; - } - } - } + last_recv_time = Instant::now(); + timeout(SEND_TIMEOUT_OTHER, forward.send(res?.into())).await??; } else { - conn.on_close("Stream reset by the peer", false); - break; + bail!("Stream reset by the peer"); } }, - _ = conn.timer.tick() => { + _ = self.timer.tick() => { if last_recv_time.elapsed() >= H1 { - conn.on_close("Timeout", false); - break; + bail!("Timeout"); } } } } } + Ok(()) } async fn send_permission(&mut self, permission: Permission, enabled: bool) { From 3d39d9c27c378dbe1cb7c1b128d8d1af75cf1305 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 25 Dec 2021 00:18:54 +0800 Subject: [PATCH 12/77] https://github.com/rustdesk/rustdesk/issues/328 --- src/server/audio_service.rs | 52 +++++++++++++++++-------------------- src/ui/cm.rs | 12 +++++---- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/src/server/audio_service.rs b/src/server/audio_service.rs index a45757ff3..6a4de338e 100644 --- a/src/server/audio_service.rs +++ b/src/server/audio_service.rs @@ -36,35 +36,31 @@ mod pa_impl { use super::*; #[tokio::main(flavor = "current_thread")] pub async fn run(sp: GenericService) -> ResultType<()> { - if let Ok(mut stream) = crate::ipc::connect(1000, "_pa").await { - let mut encoder = - Encoder::new(crate::platform::linux::PA_SAMPLE_RATE, Stereo, LowDelay)?; - allow_err!( - stream - .send(&crate::ipc::Data::Config(( - "audio-input".to_owned(), - Some(Config::get_option("audio-input")) - ))) - .await - ); - while sp.ok() { - sp.snapshot(|sps| { - sps.send(create_format_msg(crate::platform::linux::PA_SAMPLE_RATE, 2)); - Ok(()) - })?; - if let Some(data) = stream.next_timeout2(1000).await { - match data? { - Some(crate::ipc::Data::RawMessage(bytes)) => { - let data = unsafe { - std::slice::from_raw_parts::( - bytes.as_ptr() as _, - bytes.len() / 4, - ) - }; - send_f32(data, &mut encoder, &sp); - } - _ => {} + hbb_common::sleep(0.1).await; // one moment to wait for _pa ipc + let mut stream = crate::ipc::connect(1000, "_pa").await?; + let mut encoder = Encoder::new(crate::platform::linux::PA_SAMPLE_RATE, Stereo, LowDelay)?; + allow_err!( + stream + .send(&crate::ipc::Data::Config(( + "audio-input".to_owned(), + Some(Config::get_option("audio-input")) + ))) + .await + ); + while sp.ok() { + sp.snapshot(|sps| { + sps.send(create_format_msg(crate::platform::linux::PA_SAMPLE_RATE, 2)); + Ok(()) + })?; + if let Some(data) = stream.next_timeout2(1000).await { + match data? { + Some(crate::ipc::Data::RawMessage(bytes)) => { + let data = unsafe { + std::slice::from_raw_parts::(bytes.as_ptr() as _, bytes.len() / 4) + }; + send_f32(data, &mut encoder, &sp); } + _ => {} } } } diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 368769a95..15583e56b 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -405,12 +405,13 @@ async fn start_pa() { break; } let spec = pulse::sample::Spec { - format: pulse::sample::Format::F32be, + format: pulse::sample::Format::F32le, channels: 2, rate: crate::platform::linux::PA_SAMPLE_RATE, }; log::info!("pa monitor: {:?}", device); - if let Ok(s) = psimple::Simple::new( + // systemctl --user status pulseaudio.service + match psimple::Simple::new( None, // Use the default server APP_NAME, // Our application’s name pulse::stream::Direction::Record, // We want a record stream @@ -420,7 +421,7 @@ async fn start_pa() { None, // Use default channel map None, // Use default buffering attributes ) { - loop { + Ok(s) => loop { if let Some(Err(_)) = stream.next_timeout2(1).await { break; } @@ -433,9 +434,10 @@ async fn start_pa() { allow_err!(stream.send(&Data::RawMessage(out)).await); } } + }, + Err(err) => { + log::error!("Could not create simple pulse: {}", err); } - } else { - log::error!("Could not create simple pulse"); } } Err(err) => { From b3e3f6151d537a009dbbb8ef695c6fe13fd45527 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 25 Dec 2021 01:07:41 +0800 Subject: [PATCH 13/77] get last env instead of the first one avoid problem when just switch from wayland to xorg --- src/platform/linux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 7368d3c04..bdc5510d1 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -644,7 +644,7 @@ fn get_env_tries(name: &str, uid: &str, n: usize) -> String { } fn get_env(name: &str, uid: &str) -> String { - let cmd = format!("ps -u {} -o pid= | xargs -I__ cat /proc/__/environ 2>/dev/null | tr '\\0' '\\n' | grep -m1 '^{}=' | sed 's/{}=//g'", uid, name, name); + let cmd = format!("ps -u {} -o pid= | xargs -I__ cat /proc/__/environ 2>/dev/null | tr '\\0' '\\n' | grep '^{}=' | tail -1 | sed 's/{}=//g'", uid, name, name); log::debug!("Run: {}", &cmd); if let Ok(Some(x)) = run_cmds(cmd) { x.trim_end().to_string() From af218dbc836d0efbb6af503e309b649ce98a7f40 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 25 Dec 2021 16:45:22 +0800 Subject: [PATCH 14/77] internationalization --- Cargo.lock | 30 +++++++ Cargo.toml | 1 + src/client.rs | 11 ++- src/lang.rs | 35 ++++++++ src/lang/cn.rs | 190 +++++++++++++++++++++++++++++++++++++++ src/lang/en.rs | 20 +++++ src/lang/fr.rs | 190 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/ui.rs | 6 ++ src/ui/cm.rs | 5 ++ src/ui/cm.tis | 17 ++-- src/ui/common.tis | 61 +++++++++++-- src/ui/file_transfer.tis | 30 +++---- src/ui/header.tis | 79 +++++++--------- src/ui/index.tis | 166 ++++++++++++++++++---------------- src/ui/install.tis | 18 ++-- src/ui/msgbox.tis | 91 ++++++++++--------- src/ui/port_forward.tis | 14 +-- src/ui/remote.rs | 52 +++++------ 19 files changed, 774 insertions(+), 243 deletions(-) create mode 100644 src/lang.rs create mode 100644 src/lang/cn.rs create mode 100644 src/lang/en.rs create mode 100644 src/lang/fr.rs diff --git a/Cargo.lock b/Cargo.lock index 359e344bb..b07d131e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,6 +570,16 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "cstr_core" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ba9efe9e1e736671d5a03f006afc4e7e3f32503e2077e0bcaf519c0c8c1d3" +dependencies = [ + "cty", + "memchr", +] + [[package]] name = "ct-logs" version = "0.6.0" @@ -589,6 +599,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + [[package]] name = "darling" version = "0.10.2" @@ -2909,6 +2925,7 @@ dependencies = [ "serde_derive", "serde_json 1.0.66", "sha2", + "sys-locale", "uuid", "whoami", "winapi 0.3.9", @@ -3282,6 +3299,19 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sys-locale" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91f89ebb59fa30d4f65fafc2d68e94f6975256fd87e812dd99cb6e020c8563df" +dependencies = [ + "cc", + "cstr_core", + "libc", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "system-deps" version = "1.3.2" diff --git a/Cargo.toml b/Cargo.toml index b4b8ad48c..7e201c802 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ whoami = "1.1" scrap = { path = "libs/scrap" } hbb_common = { path = "libs/hbb_common" } enigo = { path = "libs/enigo" } +sys-locale = "0.1" serde_derive = "1.0" serde = "1.0" serde_json = "1.0" diff --git a/src/client.rs b/src/client.rs index 1001d1e9a..13571e585 100644 --- a/src/client.rs +++ b/src/client.rs @@ -34,6 +34,8 @@ pub const SEC30: Duration = Duration::from_secs(30); pub struct Client; +pub use super::lang::*; + #[cfg(not(any(target_os = "android")))] lazy_static::lazy_static! { static ref AUDIO_HOST: Host = cpal::default_host(); @@ -547,7 +549,8 @@ impl AudioHandler { device: &Device, ) -> ResultType<()> { let err_fn = move |err| { - log::error!("an error occurred on stream: {}", err); + // too many errors, will improve later + log::trace!("an error occurred on stream: {}", err); }; let audio_buffer = self.audio_buffer.clone(); let stream = device.build_output_stream( @@ -658,6 +661,12 @@ impl LoginConfigHandler { self.config = config; } + pub fn set_option(&mut self, k: String, v: String) { + let mut config = self.load_config(); + config.options.insert(k, v); + self.save_config(config); + } + pub fn save_view_style(&mut self, value: String) { let mut config = self.load_config(); config.view_style = value; diff --git a/src/lang.rs b/src/lang.rs new file mode 100644 index 000000000..d45461f09 --- /dev/null +++ b/src/lang.rs @@ -0,0 +1,35 @@ +use hbb_common::{config::Config, log}; +use std::ops::Deref; + +mod cn; +mod en; +mod fr; + +#[cfg(not(any(target_os = "android", target_os = "ios")))] +pub fn translate(name: String) -> String { + let locale = sys_locale::get_locale().unwrap_or_default().to_lowercase(); + log::debug!("The current locale is {}", locale); + translate_locale(name, &locale) +} + +pub fn translate_locale(name: String, locale: &str) -> String { + let mut lang = Config::get_option("lang"); + if lang.is_empty() { + lang = locale + .split("-") + .last() + .map(|x| x.split("_").last().unwrap_or_default()) + .unwrap_or_default() + .to_owned(); + } + let m = match lang.to_lowercase().as_str() { + "fr" => fr::T.deref(), + "cn" => cn::T.deref(), + _ => en::T.deref(), + }; + if let Some(v) = m.get(&name as &str) { + v.to_string() + } else { + name + } +} diff --git a/src/lang/cn.rs b/src/lang/cn.rs new file mode 100644 index 000000000..4e735ed34 --- /dev/null +++ b/src/lang/cn.rs @@ -0,0 +1,190 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "状态"), + ("Your Desktop", "你的桌面"), + ("desk_tip", "你的桌面可以通过下面的 ID和密码访问。"), + ("Password", "密码"), + ("Ready", "就绪"), + ("connecting_status", "正在接入RustDesk网络..."), + ("Enable Service", "允许服务"), + ("Start Service", "启动服务"), + ("Service is not running", "服务没有启动"), + ("not_ready_status", "未就绪,请检查网络连接"), + ("Control Remote Desktop", "控制远程桌面"), + ("Transfer File", "传输文件"), + ("Connect", "连接"), + ("Recent Sessions", "最近访问过"), + ("Address Book", "地址簿"), + ("Confirmation", "确认"), + ("TCP Tunneling", "TCP隧道"), + ("Remove", "删除"), + ("Refresh random password", "刷新随机密码"), + ("Set your own password", "设置密码"), + ("Enable Keyboard/Mouse", "允许控制键盘/鼠标"), + ("Enable Clipboard", "允许同步剪贴板"), + ("Enable File Transfer", "允许传输文件"), + ("Enable TCP Tunneling", "允许建立TCP隧道"), + ("IP Whitelisting", "IP白名单"), + ("ID/Relay Server", "ID/中继服务器"), + ("Stop service", "停止服务"), + ("Change ID", "改变ID"), + ("Website", "网站"), + ("About", "关于"), + ("Mute", "静音"), + ("Audio Input", "音频输入"), + ("ID Server", "ID服务器"), + ("Relay Server", "中继服务器"), + ("API Server", "API服务器"), + ("invalid_http", "必须以http://或者https://开头"), + ("Invalid IP", "无效IP"), + ("id_change_tip", "只可以使用字母a-z, A-Z, 0-9, _ (下划线)。首字母必须是a-z, A-Z。长度在6与16之间。"), + ("Invalid format", "无效格式"), + ("This function is turned off by the server", "服务器关闭了此功能"), + ("Not available", "已被占用"), + ("Too frequent", "修改太频繁,请稍后再试"), + ("Cancel", "取消"), + ("Skip", "跳过"), + ("Close", "关闭"), + ("Retry", "再试"), + ("OK", "确认"), + ("Password Required", "需要密码"), + ("Please enter your password", "请输入密码"), + ("Remember password", "记住密码"), + ("Wrong Password", "密码错误"), + ("Do you want to enter again?", "还想输入一次吗?"), + ("Connection Error", "连接错误"), + ("Error", "错误"), + ("Reset by the peer", "连接被对方关闭"), + ("Connecting...", "正在连接..."), + ("Connection in progress. Please wait.", "连接进行中,请稍等。"), + ("Please try 1 minute later", "一分钟后再试"), + ("Login Error", "登录错误"), + ("Successful", "成功"), + ("Connected, waiting for image...", "已连接,等待画面传输..."), + ("Name", "文件名"), + ("Modified", "修改时间"), + ("Size", "大小"), + ("Show Hidden Files", "显示隐藏文件"), + ("Receive", "接受"), + ("Send", "发送"), + ("Remote Computer", "远程电脑"), + ("Local Computer", "本地电脑"), + ("Confirm Delete", "确认删除"), + ("Are you sure you want to delete this file?", "是否删除此文件?"), + ("Do this for all conflicts", "应用于其它冲突"), + ("Deleting", "正在删除"), + ("files", "文件"), + ("Waiting", "等待..."), + ("Finished", "完成"), + ("Custom Image Quality", "设置画面质量"), + ("Privacy mode", "隐私模式"), + ("Adjust Window", "调节窗口"), + ("Original", "原始比例"), + ("Shrink", "收缩"), + ("Stretch", "伸展"), + ("Good image quality", "好画质"), + ("Balanced", "一般画质"), + ("Optimize reaction time", "优化反应时间"), + ("Custom", "自定义画质"), + ("Show remote cursor", "显示远程光标"), + ("Disable clipboard", "禁止剪贴板"), + ("Lock after session end", "断开后锁定远程电脑"), + ("Insert", "插入"), + ("Insert Lock", "锁定远程电脑"), + ("Refresh", "刷新画面"), + ("ID does not exist", "ID不存在"), + ("Failed to connect to rendezvous server", "连接注册服务器失败"), + ("Please try later", "请稍后再试"), + ("Remote desktop is offline", "远程电脑不在线"), + ("Key mismatch", "Key不匹配"), + ("Timeout", "连接超时"), + ("Failed to connect to relay server", "无法连接到中继服务器"), + ("Failed to connect via rendezvous server", "无法通过注册服务器建立连接"), + ("Failed to connect via relay server", "无法通过中继服务器建立连接"), + ("Failed to make direct connection to remote desktop", "无法建立直接连接"), + ("Set Password", "设置密码"), + ("OS Password", "操作系统密码"), + ("install_tip", "你正在运行未安装版本,由于UAC限制,作为被控端,会在某些情况下无法控制鼠标键盘,或者录制屏幕,请点击下面的按钮将RustDesk安装到系统,从而规避上述问题。"), + ("Click to upgrade", "点击这里升级"), + ("Configuration Permissions", "配置权限"), + ("Configure", "配置"), + ("config_acc", "为了能够远程控制你的桌面, 请给予RustDesk\"辅助功能\" 权限。"), + ("config_screen", "为了能够远程访问你的桌面, 请给予RustDesk\"屏幕录制\" 权限。"), + ("Installing ...", "安装 ..."), + ("Install", "安装"), + ("Installation", "安装"), + ("Installation Path", "安装路径"), + ("Create start menu shortcuts", "创建启动菜单快捷方式"), + ("Create desktop icon", "创建桌面图标"), + ("agreement_tip", "开始安装即表示接受许可协议。"), + ("Accept and Install", "同意并安装"), + ("End-user license agreement", "用户协议"), + ("Generating ...", "正在产生 ..."), + ("Your installation is lower version.", "你安装的版本比当前运行的低。"), + ("not_close_tcp_tip", "请在使用隧道的时候,不要关闭本窗口"), + ("Listening ...", "正在等待隧道连接 ..."), + ("Remote Host", "远程主机"), + ("Remote Port", "远程端口"), + ("Action", "动作"), + ("Add", "添加"), + ("Local Port", "本地端口"), + ("setup_server_tip", "如果需要更快连接速度,你可以选择自建服务器"), + ("Too short, at least 6 characters.", "太短了,至少6个字符"), + ("The confirmation is not identical.", "两次输入不匹配"), + ("Permissions", "权限"), + ("Accept", "接受"), + ("Dismiss", "拒绝"), + ("Disconnect", "断开连接"), + ("Allow using keyboard and mouse", "允许使用键盘鼠标"), + ("Allow using clipboard", "允许使用剪贴板"), + ("Allow hearing sound", "允许听到声音"), + ("Connected", "已经连接"), + ("Direct and encrypted connection", "加密直连"), + ("Relayed and encrypted connection", "加密中继连接"), + ("Direct and unencrypted connection", "非加密直连"), + ("Relayed and unencrypted connection", "非加密中继连接"), + ("Enter Remote ID", "输入对方ID"), + ("Enter your password", "输入密码"), + ("Logging in...", "正在登录..."), + ("Enable RDP session sharing", "允许RDP会话共享"), + ("Auto Login", "自动登录(设置断开后锁定才有效)"), + ("Enable Direct IP Access", "允许IP直接访问"), + ("Rename", "改名"), + ("Space", "空格"), + ("Create Desktop Shortcut", "创建桌面快捷方式"), + ("Change Path", "改变路径"), + ("Create Folder", "创建文件夹"), + ("Please enter the folder name", "请输入文件夹名称"), + ("Fix it", "修复"), + ("Warning", "警告"), + ("Login screen using Wayland is not supported", "不支持使用 Wayland 登录界面"), + ("Reboot required", "重启后才能生效"), + ("Unsupported display server ", "不支持当前显示服务器"), + ("x11 expected", "请切换到 x11"), + ("Port", "端口"), + ("Settings", "设置"), + ("Username", " 用户名"), + ("Invalid port", "无效端口"), + ("Closed manually by the peer", "被对方手动关闭"), + ("Enable remote configuration modification", "允许远程修改配置"), + ("Run without install", "无安装运行"), + ("Always connected via relay", "强制走中继连接"), + ("Always connect via relay", "强制走中继连接"), + ("whitelist_tip", "只有白名单里的ip才能访问我"), + ("Login", "登录"), + ("Logout", "登出"), + ("Tags", "标签"), + ("Search ID", "查找ID"), + ("Current Wayland display server is not supported", "不支持 Wayland 显示服务器"), + ("whitelist_sep", "可以使用逗号,分号,空格或者换行符作为分隔符"), + ("Add ID", "增加ID"), + ("Add Tag", "增加标签"), + ("Unselect all tags", "取消选择所有标签"), + ("Network error", "网络错误"), + ("Username missed", "用户名没有填写"), + ("Password missed", "密码没有填写"), + ("Wrong credentials", "用户名或者密码错误"), + ("Edit Tag", "修改标签"), + ].iter().cloned().collect(); + } diff --git a/src/lang/en.rs b/src/lang/en.rs new file mode 100644 index 000000000..7d6103428 --- /dev/null +++ b/src/lang/en.rs @@ -0,0 +1,20 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("desk_tip", "Your desktop can be accessed with this ID and password."), + ("connecting_status", "Connecting to the RustDesk network..."), + ("not_ready_status", "Not ready. Please check your connection"), + ("id_change_tip", "Only a-z, A-Z, 0-9 and _ (underscore) characters allowed. The first letter must be a-z, A-Z. Length between 6 and 16."), + ("install_tip", "Due to UAC, RustDesk can not work properly as the remote side in some cases. To avoid UAC, please click the button below to install RustDesk to the system."), + ("config_acc", "In order to control your Desktop remotely, you need to grant RustDesk \"Accessibility\" permissions."), + ("config_screen", "In order to access your Desktop remotely, you need to grant RustDesk \"Screen Recording\" permissions."), + ("agreement_tip", "By starting the installation, you accept the license agreement."), + ("not_close_tcp_tip", "Don't close this window while you are using the tunnel"), + ("setup_server_tip", "For faster connection, please set up your own server"), + ("Auto Login", "Auto Login (Only valid if you set \"Lock after session end\")"), + ("whitelist_tip", "Only whitelisted IP can access me"), + ("whitelist_sep", "Seperated by comma, semicolon, spaces or new line"), + ("Wrong credentials", "Wrong username or password"), + ("invalid_http", "must start with http:// or https://"), + ].iter().cloned().collect(); +} diff --git a/src/lang/fr.rs b/src/lang/fr.rs new file mode 100644 index 000000000..711d2e20a --- /dev/null +++ b/src/lang/fr.rs @@ -0,0 +1,190 @@ +lazy_static::lazy_static! { +pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "Statut"), + ("Your Desktop", "Votre bureau"), + ("desk_tip", "Votre bureau est accessible via l'identifiant et le mot de passe ci-dessous."), + ("Password", "Mot de passe"), + ("Ready", "Prêt"), + ("connecting_status", "Connexion au réseau RustDesk..."), + ("Enable Service", "Autoriser le service"), + ("Start Service", "Démarrer le service"), + ("Service is not running", "Le service ne fonctionne pas"), + ("not_ready_status", "Pas prêt, veuillez vérifier la connexion réseau"), + ("Control Remote Desktop", "Contrôler le bureau à distance"), + ("Transfer File", "Transférer le fichier"), + ("Connect", "Connecter"), + ("Recent Sessions", "Sessions récentes"), + ("Address Book", "Carnet d'adresses"), + ("Confirmation", "Confirmation"), + ("TCP Tunneling", "Tunneling TCP"), + ("Remove", "Supprimer"), + ("Refresh random password", "Actualiser le mot de passe aléatoire"), + ("Set your own password", "Définir votre propre mot de passe"), + ("Enable Keyboard/Mouse", "Activer le contrôle clavier/souris"), + ("Enable Clipboard", "Activer la synchronisation du presse-papiers"), + ("Enable File Transfer", "Activer le transfert de fichiers"), + ("Enable TCP Tunneling", "Activer le tunneling TCP"), + ("IP Whitelisting", "Liste blanche IP"), + ("ID/Relay Server", "ID/Serveur Relais"), + ("Stop service", "Arrêter service"), + ("Change ID", "Changer d'ID"), + ("Website", "Site Web"), + ("About", "Sur"), + ("Mute", "Muet"), + ("Audio Input", "Entrée audio"), + ("ID Server", "Serveur ID"), + ("Relay Server", "Serveur Relais"), + ("API Server", "Serveur API"), + ("invalid_http", "Doit commencer par http:// ou https://"), + ("Invalid IP", "IP invalide"), + ("id_change_tip", "Seules les lettres a-z, A-Z, 0-9, _ (trait de soulignement) peuvent être utilisées. La première lettre doit être a-z, A-Z. La longueur est comprise entre 6 et 16."), + ("Invalid format", "Format invalide"), + ("This function is turned off by the server", "Cette fonction est désactivée par le serveur"), + ("Not available", "Indisponible"), + ("Too frequent", "Modifier trop fréquemment, veuillez réessayer plus tard"), + ("Cancel", "Annuler"), + ("Skip", "Ignorer"), + ("Close", "Fermer"), + ("Retry", "Réessayer"), + ("OK", "Confirmer"), + ("Password Required", "Mot de passe requis"), + ("Please enter your password", "Veuillez saisir votre mot de passe"), + ("Remember password", "Mémoriser le mot de passe"), + ("Wrong Password", "Mauvais mot de passe"), + ("Do you want to enter again?", "Voulez-vous participer à nouveau ?"), + ("Connection Error", "Erreur de connexion"), + ("Error", "Erreur"), + ("Reset by the peer", "La connexion a été fermée par le pair"), + ("Connecting...", "Connexion..."), + ("Connection in progress. Please wait.", "Connexion en cours. Veuillez patienter."), + ("Please try 1 minute later", "Réessayez dans une minute"), + ("Login Error", "Erreur de connexion"), + ("Successful", "Succès"), + ("Connected, waiting for image...", "Connecté, en attente de transmission d'image..."), + ("Name", "Nom du fichier"), + ("Modified", "Modifié"), + ("Size", "Taille"), + ("Show Hidden Files", "Afficher les fichiers cachés"), + ("Receive", "Accepter"), + ("Send", "Envoyer"), + ("Remote Computer", "Ordinateur distant"), + ("Local Computer", "Ordinateur local"), + ("Confirm Delete", "Confirmer la suppression"), + ("Are you sure you want to delete this file?", "Voulez-vous vraiment supprimer ce fichier ?"), + ("Do this for all conflicts", "Appliquer à d'autres conflits"), + ("Deleting", "Suppression"), + ("files", "fichier"), + ("Waiting", "En attente en attente..."), + ("Finished", "Terminé"), + ("Custom Image Quality", "Définir la qualité d'image"), + ("Privacy mode", "Mode privé"), + ("Adjust Window", "Ajuster la fenêtre"), + ("Original", "Ratio d'origine"), + ("Shrink", "Rétréci"), + ("Stretch", "Étirer"), + ("Good image quality", "Bonne qualité d'image"), + ("Balanced", "Qualité d'image normale"), + ("Optimize reaction time", "Optimiser le temps de réaction"), + ("Custom", "Qualité d'image personnalisée"), + ("Show remote cursor", "Afficher le curseur distant"), + ("Disable clipboard", "Désactiver le presse-papiers"), + ("Lock after session end", "Verrouiller l'ordinateur distant après la déconnexion"), + ("Insert", "Insérer"), + ("Insert Lock", "Verrouiller l'ordinateur distant"), + ("Refresh", "Rafraîchir l'écran"), + ("ID does not exist", "L'ID n'existe pas"), + ("Failed to connect to rendezvous server", "Échec de la connexion au serveur de rendez-vous"), + ("Please try later", "Veuillez essayer plus tard"), + ("Remote desktop is offline", "Le bureau à distance est hors ligne"), + ("Key mismatch", "Discordance de clé"), + ("Timeout", "Connexion expirée"), + ("Failed to connect to relay server", "Échec de la connexion au serveur relais"), + ("Failed to connect via rendezvous server", "Échec de l'établissement d'une connexion via le serveur de rendez-vous"), + ("Failed to connect via relay server", "Impossible d'établir une connexion via le serveur relais"), + ("Failed to make direct connection to remote desktop", "Impossible d'établir une connexion directe"), + ("Set Password", "Définir le mot de passe"), + ("OS Password", "Mot de passe du système d'exploitation"), + ("install_tip", "Vous utilisez une version désinstallée. En raison des restrictions UAC, en tant que terminal contrôlé, dans certains cas, il ne sera pas en mesure de contrôler la souris et le clavier ou d'enregistrer l'écran. Veuillez cliquer sur le bouton ci-dessous pour installer RustDesk au système pour éviter la question ci-dessus."), + ("Click to upgrade", "Cliquez pour mettre à niveau"), + ("Configuration Permissions", "Autorisations de configuration"), + ("Configure", "Configurer"), + ("config_acc", "Afin de pouvoir contrôler votre bureau à distance, veuillez donner l'autorisation\"accessibilité\" à RustDesk."), + ("config_screen", "Afin de pouvoir accéder à votre bureau à distance, veuillez donner l'autorisation à RustDesk\"enregistrement d'écran\"."), + ("Installing ...", "Installation ..."), + ("Install", "Installer"), + ("Installation", "Installation"), + ("Installation Path", "Chemin d'installation"), + ("Create start menu shortcuts", "Créer des raccourcis dans le menu démarrer"), + ("Create desktop icon", "Créer une icône sur le bureau"), + ("agreement_tip", "Démarrer l'installation signifie accepter le contrat de licence."), + ("Accept and Install", "Accepter et installer"), + ("End-user license agreement", "Contrat d'utilisateur"), + ("Generating ...", "Génération ..."), + ("Your installation is lower version.", "La version que vous avez installée est inférieure à la version en cours d'exécution."), + ("not_close_tcp_tip", "Veuillez ne pas fermer cette fenêtre lors de l'utilisation du tunnel"), + ("Listening ...", "En attente de connexion tunnel..."), + ("Remote Host", "Hôte distant"), + ("Remote Port", "Port distant"), + ("Action", "Action"), + ("Add", "Ajouter"), + ("Local Port", "Port local"), + ("setup_server_tip", "Si vous avez besoin d'une vitesse de connexion plus rapide, vous pouvez choisir de créer votre propre serveur"), + ("Too short, at least 6 characters.", "Trop court, au moins 6 caractères."), + ("The confirmation is not identical.", "Les deux entrées ne correspondent pas"), + ("Permissions", "Autorisations"), + ("Accept", "Accepter"), + ("Dismiss", "Rejeter"), + ("Disconnect", "Déconnecter"), + ("Allow using keyboard and mouse", "Autoriser l'utilisation du clavier et de la souris"), + ("Allow using clipboard", "Autoriser l'utilisation du presse-papiers"), + ("Allow hearing sound", "Autoriser l'audition du son"), + ("Connected", "Connecté"), + ("Direct and encrypted connection", "Connexion directe cryptée"), + ("Relayed and encrypted connection", "Connexion relais cryptée"), + ("Direct and unencrypted connection", "Connexion directe non cryptée"), + ("Relayed and unencrypted connection", "Connexion relais non cryptée"), + ("Enter Remote ID", "Entrez l'ID à distance"), + ("Enter your password", "Entrez votre mot de passe"), + ("Logging in...", "Se connecter..."), + ("Enable RDP session sharing", "Activer le partage de session RDP"), + ("Auto Login", "Connexion automatique (le verrouillage ne sera effectif qu'après la déconnexion du paramètre)"), + ("Enable Direct IP Access", "Autoriser l'accès direct IP"), + ("Rename", "Renommer"), + ("Space", "Espace"), + ("Create Desktop Shortcut", "Créer un raccourci sur le bureau"), + ("Change Path", "Changer de chemin"), + ("Create Folder", "Créer un dossier"), + ("Please enter the folder name", "Veuillez saisir le nom du dossier"), + ("Fix it", "Réparez-le"), + ("Warning", "Avertissement"), + ("Login screen using Wayland is not supported", "L'écran de connexion utilisant Wayland n'est pas pris en charge"), + ("Reboot required", "Redémarrage pour prendre effet"), + ("Unsupported display server ", "Le serveur d'affichage actuel n'est pas pris en charge"), + ("x11 expected", "Veuillez passer à x11"), + ("Port", "Port"), + ("Settings", "Paramètres"), + ("Username", " Nom d'utilisateur"), + ("Invalid port", "Port invalide"), + ("Closed manually by the peer", "Fermé manuellement par le pair"), + ("Enable remote configuration modification", "Autoriser la modification de la configuration à distance"), + ("Run without install", "Exécuter sans installer"), + ("Always connected via relay", "Forcer la connexion relais"), + ("Always connect via relay", "Forcer la connexion relais"), + ("whitelist_tip", "Seul l'ip dans la liste blanche peut m'accéder"), + ("Login", "Connexion"), + ("Logout", "Déconnexion"), + ("Tags", "Étiqueter"), + ("Search ID", "Identifiant de recherche"), + ("Current Wayland display server is not supported", "Le serveur d'affichage Wayland n'est pas pris en charge"), + ("whitelist_sep", "Vous pouvez utiliser une virgule, un point-virgule, un espace ou une nouvelle ligne comme séparateur"), + ("Add ID", "Ajouter ID"), + ("Add Tag", "Ajouter une balise"), + ("Unselect all tags", "Désélectionner toutes les balises"), + ("Network error", "Erreur réseau"), + ("Username missed", "Nom d'utilisateur manqué"), + ("Password missed", "Mot de passe manqué"), + ("Wrong credentials", "Identifiant ou mot de passe erroné"), + ("Edit Tag", "Modifier la balise"), + ].iter().cloned().collect(); + } diff --git a/src/lib.rs b/src/lib.rs index b0cf92bea..2df657ab0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,3 +27,4 @@ use common::*; pub mod cli; #[cfg(not(any(target_os = "android", target_os = "ios")))] mod port_forward; +mod lang; diff --git a/src/ui.rs b/src/ui.rs index 8d68c833e..21694cec0 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -562,6 +562,11 @@ impl UI { allow_err!(std::process::Command::new(p).arg(url).spawn()); } + fn t(&self, name: String) -> String { + crate::client::translate(name) + } + + fn is_xfce(&self) -> bool { crate::platform::is_xfce() } @@ -569,6 +574,7 @@ impl UI { impl sciter::EventHandler for UI { sciter::dispatch_script_call! { + fn t(String); fn is_xfce(); fn get_id(); fn get_password(); diff --git a/src/ui/cm.rs b/src/ui/cm.rs index 15583e56b..ae31bc864 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -300,6 +300,10 @@ impl ConnectionManager { fn exit(&self) { std::process::exit(0); } + + fn t(&self, name: String) -> String { + crate::client::translate(name) + } } impl sciter::EventHandler for ConnectionManager { @@ -308,6 +312,7 @@ impl sciter::EventHandler for ConnectionManager { } sciter::dispatch_script_call! { + fn t(String); fn get_icon(); fn close(i32); fn authorize(i32); diff --git a/src/ui/cm.tis b/src/ui/cm.tis index 5caefd78f..6f481b0b2 100644 --- a/src/ui/cm.tis +++ b/src/ui/cm.tis @@ -33,22 +33,22 @@ class Body: Reactor.Component
    {c.name}
    ({c.peer_id})
    -
    Connected {getElaspsed(c.time)}
    +
    {translate('Connected')} {" "} {getElaspsed(c.time)}
    - {c.is_file_transfer || c.port_forward ? "" :
    Permissions
    } + {c.is_file_transfer || c.port_forward ? "" :
    {translate('Permissions')}
    } {c.is_file_transfer || c.port_forward ? "" :
    -
    -
    -
    +
    +
    +
    } {c.port_forward ?
    Port Forwarding: {c.port_forward}
    : ""}
    - {auth ? "" : } - {auth ? "" : } - {auth ? : ""} + {auth ? "" : } + {auth ? "" : } + {auth ? : ""}
    {c.is_file_transfer || c.port_forward ? "" :
    {svg_chat}
    }
    @@ -101,6 +101,7 @@ class Body: Reactor.Component connection.authorized = true; body.update(); handler.authorize(cid); + view.windowState = View.WINDOW_MINIMIZED; }); } diff --git a/src/ui/common.tis b/src/ui/common.tis index 679744439..c7c767645 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -10,6 +10,15 @@ var is_file_transfer; var is_xfce = false; try { is_xfce = handler.is_xfce(); } catch(e) {} + +function translate(name) { + try { + return handler.t(name); + } catch(_) { + return name; + } +} + function hashCode(str) { var hash = 160 << 16 + 114 << 8 + 91; for (var i = 0; i < str.length; i += 1) { @@ -207,7 +216,7 @@ function getMsgboxParams() { return msgbox_params; } -function msgbox(type, title, text, callback, height, width, retry=0) { +function msgbox(type, title, text, callback, height, width, retry=0, contentStyle="") { var has_msgbox = msgbox_params != null; if (!has_msgbox && !type) return; var remember = false; @@ -217,7 +226,8 @@ function msgbox(type, title, text, callback, height, width, retry=0) { msgbox_params = { remember: remember, type: type, text: text, title: title, getParams: getMsgboxParams, - callback: callback, retry: retry, + callback: callback, translate: translate, + retry: retry, contentStyle: contentStyle, }; if (has_msgbox) return; var dialog = { @@ -239,7 +249,7 @@ function msgbox(type, title, text, callback, height, width, retry=0) { } else if (res == "!alive") { // do nothing } else if (res.type == "input-password") { - if (!is_port_forward) connecting(); + if (!is_port_forward) handler.msgbox("connecting", "Connecting...", "Logging in..."); handler.login(res.password, res.remember); } else if (res.reconnect) { if (!is_port_forward) connecting(); @@ -251,10 +261,10 @@ function connecting() { handler.msgbox("connecting", "Connecting...", "Connection in progress. Please wait."); } -handler.msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0) { +handler.msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0, contentStyle="") { // directly call view.Dialog from native may crash, add timer here, seem safe // too short time, msgbox won't get focus, per my test, 150 is almost minimun - self.timer(150ms, function() { msgbox(type, title, text, callback, height, width, retry); }); + self.timer(150ms, function() { msgbox(type, title, text, callback, height, width, retry, contentStyle); }); } handler.block_msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0) { @@ -312,6 +322,47 @@ function Progress() this.value = ""; } +var svg_eye_cross = + + +; + +class PasswordComponent: Reactor.Component { + this var visible = false; + this var value = ''; + this var name = 'password'; + + function this(params) { + if (params && params.value) { + this.value = params.value; + } + if (params && params.name) { + this.name = params.name; + } + } + + function render() { + return
    + + {this.visible ? svg_eye_cross : svg_eye} +
    ; + } + + event click $(svg) { + var el = this.$(input); + var value = el.value; + var start = el.xcall(#selectionStart) || 0; + var end = el.xcall(#selectionEnd); + this.update({ visible: !this.visible }); + self.timer(30ms, function() { + var el = this.$(input); + view.focus = el; + el.value = value; + el.xcall(#setSelection, start, end); + }); + } +} + function isReasonableSize(r) { var x = r[0]; var y = r[1]; diff --git a/src/ui/file_transfer.tis b/src/ui/file_transfer.tis index 9c67d79ba..e3a9c115d 100644 --- a/src/ui/file_transfer.tis +++ b/src/ui/file_transfer.tis @@ -141,11 +141,11 @@ class JobTable: Reactor.Component { } function getStatus(job) { - if (!job.entries) return "Waiting"; + if (!job.entries) return translate("Waiting"); var i = job.file_num + 1; var n = job.num_entries || job.entries.length; if (i > n) i = n; - var res = i + ' / ' + n + " files"; + var res = i + ' / ' + n + " " + translate("files"); if (job.total_size > 0) { var s = getSize(0, job.finished_size); if (s) s += " / "; @@ -155,7 +155,7 @@ class JobTable: Reactor.Component { var percent = job.total_size == 0 ? 100 : (100. * job.finished_size / job.total_size).toInteger(); // (100. * i / (n || 1)).toInteger(); if (job.finished) percent = '100'; if (percent) res += ", " + percent + "%"; - if (job.finished) res = "Finished " + res; + if (job.finished) res = translate("Finished") + " " + res; if (job.speed) res += ", " + getSize(0, job.speed) + "/s"; return res; } @@ -250,7 +250,7 @@ class FolderView : Reactor.Component { return
    {svg_computer}
    {platformSvg(handler.get_platform(this.is_remote), "white")}
    -
    {this.is_remote ? "Remote Computer" : "Local Computer"}
    +
    {translate(this.is_remote ? "Remote Computer" : "Local Computer")}
    } @@ -273,7 +273,7 @@ class FolderView : Reactor.Component { function renderOpBar() { if (this.is_remote) { return
    -
    {svg_send}Receive
    +
    {svg_send}{translate('Receive')}
    {svg_add_folder}
    {svg_trash}
    @@ -283,7 +283,7 @@ class FolderView : Reactor.Component {
    {svg_add_folder}
    {svg_trash}
    -
    Send{svg_send}
    +
    {translate('Send')}{svg_send}
    ; } @@ -308,14 +308,14 @@ class FolderView : Reactor.Component { var id = (this.is_remote ? "remote" : "local") + "-folder-view"; return - + {rows} -
  • {svg_checkmark}Show Hidden Files
  • +
  • {svg_checkmark}{translate('Show Hidden Files')}
  • NameModifiedSize
    {translate('Name')}{translate('Modified')}{translate('Size')}
    ; @@ -431,8 +431,8 @@ class FolderView : Reactor.Component { event click $(.add-folder) () { var me = this; - handler.msgbox("custom", "Create Folder", "
    \ -
    Please enter the folder name:
    \ + handler.msgbox("custom", translate("Create Folder"), "
    \ +
    " + translate("Please enter the folder name") + ":
    \
    \
    ", function(res=null) { if (!res) return; @@ -523,7 +523,7 @@ class FolderView : Reactor.Component { var file_transfer; class FileTransfer: Reactor.Component { - function this(params) { + function this() { file_transfer = this; } @@ -600,7 +600,7 @@ var create_dir_jobs = {} function confirmDelete(path, is_remote) { handler.block_msgbox("custom-skip", "Confirm Delete", "
    \ -
    Are you sure you want to delete this file?
    \ +
    " + translate('Are you sure you want to delete this file?') + "
    \ " + path + "
    \
    ", function(res=null) { if (res) { @@ -620,10 +620,10 @@ handler.confirmDeleteFiles = function(id, i, name) { var file_path = job.path; if (name) file_path += handler.get_path_sep(job.is_remote) + name; handler.block_msgbox("custom-skip", "Confirm Delete", "
    \ -
    Deleting #" + (i + 1) + " of " + n + " files.
    \ -
    Are you sure you want to delete this file?
    \ +
    " + translate('Deleting') + " #" + (i + 1) + " / " + n + " " + translate('files') + ".
    \ +
    " + translate('Are you sure you want to delete this file?') + "
    \ " + name + "
    \ -
    Do this for all conflicts
    \ +
    " + translate('Do this for all conflicts') + "
    \
    ", function(res=null) { if (!res) { jt.updateJobStatus(id, i - 1, "cancel"); diff --git a/src/ui/header.tis b/src/ui/header.tis index 1fc472b7e..5307fd5d8 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -31,6 +31,10 @@ if (is_linux) { } } +function get_id() { + return handler.get_option('alias') || handler.get_id() +} + function stateChanged() { stdout.println('state changed from ' + cur_window_state + ' -> ' + view.windowState); cur_window_state = view.windowState; @@ -58,7 +62,7 @@ var old_window_state = View.WINDOW_SHOWN; var input_blocked; class Header: Reactor.Component { - function this(params) { + function this() { header = this; } @@ -67,18 +71,18 @@ class Header: Reactor.Component { var title_conn; if (this.secure_connection && this.direct_connection) { icon_conn = svg_secure; - title_conn = "Direct and secure connection"; + title_conn = translate("Direct and encrypted connection"); } else if (this.secure_connection && !this.direct_connection) { icon_conn = svg_secure_relay; - title_conn = "Relayed and secure connection"; + title_conn = translate("Relayed and encrypted connection"); } else if (!this.secure_connection && this.direct_connection) { icon_conn = svg_insecure; - title_conn = "Direct and insecure connection"; + title_conn = translate("Direct and unencrypted connection"); } else { icon_conn = svg_insecure_relay; - title_conn = "Relayed and insecure connection"; + title_conn = translate("Relayed and unencrypted connection"); } - var title = handler.get_id(); + var title = get_id(); if (pi.hostname) title += "(" + pi.username + "@" + pi.hostname + ")"; if ((pi.displays || []).length == 0) { return
    {title}
    ; @@ -89,14 +93,14 @@ class Header: Reactor.Component {
    ; }); updateWindowToolbarPosition(); - var style = "flow: horizontal;"; - if (is_osx) style += "margin: *"; + var style = "flow:horizontal;"; + if (is_osx) style += "margin:*"; self.timer(1ms, toggleMenuState); return
    {is_osx || is_xfce ? "" : {svg_fullscreen}}
    {icon_conn} -
    {handler.get_id()}
    +
    {get_id()}
    {screens}
    {this.renderGlobalScreens()}
    @@ -111,22 +115,22 @@ class Header: Reactor.Component { function renderDisplayPop() { return -
  • Adjust Window
  • +
  • {translate('Adjust Window')}
  • -
  • {svg_checkmark}Original
  • -
  • {svg_checkmark}Shrink
  • -
  • {svg_checkmark}Stretch
  • +
  • {svg_checkmark}{translate('Original')}
  • +
  • {svg_checkmark}{translate('Shrink')}
  • +
  • {svg_checkmark}{translate('Stretch')}
  • -
  • {svg_checkmark}Good image quality
  • -
  • {svg_checkmark}Balanced
  • -
  • {svg_checkmark}Optimize reaction time
  • -
  • {svg_checkmark}Custom
  • +
  • {svg_checkmark}{translate('Good image quality')}
  • +
  • {svg_checkmark}{translate('Balanced')}
  • +
  • {svg_checkmark}{translate('Optimize reaction time')}
  • +
  • {svg_checkmark}{translate('Custom')}
  • -
  • {svg_checkmark}Show remote cursor
  • - {audio_enabled ?
  • {svg_checkmark}Mute
  • : ""} - {keyboard_enabled && clipboard_enabled ?
  • {svg_checkmark}Disable clipboard
  • : ""} - {keyboard_enabled ?
  • {svg_checkmark}Lock after session end
  • : ""} - {false && pi.platform == "Windows" ?
  • {svg_checkmark}Privacy mode
  • : ""} +
  • {svg_checkmark}{translate('Show remote cursor')}
  • + {audio_enabled ?
  • {svg_checkmark}{translate('Mute')}
  • : ""} + {keyboard_enabled && clipboard_enabled ?
  • {svg_checkmark}{translate('Disable clipboard')}
  • : ""} + {keyboard_enabled ?
  • {svg_checkmark}{translate('Lock after session end')}
  • : ""} + {false && pi.platform == "Windows" ?
  • {svg_checkmark}{translate('Privacy mode')}
  • : ""} ; } @@ -134,23 +138,20 @@ class Header: Reactor.Component { function renderActionPop() { return -
  • Transfer File
  • -
  • TCP Tunneling
  • +
  • {translate('Transfer File')}
  • +
  • {translate('TCP Tunneling')}
  • - {keyboard_enabled && (pi.platform == "Linux" || pi.sas_enabled) ?
  • Insert Ctrl + Alt + Del
  • : ""} -
  • Insert Ctrl + Space
  • -
  • Insert Alt + Tab
  • - {false &&
  • Insert Win/Super + ...
  • } + {keyboard_enabled && (pi.platform == "Linux" || pi.sas_enabled) ?
  • {translate('Insert')} Ctrl + Alt + Del
  • : ""}
    - {keyboard_enabled ?
  • Insert Lock
  • : ""} + {keyboard_enabled ?
  • {translate('Insert Lock')}
  • : ""} {false && pi.platform == "Windows" ?
  • Block user input
  • : ""} - {handler.support_refresh() ?
  • Refresh
  • : ""} + {handler.support_refresh() ?
  • {translate('Refresh')}
  • : ""} ; } function renderGlobalScreens() { - if (pi.displays.length < 2) return ""; + if (pi.displays.length < 3) return ""; var x0 = 9999999; var y0 = 9999999; var x = -9999999; @@ -232,18 +233,6 @@ class Header: Reactor.Component { event click $(#ctrl-alt-del) { handler.ctrl_alt_del(); } - - event click $(#alt-tab) { - handler.alt_tab(); - } - - event click $(#ctrl-space) { - handler.ctrl_space(); - } - - event click $(#super-x) { - handler.super_x(); - } event click $(#lock-screen) { handler.lock_screen(); @@ -289,8 +278,8 @@ function handle_custom_image_quality() { var bitrate0 = tmp[0] || 50; var quantizer0 = tmp.length > 1 ? tmp[1] : 100; handler.msgbox("custom", "Custom Image Quality", "
    \ -
    x% bitrate
    \ -
    x% quantizer
    \ +
    x% bitrate
    \ +
    x% quantizer
    \
    ", function(res=null) { if (!res) return; if (!res.bitrate) return; diff --git a/src/ui/index.tis b/src/ui/index.tis index 09339a75e..542835b20 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -18,29 +18,35 @@ var svg_menu = ; +var my_id = ""; +function get_id() { + my_id = handler.get_id(); + return my_id; +} + class ConnectStatus: Reactor.Component { function render() { return
    {this.getConnectStatusStr()} - {service_stopped ? Start Service : ""} + {service_stopped ? {translate('Start Service')} : ""}
    ; } function getConnectStatusStr() { if (service_stopped) { - return "Service is not running"; + return translate("Service is not running"); } else if (connect_status == -1) { - return "Not ready. Please check your connection"; + return translate('not_ready_status'); } else if (connect_status == 0) { - return "Connecting to the RustDesk network..."; + return translate('connecting_status'); } - return "Ready"; + return translate("Ready"); } - event click $(.connect-status .link) () { - handler.set_option("stop-service", ""); + event click $(#start-service) () { + handler.set_option("stop-service", ""); } } @@ -50,7 +56,7 @@ class RecentSessions: Reactor.Component { if (sessions.length == 0) return ; sessions = sessions.map(this.getSession); return
    -
    RECENT SESSIONS
    +
    {translate("Recent Sessions")}
    {sessions}
    @@ -126,7 +132,7 @@ function createNewConnect(id, type) { id = id.replace(/\s/g, ""); app.remote_id.value = formatId(id); if (!id) return; - if (id == handler.get_id()) { + if (id == my_id) { handler.msgbox("custom-error", "Error", "You cannot connect to your own computer"); return; } @@ -149,10 +155,10 @@ class AudioInputs: Reactor.Component { inputs = ["Mute"].concat(inputs); var me = this; self.timer(1ms, function() { me.toggleMenuState() }); - return
  • Audio Input + return
  • {translate('Audio Input')} {inputs.map(function(name) { - return
  • {svg_checkmark}{name}
  • ; + return
  • {svg_checkmark}{translate(name)}
  • ; })}
  • ; @@ -190,7 +196,6 @@ class MyIdMenu: Reactor.Component { } function render() { - var me = this; return
    {this.renderPop()} ID{svg_menu} @@ -200,19 +205,18 @@ class MyIdMenu: Reactor.Component { function renderPop() { return -
  • {svg_checkmark}Enable Keyboard/Mouse
  • -
  • {svg_checkmark}Enable Clipboard
  • -
  • {svg_checkmark}Enable File Transfer
  • -
  • {svg_checkmark}Enable TCP Tunneling
  • +
  • {svg_checkmark}{translate('Enable Keyboard/Mouse')}
  • +
  • {svg_checkmark}{translate('Enable Clipboard')}
  • +
  • {svg_checkmark}{translate('Enable File Transfer')}
  • +
  • {svg_checkmark}{translate('Enable TCP Tunneling')}
  • -
  • IP Whitelisting
  • -
  • ID/Relay Server
  • +
  • {translate('IP Whitelisting')}
  • +
  • {translate('ID/Relay Server')}
  • -
  • {svg_checkmark}Enable Service
  • +
  • {svg_checkmark}{translate("Enable Service")}
  • -
  • Forum
  • -
  • About {handler.get_app_name()}
  • +
  • {translate('About')} {" "} {handler.get_app_name()}
  • ; } @@ -240,8 +244,9 @@ class MyIdMenu: Reactor.Component { } if (me.id == "whitelist") { var old_value = handler.get_option("whitelist").split(",").join("\n"); - handler.msgbox("custom-whitelist", "IP Whitelisting", "
    \ - \ + handler.msgbox("custom-whitelist", translate("IP Whitelisting"), "
    \ +
    " + translate("whitelist_sep") + "
    \ + \
    \ ", function(res=null) { if (!res) return; @@ -250,7 +255,7 @@ class MyIdMenu: Reactor.Component { var values = value.split(/[\s,;\n]+/g); for (var ip in values) { if (!ip.match(/^\d+\.\d+\.\d+\.\d+$/)) { - return "Invalid ip: " + ip; + return translate("Invalid IP") + ": " + ip; } } value = values.join("\n"); @@ -260,12 +265,12 @@ class MyIdMenu: Reactor.Component { handler.set_option("whitelist", value.replace("\n", ",")); }, 300); } else if (me.id == "custom-server") { - var configOptions = handler.get_options(); + var configOptions = handler.get_options(); var old_relay = configOptions["relay-server"] || ""; var old_id = configOptions["custom-rendezvous-server"] || ""; handler.msgbox("custom-server", "ID/Relay Server", "
    \ -
    ID Server:
    \ -
    Relay Server:
    \ +
    " + translate("ID Server") + ":
    \ +
    " + translate("Relay Server") + ":
    \
    \ ", function(res=null) { if (!res) return; @@ -274,18 +279,16 @@ class MyIdMenu: Reactor.Component { if (id == old_id && relay == old_relay) return; if (id) { var err = handler.test_if_valid_server(id); - if (err) return "ID Server: " + err; + if (err) return translate("ID Server") + ": " + err; } if (relay) { var err = handler.test_if_valid_server(relay); - if (err) return "Relay Server: " + err; + if (err) return translate("Relay Server") + ": " + err; } configOptions["custom-rendezvous-server"] = id; configOptions["relay-server"] = relay; handler.set_options(configOptions); - }); - } else if (me.id == "forum") { - handler.open_url("https:://forum.rustdesk.com"); + }, 240); } else if (me.id == "stop-service") { handler.set_option("stop-service", service_stopped ? "" : "Y"); } else if (me.id == "about") { @@ -293,7 +296,7 @@ class MyIdMenu: Reactor.Component { handler.msgbox("custom-nocancel-nook-hasclose", "About " + name, "
    \
    Version: " + handler.get_version() + " \
    Privacy Statement
    \ -
    Forum
    \ +
    Website
    \
    Copyright © 2020 CarrieZ Studio \
    Author: Carrie \

    Made with heart in this chaotic world!

    \ @@ -319,13 +322,13 @@ class App: Reactor.Component
    -
  • Connect
  • -
  • Transfer File
  • -
  • TCP Tunneling
  • -
  • RDP
  • -
  • Rename
  • -
  • Remove
  • - {is_win &&
  • Create Desktop Shortcut
  • } +
  • {translate('Connect')}
  • +
  • {translate('Transfer File')}
  • +
  • {translate('TCP Tunneling')}
  • +
  • RDP
  • +
  • {translate('Rename')}
  • +
  • {translate('Remove')}
  • + {is_win &&
  • {translate('Create Desktop Shortcut')}
  • }
    @@ -336,18 +339,18 @@ class App: Reactor.Component
    -
    Your Desktop
    -
    Your desktop can be accessed with this ID and password.
    +
    {translate('Your Desktop')}
    +
    {translate('desk_tip')}
    - - {key_confirmed ? : "Generating ..."} + + {key_confirmed ? : translate("Generating ...")}
    -
    Password
    +
    {translate('Password')}
    - {handler.is_installed() ? "": } + {handler.is_installed() ? "": } {handler.is_installed() && software_update_url ? : ""} {handler.is_installed() && !software_update_url && handler.is_installed_lower_version() ? : ""} {is_can_screen_recording ? "": } @@ -359,11 +362,11 @@ class App: Reactor.Component
    -
    Control Remote Desktop
    +
    {translate('Control Remote Desktop')}
    - - + +
    @@ -386,11 +389,12 @@ class App: Reactor.Component } } -class InstalllMe: Reactor.Component { +class InstallMe: Reactor.Component { function render() { return
    -
    Install RustDesk
    -
    Install RustDesk on this computer ...
    + +
    {translate('install_tip')}
    +
    ; } @@ -445,9 +449,9 @@ class UpgradeMe: Reactor.Component { function render() { var update_or_download = is_osx ? "download" : "update"; return
    -
    {handler.get_app_name()} Status
    -
    An update is available for RustDesk.
    -
    Click to upgrade
    +
    {translate('Status')}
    +
    {translate('Your installation is lower version.')}
    +
    {translate('Click to upgrade')}
    ; } @@ -458,9 +462,9 @@ class UpgradeMe: Reactor.Component { class UpdateMe: Reactor.Component { function render() { - var update_or_download = is_osx ? "download" : "update"; + var update_or_download = "download"; // !is_win ? "download" : "update"; return
    -
    {handler.get_app_name()} Status
    +
    {translate('Status')}
    There is a newer version of {handler.get_app_name()} ({handler.get_new_version()}) available.
    Click to {update_or_download}
    @@ -468,14 +472,16 @@ class UpdateMe: Reactor.Component { } event click $(#install-me) { - if (is_osx) { + handler.open_url("https://rustdesk.com"); + return; + if (!is_win) { handler.open_url("https://rustdesk.com"); return; } var url = software_update_url + '.' + handler.get_software_ext(); var path = handler.get_software_store_path(); var onsuccess = function(md5) { - $(#download-percent).content("Installing ..."); + $(#download-percent).content(translate("Installing ...")); handler.update_me(path); }; var onerror = function(err) { @@ -506,9 +512,9 @@ class SystemError: Reactor.Component { class TrustMe: Reactor.Component { function render() { return
    -
    Configuration Permissions
    -
    In order to control your Desktop remotely, you need to grant RustDesk "Accessibility" permissions
    -
    Configure
    +
    {translate('Configuration Permissions')}
    +
    {translate('config_acc')}
    +
    {translate('Configure')}
    ; } @@ -521,9 +527,9 @@ class TrustMe: Reactor.Component { class CanScreenRecording: Reactor.Component { function render() { return
    -
    Configuration Permissions
    -
    In order to access your Desktop remotely, you need to grant RustDesk "Screen Recording" permissions
    -
    Configure
    +
    {translate('Configuration Permissions')}
    +
    {translate('config_screen')}
    +
    {translate('Configure')}
    ; } @@ -536,9 +542,10 @@ class CanScreenRecording: Reactor.Component { class FixWayland: Reactor.Component { function render() { return
    -
    Warning
    -
    Login screen using Wayland is not supported
    -
    Fix it
    +
    {translate('Warning')}
    +
    {translate('Login screen using Wayland is not supported')}
    +
    {translate('Fix it')}
    +
    ({translate('Reboot required')})
    ; } @@ -551,9 +558,10 @@ class FixWayland: Reactor.Component { class ModifyDefaultLogin: Reactor.Component { function render() { return
    -
    Warning
    -
    Current Wayland display server is not supported
    -
    Fix it(re-login required)
    +
    {translate('Warning')}
    +
    {translate('Current Wayland display server is not supported')}
    +
    {translate('Fix it')}
    +
    ({translate('Reboot required')})
    ; } @@ -622,19 +630,19 @@ class Password: Reactor.Component { event click $(li#set-password) { var me = this; - handler.msgbox("custom-password", "Set Password", "
    \ -
    Password:
    \ -
    Confirmation:
    \ + handler.msgbox("custom-password", translate("Set Password"), "
    \ +
    " + translate('Password') + ":
    \ +
    " + translate('Confirmation') + ":
    \
    \ ", function(res=null) { if (!res) return; var p0 = (res.password || "").trim(); var p1 = (res.confirmation || "").trim(); if (p0.length < 6) { - return "Too short, at least 6 characters."; + return translate("Too short, at least 6 characters."); } if (p0 != p1) { - return "The confirmation is not identical."; + return translate("The confirmation is not identical."); } handler.update_password(p0); me.update(); @@ -644,7 +652,7 @@ class Password: Reactor.Component { class ID: Reactor.Component { function render() { - return ; } @@ -735,6 +743,10 @@ function checkConnectStatus() { key_confirmed = tmp[1]; app.update(); } + if (tmp[2] && tmp[2] != my_id) { + stdout.println("id updated"); + app.update(); + } tmp = handler.get_error(); if (system_error != tmp) { system_error = tmp; diff --git a/src/ui/install.tis b/src/ui/install.tis index 99befec1e..59c104354 100644 --- a/src/ui/install.tis +++ b/src/ui/install.tis @@ -5,17 +5,17 @@ function self.ready() { class Install: Reactor.Component { function render() { return
    -
    Installation
    -
    Installation Path:
    -
    Create start menu shortcuts
    -
    Create desktop icon
    -
    End-user license agreement
    -
    By starting the installation, you accept the license agreement.
    +
    {translate('Installation')}
    +
    {translate('Installation Path')} {": "}
    +
    {translate('Create start menu shortcuts')}
    +
    {translate('Create desktop icon')}
    +
    {translate('End-user license agreement')}
    +
    {translate('agreement_tip')}
    - - + +
    ; } @@ -42,4 +42,4 @@ class Install: Reactor.Component { } } -$(body).content(); \ No newline at end of file +$(body).content(); diff --git a/src/ui/msgbox.tis b/src/ui/msgbox.tis index ea84dcd02..eb0ef8a62 100644 --- a/src/ui/msgbox.tis +++ b/src/ui/msgbox.tis @@ -1,4 +1,5 @@ -var type, title, text, getParams, remember, retry, callback; +var type, title, text, getParams, remember, retry, callback, contentStyle; +var my_translate; function updateParams(params) { type = params.type; @@ -7,7 +8,10 @@ function updateParams(params) { getParams = params.getParams; remember = params.remember; callback = params.callback; + my_translate = params.translate; retry = params.retry; + contentStyle = params.contentStyle; + try { text = translate_text(text); } catch (e) {} if (retry > 0) { self.timer(retry * 1000, function() { view.close({ reconnect: true }); @@ -15,39 +19,20 @@ function updateParams(params) { } } +function translate_text(text) { + if (text.indexOf('Failed') == 0 && text.indexOf(': ') > 0) { + var fds = text.split(': '); + for (var i = 0; i < fds.length; ++i) { + fds[i] = my_translate(fds[i]); + } + text = fds.join(': '); + } + return text; +} + var params = view.parameters; updateParams(params); -var svg_eye_cross = - - -; - -class Password: Reactor.Component { - this var visible = false; - - function render() { - return
    - - {this.visible ? svg_eye_cross : svg_eye} -
    ; - } - - event click $(svg) { - var el = this.$(input); - var value = el.value; - var start = el.xcall(#selectionStart) || 0; - var end = el.xcall(#selectionEnd); - this.update({ visible: !this.visible }); - self.timer(30ms, function() { - var el = this.$(input); - view.focus = el; - el.value = value; - el.xcall(#setSelection, start, end); - }); - } -} - var body; class Body: Reactor.Component { @@ -74,9 +59,9 @@ class Body: Reactor.Component { function getInputPasswordContent() { var ts = remember ? { checked: true } : {}; return
    -
    Please enter your password
    - -
    Remember password
    +
    {my_translate('Please enter your password')}
    + +
    {my_translate('Remember password')}
    ; } @@ -116,27 +101,27 @@ class Body: Reactor.Component { var me = this; self.timer(1ms, function() { if (typeof content == "string") - me.$(#content).html = content; + me.$(#content).html = my_translate(content); else me.$(#content).content(content); }); return (
    - {title} + {my_translate(title)}
    {icon &&
    {icon}
    } -
    +
    - - {show_progress ? : ""} - {hasCancel || hasRetry ? : ""} - {this.hasSkip() ? : ""} - {hasOk || hasRetry ? : ""} - {hasClose ? : ""} + + + {hasCancel || hasRetry ? : ""} + {this.hasSkip() ? : ""} + {hasOk || hasRetry ? : ""} + {hasClose ? : ""}
    ); @@ -149,6 +134,17 @@ class Body: Reactor.Component { $(body).content(); +function show_progress(show=1, err="") { + if (show == -1) { + view.close() + return; + } + $(#progress).style.set { + display: show ? "inline-block" : "none" + }; + $(#error).text = err; +} + function submit() { if ($(button#submit)) { $(button#submit).sendEvent("click"); @@ -211,9 +207,12 @@ event click $(button#submit) { } var values = getValues(); if (callback) { - var err = callback(values); + var err = callback(values, show_progress); + if (err && !err.trim()) { + return; + } if (err) { - $(#error).text = err; + show_progress(false, err); return; } } @@ -235,7 +234,7 @@ event keydown (evt) { function set_outline_focus() { self.timer(30ms, function() { - var el = $(input.outline-focus); + var el = $(.outline-focus); if (el) view.focus = el; else { el = $(#submit); diff --git a/src/ui/port_forward.tis b/src/ui/port_forward.tis index d30367710..a30f698c5 100644 --- a/src/ui/port_forward.tis +++ b/src/ui/port_forward.tis @@ -21,17 +21,17 @@ class PortForward: Reactor.Component { }); return
    {pfs.length ?
    - Listening ...
    - Don't close this window while you are using the tunnel + {translate('Listening ...')}
    + {translate('not_close_tcp_tip')}
    : ""} - + - - {args.length ? "" : } + + + {args.length ? "" : } @@ -41,7 +41,7 @@ class PortForward: Reactor.Component { - + } {pfs} diff --git a/src/ui/remote.rs b/src/ui/remote.rs index a9759cbf4..2b5c2f271 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -54,7 +54,6 @@ pub struct HandlerInner { sender: Option>, thread: Option>, close_state: HashMap, - last_down_key: Option<(String, i32, bool)>, } #[derive(Clone, Default)] @@ -64,7 +63,6 @@ pub struct Handler { id: String, args: Vec, lc: Arc>, - super_on: bool, } impl Deref for Handler { @@ -146,6 +144,8 @@ impl sciter::EventHandler for Handler { fn get_id(); fn get_default_pi(); fn get_option(String); + fn t(String); + fn set_option(String, String); fn save_close_state(String, String); fn is_file_transfer(); fn is_port_forward(); @@ -155,9 +155,6 @@ impl sciter::EventHandler for Handler { fn send_mouse(i32, i32, i32, bool, bool, bool, bool); fn key_down_or_up(bool, String, i32, bool, bool, bool, bool, bool); fn ctrl_alt_del(); - fn ctrl_space(); - fn alt_tab(); - fn super_x(); fn transfer_file(); fn tunnel(); fn lock_screen(); @@ -286,6 +283,10 @@ impl Handler { self.lc.read().unwrap().remember } + fn t(&self, name: String) -> String { + crate::client::translate(name) + } + fn is_xfce(&self) -> bool { crate::platform::is_xfce() } @@ -408,6 +409,10 @@ impl Handler { self.lc.read().unwrap().get_option(&k) } + fn set_option(&self, k: String, v: String) { + self.lc.write().unwrap().set_option(k, v); + } + fn save_close_state(&self, k: String, v: String) { self.write().unwrap().close_state.insert(k, v); } @@ -534,7 +539,6 @@ impl Handler { fn reconnect(&mut self) { let cloned = self.clone(); let mut lock = self.write().unwrap(); - lock.last_down_key.take(); lock.thread.take().map(|t| t.join()); lock.thread = Some(std::thread::spawn(move || { io_loop(cloned); @@ -667,7 +671,6 @@ impl Handler { let evt_type = mask & 0x7; if buttons == 1 && evt_type == 1 && ctrl && self.peer_platform() != "Mac OS" { self.send_mouse((1 << 3 | 2) as _, x, y, alt, ctrl, shift, command); - return; } } } @@ -820,20 +823,6 @@ impl Handler { } } - fn super_x(&mut self) { - self.super_on = true; - } - - fn ctrl_space(&mut self) { - let key = "VK_SPACE".to_owned(); - self.key_down_or_up(3, key, 0, false, true, false, false, false); - } - - fn alt_tab(&mut self) { - let key = "VK_TAB".to_owned(); - self.key_down_or_up(3, key, 0, true, false, false, false, false); - } - fn lock_screen(&mut self) { let lock = "LOCK_SCREEN".to_owned(); self.key_down_or_up(1, lock, 0, false, false, false, false, false); @@ -866,6 +855,18 @@ impl Handler { command: bool, extended: bool, ) { + + if self.peer_platform() == "Windows" { + if ctrl && alt && name == "VK_DELETE" { + self.ctrl_alt_del(); + return; + } + if command && name == "VK_L" { + self.lock_screen(); + return; + } + } + // extended: e.g. ctrl key on right side, https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-keybd_event // not found api of osx and xdo log::debug!( @@ -881,15 +882,6 @@ impl Handler { extended, ); - let mut command = command; - if self.super_on { - command = true; - } - - if down_or_up == 0 { - self.super_on = false; - } - let mut name = name; #[cfg(target_os = "linux")] if code == 65383 { From 9903e9df9e66885e96715ff9424804f1f0432e7a Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Sat, 25 Dec 2021 16:55:01 +0800 Subject: [PATCH 15/77] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6991451fd..b0a65dbde 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ StructureSnapshot
    [中文] | [Español] | [Français] | [Deutsch] | [Polski] | [Suomi] | [മലയാളം] | [日本語] | [Nederlands] | [Русский] | [Português]
    - We need your help to translate this README to your native language + We need your help to translate this README and RustDesk UI to your native language

    Chat with us: [Discord](https://discord.gg/nDceKgxnkV) | [Reddit](https://www.reddit.com/r/rustdesk) From d4d90da196c60e9028526a2211ea8f30c3bd664c Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 25 Dec 2021 22:31:42 +0800 Subject: [PATCH 16/77] https://github.com/rustdesk/rustdesk/issues/301 --- 128x128.png | Bin 0 -> 10123 bytes 128x128@2x.png | Bin 0 -> 25356 bytes 32x32.png | Bin 0 -> 4193 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 128x128.png create mode 100644 128x128@2x.png create mode 100644 32x32.png diff --git a/128x128.png b/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..045d8f89476309b36680e0c373000be5f89ab981 GIT binary patch literal 10123 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 XFgC7uZ$0_<<^U+ls>;+!nTP)`s}Kb4 literal 0 HcmV?d00001 diff --git a/128x128@2x.png b/128x128@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..39e2b23cf62d86a3ec4a4cd29a632dc1d1fd1a18 GIT binary patch literal 25356 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 Ef?R_wi2wiq literal 0 HcmV?d00001 diff --git a/32x32.png b/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..bba85feb6bc83e16410e2bfaa94551c224d27aa8 GIT binary patch literal 4193 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 Date: Sun, 26 Dec 2021 15:34:10 +0800 Subject: [PATCH 17/77] update package --- Cargo.lock | 1163 +++++++++++++++++------------------- Cargo.toml | 26 +- libs/hbb_common/Cargo.toml | 10 +- 3 files changed, 578 insertions(+), 621 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b07d131e0..f7e1a1bc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.16.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" +checksum = "e7a2e47a1fbe209ee101dd6d61285226744c6c8d3c21c8dc878ba6cb9f467f3a" dependencies = [ "gimli", ] @@ -25,23 +25,23 @@ checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" [[package]] name = "aho-corasick" -version = "0.7.18" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] [[package]] name = "alsa" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18" +checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b" dependencies = [ "alsa-sys", "bitflags", "libc", - "nix 0.20.0", + "nix 0.23.1", ] [[package]] @@ -62,36 +62,36 @@ checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e" [[package]] name = "android_logger" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ec2333c185d826313162cee39d3fcc6a84ba08114a839bebf53b961e7e75773" +checksum = "d9ed09b18365ed295d722d0b5ed59c01b79a826ff2d2a8f73d5ecca8e6fb2f66" dependencies = [ "android_log-sys", - "env_logger 0.7.1", + "env_logger 0.8.4", "lazy_static", "log", ] [[package]] name = "ansi_term" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ "winapi 0.3.9", ] [[package]] name = "anyhow" -version = "1.0.42" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" +checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3" [[package]] name = "arboard" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f838ae439a56a92181ba4098c2da5eb7ea8283a15ac8226db6cae32a3a24a26" +checksum = "1d76e1fe0171b6d0857afca5671db12a44e71e80823db13ab39f776fb09ad079" dependencies = [ "clipboard-win", "core-graphics", @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.51" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" dependencies = [ "proc-macro2", "quote", @@ -144,9 +144,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.61" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" +checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744" dependencies = [ "addr2line", "cc", @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bindgen" @@ -184,15 +184,15 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" dependencies = [ "bitflags", - "cexpr 0.5.0", + "cexpr 0.6.0", "clang-sys", "clap", - "env_logger 0.8.4", + "env_logger 0.9.0", "lazy_static", "lazycell", "log", @@ -201,27 +201,15 @@ dependencies = [ "quote", "regex", "rustc-hash", - "shlex 1.0.0", - "which", + "shlex 1.1.0", + "which 4.2.2", ] [[package]] name = "bitflags" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da1976d75adbe5fbc88130ecd119529cf1cc6a93ae1546d8696ee66f0d21af1" - -[[package]] -name = "bitvec" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "block" @@ -231,24 +219,24 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block-buffer" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" dependencies = [ "generic-array", ] [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" [[package]] name = "bytemuck" -version = "1.7.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" +checksum = "439989e6b8c38d1b6570a384ef1e49c8848128f5a97f3914baef02920842712f" [[package]] name = "byteorder" @@ -258,21 +246,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "0.5.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - -[[package]] -name = "bytes" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cc" -version = "1.0.69" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" dependencies = [ "jobserver", ] @@ -294,11 +276,11 @@ dependencies = [ [[package]] name = "cexpr" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom 6.1.2", + "nom 7.1.0", ] [[package]] @@ -313,24 +295,11 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits 0.2.14", - "time", - "winapi 0.3.9", -] - [[package]] name = "clang-sys" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" +checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" dependencies = [ "glob", "libc", @@ -339,9 +308,9 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", @@ -354,9 +323,9 @@ dependencies = [ [[package]] name = "clipboard-master" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd1cb2f0df685eb4a61c656faeb6ef391ad776943d3723afb12bdcbceff824d" +checksum = "459887701008d8ee21f8de7f45f0f0707417c7eea3311973f6e67222bd686b7a" dependencies = [ "objc", "objc-foundation", @@ -368,9 +337,9 @@ dependencies = [ [[package]] name = "clipboard-win" -version = "4.2.1" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4ea1881992efc993e4dc50a324cdbd03216e41bdc8385720ff47efc9bd2ca8" +checksum = "3db8340083d28acb43451166543b98c838299b7e0863621be53a338adceea0ed" dependencies = [ "error-code", "str-buf", @@ -388,9 +357,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" +checksum = "b7b858541263efe664aead4a5209a4ae5c5d2811167d4ed4ee0944503f8d2089" dependencies = [ "cc", ] @@ -404,7 +373,7 @@ dependencies = [ "bitflags", "block", "cocoa-foundation", - "core-foundation 0.9.1", + "core-foundation", "core-graphics", "foreign-types", "libc", @@ -419,7 +388,7 @@ checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" dependencies = [ "bitflags", "block", - "core-foundation 0.9.1", + "core-foundation", "core-graphics-types", "foreign-types", "libc", @@ -434,11 +403,11 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "combine" -version = "4.6.0" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d47c1b11006b87e492b53b313bb699ce60e16613c4dddaa91f8f7c220ab2fa" +checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" dependencies = [ - "bytes 1.0.1", + "bytes", "memchr", ] @@ -448,50 +417,34 @@ version = "0.4.1" source = "git+https://github.com/open-trade/confy#27fa12941291b44ccd856aef4a5452c1eb646047" dependencies = [ "directories", - "serde 1.0.127", + "serde 1.0.132", "toml", ] [[package]] name = "core-foundation" -version = "0.7.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" dependencies = [ - "core-foundation-sys 0.7.0", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62" -dependencies = [ - "core-foundation-sys 0.8.2", + "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" -version = "0.7.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" - -[[package]] -name = "core-foundation-sys" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "core-graphics" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ "bitflags", - "core-foundation 0.9.1", + "core-foundation", "core-graphics-types", "foreign-types", "libc", @@ -504,7 +457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" dependencies = [ "bitflags", - "core-foundation 0.9.1", + "core-foundation", "foreign-types", "libc", ] @@ -531,19 +484,19 @@ dependencies = [ [[package]] name = "cpal" version = "0.13.4" -source = "git+https://github.com/open-trade/cpal#6b0b769f3d8ea22abdc3a6ea0c74311bf0cfbac3" +source = "git+https://github.com/open-trade/cpal#3a30569687271c2d5d67279c4883d63f4003d34c" dependencies = [ "alsa", - "core-foundation-sys 0.8.2", + "core-foundation-sys", "coreaudio-rs", - "jni 0.19.0", + "jni", "js-sys", "lazy_static", "libc", "mach", "ndk", "ndk-glue", - "nix 0.20.0", + "nix 0.23.1", "oboe", "parking_lot", "stdweb", @@ -554,22 +507,31 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.1.5" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66c99696f6c9dd7f35d486b9d04d7e6e202aa3e8c40d553f2fdf5e7e0c6a71ef" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "crypto-common" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0" +dependencies = [ + "generic-array", +] + [[package]] name = "cstr_core" version = "0.2.4" @@ -580,22 +542,13 @@ dependencies = [ "memchr", ] -[[package]] -name = "ct-logs" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3686f5fa27dbc1d76c751300376e167c5a43387f44bb451fd1c24776e49113" -dependencies = [ - "sct", -] - [[package]] name = "ctrlc" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377c9b002a72a0b2c1a18c62e2f3864bdfea4a015e3683a96e24aa45dd6c02d1" +checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf" dependencies = [ - "nix 0.22.0", + "nix 0.23.1", "winapi 0.3.9", ] @@ -642,9 +595,9 @@ dependencies = [ [[package]] name = "darwin-libproc" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb90051930c9a0f09e585762152048e23ac74d20c10590ef7cf01c0343c3046" +checksum = "cc629b7cf42586fee31dae31f9ab73fa5ff5f0170016aa61be5fcbc12a90c516" dependencies = [ "darwin-libproc-sys", "libc", @@ -653,9 +606,9 @@ dependencies = [ [[package]] name = "darwin-libproc-sys" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57cebb5bde66eecdd30ddc4b9cd208238b15db4982ccc72db59d699ea10867c1" +checksum = "ef0aa083b94c54aa4cfd9bbfd37856714c139d1dc511af80270558c7ba3b4816" dependencies = [ "libc", ] @@ -781,9 +734,9 @@ dependencies = [ [[package]] name = "dbus" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8862bb50aa3b2a2db5bfd2c875c73b3038aa931c411087e335ca8ca0ed430b9" +checksum = "de0a745c25b32caa56b82a3950f5fec7893a960f4c10ca3b02060b0c38d8c2ce" dependencies = [ "libc", "libdbus-sys", @@ -813,9 +766,9 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.16" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "proc-macro2", "quote", @@ -824,10 +777,12 @@ dependencies = [ [[package]] name = "digest" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b" dependencies = [ + "block-buffer", + "crypto-common", "generic-array", ] @@ -897,7 +852,7 @@ checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f" dependencies = [ "lazy_static", "regex", - "serde 1.0.127", + "serde 1.0.132", "strsim 0.10.0", ] @@ -909,9 +864,9 @@ checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" [[package]] name = "ed25519" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc" +checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816" dependencies = [ "signature", ] @@ -931,33 +886,20 @@ dependencies = [ "log", "objc", "pkg-config", - "serde 1.0.127", + "serde 1.0.132", "serde_derive", "unicode-segmentation", "winapi 0.3.9", ] -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "log", - "regex", -] - [[package]] name = "env_logger" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ - "atty", - "humantime", "log", "regex", - "termcolor", ] [[package]] @@ -973,20 +915,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "err-derive" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22deed3a8124cff5fa835713fa105621e43bbdc46690c3a6b68328a012d350d4" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "rustversion", - "syn", - "synstructure", -] - [[package]] name = "err-derive" version = "0.3.0" @@ -1034,9 +962,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ "cfg-if 1.0.0", "crc32fast", @@ -1046,18 +974,19 @@ dependencies = [ [[package]] name = "flexi_logger" -version = "0.17.1" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab94b6ac8eb69f1496a6993f26f785b5fd6d99b7416023eb2a6175c0b242b1" +checksum = "11be38a063886b7be57de89636d65c07d318c1f9bd985cd8ab2c343786a910bc" dependencies = [ + "ansi_term", "atty", - "chrono", "glob", "lazy_static", "log", "regex", + "rustversion", "thiserror", - "yansi", + "time", ] [[package]] @@ -1103,17 +1032,11 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "futures" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adc00f486adfc9ce99f77d717836f0c5aa84965eb0b4f051f4e83f7cab53f8b" +checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4" dependencies = [ "futures-channel", "futures-core", @@ -1126,9 +1049,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ed2411805f6e4e3d9bc904c95d5d423b89b3b25dc0250aa74729de20629ff9" +checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b" dependencies = [ "futures-core", "futures-sink", @@ -1136,15 +1059,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99" +checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7" [[package]] name = "futures-executor" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d0d535a57b87e1ae31437b892713aee90cd2d7b0ee48727cd11fc72ef54761c" +checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a" dependencies = [ "futures-core", "futures-task", @@ -1153,18 +1076,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" +checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2" [[package]] name = "futures-macro" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57" +checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c" dependencies = [ - "autocfg 1.0.1", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -1172,23 +1093,22 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53" +checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508" [[package]] name = "futures-task" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2" +checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" [[package]] name = "futures-util" -version = "0.3.16" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78" +checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164" dependencies = [ - "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -1196,13 +1116,20 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.7", + "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -1223,17 +1150,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.3" @@ -1242,14 +1158,14 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "gimli" -version = "0.25.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" [[package]] name = "glib" @@ -1451,7 +1367,7 @@ name = "hbb_common" version = "0.1.0" dependencies = [ "anyhow", - "bytes 1.0.1", + "bytes", "confy", "directories-next", "dirs-next", @@ -1466,12 +1382,12 @@ dependencies = [ "protobuf-codegen-pure", "quinn", "rand 0.8.4", - "serde 1.0.127", + "serde 1.0.132", "serde_derive", - "serde_json 1.0.66", - "socket2", + "serde_json 1.0.73", + "socket2 0.3.19", "sodiumoxide", - "tokio 1.10.0", + "tokio", "tokio-util", "toml", "winapi 0.3.9", @@ -1532,9 +1448,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if 1.0.0", ] @@ -1565,23 +1481,15 @@ checksum = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] -name = "jni" -version = "0.18.0" +name = "itoa" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24967112a1e4301ca5342ea339763613a37592b8a6ce6cf2e4494537c7a42faf" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "jni" @@ -1605,9 +1513,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ca711fd837261e14ec9e674f092cbb931d3fa1482b017ae59328ddc6f3212b" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ "libc", ] @@ -1620,9 +1528,9 @@ checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" [[package]] name = "js-sys" -version = "0.3.52" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ "wasm-bindgen", ] @@ -1651,24 +1559,24 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.99" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "libdbus-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0" +checksum = "c185b5b7ad900923ef3a8ff594083d4d9b5aea80bb4f32b8342363138c0d456b" dependencies = [ "pkg-config", ] [[package]] name = "libloading" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" dependencies = [ "cfg-if 1.0.0", "winapi 0.3.9", @@ -1676,9 +1584,9 @@ dependencies = [ [[package]] name = "libpulse-binding" -version = "2.24.0" +version = "2.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04b4154b9bc606019cb15125f96e08e1e9c4f53d55315f1ef69ae229e30d1765" +checksum = "86835d7763ded6bc16b6c0061ec60214da7550dfcd4ef93745f6f0096129676a" dependencies = [ "bitflags", "libc", @@ -1690,9 +1598,9 @@ dependencies = [ [[package]] name = "libpulse-simple-binding" -version = "2.24.0" +version = "2.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165af13c42b9c325582b1a75eaa4a0f176c9094bb3a13877826e9be24881231" +checksum = "d6a22538257c4d522bea6089d6478507f5d2589ea32150e20740aaaaaba44590" dependencies = [ "libpulse-binding", "libpulse-simple-sys", @@ -1701,9 +1609,9 @@ dependencies = [ [[package]] name = "libpulse-simple-sys" -version = "1.19.0" +version = "1.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83346d68605e656afdefa9a8a2f1968fa05ab9369b55f2e26f7bf2a11b7e8444" +checksum = "7c73f96f9ca34809692c4760cfe421225860aa000de50edab68a16221fd27cc1" dependencies = [ "libpulse-sys", "pkg-config", @@ -1711,9 +1619,9 @@ dependencies = [ [[package]] name = "libpulse-sys" -version = "1.19.1" +version = "1.19.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ebed2cc92c38cac12307892ce6fb17e2e950bfda1ed17b3e1d47fd5184c8f2b" +checksum = "991e6bd0efe2a36e6534e136e7996925e4c1a8e35b7807fe533f2beffff27c30" dependencies = [ "libc", "num-derive", @@ -1745,9 +1653,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -1791,10 +1699,10 @@ dependencies = [ [[package]] name = "magnum-opus" -version = "0.3.4-2" -source = "git+https://github.com/open-trade/magnum-opus#ad0836164abf4a4df69009b1ee08eabe3a13b33f" +version = "0.4.0" +source = "git+https://github.com/open-trade/magnum-opus#3c3d0b86ae95c84930bebffe4bcb03b3bd83342b" dependencies = [ - "bindgen 0.59.1", + "bindgen 0.59.2", "target_build_utils", ] @@ -1809,19 +1717,25 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.0" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "memoffset" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ "autocfg 1.0.1", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.3.7" @@ -1862,9 +1776,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" dependencies = [ "libc", "log", @@ -1906,6 +1820,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "miow" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e" +dependencies = [ + "windows-sys", +] + [[package]] name = "muldiv" version = "0.2.1" @@ -1914,10 +1837,11 @@ checksum = "0419348c027fa7be448d2ae7ea0e4e04c2334c31dc4e74ab29f00a2a7ca69204" [[package]] name = "ndk" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" +checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" dependencies = [ + "bitflags", "jni-sys", "ndk-sys", "num_enum", @@ -1926,9 +1850,9 @@ dependencies = [ [[package]] name = "ndk-glue" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" +checksum = "d3e9e94628f24e7a3cb5b96a2dc5683acd9230bf11991c2a1677b87695138420" dependencies = [ "lazy_static", "libc", @@ -1953,9 +1877,9 @@ dependencies = [ [[package]] name = "ndk-sys" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" [[package]] name = "net2" @@ -1968,19 +1892,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "nix" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" -dependencies = [ - "bitflags", - "cc", - "cfg-if 0.1.10", - "libc", - "void", -] - [[package]] name = "nix" version = "0.20.0" @@ -2006,6 +1917,19 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + [[package]] name = "nom" version = "5.1.2" @@ -2018,13 +1942,12 @@ dependencies = [ [[package]] name = "nom" -version = "6.1.2" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ - "bitvec", - "funty", "memchr", + "minimal-lexical", "version_check", ] @@ -2109,9 +2032,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -2119,9 +2042,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2c8fd66061a707503d515639b8af10fd3807a5b5ee6959f7ff1bd303634bd5" +checksum = "085fe377a4b2805c0fbc09484415ec261174614b7f080b0e0d520456ac421a67" dependencies = [ "derivative", "num_enum_derive", @@ -2129,11 +2052,11 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474fd1d096da3ad17084694eebed40ba09c4a36c5255cd772bd8b98859cc562e" +checksum = "5249369707a1e07b39f78d98c8f34e00aca7dcb053812fdbb5ad7be82c1bba38" dependencies = [ - "proc-macro-crate 1.0.0", + "proc-macro-crate 1.1.0", "proc-macro2", "quote", "syn", @@ -2170,20 +2093,17 @@ dependencies = [ [[package]] name = "object" -version = "0.26.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" -dependencies = [ - "memchr", -] +checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" [[package]] name = "oboe" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa187b38ae20374617b7ad418034ed3dc90ac980181d211518bd03537ae8f8d" +checksum = "e15e22bc67e047fe342a32ecba55f555e3be6166b04dd157cd0f803dfa9f48e1" dependencies = [ - "jni 0.18.0", + "jni", "ndk", "ndk-glue", "num-derive", @@ -2193,24 +2113,18 @@ dependencies = [ [[package]] name = "oboe-sys" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88e64835aa3f579c08d182526dc34e3907343d5b97e87b71a40ba5bca7aca9e" +checksum = "338142ae5ab0aaedc8275aa8f67f460e43ae0fca76a695a742d56da0a269eadc" dependencies = [ "cc", ] [[package]] name = "once_cell" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "openssl-probe" @@ -2220,24 +2134,24 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "parity-tokio-ipc" -version = "0.7.2" -source = "git+https://github.com/open-trade/parity-tokio-ipc#9bec4ec39d9c013b696e59e10497cf0374e4ff52" +version = "0.7.3" +source = "git+https://github.com/open-trade/parity-tokio-ipc#52515618bd30ea8101bf46f6c7835e88cec9187f" dependencies = [ "futures", "libc", "log", "mio-named-pipes", - "miow 0.3.7", + "miow 0.4.0", "rand 0.8.4", - "tokio 1.10.0", + "tokio", "winapi 0.3.9", ] [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -2246,9 +2160,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if 1.0.0", "instant", @@ -2260,9 +2174,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] name = "peeking_take_while" @@ -2308,12 +2222,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.7" @@ -2328,15 +2236,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "platforms" -version = "0.2.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb3b2b1033b8a60b4da6ee470325f887758c95d5320f52f9ce0df055a55940e" +checksum = "e8d0eef3571242013a0d5dc84861c3ae4a652e56e12adf8bdc26ff5f8cb34c94" [[package]] name = "png" @@ -2352,9 +2260,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "pretty-hex" @@ -2382,9 +2290,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fdbd1df62156fbc5945f4762632564d7d038153091c3fcf1067f6aef7cff92" +checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" dependencies = [ "thiserror", "toml", @@ -2414,61 +2322,82 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" -version = "1.0.28" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" dependencies = [ "unicode-xid", ] [[package]] name = "protobuf" -version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#bad0b8d3eb77bbee609684d6cee8339ee686f3a3" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5ef59c35c7472ce5e1b6c5924b87585143d1fc2cf39eae0009bba6c4df62f1" [[package]] name = "protobuf-codegen" -version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#bad0b8d3eb77bbee609684d6cee8339ee686f3a3" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89100ee819f69b77a4cab389fec9dd155a305af4c615e6413ec1ef9341f333ef" dependencies = [ + "anyhow", "protobuf", + "protobuf-parse", + "thiserror", ] [[package]] name = "protobuf-codegen-pure" -version = "3.0.0-pre" -source = "git+https://github.com/stepancheg/rust-protobuf#bad0b8d3eb77bbee609684d6cee8339ee686f3a3" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79453e74d08190551e821533ee42c447f9e21ca26f83520e120e6e8af27f6879" dependencies = [ + "anyhow", "protobuf", "protobuf-codegen", + "protobuf-parse", + "thiserror", +] + +[[package]] +name = "protobuf-parse" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c265ffc69976efc3056955b881641add3186ad0be893ef10622482d80d1d2b68" +dependencies = [ + "anyhow", + "protobuf", + "protoc", + "tempfile", + "thiserror", +] + +[[package]] +name = "protoc" +version = "3.0.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f1f8b318a54d18fbe542513331e058f4f8ce6502e542e057c50c7e5e803fdab" +dependencies = [ + "anyhow", + "log", + "thiserror", + "which 4.2.2", ] [[package]] name = "psutil" version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e780a52bf9358cb8257cac630b130dc603901f7488f8eef13e2d512cead10739" +source = "git+https://github.com/open-trade/rust-psutil#22b2e1bb4e29433a6ddb0c1bb259fe01e894c94f" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "darwin-libproc", "derive_more", "glob", "mach", - "nix 0.17.0", + "nix 0.23.1", "num_cpus", "once_cell", "platforms", @@ -2490,56 +2419,76 @@ dependencies = [ ] [[package]] -name = "quinn" -version = "0.6.2" +name = "quick-xml" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a626bb32aee973667aff87a9f5187bd076a78a09f79c262f78ab260b9ba0077" +checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b" dependencies = [ - "bytes 0.5.6", - "err-derive 0.2.4", - "futures", - "libc", - "mio 0.6.23", + "memchr", +] + +[[package]] +name = "quinn" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a84d97630b137463c8e6802adc1dfe9de81457b41bb1ac59189e6761ab9255" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "fxhash", "quinn-proto", + "quinn-udp", "rustls", - "socket2", - "tokio 0.2.25", + "thiserror", + "tokio", "tracing", "webpki", ] [[package]] name = "quinn-proto" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ea0a358c179c6b7af34805c675d1664a9c6a234a7acd7efdbb32d2f39d3d2a" +checksum = "063dedf7983c8d57db474218f258daa85b627de6f2dbc458b690a93b1de790e8" dependencies = [ - "bytes 0.5.6", - "ct-logs", - "err-derive 0.2.4", - "rand 0.7.3", + "bytes", + "fxhash", + "rand 0.8.4", "ring", "rustls", "rustls-native-certs", + "rustls-pemfile", "slab", + "thiserror", + "tinyvec", "tracing", "webpki", ] [[package]] -name = "quote" -version = "1.0.9" +name = "quinn-udp" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "5f7996776e9ee3fc0e5c14476c1a640a17e993c847ae9c81191c2c102fbef903" dependencies = [ - "proc-macro2", + "futures-util", + "libc", + "mio 0.7.14", + "quinn-proto", + "socket2 0.4.2", + "tokio", + "tracing", ] [[package]] -name = "radium" -version = "0.5.3" +name = "quote" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] [[package]] name = "rand" @@ -2560,19 +2509,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.4" @@ -2595,16 +2531,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - [[package]] name = "rand_chacha" version = "0.3.1" @@ -2630,22 +2556,13 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - [[package]] name = "rand_core" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.3", + "getrandom", ] [[package]] @@ -2657,15 +2574,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "rand_hc" version = "0.3.1" @@ -2761,15 +2669,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.2.3", + "getrandom", "redox_syscall", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" dependencies = [ "aho-corasick", "memchr", @@ -2839,9 +2747,9 @@ dependencies = [ [[package]] name = "rubato" -version = "0.8.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32df824bfec62fa252d850f346e867f43b66e5d429161f99ccfb7f1cb9ec148" +checksum = "d29cf25e25288b595458df0e00c3065db08c31afe4b4e5a74cbfc5a9b8e763cd" dependencies = [ "log", "num-complex", @@ -2857,22 +2765,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a620b0994a180cdfa25c0439e6d58c0628272571501880d626ffff58e96a0799" dependencies = [ "cc", - "which", + "which 3.1.1", ] [[package]] name = "rust-pulsectl" -version = "0.2.10" -source = "git+https://github.com/open-trade/pulsectl#53beb1d5b45f8bff725f32cf2f786d7e091f83b5" +version = "0.2.11" +source = "git+https://github.com/open-trade/pulsectl#f8ed9c538d48e486ee2cc5678aa7aee26b377646" dependencies = [ "libpulse-binding", ] [[package]] name = "rustc-demangle" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc-hash" @@ -2892,7 +2800,7 @@ dependencies = [ "clap", "clipboard-master", "cocoa", - "core-foundation 0.9.1", + "core-foundation", "core-graphics", "cpal", "crc32fast", @@ -2921,16 +2829,16 @@ dependencies = [ "samplerate", "sciter-rs", "scrap", - "serde 1.0.127", + "serde 1.0.132", "serde_derive", - "serde_json 1.0.66", + "serde_json 1.0.73", "sha2", "sys-locale", "uuid", "whoami", "winapi 0.3.9", "windows-service", - "winreg 0.7.0", + "winreg 0.10.1", "winres", ] @@ -2950,12 +2858,10 @@ dependencies = [ [[package]] name = "rustls" -version = "0.17.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0d4a31f5d68413404705d6982529b0e11a9aacd4839d1d6222ee3b8cb4015e1" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" dependencies = [ - "base64", - "log", "ring", "sct", "webpki", @@ -2963,27 +2869,36 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.3.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75ffeb84a6bd9d014713119542ce415db3a3e4748f0bfce1e1416cd224a23a5" +checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" dependencies = [ "openssl-probe", - "rustls", + "rustls-pemfile", "schannel", "security-framework", ] [[package]] -name = "rustversion" -version = "1.0.5" +name = "rustls-pemfile" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64", +] + +[[package]] +name = "rustversion" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "same-file" @@ -3034,7 +2949,7 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" name = "scrap" version = "0.5.0" dependencies = [ - "bindgen 0.59.1", + "bindgen 0.59.2", "block", "cfg-if 1.0.0", "dbus", @@ -3046,7 +2961,7 @@ dependencies = [ "num_cpus", "quest", "repng", - "serde 1.0.127", + "serde 1.0.132", "target_build_utils", "tracing", "webm", @@ -3055,9 +2970,9 @@ dependencies = [ [[package]] name = "sct" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ "ring", "untrusted", @@ -3065,24 +2980,24 @@ dependencies = [ [[package]] name = "security-framework" -version = "0.4.4" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ "bitflags", - "core-foundation 0.7.0", - "core-foundation-sys 0.7.0", + "core-foundation", + "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "0.4.3" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" dependencies = [ - "core-foundation-sys 0.7.0", + "core-foundation-sys", "libc", ] @@ -3094,18 +3009,18 @@ checksum = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" [[package]] name = "serde" -version = "1.0.127" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.127" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" dependencies = [ "proc-macro2", "quote", @@ -3126,26 +3041,24 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.66" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" +checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" dependencies = [ - "itoa 0.4.7", + "itoa 1.0.1", "ryu", - "serde 1.0.127", + "serde 1.0.132", ] [[package]] name = "sha2" -version = "0.9.5" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" +checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6" dependencies = [ - "block-buffer", "cfg-if 1.0.0", "cpufeatures", "digest", - "opaque-debug", ] [[package]] @@ -3156,9 +3069,9 @@ checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] name = "shlex" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" [[package]] name = "signal-hook-registry" @@ -3171,9 +3084,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" [[package]] name = "siphasher" @@ -3183,15 +3096,15 @@ checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" [[package]] name = "slab" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "socket2" @@ -3204,6 +3117,16 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "socket2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +dependencies = [ + "libc", + "winapi 0.3.9", +] + [[package]] name = "sodiumoxide" version = "0.2.7" @@ -3213,7 +3136,7 @@ dependencies = [ "ed25519", "libc", "libsodium-sys", - "serde 1.0.127", + "serde 1.0.132", ] [[package]] @@ -3278,9 +3201,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.74" +version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b" dependencies = [ "proc-macro2", "quote", @@ -3289,9 +3212,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.5" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", @@ -3327,12 +3250,6 @@ dependencies = [ "version-compare", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "target_build_utils" version = "0.3.1" @@ -3387,18 +3304,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.26" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.26" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -3418,42 +3335,50 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" dependencies = [ + "itoa 0.4.8", "libc", - "winapi 0.3.9", + "time-macros", ] [[package]] -name = "tokio" -version = "0.2.25" +name = "time-macros" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ - "bytes 0.5.6", - "lazy_static", - "mio 0.6.23", - "pin-project-lite 0.1.12", - "slab", + "tinyvec_macros", ] [[package]] -name = "tokio" -version = "1.10.0" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cf844b23c6131f624accf65ce0e4e9956a8bb329400ea5bcc26ae3a5c20b0b" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838" dependencies = [ - "autocfg 1.0.1", - "bytes 1.0.1", + "bytes", "libc", "memchr", - "mio 0.7.13", + "mio 0.7.14", "num_cpus", "once_cell", "parking_lot", - "pin-project-lite 0.2.7", + "pin-project-lite", "signal-hook-registry", "tokio-macros", "winapi 0.3.9", @@ -3461,9 +3386,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", @@ -3472,18 +3397,18 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.7" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ - "bytes 1.0.1", + "bytes", "futures-core", "futures-io", "futures-sink", "log", - "pin-project-lite 0.2.7", + "pin-project-lite", "slab", - "tokio 1.10.0", + "tokio", ] [[package]] @@ -3492,26 +3417,26 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ - "serde 1.0.127", + "serde 1.0.132", ] [[package]] name = "tracing" -version = "0.1.26" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ "cfg-if 1.0.0", - "pin-project-lite 0.2.7", + "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" dependencies = [ "proc-macro2", "quote", @@ -3520,9 +3445,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.18" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ff14f98b1a4b289c6248a023c1c2fa1491062964e9fed67ab29c4e4da4a052" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" dependencies = [ "lazy_static", ] @@ -3539,9 +3464,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "unescape" @@ -3557,9 +3482,9 @@ checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -3579,7 +3504,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.3", + "getrandom", ] [[package]] @@ -3600,12 +3525,6 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - [[package]] name = "walkdir" version = "2.3.2" @@ -3617,12 +3536,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -3631,9 +3544,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -3641,9 +3554,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" dependencies = [ "bumpalo", "lazy_static", @@ -3656,9 +3569,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3666,9 +3579,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" dependencies = [ "proc-macro2", "quote", @@ -3679,15 +3592,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.75" +version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" [[package]] name = "web-sys" -version = "0.3.52" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c70a82d842c9979078c772d4a1344685045f1a5628f677c2b2eab4dd7d2696" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" dependencies = [ "js-sys", "wasm-bindgen", @@ -3713,9 +3626,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.21.4" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ "ring", "untrusted", @@ -3738,10 +3651,21 @@ dependencies = [ ] [[package]] -name = "whoami" -version = "1.1.2" +name = "which" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abacf325c958dfeaf1046931d37f2a901b6dfe0968ee965a29e94c6766b2af6" +checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" +dependencies = [ + "either", + "lazy_static", + "libc", +] + +[[package]] +name = "whoami" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" dependencies = [ "wasm-bindgen", "web-sys", @@ -3808,14 +3732,28 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-service" version = "0.4.0" -source = "git+https://github.com/mullvad/windows-service-rs.git#3a41950d4e432f784ab229cf8dfddc04bd925713" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c643e10139d127d30d6d753398c8a6f0a43532e8370f6c9d29ebbff29b984ab" dependencies = [ "bitflags", - "err-derive 0.3.0", + "err-derive", "widestring", "winapi 0.3.9", ] +[[package]] +name = "windows-sys" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + [[package]] name = "windows-win" version = "2.4.1" @@ -3825,6 +3763,36 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "windows_aarch64_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2" + +[[package]] +name = "windows_i686_gnu" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a" + +[[package]] +name = "windows_i686_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f" + [[package]] name = "winreg" version = "0.6.2" @@ -3836,18 +3804,18 @@ dependencies = [ [[package]] name = "winreg" -version = "0.7.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi 0.3.9", ] [[package]] name = "winres" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4fb510bbfe5b8992ff15f77a2e6fe6cf062878f0eda00c0f44963a807ca5dc" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" dependencies = [ "toml", ] @@ -3862,17 +3830,11 @@ dependencies = [ "winapi-build", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "x11-clipboard" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b397ace6e980510de59a4fe3d4c758dffab231d6d747ce9fa1aba6b6035d5f32" +checksum = "473068b7b80ac86a18328824f1054e5e007898c47b5bbc281bd7abe32bc3653c" dependencies = [ "xcb", ] @@ -3891,34 +3853,29 @@ dependencies = [ [[package]] name = "xcb" -version = "0.9.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62056f63138b39116f82a540c983cc11f1c90cd70b3d492a70c25eaa50bd22a6" +checksum = "771e2b996df720cd1c6dd9ff90f62d91698fd3610cc078388d0564bdd6622a9c" dependencies = [ "libc", "log", + "quick-xml", ] -[[package]] -name = "yansi" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" - [[package]] name = "zstd" -version = "0.9.0+zstd.1.5.0" +version = "0.9.1+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" +checksum = "538b8347df9257b7fbce37677ef7535c00a3c7bf1f81023cc328ed7fe4b41de8" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.1+zstd.1.5.0" +version = "4.1.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" +checksum = "9fb4cfe2f6e6d35c5d27ecd9d256c4b6f7933c4895654917460ec56c29336cc1" dependencies = [ "libc", "zstd-sys", @@ -3926,9 +3883,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.1+zstd.1.5.0" +version = "1.6.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" +checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 7e201c802..045abc800 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ default = ["use_dasp"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -whoami = "1.1" +whoami = "1.2" scrap = { path = "libs/scrap" } hbb_common = { path = "libs/hbb_common" } enigo = { path = "libs/enigo" } @@ -27,20 +27,20 @@ serde = "1.0" serde_json = "1.0" cfg-if = "1.0" lazy_static = "1.4" -sha2 = "0.9" +sha2 = "0.10" repng = "0.2" libc = "0.2" parity-tokio-ipc = { git = "https://github.com/open-trade/parity-tokio-ipc" } -flexi_logger = "0.17" +flexi_logger = "0.22" runas = "0.2" magnum-opus = { git = "https://github.com/open-trade/magnum-opus" } dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"], optional = true } -rubato = { version = "0.8", optional = true } +rubato = { version = "0.10", optional = true } samplerate = { version = "0.2", optional = true } async-trait = "0.1" -crc32fast = "1.2" +crc32fast = "1.3" uuid = { version = "0.8", features = ["v4"] } -clap = "2.33" +clap = "2.34" rpassword = "5.0" [target.'cfg(not(any(target_os = "android")))'.dependencies] @@ -52,13 +52,13 @@ mac_address = "1.1" sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" } ctrlc = "3.2" arboard = "2.0" -clipboard-master = "3" +clipboard-master = "3.1" [target.'cfg(target_os = "windows")'.dependencies] #systray = { git = "https://github.com/open-trade/systray-rs" } winapi = { version = "0.3", features = ["winuser"] } -winreg = "0.7" -windows-service = { git = 'https://github.com/mullvad/windows-service-rs.git' } +winreg = "0.10" +windows-service = "0.4" [target.'cfg(target_os = "macos")'.dependencies] objc = "0.2" @@ -68,15 +68,15 @@ core-foundation = "0.9" core-graphics = "0.22" [target.'cfg(target_os = "linux")'.dependencies] -libpulse-simple-binding = "2.16" -libpulse-binding = "2.16" +libpulse-simple-binding = "2.24" +libpulse-binding = "2.25" rust-pulsectl = { git = "https://github.com/open-trade/pulsectl" } [target.'cfg(not(any(target_os = "windows", target_os = "android", target_os = "ios")))'.dependencies] -psutil = "3.2" +psutil = { version = "3.2", features = [ "process" ], git = "https://github.com/open-trade/rust-psutil" } [target.'cfg(target_os = "android")'.dependencies] -android_logger = "0.9" +android_logger = "0.10" [workspace] members = ["libs/scrap", "libs/hbb_common", "libs/enigo"] diff --git a/libs/hbb_common/Cargo.toml b/libs/hbb_common/Cargo.toml index 5858df95e..c67c71647 100644 --- a/libs/hbb_common/Cargo.toml +++ b/libs/hbb_common/Cargo.toml @@ -7,16 +7,16 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -protobuf = { version = "3.0.0-pre", git = "https://github.com/stepancheg/rust-protobuf" } -tokio = { version = "1.10", features = ["full"] } +protobuf = "3.0.0-alpha.2" +tokio = { version = "1.15", features = ["full"] } tokio-util = { version = "0.6", features = ["full"] } futures = "0.3" -bytes = "1.0" +bytes = "1.1" log = "0.4" env_logger = "0.9" socket2 = { version = "0.3", features = ["reuseport"] } zstd = "0.9" -quinn = {version = "0.6", optional = true } +quinn = {version = "0.8", optional = true } anyhow = "1.0" futures-util = "0.3" directories-next = "2.0" @@ -36,7 +36,7 @@ mac_address = "1.1" quic = ["quinn"] [build-dependencies] -protobuf-codegen-pure = { version = "3.0.0-pre", git = "https://github.com/stepancheg/rust-protobuf" } +protobuf-codegen-pure = "3.0.0-alpha.2" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3", features = ["winuser"] } From dbdff120bc097c8d9e2fdcc7fb1dff969e0c9586 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 27 Dec 2021 00:24:57 +0800 Subject: [PATCH 18/77] move get_version_number to hbb_common --- libs/hbb_common/src/lib.rs | 8 ++++++++ src/ui.rs | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 91cc076d3..dc0c3e3e2 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -179,6 +179,14 @@ where Ok(io::BufReader::new(file).lines()) } +pub fn get_version_number(v: &str) -> i64 { + let mut n = 0; + for x in v.split(".") { + n = n * 1000 + x.parse::().unwrap_or(0); + } + n +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/ui.rs b/src/ui.rs index 21694cec0..27d5f1476 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -369,8 +369,8 @@ impl UI { #[cfg(windows)] { let installed_version = crate::platform::windows::get_installed_version(); - let a = crate::common::get_version_number(crate::VERSION); - let b = crate::common::get_version_number(&installed_version); + let a = hbb_common::get_version_number(crate::VERSION); + let b = hbb_common::get_version_number(&installed_version); return a > b; } } From 7225c1fcf0ee8c41e26bfe88edc11f08686fe8bc Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 27 Dec 2021 02:28:25 +0800 Subject: [PATCH 19/77] session list style and refactor --- src/ui/ab.tis | 171 ++++++++++++++++++++++++++++++++++++++++++++++ src/ui/header.tis | 2 +- src/ui/index.css | 70 +++++++++++++++++-- src/ui/index.html | 1 + src/ui/index.tis | 85 ++--------------------- 5 files changed, 242 insertions(+), 87 deletions(-) create mode 100644 src/ui/ab.tis diff --git a/src/ui/ab.tis b/src/ui/ab.tis new file mode 100644 index 000000000..5aaa9b881 --- /dev/null +++ b/src/ui/ab.tis @@ -0,0 +1,171 @@ +var svg_tile = ; +var svg_list = ; + +function getSessionsStyleOption(type) { + return (type || "recent") + "-sessions-style"; +} + +function getSessionsStyle(type) { + var v = handler.get_option(getSessionsStyleOption(type)); + if (!v) v = type == "ab" ? "list" : "tile"; + return v; +} + +function stupidUpdate(me) { + /* hidden is workaround of stupid sciter bug */ + me.hidden = true; + me.update(); + self.timer(60ms, function() { + me.hidden = false; + me.update(); + }); +} + +class SessionStyle: Reactor.Component { + this var type = ""; + + function this(params) { + this.type = (params || {}).type; + } + + function render() { + var sessionsStyle = getSessionsStyle(this.type); + return
    + {svg_tile} + {svg_list} +
    ; + } + + event click $(span.inactive) { + var option = getSessionsStyleOption(this.type); + var sessionsStyle = getSessionsStyle(this.type); + handler.set_option(option, sessionsStyle == "tile" ? "list" : "tile"); + stupidUpdate(app); + } +} + +class SessionList: Reactor.Component { + this var sessions = []; + this var type = ""; + this var style; + + function this(params) { + this.sessions = params.sessions; + this.type = params.type; + this.style = getSessionsStyle(params.type); + } + + function render() { + var sessions = this.sessions; + if (sessions.length == 0) return ; + var me = this; + sessions = sessions.map(function(x) { return me.getSession(x); }); + return
    + + +
  • {translate('Connect')}
  • +
  • {translate('Transfer File')}
  • +
  • {translate('TCP Tunneling')}
  • + {false && !handler.using_public_server() &&
  • {svg_checkmark}{translate('Always connect via relay')}
  • } +
  • RDP
  • +
  • {translate('Rename')}
  • +
  • {translate('Remove')}
  • + {is_win &&
  • {translate('Create Desktop Shortcut')}
  • } + +
    + {sessions} +
    ; + } + + function getSession(s) { + var id = s[0] || s.id || ""; + var username = s[1] || s.username || ""; + var hostname = s[2] || s.hostname || ""; + var platform = s[3] || s.platform || ""; + var alias = s[4] || s.alias || ""; + if (this.style == "list") { + return
    +
    + {platformSvg(platform, "white")} +
    +
    +
    +
    {alias ? alias : formatId(id)}
    +
    {username}@{hostname}
    +
    +
    +
    + {svg_menu} +
    +
    ; + } + return
    +
    + {platformSvg(platform, "white")} +
    {username}@{hostname}
    +
    +
    +
    {alias ? alias : formatId(id)}
    + {svg_menu} +
    +
    ; + } + + event dblclick $(div.remote-session-link) (evt, me) { + createNewConnect(me.id, "connect"); + } + + event click $(#menu) (_, me) { + var id = me.parent.parent.id; + var platform = me.parent.parent.attributes["platform"]; + $(#rdp).style.set{ + display: (platform == "Windows" && is_win) ? "block" : "none", + }; + // https://sciter.com/forums/topic/replacecustomize-context-menu/ + var menu = $(menu#remote-context); + menu.attributes["remote-id"] = id; + var el = $(li#force-always-relay); + if (el) { + var force = handler.get_peer_option(id, "force-always-relay"); + el.attributes.toggleClass("selected", force == "Y"); + el.attributes.toggleClass("line-through", force != "Y"); + } + me.popup(menu); + } + + event click $(menu#remote-context li) (evt, me) { + var action = me.id; + var id = me.parent.attributes["remote-id"]; + if (action == "connect") { + createNewConnect(id, "connect"); + } else if (action == "transfer") { + createNewConnect(id, "file-transfer"); + } else if (action == "remove") { + if (!this.type) { + handler.remove_peer(id); + app.update(); + } + } else if (action == "shortcut") { + handler.create_shortcut(id); + } else if (action == "rdp") { + createNewConnect(id, "rdp"); + } else if (action == "tunnel") { + createNewConnect(id, "port-forward"); + } else if (action == "rename") { + var old_name = handler.get_peer_option(id, "alias"); + handler.msgbox("custom-rename", "Rename", "
    \ +
    \ +
    \ + ", function(res=null) { + if (!res) return; + var name = (res.name || "").trim(); + if (name != old_name) { + handler.set_peer_option(id, "alias", name); + } + try { + self.select('#' + id).select('#alias').text = name || id; + } catch (e) {} + }); + } + } +} diff --git a/src/ui/header.tis b/src/ui/header.tis index 5307fd5d8..257231bca 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -397,7 +397,7 @@ function startChat() { height: h, client: true, parameters: { msgs: chat_msgs, callback: sendMsg, icon: icon }, - caption: handler.get_id(), + caption: get_id(), }; var html = handler.get_chatbox(); if (html) params.html = html; diff --git a/src/ui/index.css b/src/ui/index.css index 5ed7008e7..6e69bddd7 100644 --- a/src/ui/index.css +++ b/src/ui/index.css @@ -132,11 +132,30 @@ div.recent-sessions-content { flow: horizontal-flow; } -div.recent-sessions-title { +div#sessions-bar { color: color(light-text); padding-top: 0.5em; border-top: color(border) solid 1px; margin-bottom: 1em; + position: relative; + flow: horizontal; +} + +div#sessions-bar span { + display: inline-block; + padding: 0.5em 1em; + cursor: pointer; +} + +div#sessions-bar svg { + size: 14px; +} + +div#sessions-bar span.active { + cursor: default; + border-radius: 3px; + background: white; + color: black; } div.remote-session { @@ -148,7 +167,7 @@ div.remote-session { border: none; } -div.remote-session:hover { +div.remote-session:hover, div.remote-session-list:hover { outline: color(button) solid 2px -2px; } @@ -176,6 +195,41 @@ div.remote-session .platform svg { background: none; } +div.remote-session-list { + background: white; + width: 240px; + flow: horizontal; +} + +div.remote-session-list .platform { + size: 42px; +} + +div.remote-session-list .platform svg { + width: 30px; + height: 30px; + background: none; + padding: 6px; +} + +div.remote-session-list .name { + size: *; + padding-left: 1em; +} + +div.remote-session-list .name >div { + margin-top: *; + margin-bottom: *; + width: *; +} + +div.remote-session-list .name .username { + margin-top: 3px; + font-size: 0.8em; + color: color(lighter-text); + overflow: hidden; +} + div.remote-session .text { background: white; position: absolute; @@ -200,20 +254,22 @@ svg#menu { color: color(light-text); } -svg#menu:active { +.remote-session-list svg#menu { + margin-right: 0; +} + +svg#menu:hover { color: black; border-radius: 1em; background: color(gray-bg); } -svg#edit:active { - opacity: 0.5; +svg#edit:hover { + color: black; } svg#edit { display: inline-block; - margin-top: 0.25em; - margin-bottom: 0; } div.install-me, div.trust-me { diff --git a/src/ui/index.html b/src/ui/index.html index c51c64d84..fc24b564a 100644 --- a/src/ui/index.html +++ b/src/ui/index.html @@ -7,6 +7,7 @@ diff --git a/src/ui/index.tis b/src/ui/index.tis index 542835b20..962eeacc7 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -54,78 +54,16 @@ class RecentSessions: Reactor.Component { function render() { var sessions = handler.get_recent_sessions(); if (sessions.length == 0) return ; - sessions = sessions.map(this.getSession); return
    -
    {translate("Recent Sessions")}
    -
    - {sessions} +
    +
    + {translate("Recent Sessions")}
    + {!app.hidden && } +
    + {!app.hidden && }
    ; } - - function getSession(s) { - var id = s[0]; - var username = s[1]; - var hostname = s[2]; - var platform = s[3]; - var alias = s[4]; - return
    -
    - {platformSvg(platform, "white")} -
    {username}@{hostname}
    -
    -
    -
    {alias ? alias : formatId(id)}
    - {svg_menu} -
    -
    ; - } - - event dblclick $(div.remote-session) (evt, me) { - createNewConnect(me.id, "connect"); - } - - event click $(#menu) (_, me) { - var id = me.parent.parent.id; - var platform = me.parent.parent.attributes["platform"]; - $(#rdp).style.set{ - display: (platform == "Windows" && is_win) ? "block" : "none", - }; - // https://sciter.com/forums/topic/replacecustomize-context-menu/ - var menu = $(menu#remote-context); - menu.attributes["remote-id"] = id; - me.popup(menu); - } -} - -event click $(menu#remote-context li) (evt, me) { - var action = me.id; - var id = me.parent.attributes["remote-id"]; - if (action == "connect") { - createNewConnect(id, "connect"); - } else if (action == "transfer") { - createNewConnect(id, "file-transfer"); - } else if (action == "remove") { - handler.remove_peer(id); - app.recent_sessions.update(); - } else if (action == "shortcut") { - handler.create_shortcut(id); - } else if (action == "rdp") { - createNewConnect(id, "rdp"); - } else if (action == "tunnel") { - createNewConnect(id, "port-forward"); - } else if (action == "rename") { - var old_name = handler.get_peer_option(id, "alias"); - handler.msgbox("custom-rename", "Rename", "
    \ -
    \ -
    \ - ", function(res=null) { - if (!res) return; - var name = (res.name || "").trim(); - if (name != old_name) handler.set_peer_option(id, "alias", name); - self.select('#' + id).select('#alias').text = name || id; - }); - } } function createNewConnect(id, type) { @@ -320,17 +258,6 @@ class App: Reactor.Component var is_can_screen_recording = handler.is_can_screen_recording(false); return
    - - -
  • {translate('Connect')}
  • -
  • {translate('Transfer File')}
  • -
  • {translate('TCP Tunneling')}
  • -
  • RDP
  • -
  • {translate('Rename')}
  • -
  • {translate('Remove')}
  • - {is_win &&
  • {translate('Create Desktop Shortcut')}
  • } - -
  • Refresh random password
  • From da629ec42ccc1344aacd8df9cb904987ce67c94a Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 27 Dec 2021 02:38:22 +0800 Subject: [PATCH 20/77] remove unused --- src/ui/ab.tis | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 5aaa9b881..5ed992480 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -66,7 +66,6 @@ class SessionList: Reactor.Component {
  • {translate('Connect')}
  • {translate('Transfer File')}
  • {translate('TCP Tunneling')}
  • - {false && !handler.using_public_server() &&
  • {svg_checkmark}{translate('Always connect via relay')}
  • }
  • RDP
  • {translate('Rename')}
  • {translate('Remove')}
  • @@ -122,14 +121,8 @@ class SessionList: Reactor.Component { display: (platform == "Windows" && is_win) ? "block" : "none", }; // https://sciter.com/forums/topic/replacecustomize-context-menu/ - var menu = $(menu#remote-context); + var menu = this.$(menu#remote-context); menu.attributes["remote-id"] = id; - var el = $(li#force-always-relay); - if (el) { - var force = handler.get_peer_option(id, "force-always-relay"); - el.attributes.toggleClass("selected", force == "Y"); - el.attributes.toggleClass("line-through", force != "Y"); - } me.popup(menu); } From f1444049bf10e14c977bb49f70d940ae4ef84cbb Mon Sep 17 00:00:00 2001 From: liyue Date: Tue, 28 Dec 2021 14:18:37 +0800 Subject: [PATCH 21/77] fix dependence --- Cargo.lock | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- src/ui.rs | 3 +- 3 files changed, 261 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7e1a1bc6..65621bb61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,6 +119,32 @@ dependencies = [ "syn", ] +[[package]] +name = "atk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812b4911e210bd51b24596244523c856ca749e6223c50a7fbbba3f89ee37c426" +dependencies = [ + "atk-sys", + "bitflags", + "glib", + "glib-sys", + "gobject-sys", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f530e4af131d94cc4fa15c5c9d0348f0ef28bac64ba660b6b2a1cf2605dedfce" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "atty" version = "0.2.14" @@ -250,6 +276,32 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +[[package]] +name = "cairo-rs" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5c0f2e047e8ca53d0ff249c54ae047931d7a6ebe05d00af73e0ffeb6e34bdb8" +dependencies = [ + "bitflags", + "cairo-sys-rs", + "glib", + "glib-sys", + "gobject-sys", + "libc", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed2639b9ad5f1d6efa76de95558e11339e7318426d84ac4890b86c03e828ca7" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "cc" version = "1.0.72" @@ -1130,6 +1182,71 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gdk" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db00839b2a68a7a10af3fa28dfb3febaba3a20c3a9ac2425a33b7df1f84a6b7d" +dependencies = [ + "bitflags", + "cairo-rs", + "cairo-sys-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6dae3cb99dd49b758b88f0132f8d401108e63ae8edd45f432d42cdff99998a" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bfe468a7f43e97b8d193a762b6c5cf67a7d36cacbc0b9291dbcae24bfea1e8f" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a9653cfc500fd268015b1ac055ddbc3df7a5c9ea3f4ccef147b3957bd140d69" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -1167,6 +1284,40 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" +[[package]] +name = "gio" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb60242bfff700772dae5d9e3a1f7aa2e4ebccf18b89662a16acb2822568561" +dependencies = [ + "bitflags", + "futures", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e24fb752f8f5d2cf6bbc2c606fd2bc989c81c5e2fe321ab974d54f8b6344eac" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi 0.3.9", +] + [[package]] name = "glib" version = "0.10.3" @@ -1362,6 +1513,52 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gtk" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f022f2054072b3af07666341984562c8e626a79daa8be27b955d12d06a5ad6a" +dependencies = [ + "atk", + "bitflags", + "cairo-rs", + "cairo-sys-rs", + "cc", + "gdk", + "gdk-pixbuf", + "gdk-pixbuf-sys", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk-sys", + "libc", + "once_cell", + "pango", + "pango-sys", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89acda6f084863307d948ba64a4b1ef674e8527dddab147ee4cdcc194c880457" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + [[package]] name = "hbb_common" version = "0.1.0" @@ -1557,6 +1754,27 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "libappindicator" +version = "0.6.1" +source = "git+https://github.com/liyue201/libappindicator-rs#3763cfd629dd90050af1feafa643cbfca0bf487e" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.6.1" +source = "git+https://github.com/liyue201/libappindicator-rs#3763cfd629dd90050af1feafa643cbfca0bf487e" +dependencies = [ + "gtk-sys", + "pkg-config", +] + [[package]] name = "libc" version = "0.2.112" @@ -2132,6 +2350,33 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +[[package]] +name = "pango" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9937068580bebd8ced19975938573803273ccbcbd598c58d4906efd4ac87c438" +dependencies = [ + "bitflags", + "glib", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d2650c8b62d116c020abd0cea26a4ed96526afda89b1c4ea567131fdefc890" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "parity-tokio-ipc" version = "0.7.3" @@ -2834,6 +3079,7 @@ dependencies = [ "serde_json 1.0.73", "sha2", "sys-locale", + "systray", "uuid", "whoami", "winapi 0.3.9", @@ -3250,6 +3496,19 @@ dependencies = [ "version-compare", ] +[[package]] +name = "systray" +version = "0.4.1" +source = "git+https://github.com/liyue201/systray-rs#84cca4b4171661bc6c4d1ba5aaa2320ff8e085aa" +dependencies = [ + "glib", + "gtk", + "libappindicator", + "libc", + "log", + "winapi 0.3.9", +] + [[package]] name = "target_build_utils" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 045abc800..57b31dd59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ arboard = "2.0" clipboard-master = "3.1" [target.'cfg(target_os = "windows")'.dependencies] -#systray = { git = "https://github.com/open-trade/systray-rs" } +systray = { git = "https://github.com/liyue201/systray-rs" } winapi = { version = "0.3", features = ["winuser"] } winreg = "0.10" windows-service = "0.4" diff --git a/src/ui.rs b/src/ui.rs index 27d5f1476..3b97e93d4 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -145,7 +145,6 @@ pub fn start(args: &mut [String]) { #[cfg(windows)] fn start_tray() -> hbb_common::ResultType<()> { - /* let mut app = systray::Application::new()?; let icon = include_bytes!("./tray-icon.ico"); app.set_icon_from_buffer(icon, 32, 32).unwrap(); @@ -184,7 +183,7 @@ fn start_tray() -> hbb_common::ResultType<()> { Ok::<_, systray::Error>(()) })?; allow_err!(app.wait_for_message()); - */ + Ok(()) } From 66e39b62a2fb6f1b2171bd12c4777d73d1bffaf3 Mon Sep 17 00:00:00 2001 From: open-trade Date: Tue, 28 Dec 2021 18:33:36 +0800 Subject: [PATCH 22/77] https://github.com/rustdesk/rustdesk/issues/223 --- Cargo.lock | 1 + Cargo.toml | 1 + libs/hbb_common/protos/message.proto | 1 - src/client.rs | 56 ++++++++++++++++++++-------- src/server.rs | 16 ++++---- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65621bb61..9d2cc69d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3040,6 +3040,7 @@ dependencies = [ "android_logger", "arboard", "async-trait", + "base64", "cc", "cfg-if 1.0.0", "clap", diff --git a/Cargo.toml b/Cargo.toml index 57b31dd59..d5029532f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ crc32fast = "1.3" uuid = { version = "0.8", features = ["v4"] } clap = "2.34" rpassword = "5.0" +base64 = "0.13" [target.'cfg(not(any(target_os = "android")))'.dependencies] cpal = { git = "https://github.com/open-trade/cpal" } diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index a8e8d34b5..24bc189b2 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -359,7 +359,6 @@ message PublicKey { message SignedId { bytes id = 1; - bytes pk = 2; } message AudioFormat { diff --git a/src/client.rs b/src/client.rs index 13571e585..c3096cb53 100644 --- a/src/client.rs +++ b/src/client.rs @@ -297,28 +297,51 @@ impl Client { } async fn secure_connection(peer_id: &str, pk: Vec, conn: &mut Stream) -> ResultType<()> { + let mut pk = pk; + const RS_PK: &[u8; 32] = &[ + 177, 155, 15, 73, 116, 147, 172, 11, 55, 38, 92, 168, 30, 116, 213, 196, 12, 134, 130, + 170, 181, 161, 192, 176, 132, 229, 139, 178, 17, 165, 150, 51, + ]; + if !pk.is_empty() { + let tmp = sign::PublicKey(*RS_PK); + if let Ok(data) = sign::verify(&pk, &tmp) { + pk = data; + } else { + log::error!("Handshake failed: invalid public key from rendezvous server"); + pk.clear(); + } + } if pk.len() != sign::PUBLICKEYBYTES { // send an empty message out in case server is setting up secure and waiting for first message conn.send(&Message::new()).await?; return Ok(()); } - let mut pk_ = [0u8; sign::PUBLICKEYBYTES]; - pk_[..].copy_from_slice(&pk); - let pk = sign::PublicKey(pk_); + let mut tmp = [0u8; sign::PUBLICKEYBYTES]; + tmp[..].copy_from_slice(&pk); + let sign_pk = sign::PublicKey(tmp); match timeout(CONNECT_TIMEOUT, conn.next()).await? { Some(res) => { let bytes = res?; if let Ok(msg_in) = Message::parse_from_bytes(&bytes) { if let Some(message::Union::signed_id(si)) = msg_in.union { - let their_pk_b = if si.pk.len() == box_::PUBLICKEYBYTES { - let mut pk_ = [0u8; box_::PUBLICKEYBYTES]; - pk_[..].copy_from_slice(&si.pk); - box_::PublicKey(pk_) - } else { - bail!("Handshake failed: invalid public box key length from peer"); - }; - if let Ok(id) = sign::verify(&si.id, &pk) { - if id == peer_id.as_bytes() { + if let Ok(data) = sign::verify(&si.id, &sign_pk) { + let s = String::from_utf8_lossy(&data); + let mut it = s.split("\0"); + let id = it.next().unwrap_or_default(); + let pk = + base64::decode(it.next().unwrap_or_default()).unwrap_or_default(); + let their_pk_b = if pk.len() == box_::PUBLICKEYBYTES { + let mut pk_ = [0u8; box_::PUBLICKEYBYTES]; + pk_[..].copy_from_slice(&pk); + box_::PublicKey(pk_) + } else { + log::error!( + "Handshake failed: invalid public box key length from peer" + ); + conn.send(&Message::new()).await?; + return Ok(()); + }; + if id == peer_id { let (our_pk_b, out_sk_b) = box_::gen_keypair(); let key = secretbox::gen_key(); let nonce = box_::Nonce([0u8; box_::NONCEBYTES]); @@ -332,7 +355,8 @@ impl Client { timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??; conn.set_key(key); } else { - bail!("Handshake failed: sign failure"); + log::error!("Handshake failed: sign failure"); + conn.send(&Message::new()).await?; } } else { // fall back to non-secure connection in case pk mismatch @@ -342,10 +366,12 @@ impl Client { timeout(CONNECT_TIMEOUT, conn.send(&msg_out)).await??; } } else { - bail!("Handshake failed: invalid message type"); + log::error!("Handshake failed: invalid message type"); + conn.send(&Message::new()).await?; } } else { - bail!("Handshake failed: invalid message format"); + log::error!("Handshake failed: invalid message format"); + conn.send(&Message::new()).await?; } } None => { diff --git a/src/server.rs b/src/server.rs index 541d88f29..270b8075e 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,5 +1,5 @@ use crate::ipc::Data; -use connection::{ConnInner, Connection}; +pub use connection::*; use hbb_common::{ allow_err, anyhow::{anyhow, Context}, @@ -69,12 +69,12 @@ async fn accept_connection_(server: ServerPtr, socket: Stream, secure: bool) -> let listener = new_listener(local_addr, true).await?; log::info!("Server listening on: {}", &listener.local_addr()?); if let Ok((stream, addr)) = timeout(CONNECT_TIMEOUT, listener.accept()).await? { - create_tcp_connection_(server, Stream::from(stream), addr, secure).await?; + create_tcp_connection(server, Stream::from(stream), addr, secure).await?; } Ok(()) } -async fn create_tcp_connection_( +pub async fn create_tcp_connection( server: ServerPtr, stream: Stream, addr: SocketAddr, @@ -92,11 +92,13 @@ async fn create_tcp_connection_( sk_[..].copy_from_slice(&sk); let sk = sign::SecretKey(sk_); let mut msg_out = Message::new(); - let signed_id = sign::sign(Config::get_id().as_bytes(), &sk); let (our_pk_b, our_sk_b) = box_::gen_keypair(); + let signed_id = sign::sign( + format!("{}\0{}", Config::get_id(), base64::encode(our_pk_b.0)).as_bytes(), + &sk, + ); msg_out.set_signed_id(SignedId { id: signed_id, - pk: our_pk_b.0.into(), ..Default::default() }); timeout(CONNECT_TIMEOUT, stream.send(&msg_out)).await??; @@ -122,8 +124,8 @@ async fn create_tcp_connection_( key[..].copy_from_slice(&symmetric_key); stream.set_key(secretbox::Key(key)); } else if pk.asymmetric_value.is_empty() { - // force a trial to update_pk to rendezvous server Config::set_key_confirmed(false); + log::info!("Force to update pk"); } else { bail!("Handshake failed: invalid public sign key length from peer"); } @@ -193,7 +195,7 @@ async fn create_relay_connection_( ..Default::default() }); stream.send(&msg_out).await?; - create_tcp_connection_(server, stream, peer_addr, secure).await?; + create_tcp_connection(server, stream, peer_addr, secure).await?; Ok(()) } From f69f6bc8d424daf29d8d886d6cb7fe80e5140ed2 Mon Sep 17 00:00:00 2001 From: csf Date: Tue, 28 Dec 2021 22:36:43 +0800 Subject: [PATCH 23/77] optimize audio --- src/platform/linux.rs | 2 +- src/server/audio_service.rs | 49 +++++++++++++++++++++++++------------ src/ui/cm.rs | 13 ++++------ 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/platform/linux.rs b/src/platform/linux.rs index bdc5510d1..e6c8172be 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -11,7 +11,7 @@ use std::{ }; type Xdo = *const c_void; -pub const PA_SAMPLE_RATE: u32 = 24000; +pub const PA_SAMPLE_RATE: u32 = 48000; static mut UNMODIFIED: bool = true; thread_local! { diff --git a/src/server/audio_service.rs b/src/server/audio_service.rs index 6a4de338e..c32a08f7e 100644 --- a/src/server/audio_service.rs +++ b/src/server/audio_service.rs @@ -115,9 +115,6 @@ mod cpal_impl { encoder: &mut Encoder, sp: &GenericService, ) { - if data.iter().filter(|x| **x != 0.).next().is_none() { - return; - } let buffer; let data = if sample_rate0 != sample_rate { buffer = crate::common::resample_channels(data, sample_rate0, sample_rate, channels); @@ -194,7 +191,6 @@ mod cpal_impl { log::error!("an error occurred on stream: {}", err); }; // Sample rate must be one of 8000, 12000, 16000, 24000, or 48000. - // Note: somehow 48000 not work let sample_rate_0 = config.sample_rate().0; let sample_rate = if sample_rate_0 < 12000 { 8000 @@ -202,9 +198,12 @@ mod cpal_impl { 12000 } else if sample_rate_0 < 24000 { 16000 - } else { + } else if sample_rate_0 < 48000 { 24000 + } else { + 48000 }; + log::debug!("Audio sample rate : {}",sample_rate); let mut encoder = Encoder::new( sample_rate, if config.channels() > 1 { Stereo } else { Mono }, @@ -278,19 +277,39 @@ fn create_format_msg(sample_rate: u32, channels: u16) -> Message { msg } +// use AUDIO_ZERO_COUNT for the Noise(Zero) Gate Attack Time +// every audio data length is set to 480 +// MAX_AUDIO_ZERO_COUNT=800 is similar as Gate Attack Time 3~5s(Linux) || 6~8s(Windows) +const MAX_AUDIO_ZERO_COUNT: u16 = 800; +static mut AUDIO_ZERO_COUNT: u16 = 0; + fn send_f32(data: &[f32], encoder: &mut Encoder, sp: &GenericService) { if data.iter().filter(|x| **x != 0.).next().is_some() { - match encoder.encode_vec_float(data, data.len() * 6) { - Ok(data) => { - let mut msg_out = Message::new(); - msg_out.set_audio_frame(AudioFrame { - data, - ..Default::default() - }); - sp.send(msg_out); - } - Err(_) => {} + unsafe { + AUDIO_ZERO_COUNT = 0; } + } else { + unsafe { + if AUDIO_ZERO_COUNT > MAX_AUDIO_ZERO_COUNT { + if AUDIO_ZERO_COUNT == MAX_AUDIO_ZERO_COUNT + 1 { + log::debug!("Audio Zero Gate Attack"); + AUDIO_ZERO_COUNT += 1; + } + return; + } + AUDIO_ZERO_COUNT += 1; + } + } + match encoder.encode_vec_float(data, data.len() * 6) { + Ok(data) => { + let mut msg_out = Message::new(); + msg_out.set_audio_frame(AudioFrame { + data, + ..Default::default() + }); + sp.send(msg_out); + } + Err(_) => {} } } diff --git a/src/ui/cm.rs b/src/ui/cm.rs index ae31bc864..77ec90ff8 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -416,6 +416,7 @@ async fn start_pa() { }; log::info!("pa monitor: {:?}", device); // systemctl --user status pulseaudio.service + let mut buf: Vec = vec![0; 480 * 4]; match psimple::Simple::new( None, // Use the default server APP_NAME, // Our application’s name @@ -430,14 +431,10 @@ async fn start_pa() { if let Some(Err(_)) = stream.next_timeout2(1).await { break; } - let mut out: Vec = Vec::with_capacity(480 * 4); - unsafe { - out.set_len(out.capacity()); - } - if let Ok(_) = s.read(&mut out) { - if out.iter().filter(|x| **x != 0).next().is_some() { - allow_err!(stream.send(&Data::RawMessage(out)).await); - } + if let Ok(_) = s.read(&mut buf) { + allow_err!( + stream.send(&Data::RawMessage(buf.clone())).await + ); } }, Err(err) => { From 2631c68b8831ff5876252cf1862e975c4b0f1313 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 29 Dec 2021 00:05:52 +0800 Subject: [PATCH 24/77] fix cm minimized not working sometimes --- src/ui/cm.tis | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/cm.tis b/src/ui/cm.tis index 6f481b0b2..71a8e39a6 100644 --- a/src/ui/cm.tis +++ b/src/ui/cm.tis @@ -101,7 +101,9 @@ class Body: Reactor.Component connection.authorized = true; body.update(); handler.authorize(cid); - view.windowState = View.WINDOW_MINIMIZED; + self.timer(30ms, function() { + view.windowState = View.WINDOW_MINIMIZED; + }); }); } From 6c713f31357a7de302e2f83148371367ab8c6d74 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 29 Dec 2021 00:20:51 +0800 Subject: [PATCH 25/77] reset AUDIO_ZERO_COUNT --- src/server/audio_service.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/server/audio_service.rs b/src/server/audio_service.rs index c32a08f7e..025dde557 100644 --- a/src/server/audio_service.rs +++ b/src/server/audio_service.rs @@ -38,6 +38,9 @@ mod pa_impl { pub async fn run(sp: GenericService) -> ResultType<()> { hbb_common::sleep(0.1).await; // one moment to wait for _pa ipc let mut stream = crate::ipc::connect(1000, "_pa").await?; + unsafe { + AUDIO_ZERO_COUNT = 0; + } let mut encoder = Encoder::new(crate::platform::linux::PA_SAMPLE_RATE, Stereo, LowDelay)?; allow_err!( stream @@ -203,7 +206,10 @@ mod cpal_impl { } else { 48000 }; - log::debug!("Audio sample rate : {}",sample_rate); + log::debug!("Audio sample rate : {}", sample_rate); + unsafe { + AUDIO_ZERO_COUNT = 0; + } let mut encoder = Encoder::new( sample_rate, if config.channels() > 1 { Stereo } else { Mono }, From 1141be01f52b258b706724a7be25d6995fa15ec2 Mon Sep 17 00:00:00 2001 From: Alessandro Rinaldi Date: Tue, 28 Dec 2021 17:42:50 +0100 Subject: [PATCH 26/77] Italian translation --- src/lang/it.rs | 191 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 src/lang/it.rs diff --git a/src/lang/it.rs b/src/lang/it.rs new file mode 100644 index 000000000..0b6f2ee15 --- /dev/null +++ b/src/lang/it.rs @@ -0,0 +1,191 @@ +lazy_static::lazy_static! { + pub static ref T: std::collections::HashMap<&'static str, &'static str> = + [ + ("Status", "Stato"), + ("Your Desktop", "Il tuo desktop"), + ("desk_tip", "Puoi accedere al tuo desktop usando l'ID e la password riportati qui."), + ("Password", "Password"), + ("Ready", "Pronto"), + ("connecting_status", "Connessione alla rete RustDesk in corso..."), + ("Enable Service", "Abilita servizio"), + ("Start Service", "Avvia servizio"), + ("Service is not running", "Il servizio non è in esecuzione"), + ("not_ready_status", "Non pronto. Verifica la tua connessione"), + ("Control Remote Desktop", "Controlla una scrivania remota"), + ("Transfer File", "Trasferisci file"), + ("Connect", "Connetti"), + ("Recent Sessions", "Sessioni recenti"), + ("Address Book", "Rubrica"), + ("Confirmation", "Conferma"), + ("TCP Tunneling", "Tunnel TCP"), + ("Remove", "Rimuovi"), + ("Refresh random password", "Nuova password casuale"), + ("Set your own password", "Imposta la tua password"), + ("Enable Keyboard/Mouse", "Abilita tastiera/mouse"), + ("Enable Clipboard", "Abilita appunti"), + ("Enable File Transfer", "Abilita trasferimento file"), + ("Enable TCP Tunneling", "Abilita tunnel TCP"), + ("IP Whitelisting", "IP autorizzati"), + ("ID/Relay Server", "Server ID/Relay"), + ("Stop service", "Arresta servizio"), + ("Change ID", "Cambia ID"), + ("Website", "Sito web"), + ("About", "Informazioni"), + ("Mute", "Silenzia"), + ("Audio Input", "Input audio"), + ("ID Server", "ID server"), + ("Relay Server", "Server relay"), + ("API Server", "Server API"), + ("invalid_http", "deve iniziare con http:// o https://"), + ("Invalid IP", "Indirizzo IP non valido"), + ("id_change_tip", "Puoi usare solo i caratteri a-z, A-Z, 0-9 e _ (underscore). Il primo carattere deve essere a-z o A-Z. La lunghezza deve essere fra 6 e 16 caratteri."), + ("Invalid format", "Formato non valido"), + ("This function is turned off by the server", "Questa funzione è disabilitata sul server"), + ("Not available", "Non disponibile"), + ("Too frequent", "Troppo frequente"), + ("Cancel", "Annulla"), + ("Skip", "Ignora"), + ("Close", "Chiudi"), + ("Retry", "Riprova"), + ("OK", "OK"), + ("Password Required", "Password richiesta"), + ("Please enter your password", "Inserisci la tua password"), + ("Remember password", "Ricorda password"), + ("Wrong Password", "Password errata"), + ("Do you want to enter again?", "Vuoi riprovare?"), + ("Connection Error", "Errore di connessione"), + ("Error", "Errore"), + ("Reset by the peer", "Reimpostata dal peer"), + ("Connecting...", "Connessione..."), + ("Connection in progress. Please wait.", "Connessione in corso. Attendi."), + ("Please try 1 minute later", "Per favore riprova fra 1 minuto"), + ("Login Error", "Errore di login"), + ("Successful", "Successo"), + ("Connected, waiting for image...", "Connesso, in attesa dell'immagine..."), + ("Name", "Nome"), + ("Modified", "Modificato"), + ("Size", "Dimensione"), + ("Show Hidden Files", "Mostra file nascosti"), + ("Receive", "Ricevi"), + ("Send", "Invia"), + ("Remote Computer", "Computer remoto"), + ("Local Computer", "Computer locale"), + ("Confirm Delete", "Conferma cancellazione"), + ("Are you sure you want to delete this file?", "Vuoi davvero eliminare questo file?"), + ("Do this for all conflicts", "Ricorca questa scelta per tutti i conflitti"), + ("Deleting", "Cancellazione di"), + ("files", "file"), + ("Waiting", "In attesa"), + ("Finished", "Terminato"), + ("Custom Image Quality", "Qualità immagine personalizzata"), + ("Privacy mode", "Modalità privacy"), + ("Adjust Window", "Adatta la finestra"), + ("Original", "Originale"), + ("Shrink", "Restringi"), + ("Stretch", "Allarga"), + ("Good image quality", "Buona qualità immagine"), + ("Balanced", "Bilanciato"), + ("Optimize reaction time", "Ottimizza il tempo di reazione"), + ("Custom", "Personalizzato"), + ("Show remote cursor", "Mostra il cursore remoto"), + ("Disable clipboard", "Disabilita appunti"), + ("Lock after session end", "Blocca al termine della sessione"), + ("Insert", "Inserisci"), + ("Insert Lock", "Blocco inserimento"), + ("Refresh", "Aggiorna"), + ("ID does not exist", "L'ID non esiste"), + ("Failed to connect to rendezvous server", "Errore di connessione al server rendezvous"), + ("Please try later", "Riprova più tardi"), + ("Remote desktop is offline", "Il desktop remoto è offline"), + ("Key mismatch", "La chiave non corrisponde"), + ("Timeout", "Timeout"), + ("Failed to connect to relay server", "Errore di connessione al server relay"), + ("Failed to connect via rendezvous server", "Errore di connessione tramite il server rendezvous"), + ("Failed to connect via relay server", "Errore di connessione tramite il server relay"), + ("Failed to make direct connection to remote desktop", "Impossibile connettersi direttamente al desktop remoto"), + ("Set Password", "Imposta password"), + ("OS Password", "Password del sistema operativo"), + ("install_tip", "A causa del Controllo Account Utente, RustDesk potrebbe non funzionare correttamente come desktop remoto. Per evitare questo problema, fai click sul tasto qui sotto per installare RustDesk a livello di sistema."), + ("Click to upgrade", "Fai click per aggiornare"), + ("Configuration Permissions", "Permessi di configurazione"), + ("Configure", "Configura"), + ("config_acc", "Per controllare il tuo desktop dall'esterno, devi fornire a RustDesk il permesso \"Accessibilità\"."), + ("config_screen", "Per controllare il tuo desktop dall'esterno, devi fornire a RustDesk il permesso \"Registrazione schermo\"."), + ("Installing ...", "Installazione ..."), + ("Install", "Installa"), + ("Installation", "Installazione"), + ("Installation Path", "Percorso di installazione"), + ("Create start menu shortcuts", "Crea i collegamenti nel menu di avvio"), + ("Create desktop icon", "Crea un'icona sul desktop"), + ("agreement_tip", "Avviando l'installazione, accetti i termini del contratto di licenza."), + ("Accept and Install", "Accetta e installa"), + ("End-user license agreement", "Contratto di licenza con l'utente finale"), + ("Generating ...", "Generazione ..."), + ("Your installation is lower version.", "La tua installazione non è aggiornata."), + ("not_close_tcp_tip", "Non chiudere questa finestra mentre stai usando il tunnel"), + ("Listening ...", "In ascolto ..."), + ("Remote Host", "Host remoto"), + ("Remote Port", "Porta remota"), + ("Action", "Azione"), + ("Add", "Aggiungi"), + ("Local Port", "Porta locale"), + ("setup_server_tip", "Per una connessione più veloce, configura un tuo server"), + ("Too short, at least 6 characters.", "Troppo breve, almeno 6 caratteri"), + ("The confirmation is not identical.", "La conferma non corrisponde"), + ("Permissions", "Permessi"), + ("Accept", "Accetta"), + ("Dismiss", "Rifiuta"), + ("Disconnect", "Disconnetti"), + ("Allow using keyboard and mouse", "Consenti l'uso di tastiera e mouse"), + ("Allow using clipboard", "Consenti l'uso degli appunti"), + ("Allow hearing sound", "Consenti la riproduzione dell'audio"), + ("Connected", "Connesso"), + ("Direct and encrypted connection", "Connessione diretta e cifrata"), + ("Relayed and encrypted connection", "Connessione tramite relay e cifrata"), + ("Direct and unencrypted connection", "Connessione diretta e non cifrata"), + ("Relayed and unencrypted connection", "Connessione tramite relay e non cifrata"), + ("Enter Remote ID", "Inserisci l'ID remoto"), + ("Enter your password", "Inserisci la tua password"), + ("Logging in...", "Autenticazione..."), + ("Enable RDP session sharing", "Abilita la condivisione della sessione RDP"), + ("Auto Login", "Login automatico"), + ("Enable Direct IP Access", "Abilita l'accesso diretto tramite IP"), + ("Rename", "Rinomina"), + ("Space", "Spazio"), + ("Create Desktop Shortcut", "Crea collegamento sul desktop"), + ("Change Path", "Cambia percorso"), + ("Create Folder", "Crea cartella"), + ("Please enter the folder name", "Inserisci il nome della cartella"), + ("Fix it", "Risolvi"), + ("Warning", "Avviso"), + ("Login screen using Wayland is not supported", "La schermata di login non è supportata utilizzando Wayland"), + ("Reboot required", "Riavvio necessario"), + ("Unsupported display server ", "Display server non supportato"), + ("x11 expected", "x11 necessario"), + ("Port", "Porta"), + ("Settings", "Impostazioni"), + ("Username", " Nome utente"), + ("Invalid port", "Porta non valida"), + ("Closed manually by the peer", "Chiuso manualmente dal peer"), + ("Enable remote configuration modification", "Abilita la modifica remota della configurazione"), + ("Run without install", "Avvia senza installare"), + ("Always connected via relay", "Connesso sempre tramite relay"), + ("Always connect via relay", "Connetti sempre tramite relay"), + ("whitelist_tip", "Solo gli indirizzi IP autorizzati possono connettersi a questo desktop"), + ("Login", "Accedi"), + ("Logout", "Esci"), + ("Tags", "Tag"), + ("Search ID", "Cerca ID"), + ("Current Wayland display server is not supported", "Questo display server Wayland non è supportato"), + ("whitelist_sep", "Separati da virgola, punto e virgola, spazio o a capo"), + ("Add ID", "Aggiungi ID"), + ("Add Tag", "Aggiungi tag"), + ("Unselect all tags", "Deseleziona tutti i tag"), + ("Network error", "Errore di rete"), + ("Username missed", "Nome utente dimenticato"), + ("Password missed", "Password dimenticata"), + ("Wrong credentials", "Credenziali errate"), + ("Edit Tag", "Modifica tag"), + ].iter().cloned().collect(); + } + \ No newline at end of file From 8be7331cb62ddc75b405ddf4d5610a20db972434 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 29 Dec 2021 00:48:58 +0800 Subject: [PATCH 27/77] add it --- src/lang.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lang.rs b/src/lang.rs index d45461f09..aae31554c 100644 --- a/src/lang.rs +++ b/src/lang.rs @@ -4,6 +4,7 @@ use std::ops::Deref; mod cn; mod en; mod fr; +mod it; #[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn translate(name: String) -> String { @@ -25,6 +26,7 @@ pub fn translate_locale(name: String, locale: &str) -> String { let m = match lang.to_lowercase().as_str() { "fr" => fr::T.deref(), "cn" => cn::T.deref(), + "it" => it::T.deref(), _ => en::T.deref(), }; if let Some(v) = m.get(&name as &str) { From 365fc90d8b62b3c780c09f6a755711235058e582 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 29 Dec 2021 11:42:43 +0800 Subject: [PATCH 28/77] refactor msgbox --- Cargo.lock | 8 ++++---- src/ui/ab.tis | 2 +- src/ui/common.tis | 18 ++++++------------ src/ui/file_transfer.tis | 14 +++++++------- src/ui/header.tis | 2 +- src/ui/index.tis | 14 +++++++------- src/ui/remote.rs | 4 +++- 7 files changed, 29 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d2cc69d7..64a074950 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2569,9 +2569,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.34" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] @@ -2728,9 +2728,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" dependencies = [ "proc-macro2", ] diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 5ed992480..0a6dadf1a 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -146,7 +146,7 @@ class SessionList: Reactor.Component { createNewConnect(id, "port-forward"); } else if (action == "rename") { var old_name = handler.get_peer_option(id, "alias"); - handler.msgbox("custom-rename", "Rename", "
    \ + msgbox("custom-rename", "Rename", "
    \
    \
    \ ", function(res=null) { diff --git a/src/ui/common.tis b/src/ui/common.tis index c7c767645..97aa81b73 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -216,7 +216,7 @@ function getMsgboxParams() { return msgbox_params; } -function msgbox(type, title, text, callback, height, width, retry=0, contentStyle="") { +function msgbox(type, title, text, callback=null, height=180, width=500, retry=0, contentStyle="") { var has_msgbox = msgbox_params != null; if (!has_msgbox && !type) return; var remember = false; @@ -249,7 +249,7 @@ function msgbox(type, title, text, callback, height, width, retry=0, contentStyl } else if (res == "!alive") { // do nothing } else if (res.type == "input-password") { - if (!is_port_forward) handler.msgbox("connecting", "Connecting...", "Logging in..."); + if (!is_port_forward) msgbox("connecting", "Connecting...", "Logging in..."); handler.login(res.password, res.remember); } else if (res.reconnect) { if (!is_port_forward) connecting(); @@ -261,19 +261,13 @@ function connecting() { handler.msgbox("connecting", "Connecting...", "Connection in progress. Please wait."); } -handler.msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0, contentStyle="") { - // directly call view.Dialog from native may crash, add timer here, seem safe - // too short time, msgbox won't get focus, per my test, 150 is almost minimun - self.timer(150ms, function() { msgbox(type, title, text, callback, height, width, retry, contentStyle); }); -} - -handler.block_msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0) { - msgbox(type, title, text, callback, height, width, retry); +handler.msgbox = function(type, title, text, retry=0) { + self.timer(30ms, function() { msgbox(type, title, text, null, 180, 500, retry); }); } var reconnectTimeout = 1; -handler.msgbox_retry = function(type, title, text, hasRetry, callback=null, height=180, width=500) { - handler.msgbox(type, title, text, callback, height, width, hasRetry ? reconnectTimeout : 0); +handler.msgbox_retry = function(type, title, text, hasRetry) { + handler.msgbox(type, title, text, hasRetry ? reconnectTimeout : 0); if (hasRetry) { reconnectTimeout *= 2; } else { diff --git a/src/ui/file_transfer.tis b/src/ui/file_transfer.tis index e3a9c115d..83365d0ee 100644 --- a/src/ui/file_transfer.tis +++ b/src/ui/file_transfer.tis @@ -431,7 +431,7 @@ class FolderView : Reactor.Component { event click $(.add-folder) () { var me = this; - handler.msgbox("custom", translate("Create Folder"), "
    \ + msgbox("custom", translate("Create Folder"), "
    \
    " + translate("Please enter the folder name") + ":
    \
    \
    ", function(res=null) { @@ -440,7 +440,7 @@ class FolderView : Reactor.Component { var name = res.name.trim(); if (!name) return; if (name.indexOf(me.sep()) >= 0) { - handler.msgbox("custom-error", "Create Folder", "Invalid folder name"); + msgbox("custom-error", "Create Folder", "Invalid folder name"); return; } var path = me.joinPath(name); @@ -576,16 +576,16 @@ handler.jobDone = function(id, file_num = -1) { handler.jobError = function(id, err, file_num = -1) { var job = deleting_single_file_jobs[id]; if (job) { - handler.msgbox("custom-error", "Delete File", err); + msgbox("custom-error", "Delete File", err); return; } job = create_dir_jobs[id]; if (job) { - handler.msgbox("custom-error", "Create Folder", err); + msgbox("custom-error", "Create Folder", err); return; } if (file_num < 0) { - handler.msgbox("custom-error", "Failed", err); + msgbox("custom-error", "Failed", err); } file_transfer.job_table.updateJobStatus(id, file_num, err); } @@ -599,7 +599,7 @@ var deleting_single_file_jobs = {}; var create_dir_jobs = {} function confirmDelete(path, is_remote) { - handler.block_msgbox("custom-skip", "Confirm Delete", "
    \ + msgbox("custom-skip", "Confirm Delete", "
    \
    " + translate('Are you sure you want to delete this file?') + "
    \ " + path + "
    \
    ", function(res=null) { @@ -619,7 +619,7 @@ handler.confirmDeleteFiles = function(id, i, name) { if (i >= n) return; var file_path = job.path; if (name) file_path += handler.get_path_sep(job.is_remote) + name; - handler.block_msgbox("custom-skip", "Confirm Delete", "
    \ + msgbox("custom-skip", "Confirm Delete", "
    \
    " + translate('Deleting') + " #" + (i + 1) + " / " + n + " " + translate('files') + ".
    \
    " + translate('Are you sure you want to delete this file?') + "
    \ " + name + "
    \ diff --git a/src/ui/header.tis b/src/ui/header.tis index 257231bca..0c40df158 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -277,7 +277,7 @@ function handle_custom_image_quality() { var tmp = handler.get_custom_image_quality(); var bitrate0 = tmp[0] || 50; var quantizer0 = tmp.length > 1 ? tmp[1] : 100; - handler.msgbox("custom", "Custom Image Quality", "
    \ + msgbox("custom", "Custom Image Quality", "
    \
    x% bitrate
    \
    x% quantizer
    \
    ", function(res=null) { diff --git a/src/ui/index.tis b/src/ui/index.tis index 962eeacc7..777c73b1d 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -71,7 +71,7 @@ function createNewConnect(id, type) { app.remote_id.value = formatId(id); if (!id) return; if (id == my_id) { - handler.msgbox("custom-error", "Error", "You cannot connect to your own computer"); + msgbox("custom-error", "Error", "You cannot connect to your own computer"); return; } handler.set_remote_id(id); @@ -182,7 +182,7 @@ class MyIdMenu: Reactor.Component { } if (me.id == "whitelist") { var old_value = handler.get_option("whitelist").split(",").join("\n"); - handler.msgbox("custom-whitelist", translate("IP Whitelisting"), "
    \ + msgbox("custom-whitelist", translate("IP Whitelisting"), "
    \
    " + translate("whitelist_sep") + "
    \ \
    \ @@ -206,7 +206,7 @@ class MyIdMenu: Reactor.Component { var configOptions = handler.get_options(); var old_relay = configOptions["relay-server"] || ""; var old_id = configOptions["custom-rendezvous-server"] || ""; - handler.msgbox("custom-server", "ID/Relay Server", "
    \ + msgbox("custom-server", "ID/Relay Server", "
    \
    " + translate("ID Server") + ":
    \
    " + translate("Relay Server") + ":
    \
    \ @@ -231,7 +231,7 @@ class MyIdMenu: Reactor.Component { handler.set_option("stop-service", service_stopped ? "" : "Y"); } else if (me.id == "about") { var name = handler.get_app_name(); - handler.msgbox("custom-nocancel-nook-hasclose", "About " + name, "
    \ + msgbox("custom-nocancel-nook-hasclose", "About " + name, "
    \
    Version: " + handler.get_version() + " \
    Privacy Statement
    \
    Website
    \ @@ -412,7 +412,7 @@ class UpdateMe: Reactor.Component { handler.update_me(path); }; var onerror = function(err) { - handler.msgbox("custom-error", "Download Error", "Failed to download"); + msgbox("custom-error", "Download Error", "Failed to download"); }; var onprogress = function(loaded, total) { if (!total) total = 5 * 1024 * 1024; @@ -494,7 +494,7 @@ class ModifyDefaultLogin: Reactor.Component { event click $(#modify-default-login) { if (var r = handler.modify_default_login()) { - handler.msgbox("custom-error", "Error", r); + msgbox("custom-error", "Error", r); } app.update(); } @@ -557,7 +557,7 @@ class Password: Reactor.Component { event click $(li#set-password) { var me = this; - handler.msgbox("custom-password", translate("Set Password"), "
    \ + msgbox("custom-password", translate("Set Password"), "
    \
    " + translate('Password') + ":
    \
    " + translate('Confirmation') + ":
    \
    \ diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 2b5c2f271..22c7dc8b9 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -80,6 +80,9 @@ impl sciter::EventHandler for Handler { fn attached(&mut self, root: HELEMENT) { self.write().unwrap().element = Some(Element::from(root)); + if self.is_port_forward() { + return; + } } fn detached(&mut self, _root: HELEMENT) { @@ -855,7 +858,6 @@ impl Handler { command: bool, extended: bool, ) { - if self.peer_platform() == "Windows" { if ctrl && alt && name == "VK_DELETE" { self.ctrl_alt_del(); From 3491c79cbcd924a21ebde6a1aef38b66966613e3 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 29 Dec 2021 17:53:36 +0800 Subject: [PATCH 29/77] get_local_option for ui style, todo: set_local_option --- .gitignore | 1 + src/server/audio_service.rs | 3 ++- src/ui.rs | 5 +++++ src/ui/ab.tis | 2 +- src/ui/remote.rs | 3 --- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index a620ac0bd..cce3b90a1 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ extractor __pycache__ src/version.rs *dmg +sciter.dll diff --git a/src/server/audio_service.rs b/src/server/audio_service.rs index 025dde557..98cbe0d7f 100644 --- a/src/server/audio_service.rs +++ b/src/server/audio_service.rs @@ -191,7 +191,8 @@ mod cpal_impl { let (device, config) = get_device()?; let sp = sp.clone(); let err_fn = move |err| { - log::error!("an error occurred on stream: {}", err); + // too many UnknownErrno, will improve later + log::trace!("an error occurred on stream: {}", err); }; // Sample rate must be one of 8000, 12000, 16000, 24000, or 48000. let sample_rate_0 = config.sample_rate().0; diff --git a/src/ui.rs b/src/ui.rs index 3b97e93d4..47ee0caa7 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -277,6 +277,10 @@ impl UI { } } + fn get_local_option(&self, key: String) -> String { + Config::get_option(&key) + } + fn get_peer_option(&self, id: String, name: String) -> String { let c = PeerConfig::load(&id); c.options.get(&name).unwrap_or(&"".to_owned()).to_owned() @@ -603,6 +607,7 @@ impl sciter::EventHandler for UI { fn modify_default_login(); fn get_options(); fn get_option(String); + fn get_local_option(String); fn get_peer_option(String, String); fn set_peer_option(String, String, String); fn test_if_valid_server(String); diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 0a6dadf1a..5a725afa0 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -6,7 +6,7 @@ function getSessionsStyleOption(type) { } function getSessionsStyle(type) { - var v = handler.get_option(getSessionsStyleOption(type)); + var v = handler.get_local_option(getSessionsStyleOption(type)); if (!v) v = type == "ab" ? "list" : "tile"; return v; } diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 22c7dc8b9..d4fde3f38 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -80,9 +80,6 @@ impl sciter::EventHandler for Handler { fn attached(&mut self, root: HELEMENT) { self.write().unwrap().element = Some(Element::from(root)); - if self.is_port_forward() { - return; - } } fn detached(&mut self, _root: HELEMENT) { From e0bb25cbe52057725084414932b7639b9354b0d5 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 29 Dec 2021 19:00:29 +0800 Subject: [PATCH 30/77] upgrade vcpkg --- README-DE.md | 2 +- README-ES.md | 2 +- README-FI.md | 2 +- README-FR.md | 2 +- README-JP.md | 2 +- README-ML.md | 2 +- README-NL.md | 2 +- README-PL.md | 2 +- README-ZH.md | 2 +- README.md | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README-DE.md b/README-DE.md index 5d1d4b458..2ac9a6bdd 100644 --- a/README-DE.md +++ b/README-DE.md @@ -73,7 +73,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README-ES.md b/README-ES.md index d8b3cdbfb..a28864901 100644 --- a/README-ES.md +++ b/README-ES.md @@ -71,7 +71,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README-FI.md b/README-FI.md index 8b36e56ad..86e87befa 100644 --- a/README-FI.md +++ b/README-FI.md @@ -72,7 +72,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README-FR.md b/README-FR.md index 9908f91e2..2cf4e81c0 100644 --- a/README-FR.md +++ b/README-FR.md @@ -71,7 +71,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README-JP.md b/README-JP.md index 79cca60c6..e4d0ed71d 100644 --- a/README-JP.md +++ b/README-JP.md @@ -72,7 +72,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README-ML.md b/README-ML.md index 1f66bf287..4348bd1dd 100644 --- a/README-ML.md +++ b/README-ML.md @@ -72,7 +72,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README-NL.md b/README-NL.md index a063c281e..6d8b51e0b 100644 --- a/README-NL.md +++ b/README-NL.md @@ -72,7 +72,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README-PL.md b/README-PL.md index a9fd68452..ed937da7b 100644 --- a/README-PL.md +++ b/README-PL.md @@ -72,7 +72,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README-ZH.md b/README-ZH.md index 5a9bcfdf1..8b51c6357 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -72,7 +72,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg diff --git a/README.md b/README.md index b0a65dbde..7d6713ddc 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ sudo pacman -Syu --needed unzip git cmake gcc curl wget yasm nasm zip make pkg-c ```sh git clone https://github.com/microsoft/vcpkg cd vcpkg -git checkout 134505003bb46e20fbace51ccfb69243fbbc5f82 +git checkout 2021.12.01 cd .. vcpkg/bootstrap-vcpkg.sh export VCPKG_ROOT=$HOME/vcpkg From e26a8388821efadc53dbf780dd1e9b0efa142e92 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 29 Dec 2021 19:01:36 +0800 Subject: [PATCH 31/77] fix on log after upgrade --- src/main.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 1656ecc91..e2d00d0c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,16 +43,18 @@ fn main() { } } use flexi_logger::*; - Logger::with_env_or_str("debug") - .log_to_file() - .format(opt_format) - .rotate( - Criterion::Age(Age::Day), - Naming::Timestamps, - Cleanup::KeepLogFiles(6), - ) - .directory(path) - .start() + Logger::try_with_env_or_str("debug") + .map(|x| { + x.log_to_file(FileSpec::default().directory(path)) + .format(opt_format) + .rotate( + Criterion::Age(Age::Day), + Naming::Timestamps, + Cleanup::KeepLogFiles(6), + ) + .start() + .ok(); + }) .ok(); } if args.is_empty() { From 66af938858d43f64db1aca33a90de2b85c17e6bf Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 29 Dec 2021 23:40:24 +0800 Subject: [PATCH 32/77] https://sciter.com/forums/topic/menu-not-be-hidden-when-open-dialog-on-linux/ --- src/ui/common.tis | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ui/common.tis b/src/ui/common.tis index 97aa81b73..09ffae08c 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -216,7 +216,19 @@ function getMsgboxParams() { return msgbox_params; } +// tmp workaround https://sciter.com/forums/topic/menu-not-be-hidden-when-open-dialog-on-linux/ function msgbox(type, title, text, callback=null, height=180, width=500, retry=0, contentStyle="") { + if (is_linux) { // fix menu not hidden issue + self.timer(1ms, + function() { + msgbox_(type, title, text, callback, height, width, retry, contentStyle); + }); + } else { + msgbox_(type, title, text, callback, height, width, retry, contentStyle); + } +} + +function msgbox_(type, title, text, callback, height, width, retry, contentStyle) { var has_msgbox = msgbox_params != null; if (!has_msgbox && !type) return; var remember = false; From cb1818ab37ea4f57eb3ecb05cbd67ad59c684b45 Mon Sep 17 00:00:00 2001 From: open-trade Date: Thu, 30 Dec 2021 16:31:33 +0800 Subject: [PATCH 33/77] same width of session card --- src/ui/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/index.css b/src/ui/index.css index 6e69bddd7..c47da6d2f 100644 --- a/src/ui/index.css +++ b/src/ui/index.css @@ -197,7 +197,7 @@ div.remote-session .platform svg { div.remote-session-list { background: white; - width: 240px; + width: 220px; flow: horizontal; } From ee088a8ddfdd933a490754ab86ee4b1f7e6af2b6 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 31 Dec 2021 18:38:46 +0800 Subject: [PATCH 34/77] workaround for stupid sciter --- src/ui/remote.tis | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ui/remote.tis b/src/ui/remote.tis index 061fb5241..af936e112 100644 --- a/src/ui/remote.tis +++ b/src/ui/remote.tis @@ -173,10 +173,14 @@ function handler.onMouse(evt) wait_window_toolbar = true; self.timer(300ms, function() { if (!wait_window_toolbar) return; + var extra = 0; + // workaround for stupid Sciter, without this, click + // event not triggered on top part of buttons on toolbar + if (is_osx) extra = 10; if (view.windowState == View.WINDOW_FULL_SCREEN) { $(header).style.set { display: "block", - padding: (2 * workarea_offset) + "px 0 0 0", + padding: (2 * workarea_offset + extra) + "px 0 0 0", }; } wait_window_toolbar = false; From 15f3c36c5f131f8113e0ca64be5f4b3e4542f44d Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 1 Jan 2022 17:18:10 +0800 Subject: [PATCH 35/77] header button hover bg --- src/ui/header.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ui/header.css b/src/ui/header.css index f7f03d908..4efeba514 100644 --- a/src/ui/header.css +++ b/src/ui/header.css @@ -42,6 +42,14 @@ header .remote-id { margin: * 0; } +header span:hover { + background: #f7f7f7; +} + +header #screen:hover { + background: #d9d9d9; +} + header span:active, header #screen:active { color: black; background: color(gray-bg); From cedc384ba1678ea44d43a6768667e63a4bbfe62f Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sat, 1 Jan 2022 19:44:02 +0800 Subject: [PATCH 36/77] working on search bar --- src/ui/ab.tis | 31 +++++++++++++++++++++++++++++++ src/ui/index.css | 22 ++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 5a725afa0..c2edf8e0b 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -1,5 +1,7 @@ var svg_tile = ; var svg_list = ; +var search_icon = ; +var clear_icon = ; function getSessionsStyleOption(type) { return (type || "recent") + "-sessions-style"; @@ -21,6 +23,35 @@ function stupidUpdate(me) { }); } +class SearchBar: Reactor.Component { + this var parent; + this var value = ""; + + function this(params) { + this.parent = params.parent; + } + + function render() { + return
    + {this.value && {clear_icon}} +
    ; + } + + event click $(span.clear-input svg) { + this.search_id.value = ''; + this.onChange(); + } + + event change $(input) (_, el) { + this.value = el.value; + this.onChange(); + } + + function onChange() { + this.parent.onChange(); + } +} + class SessionStyle: Reactor.Component { this var type = ""; diff --git a/src/ui/index.css b/src/ui/index.css index c47da6d2f..5ab163f83 100644 --- a/src/ui/index.css +++ b/src/ui/index.css @@ -39,6 +39,28 @@ body { padding: 20px; } +div#search-id { + padding: 0; + position: relative; +} + +span.clear-input svg { + display: none; + position: absolute; + right: 6px; + top: 10px; + size: 1.4em; + color: color(border); +} + +div#search-id:hover span.clear-input svg { + display: inline-block; +} + +span.clear-input svg:hover { + color: black; +} + .your-desktop { border-spacing: 0.5em; border-left: color(accent) solid 2px; From 40730cbbae816f4c58736a6707a8eb5894a55e04 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 2 Jan 2022 11:40:30 +0800 Subject: [PATCH 37/77] ID search --- src/ui/ab.tis | 41 ++++++++++++++----- src/ui/index.css | 104 +++++++++++++++++++++++++++++------------------ src/ui/index.tis | 17 +++++--- 3 files changed, 106 insertions(+), 56 deletions(-) diff --git a/src/ui/ab.tis b/src/ui/ab.tis index c2edf8e0b..4b03f8cea 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -32,23 +32,26 @@ class SearchBar: Reactor.Component { } function render() { - return
    + return
    + {search_icon} + {this.value && {clear_icon}}
    ; } - event click $(span.clear-input svg) { + event click $(span.clear-input) { this.search_id.value = ''; - this.onChange(); + this.onChange(''); } event change $(input) (_, el) { - this.value = el.value; - this.onChange(); + this.onChange(el.value.trim()); } - function onChange() { - this.parent.onChange(); + function onChange(v) { + this.value = v; + this.update(); + this.parent.filter(v); } } @@ -61,7 +64,7 @@ class SessionStyle: Reactor.Component { function render() { var sessionsStyle = getSessionsStyle(this.type); - return
    + return
    {svg_tile} {svg_list}
    ; @@ -71,7 +74,8 @@ class SessionStyle: Reactor.Component { var option = getSessionsStyleOption(this.type); var sessionsStyle = getSessionsStyle(this.type); handler.set_option(option, sessionsStyle == "tile" ? "list" : "tile"); - stupidUpdate(app); + //stupidUpdate(app); // seems fixed in new sciter + app.update(); } } @@ -79,6 +83,7 @@ class SessionList: Reactor.Component { this var sessions = []; this var type = ""; this var style; + this var filterPattern = ""; function this(params) { this.sessions = params.sessions; @@ -86,8 +91,24 @@ class SessionList: Reactor.Component { this.style = getSessionsStyle(params.type); } + function filter(v) { + this.filterPattern = v; + this.update(); + } + + function getSessions() { + var p = this.filterPattern; + if (!p) return this.sessions; + var tmp = []; + this.sessions.map(function(s) { + var name = s[4] || s.alias || s[0] || s.id || ""; + if (name.indexOf(p) >= 0) tmp.push(s); + }); + return tmp; + } + function render() { - var sessions = this.sessions; + var sessions = this.getSessions(); if (sessions.length == 0) return ; var me = this; sessions = sessions.map(function(x) { return me.getSession(x); }); diff --git a/src/ui/index.css b/src/ui/index.css index 5ab163f83..ccc14edd1 100644 --- a/src/ui/index.css +++ b/src/ui/index.css @@ -39,25 +39,75 @@ body { padding: 20px; } -div#search-id { +div.sessions-bar { + color: color(light-text); + padding-top: 0.5em; + border-top: color(border) solid 1px; + margin-bottom: 1em; + position: relative; + flow: horizontal; +} + +div.sessions-style { + margin-left: 0.5em; +} + +div.sessions-style span { + display: inline-block; + padding: 6px 12px; + cursor: pointer; +} + +div.sessions-style svg { + size: 14px; +} + +div.sessions-style span.active { + cursor: default; + border-radius: 3px; + background: white; + color: black; +} + +div.search-id { + width: 200px; padding: 0; position: relative; -} - -span.clear-input svg { - display: none; - position: absolute; - right: 6px; - top: 10px; - size: 1.4em; - color: color(border); -} - -div#search-id:hover span.clear-input svg { display: inline-block; } -span.clear-input svg:hover { +div.search-id input { + font-size: 1em; + height: 20px; + border: none; + padding-left: 26px; +} + +div.search-id span { + position: absolute; + top: 0px; + padding: 6px; + color: color(border); +} + +div.search-id svg { + size: 14px; +} + +span.search-icon { + left: 0px; +} + +span.clear-input { + display: none; + right: 0px; +} + +div.search-id:hover span.clear-input { + display: inline-block; +} + +span.clear-input:hover { color: black; } @@ -154,32 +204,6 @@ div.recent-sessions-content { flow: horizontal-flow; } -div#sessions-bar { - color: color(light-text); - padding-top: 0.5em; - border-top: color(border) solid 1px; - margin-bottom: 1em; - position: relative; - flow: horizontal; -} - -div#sessions-bar span { - display: inline-block; - padding: 0.5em 1em; - cursor: pointer; -} - -div#sessions-bar svg { - size: 14px; -} - -div#sessions-bar span.active { - cursor: default; - border-radius: 3px; - background: white; - color: black; -} - div.remote-session { border-radius: 1em; height: 140px; diff --git a/src/ui/index.tis b/src/ui/index.tis index 777c73b1d..0980f2fe9 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -55,15 +55,20 @@ class RecentSessions: Reactor.Component { var sessions = handler.get_recent_sessions(); if (sessions.length == 0) return ; return
    -
    -
    - {translate("Recent Sessions")} +
    +
    + {translate("Recent Sessions")} +
    + + {!app.hidden && }
    - {!app.hidden && } -
    - {!app.hidden && } + {!app.hidden && }
    ; } + + function filter(v) { + this.sessionList.filter(v); + } } function createNewConnect(id, type) { From 241623c406122678d17bdb8f7cd1e754a0c3e0f7 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 2 Jan 2022 13:56:47 +0800 Subject: [PATCH 38/77] reload session list if alias change --- Cargo.lock | 66 +++++++++++++++++++++------------------------------ src/ui/ab.tis | 4 +--- 2 files changed, 28 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 64a074950..9af999253 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -469,7 +469,7 @@ version = "0.4.1" source = "git+https://github.com/open-trade/confy#27fa12941291b44ccd856aef4a5452c1eb646047" dependencies = [ "directories", - "serde 1.0.132", + "serde 1.0.133", "toml", ] @@ -805,17 +805,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "derive_more" version = "0.99.17" @@ -904,7 +893,7 @@ checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f" dependencies = [ "lazy_static", "regex", - "serde 1.0.132", + "serde 1.0.133", "strsim 0.10.0", ] @@ -938,7 +927,7 @@ dependencies = [ "log", "objc", "pkg-config", - "serde 1.0.132", + "serde 1.0.133", "serde_derive", "unicode-segmentation", "winapi 0.3.9", @@ -1579,9 +1568,9 @@ dependencies = [ "protobuf-codegen-pure", "quinn", "rand 0.8.4", - "serde 1.0.132", + "serde 1.0.133", "serde_derive", - "serde_json 1.0.73", + "serde_json 1.0.74", "socket2 0.3.19", "sodiumoxide", "tokio", @@ -2260,19 +2249,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "085fe377a4b2805c0fbc09484415ec261174614b7f080b0e0d520456ac421a67" +checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" dependencies = [ - "derivative", "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5249369707a1e07b39f78d98c8f34e00aca7dcb053812fdbb5ad7be82c1bba38" +checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" dependencies = [ "proc-macro-crate 1.1.0", "proc-macro2", @@ -2469,9 +2457,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" [[package]] name = "pin-utils" @@ -2505,9 +2493,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "pretty-hex" @@ -3075,9 +3063,9 @@ dependencies = [ "samplerate", "sciter-rs", "scrap", - "serde 1.0.132", + "serde 1.0.133", "serde_derive", - "serde_json 1.0.73", + "serde_json 1.0.74", "sha2", "sys-locale", "systray", @@ -3208,7 +3196,7 @@ dependencies = [ "num_cpus", "quest", "repng", - "serde 1.0.132", + "serde 1.0.133", "target_build_utils", "tracing", "webm", @@ -3256,18 +3244,18 @@ checksum = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" [[package]] name = "serde" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008" +checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276" +checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537" dependencies = [ "proc-macro2", "quote", @@ -3288,13 +3276,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142" dependencies = [ "itoa 1.0.1", "ryu", - "serde 1.0.132", + "serde 1.0.133", ] [[package]] @@ -3383,7 +3371,7 @@ dependencies = [ "ed25519", "libc", "libsodium-sys", - "serde 1.0.132", + "serde 1.0.133", ] [[package]] @@ -3677,7 +3665,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ - "serde 1.0.132", + "serde 1.0.133", ] [[package]] @@ -3781,9 +3769,9 @@ checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 4b03f8cea..ad9bbd52a 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -207,9 +207,7 @@ class SessionList: Reactor.Component { if (name != old_name) { handler.set_peer_option(id, "alias", name); } - try { - self.select('#' + id).select('#alias').text = name || id; - } catch (e) {} + app.update(); }); } } From 042114ae37ab37487582e26aded64dfd1d5e0c91 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 2 Jan 2022 14:23:32 +0800 Subject: [PATCH 39/77] refactor --- src/ui/ab.tis | 2 +- src/ui/index.css | 10 +++------- src/ui/index.tis | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/ui/ab.tis b/src/ui/ab.tis index ad9bbd52a..b6a54f3ab 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -64,7 +64,7 @@ class SessionStyle: Reactor.Component { function render() { var sessionsStyle = getSessionsStyle(this.type); - return
    + return
    {svg_tile} {svg_list}
    ; diff --git a/src/ui/index.css b/src/ui/index.css index ccc14edd1..69b3dae4c 100644 --- a/src/ui/index.css +++ b/src/ui/index.css @@ -48,21 +48,17 @@ div.sessions-bar { flow: horizontal; } -div.sessions-style { - margin-left: 0.5em; -} - -div.sessions-style span { +div.sessions-tab span { display: inline-block; padding: 6px 12px; cursor: pointer; } -div.sessions-style svg { +div.sessions-tab svg { size: 14px; } -div.sessions-style span.active { +div.sessions-tab span.active { cursor: default; border-radius: 3px; background: white; diff --git a/src/ui/index.tis b/src/ui/index.tis index 0980f2fe9..f764ccc81 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -59,7 +59,7 @@ class RecentSessions: Reactor.Component {
    {translate("Recent Sessions")}
    - + {!app.hidden && } {!app.hidden && }
    {!app.hidden && } From f0a6c706faa2fcde739e69499ec8300c5903e5b2 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 2 Jan 2022 15:09:44 +0800 Subject: [PATCH 40/77] https://github.com/rustdesk/rustdesk/issues/275 --- src/lang/cn.rs | 1 + src/ui.rs | 13 ++++++++++++- src/ui/ab.tis | 9 ++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 4e735ed34..81613a672 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -186,5 +186,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Password missed", "密码没有填写"), ("Wrong credentials", "用户名或者密码错误"), ("Edit Tag", "修改标签"), + ("Unremember Password", "忘掉密码"), ].iter().cloned().collect(); } diff --git a/src/ui.rs b/src/ui.rs index 47ee0caa7..355cf5b47 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -281,6 +281,16 @@ impl UI { Config::get_option(&key) } + fn peer_has_password(&self, id: String) -> bool { + !PeerConfig::load(&id).password.is_empty() + } + + fn forget_password(&self, id: String) { + let mut c = PeerConfig::load(&id); + c.password.clear(); + c.store(&id); + } + fn get_peer_option(&self, id: String, name: String) -> String { let c = PeerConfig::load(&id); c.options.get(&name).unwrap_or(&"".to_owned()).to_owned() @@ -569,7 +579,6 @@ impl UI { crate::client::translate(name) } - fn is_xfce(&self) -> bool { crate::platform::is_xfce() } @@ -609,6 +618,8 @@ impl sciter::EventHandler for UI { fn get_option(String); fn get_local_option(String); fn get_peer_option(String, String); + fn peer_has_password(String); + fn forget_password(String); fn set_peer_option(String, String, String); fn test_if_valid_server(String); fn get_sound_inputs(); diff --git a/src/ui/ab.tis b/src/ui/ab.tis index b6a54f3ab..2dfd525a7 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -119,9 +119,11 @@ class SessionList: Reactor.Component {
  • {translate('Transfer File')}
  • {translate('TCP Tunneling')}
  • RDP
  • +
  • {translate('Rename')}
  • {translate('Remove')}
  • {is_win &&
  • {translate('Create Desktop Shortcut')}
  • } +
  • {translate('Unremember Password')}
  • {sessions} @@ -169,9 +171,12 @@ class SessionList: Reactor.Component { event click $(#menu) (_, me) { var id = me.parent.parent.id; var platform = me.parent.parent.attributes["platform"]; - $(#rdp).style.set{ + this.$(#rdp).style.set{ display: (platform == "Windows" && is_win) ? "block" : "none", }; + this.$(#forget-password).style.set{ + display: handler.peer_has_password(id) ? "block" : "none", + }; // https://sciter.com/forums/topic/replacecustomize-context-menu/ var menu = this.$(menu#remote-context); menu.attributes["remote-id"] = id; @@ -190,6 +195,8 @@ class SessionList: Reactor.Component { handler.remove_peer(id); app.update(); } + } else if (action == "forget-password") { + handler.forget_password(id); } else if (action == "shortcut") { handler.create_shortcut(id); } else if (action == "rdp") { From 1552402907ad88c4dd63cff45c0d68d7a5550a60 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 2 Jan 2022 21:56:04 +0800 Subject: [PATCH 41/77] working on fav --- libs/hbb_common/src/config.rs | 26 +++++++++++++++++ src/ui.rs | 54 +++++++++++++++++++++++++---------- src/ui/index.css | 2 +- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index cf80cd49b..26b8d160f 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -688,6 +688,32 @@ impl PeerConfig { } } +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct Fav { + #[serde(default)] + pub peers: Vec, +} + +impl Fav { + pub fn load() -> Fav { + let _ = CONFIG.read().unwrap(); // for lock + match confy::load_path(&Config::file_("_fav")) { + Ok(fav) => fav, + Err(err) => { + log::error!("Failed to load fav: {}", err); + Default::default() + } + } + } + + pub fn store(peers: Vec) { + let f = Fav { peers }; + if let Err(err) = confy::store_path(Config::file_("_fav"), f) { + log::error!("Failed to store fav: {}", err); + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/ui.rs b/src/ui.rs index 355cf5b47..da7141284 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -8,7 +8,7 @@ use crate::common::SOFTWARE_UPDATE_URL; use crate::ipc; use hbb_common::{ allow_err, - config::{Config, PeerConfig, APP_NAME, ICON}, + config::{Config, Fav, PeerConfig, APP_NAME, ICON}, log, sleep, tokio::{self, time}, }; @@ -411,22 +411,43 @@ impl UI { v } + #[inline] + fn get_peer_value(id: String, p: PeerConfig) -> Value { + let values = vec![ + id, + p.info.username.clone(), + p.info.hostname.clone(), + p.info.platform.clone(), + p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(), + ]; + Value::from_iter(values) + } + + fn get_peer(&self, id: String) -> Value { + let c = PeerConfig::load(&id); + Self::get_peer_value(id, c) + } + + fn get_fav(&self) -> Value { + Value::from_iter(Fav::load().peers) + } + + fn store_fav(&self, fav: Value) { + let mut tmp = vec![]; + fav.values().for_each(|v| { + if let Some(v) = v.as_string() { + if !v.is_empty() { + tmp.push(v); + } + } + }); + Fav::store(tmp); + } + fn get_recent_sessions(&mut self) -> Value { let peers: Vec = PeerConfig::peers() - .iter() - .map(|p| { - let values = vec![ - p.0.clone(), - p.2.info.username.clone(), - p.2.info.hostname.clone(), - p.2.info.platform.clone(), - p.2.options - .get("alias") - .unwrap_or(&"".to_owned()) - .to_owned(), - ]; - Value::from_iter(values) - }) + .drain(..) + .map(|p| Self::get_peer_value(p.0, p.2)) .collect(); Value::from_iter(peers) } @@ -599,6 +620,9 @@ impl sciter::EventHandler for UI { fn remove_peer(String); fn get_connect_status(); fn get_recent_sessions(); + fn get_peer(String); + fn get_fav(); + fn store_fav(Value); fn recent_sessions_updated(); fn get_icon(); fn get_msgbox(); diff --git a/src/ui/index.css b/src/ui/index.css index 69b3dae4c..16841777f 100644 --- a/src/ui/index.css +++ b/src/ui/index.css @@ -66,7 +66,7 @@ div.sessions-tab span.active { } div.search-id { - width: 200px; + width: 160px; padding: 0; position: relative; display: inline-block; From 64f181e4a15a928f138f98b536c04443fe011cc9 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 3 Jan 2022 00:24:36 +0800 Subject: [PATCH 42/77] fav --- src/lang/cn.rs | 4 ++ src/ui/ab.tis | 126 ++++++++++++++++++++++++++++++++++------------- src/ui/index.tis | 25 +--------- 3 files changed, 99 insertions(+), 56 deletions(-) diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 81613a672..2616e8ed2 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -187,5 +187,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Wrong credentials", "用户名或者密码错误"), ("Edit Tag", "修改标签"), ("Unremember Password", "忘掉密码"), + ("Favorites", "收藏"), + ("Add to Favorites", "加入到收藏"), + ("Remove from Favorites", "从收藏中删除"), + ("Empty", "空空如也"), ].iter().cloned().collect(); } diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 2dfd525a7..6b073a696 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -13,34 +13,27 @@ function getSessionsStyle(type) { return v; } -function stupidUpdate(me) { - /* hidden is workaround of stupid sciter bug */ - me.hidden = true; - me.update(); - self.timer(60ms, function() { - me.hidden = false; - me.update(); - }); -} +var searchPatterns = {}; class SearchBar: Reactor.Component { - this var parent; - this var value = ""; + this var type = ""; function this(params) { - this.parent = params.parent; + this.type = (params || {}).type || ""; } function render() { + var value = searchPatterns[this.type] || ""; + var me = this; + self.timer(1ms, function() { me.search_id.value = value; }); return
    {search_icon} - {this.value && {clear_icon}} + {value && {clear_icon}}
    ; } event click $(span.clear-input) { - this.search_id.value = ''; this.onChange(''); } @@ -49,9 +42,8 @@ class SearchBar: Reactor.Component { } function onChange(v) { - this.value = v; - this.update(); - this.parent.filter(v); + searchPatterns[this.type] = v; + app.multipleSessions.update(); } } @@ -59,12 +51,12 @@ class SessionStyle: Reactor.Component { this var type = ""; function this(params) { - this.type = (params || {}).type; + this.type = (params || {}).type || ""; } function render() { var sessionsStyle = getSessionsStyle(this.type); - return
    + return
    {svg_tile} {svg_list}
    ; @@ -74,8 +66,7 @@ class SessionStyle: Reactor.Component { var option = getSessionsStyleOption(this.type); var sessionsStyle = getSessionsStyle(this.type); handler.set_option(option, sessionsStyle == "tile" ? "list" : "tile"); - //stupidUpdate(app); // seems fixed in new sciter - app.update(); + app.multipleSessions.update(); } } @@ -83,21 +74,15 @@ class SessionList: Reactor.Component { this var sessions = []; this var type = ""; this var style; - this var filterPattern = ""; function this(params) { this.sessions = params.sessions; - this.type = params.type; - this.style = getSessionsStyle(params.type); - } - - function filter(v) { - this.filterPattern = v; - this.update(); + this.type = params.type || ""; + this.style = getSessionsStyle(this.type); } function getSessions() { - var p = this.filterPattern; + var p = searchPatterns[this.type]; if (!p) return this.sessions; var tmp = []; this.sessions.map(function(s) { @@ -109,7 +94,9 @@ class SessionList: Reactor.Component { function render() { var sessions = this.getSessions(); - if (sessions.length == 0) return ; + if (sessions.length == 0) { + return
    {translate("Empty")}
    ; + } var me = this; sessions = sessions.map(function(x) { return me.getSession(x); }); return
    @@ -124,6 +111,8 @@ class SessionList: Reactor.Component {
  • {translate('Remove')}
  • {is_win &&
  • {translate('Create Desktop Shortcut')}
  • }
  • {translate('Unremember Password')}
  • + {(!this.type || this.type == "fav") &&
  • {translate('Add to Favorites')}
  • } + {(!this.type || this.type == "fav") &&
  • {translate('Remove from Favorites')}
  • } {sessions} @@ -139,7 +128,7 @@ class SessionList: Reactor.Component { if (this.style == "list") { return
    - {platformSvg(platform, "white")} + {platform && platformSvg(platform, "white")}
    @@ -154,7 +143,7 @@ class SessionList: Reactor.Component { } return
    - {platformSvg(platform, "white")} + {platform && platformSvg(platform, "white")}
    {username}@{hostname}
    @@ -177,6 +166,15 @@ class SessionList: Reactor.Component { this.$(#forget-password).style.set{ display: handler.peer_has_password(id) ? "block" : "none", }; + if (!this.type || this.type == "fav") { + var in_fav = handler.get_fav().indexOf(id) >= 0; + this.$(#add-fav).style.set{ + display: in_fav ? "none" : "block", + }; + this.$(#remove-fav).style.set{ + display: in_fav ? "block" : "none", + }; + } // https://sciter.com/forums/topic/replacecustomize-context-menu/ var menu = this.$(menu#remote-context); menu.attributes["remote-id"] = id; @@ -201,6 +199,20 @@ class SessionList: Reactor.Component { handler.create_shortcut(id); } else if (action == "rdp") { createNewConnect(id, "rdp"); + } else if (action == "add-fav") { + var favs = handler.get_fav(); + if (favs.indexOf(id) < 0) { + favs = [id].concat(favs); + handler.store_fav(favs); + } + app.multipleSessions.update(); + app.update(); + } else if (action == "remove-fav") { + var favs = handler.get_fav(); + var i = favs.indexOf(id); + favs.splice(i, 1); + handler.store_fav(favs); + app.multipleSessions.update(); } else if (action == "tunnel") { createNewConnect(id, "port-forward"); } else if (action == "rename") { @@ -219,3 +231,51 @@ class SessionList: Reactor.Component { } } } + +function getSessionsType() { + return handler.get_local_option("show-sessions-type"); +} + +class Favorites: Reactor.Component { + function render() { + var sessions = handler.get_fav().map(function(f) { + return handler.get_peer(f); + }); + return ; + } +} + +class MultipleSessions: Reactor.Component { + function render() { + var type = getSessionsType(); + return
    +
    +
    + {translate('Recent Sessions')} + {translate('Favorites')} +
    + {!this.hidden && } + {!this.hidden && } +
    + {!this.hidden && + ((type == "fav" && ) || + )} +
    ; + } + + function stupidUpdate() { + /* hidden is workaround of stupid sciter bug */ + this.hidden = true; + this.update(); + var me = this; + self.timer(60ms, function() { + me.hidden = false; + me.update(); + }); + } + + event click $(div#sessions-type span.inactive) (_, el) { + handler.set_option('show-sessions-type', el.id || ""); + this.stupidUpdate(); + } +} \ No newline at end of file diff --git a/src/ui/index.tis b/src/ui/index.tis index f764ccc81..6680093ac 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -50,27 +50,6 @@ class ConnectStatus: Reactor.Component { } } -class RecentSessions: Reactor.Component { - function render() { - var sessions = handler.get_recent_sessions(); - if (sessions.length == 0) return ; - return
    -
    -
    - {translate("Recent Sessions")} -
    - {!app.hidden && } - {!app.hidden && } -
    - {!app.hidden && } -
    ; - } - - function filter(v) { - this.sessionList.filter(v); - } -} - function createNewConnect(id, type) { id = id.replace(/\s/g, ""); app.remote_id.value = formatId(id); @@ -301,7 +280,7 @@ class App: Reactor.Component
    - +
    @@ -691,7 +670,7 @@ function checkConnectStatus() { } if (handler.recent_sessions_updated()) { stdout.println("recent sessions updated"); - app.recent_sessions.update(); + app.multipleSessions.update(); } checkConnectStatus(); }); From d6b56a2f35d4d8767fd7db73cd7eb56e8544e217 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 3 Jan 2022 11:16:07 +0800 Subject: [PATCH 43/77] refactor --- src/ui/ab.tis | 10 +++++----- src/ui/index.tis | 12 +++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 6b073a696..3e94eaec5 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -108,7 +108,7 @@ class SessionList: Reactor.Component {
  • RDP
  • {translate('Rename')}
  • -
  • {translate('Remove')}
  • + {this.type != "fav" &&
  • {translate('Remove')}
  • } {is_win &&
  • {translate('Create Desktop Shortcut')}
  • }
  • {translate('Unremember Password')}
  • {(!this.type || this.type == "fav") &&
  • {translate('Add to Favorites')}
  • } @@ -241,7 +241,7 @@ class Favorites: Reactor.Component { var sessions = handler.get_fav().map(function(f) { return handler.get_peer(f); }); - return ; + return ; } } @@ -258,8 +258,8 @@ class MultipleSessions: Reactor.Component { {!this.hidden && }
    {!this.hidden && - ((type == "fav" && ) || - )} + ((type == "fav" && ) || + )}
    ; } @@ -278,4 +278,4 @@ class MultipleSessions: Reactor.Component { handler.set_option('show-sessions-type', el.id || ""); this.stupidUpdate(); } -} \ No newline at end of file +} diff --git a/src/ui/index.tis b/src/ui/index.tis index 6680093ac..89b6fa063 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -242,13 +242,11 @@ class App: Reactor.Component var is_can_screen_recording = handler.is_can_screen_recording(false); return
    - - -
  • Refresh random password
  • -
  • Set your own password
  • - -
    -
    + +
  • {translate('Refresh random password')}
  • +
  • {translate('Set your own password')}
  • +
    +
    {translate('Your Desktop')}
    {translate('desk_tip')}
    From b17bda9a55fd7544ffeade0ba6dcec2f103d34cd Mon Sep 17 00:00:00 2001 From: open-trade Date: Mon, 3 Jan 2022 16:31:13 +0800 Subject: [PATCH 44/77] resize tab --- src/ui/ab.tis | 9 +++++++++ src/ui/index.css | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 3e94eaec5..6400426ad 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -278,4 +278,13 @@ class MultipleSessions: Reactor.Component { handler.set_option('show-sessions-type', el.id || ""); this.stupidUpdate(); } + + function onSize() { + var w = this.$(.sessions-bar).box(#width) - 220; + this.$(#sessions-type span).style.set{ + "max-width": (w / 2) + "px", + }; + } } + +view.on("size", function() { app.multipleSessions.onSize(); }); \ No newline at end of file diff --git a/src/ui/index.css b/src/ui/index.css index 16841777f..b5844db37 100644 --- a/src/ui/index.css +++ b/src/ui/index.css @@ -52,6 +52,9 @@ div.sessions-tab span { display: inline-block; padding: 6px 12px; cursor: pointer; + text-overflow: ellipsis; + white-space: nowrap; + overflow-x: hidden; } div.sessions-tab svg { @@ -66,7 +69,7 @@ div.sessions-tab span.active { } div.search-id { - width: 160px; + width: 120px; padding: 0; position: relative; display: inline-block; From 6d506cbb649ab60e9e978ebfab8b4d16043a4252 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 2 Jan 2022 22:55:33 +0800 Subject: [PATCH 45/77] socks5 support Signed-off-by: fufesou --- Cargo.lock | 41 +++++ libs/hbb_common/Cargo.toml | 5 + libs/hbb_common/src/config.rs | 23 +++ libs/hbb_common/src/lib.rs | 4 + libs/hbb_common/src/socket_client.rs | 87 +++++++++ libs/hbb_common/src/tcp.rs | 156 ++++++++++++++-- libs/hbb_common/src/udp.rs | 185 ++++++++++++++++--- src/client.rs | 23 +-- src/common.rs | 60 +++++-- src/rendezvous_mediator.rs | 255 ++++++++++++++++++--------- src/server.rs | 13 +- 11 files changed, 704 insertions(+), 148 deletions(-) create mode 100644 libs/hbb_common/src/socket_client.rs diff --git a/Cargo.lock b/Cargo.lock index 9af999253..16159ab24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1553,6 +1553,7 @@ name = "hbb_common" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "bytes", "confy", "directories-next", @@ -1560,10 +1561,13 @@ dependencies = [ "env_logger 0.9.0", "filetime", "futures", + "futures-core", + "futures-sink", "futures-util", "lazy_static", "log", "mac_address", + "pin-project", "protobuf", "protobuf-codegen-pure", "quinn", @@ -1574,6 +1578,7 @@ dependencies = [ "socket2 0.3.19", "sodiumoxide", "tokio", + "tokio-socks", "tokio-util", "toml", "winapi 0.3.9", @@ -2455,6 +2460,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.8" @@ -3643,6 +3668,22 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "git+https://github.com/fufesou/tokio-socks#121a780c7e6a31c3aac70e7234f5c62eecaf0629" +dependencies = [ + "bytes", + "either", + "futures-core", + "futures-sink", + "futures-util", + "pin-project", + "thiserror", + "tokio", + "tokio-util", +] + [[package]] name = "tokio-util" version = "0.6.9" diff --git a/libs/hbb_common/Cargo.toml b/libs/hbb_common/Cargo.toml index c67c71647..dbebe8206 100644 --- a/libs/hbb_common/Cargo.toml +++ b/libs/hbb_common/Cargo.toml @@ -28,6 +28,11 @@ confy = { git = "https://github.com/open-trade/confy" } dirs-next = "2.0" filetime = "0.2" sodiumoxide = "0.2" +tokio-socks = { git = "https://github.com/fufesou/tokio-socks" } +futures-core = "0.3" +futures-sink = "0.3" +async-trait = "0.1" +pin-project = "1" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] mac_address = "1.1" diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 26b8d160f..fb558eef1 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -71,6 +71,16 @@ pub struct Config { keys_confirmed: HashMap, } +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct Socks5Server { + #[serde(default)] + pub proxy: String, + #[serde(default)] + pub username: String, + #[serde(default)] + pub password: String, +} + // more variable configs #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct Config2 { @@ -85,6 +95,9 @@ pub struct Config2 { #[serde(default)] serial: i32, + #[serde(default)] + socks: Option, + // the other scalar value must before this #[serde(default)] pub options: HashMap, @@ -619,6 +632,16 @@ impl Config { pub fn get_remote_id() -> String { CONFIG2.read().unwrap().remote_id.clone() } + + pub fn set_socks(socks: Option) { + let mut config = CONFIG2.write().unwrap(); + config.socks = socks; + config.store(); + } + + pub fn get_socks() -> Option { + CONFIG2.read().unwrap().socks.clone() + } } const PEERS: &str = "peers"; diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index dc0c3e3e2..4bc90d198 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -17,16 +17,20 @@ pub use tokio; pub use tokio_util; pub mod tcp; pub mod udp; +pub mod socket_client; pub use env_logger; pub use log; pub mod bytes_codec; #[cfg(feature = "quic")] pub mod quic; pub use anyhow::{self, bail}; +pub use futures_core; +pub use futures_sink; pub use futures_util; pub mod config; pub mod fs; pub use sodiumoxide; +pub use tokio_socks; #[cfg(feature = "quic")] pub type Stream = quic::Connection; diff --git a/libs/hbb_common/src/socket_client.rs b/libs/hbb_common/src/socket_client.rs new file mode 100644 index 000000000..596a96eaf --- /dev/null +++ b/libs/hbb_common/src/socket_client.rs @@ -0,0 +1,87 @@ +use crate::{ + config::{Config, Socks5Server}, + tcp::FramedStream, + udp::{FramedSocket, UdpFramedWrapper}, + ResultType, +}; +use anyhow::{bail, Context}; +use std::net::SocketAddr; +use tokio::net::ToSocketAddrs; +use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr}; +use tokio_util::{codec::BytesCodec, udp::UdpFramed}; + +pub fn get_socks5_conf() -> Option { + // Config::set_socks(Some(Socks5Server { + // proxy: "139.186.136.143:1080".to_owned(), + // ..Default::default() + // })); + Config::get_socks() +} + +pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( + target: T, + local: SocketAddr, + ms_timeout: u64, +) -> ResultType { + let target_addr = target.into_target_addr()?; + + if let Some(conf) = get_socks5_conf() { + FramedStream::connect( + conf.proxy.as_str(), + target_addr, + local, + conf.username.as_str(), + conf.password.as_str(), + ms_timeout, + ) + .await + } else { + let addrs: Vec = + std::net::ToSocketAddrs::to_socket_addrs(&target_addr)?.collect(); + if addrs.is_empty() { + bail!("Invalid target addr"); + }; + + FramedStream::new(addrs[0], local, ms_timeout) + .await + .with_context(|| "Failed to connect to rendezvous server") + } +} + +// TODO: merge connect_udp and connect_udp_socks5 +pub async fn connect_udp_socket( + local: T1, +) -> ResultType<( + FramedSocket>>, + Option, +)> { + Ok((FramedSocket::new(local).await?, None)) +} + +pub async fn connect_udp_socks5<'t, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( + target: T1, + local: T2, + socks5: &Option, + ms_timeout: u64, +) -> ResultType<( + FramedSocket>, + Option, +)> { + match socks5 { + Some(conf) => { + let (socket, addr) = FramedSocket::connect( + conf.proxy.as_str(), + target, + local, + conf.username.as_str(), + conf.password.as_str(), + ms_timeout, + ) + .await?; + Ok((socket, Some(addr))) + } + None => { + bail!("Nil socks5 server config") + } + } +} diff --git a/libs/hbb_common/src/tcp.rs b/libs/hbb_common/src/tcp.rs index 4189963ba..9ee33ca5a 100644 --- a/libs/hbb_common/src/tcp.rs +++ b/libs/hbb_common/src/tcp.rs @@ -4,16 +4,31 @@ use futures::{SinkExt, StreamExt}; use protobuf::Message; use sodiumoxide::crypto::secretbox::{self, Key, Nonce}; use std::{ - io::{Error, ErrorKind}, + io::{self, Error, ErrorKind}, + net::SocketAddr, ops::{Deref, DerefMut}, + pin::Pin, + task::{Context, Poll}, }; -use tokio::net::{lookup_host, TcpListener, TcpSocket, TcpStream, ToSocketAddrs}; +use tokio::{ + io::{AsyncRead, AsyncWrite, ReadBuf}, + net::{lookup_host, TcpListener, TcpSocket, ToSocketAddrs}, +}; +use tokio_socks::{tcp::Socks5Stream, IntoTargetAddr, ToProxyAddrs}; use tokio_util::codec::Framed; -pub struct FramedStream(Framed, Option<(Key, u64, u64)>, u64); +pub trait TcpStreamTrait: AsyncRead + AsyncWrite + Unpin {} +pub struct DynTcpStream(Box); + +pub struct FramedStream( + Framed, + SocketAddr, + Option<(Key, u64, u64)>, + u64, +); impl Deref for FramedStream { - type Target = Framed; + type Target = Framed; fn deref(&self) -> &Self::Target { &self.0 @@ -26,6 +41,20 @@ impl DerefMut for FramedStream { } } +impl Deref for DynTcpStream { + type Target = Box; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for DynTcpStream { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result { let socket = match addr { std::net::SocketAddr::V4(..) => TcpSocket::new_v4()?, @@ -44,8 +73,8 @@ fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result( - remote_addr: T, + pub async fn new( + remote_addr: T1, local_addr: T2, ms_timeout: u64, ) -> ResultType { @@ -56,27 +85,86 @@ impl FramedStream { new_socket(local_addr, true)?.connect(remote_addr), ) .await??; - return Ok(Self(Framed::new(stream, BytesCodec::new()), None, 0)); + let addr = stream.local_addr()?; + return Ok(Self( + Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()), + addr, + None, + 0, + )); } } bail!("could not resolve to any address"); } - pub fn set_send_timeout(&mut self, ms: u64) { - self.2 = ms; + pub async fn connect<'a, 't, P, T1, T2>( + proxy: P, + target: T1, + local: T2, + username: &'a str, + password: &'a str, + ms_timeout: u64, + ) -> ResultType + where + P: ToProxyAddrs, + T1: IntoTargetAddr<'t>, + T2: ToSocketAddrs, + { + if let Some(local) = lookup_host(&local).await?.next() { + if let Some(proxy) = proxy.to_proxy_addrs().next().await { + let stream = + super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy?)).await??; + let stream = if username.trim().is_empty() { + super::timeout( + ms_timeout, + Socks5Stream::connect_with_socket(stream, target), + ) + .await?? + } else { + super::timeout( + ms_timeout, + Socks5Stream::connect_with_password_and_socket( + stream, target, username, password, + ), + ) + .await?? + }; + let addr = stream.local_addr()?; + return Ok(Self( + Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()), + addr, + None, + 0, + )); + }; + }; + bail!("could not resolve to any address"); } - pub fn from(stream: TcpStream) -> Self { - Self(Framed::new(stream, BytesCodec::new()), None, 0) + pub fn local_addr(&self) -> SocketAddr { + self.1 + } + + pub fn set_send_timeout(&mut self, ms: u64) { + self.3 = ms; + } + + pub fn from(stream: impl TcpStreamTrait + Send + 'static, addr: SocketAddr) -> Self { + Self( + Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()), + addr, + None, + 0, + ) } pub fn set_raw(&mut self) { self.0.codec_mut().set_raw(); - self.1 = None; + self.2 = None; } pub fn is_secured(&self) -> bool { - self.1.is_some() + self.2.is_some() } #[inline] @@ -87,7 +175,7 @@ impl FramedStream { #[inline] pub async fn send_raw(&mut self, msg: Vec) -> ResultType<()> { let mut msg = msg; - if let Some(key) = self.1.as_mut() { + if let Some(key) = self.2.as_mut() { key.1 += 1; let nonce = Self::get_nonce(key.1); msg = secretbox::seal(&msg, &nonce, &key.0); @@ -98,8 +186,8 @@ impl FramedStream { #[inline] pub async fn send_bytes(&mut self, bytes: Bytes) -> ResultType<()> { - if self.2 > 0 { - super::timeout(self.2, self.0.send(bytes)).await??; + if self.3 > 0 { + super::timeout(self.3, self.0.send(bytes)).await??; } else { self.0.send(bytes).await?; } @@ -109,7 +197,7 @@ impl FramedStream { #[inline] pub async fn next(&mut self) -> Option> { let mut res = self.0.next().await; - if let Some(key) = self.1.as_mut() { + if let Some(key) = self.2.as_mut() { if let Some(Ok(bytes)) = res.as_mut() { key.2 += 1; let nonce = Self::get_nonce(key.2); @@ -137,7 +225,7 @@ impl FramedStream { } pub fn set_key(&mut self, key: Key) { - self.1 = Some((key, 0, 0)); + self.2 = Some((key, 0, 0)); } fn get_nonce(seqnum: u64) -> Nonce { @@ -161,3 +249,35 @@ pub async fn new_listener(addr: T, reuse: bool) -> ResultType< bail!("could not resolve to any address"); } } + +impl Unpin for DynTcpStream {} + +impl AsyncRead for DynTcpStream { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + AsyncRead::poll_read(Pin::new(&mut self.0), cx, buf) + } +} + +impl AsyncWrite for DynTcpStream { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + AsyncWrite::poll_write(Pin::new(&mut self.0), cx, buf) + } + + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + AsyncWrite::poll_flush(Pin::new(&mut self.0), cx) + } + + fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + AsyncWrite::poll_shutdown(Pin::new(&mut self.0), cx) + } +} + +impl TcpStreamTrait for R {} diff --git a/libs/hbb_common/src/udp.rs b/libs/hbb_common/src/udp.rs index 637de6218..8203c47d0 100644 --- a/libs/hbb_common/src/udp.rs +++ b/libs/hbb_common/src/udp.rs @@ -1,26 +1,62 @@ use crate::{bail, ResultType}; -use bytes::BytesMut; +use anyhow::anyhow; +use bytes::{Bytes, BytesMut}; use futures::{SinkExt, StreamExt}; +use futures_core::Stream; +use futures_sink::Sink; +use pin_project::pin_project; use protobuf::Message; use socket2::{Domain, Socket, Type}; use std::{ - io::Error, net::SocketAddr, ops::{Deref, DerefMut}, + pin::Pin, + task::{Context, Poll}, +}; +use tokio::net::{ToSocketAddrs, UdpSocket}; +use tokio_socks::{ + udp::{Socks5UdpFramed, Socks5UdpMessage}, + IntoTargetAddr, TargetAddr, ToProxyAddrs, }; -use tokio::{net::ToSocketAddrs, net::UdpSocket}; use tokio_util::{codec::BytesCodec, udp::UdpFramed}; -pub struct FramedSocket(UdpFramed); +pub struct FramedSocket(F); -impl Deref for FramedSocket { - type Target = UdpFramed; +#[pin_project] +pub struct UdpFramedWrapper(#[pin] F); + +pub trait BytesMutGetter<'a> { + fn get_bytes_mut(&'a self) -> &'a BytesMut; +} + +impl Deref for FramedSocket { + type Target = F; fn deref(&self) -> &Self::Target { &self.0 } } +impl DerefMut for FramedSocket { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl Deref for UdpFramedWrapper { + type Target = F; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for UdpFramedWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + fn new_socket(addr: SocketAddr, reuse: bool) -> Result { let socket = match addr { SocketAddr::V4(..) => Socket::new(Domain::ipv4(), Type::dgram(), None), @@ -38,50 +74,101 @@ fn new_socket(addr: SocketAddr, reuse: bool) -> Result { Ok(socket) } -impl DerefMut for FramedSocket { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl FramedSocket { +impl FramedSocket>> { pub async fn new(addr: T) -> ResultType { let socket = UdpSocket::bind(addr).await?; - Ok(Self(UdpFramed::new(socket, BytesCodec::new()))) + Ok(Self(UdpFramedWrapper(UdpFramed::new( + socket, + BytesCodec::new(), + )))) } #[allow(clippy::never_loop)] pub async fn new_reuse(addr: T) -> ResultType { for addr in addr.to_socket_addrs()? { - return Ok(Self(UdpFramed::new( - UdpSocket::from_std(new_socket(addr, true)?.into_udp_socket())?, + let socket = new_socket(addr, true)?.into_udp_socket(); + return Ok(Self(UdpFramedWrapper(UdpFramed::new( + UdpSocket::from_std(socket)?, BytesCodec::new(), - ))); + )))); } bail!("could not resolve to any address"); } +} + +impl FramedSocket> { + pub async fn connect<'a, 't, P: ToProxyAddrs, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( + proxy: P, + target: T1, + local: T2, + username: &'a str, + password: &'a str, + ms_timeout: u64, + ) -> ResultType<(Self, SocketAddr)> { + let framed = if username.trim().is_empty() { + super::timeout( + ms_timeout, + Socks5UdpFramed::connect(proxy, target, Some(local)), + ) + .await?? + } else { + super::timeout( + ms_timeout, + Socks5UdpFramed::connect_with_password( + proxy, + target, + Some(local), + username, + password, + ), + ) + .await?? + }; + let addr = if let TargetAddr::Ip(c) = framed.target_addr() { + c + } else { + unreachable!() + }; + log::trace!( + "Socks5 udp connected, local addr: {}, target addr: {}", + framed.local_addr().unwrap(), + &addr + ); + Ok((Self(UdpFramedWrapper(framed)), addr)) + } +} + +// TODO: simplify this constraint +impl FramedSocket +where + F: Unpin + Stream + Sink<(Bytes, SocketAddr)>, + >::Error: Sync + Send + std::error::Error + 'static, +{ + pub async fn new_with(self) -> ResultType { + Ok(self) + } #[inline] pub async fn send(&mut self, msg: &impl Message, addr: SocketAddr) -> ResultType<()> { self.0 - .send((bytes::Bytes::from(msg.write_to_bytes().unwrap()), addr)) + .send((Bytes::from(msg.write_to_bytes().unwrap()), addr)) .await?; Ok(()) } #[inline] pub async fn send_raw(&mut self, msg: &'static [u8], addr: SocketAddr) -> ResultType<()> { - self.0.send((bytes::Bytes::from(msg), addr)).await?; + self.0.send((Bytes::from(msg), addr)).await?; Ok(()) } #[inline] - pub async fn next(&mut self) -> Option> { + pub async fn next(&mut self) -> Option<::Item> { self.0.next().await } #[inline] - pub async fn next_timeout(&mut self, ms: u64) -> Option> { + pub async fn next_timeout(&mut self, ms: u64) -> Option<::Item> { if let Ok(res) = tokio::time::timeout(std::time::Duration::from_millis(ms), self.0.next()).await { @@ -91,3 +178,59 @@ impl FramedSocket { } } } + +impl<'a> BytesMutGetter<'a> for BytesMut { + fn get_bytes_mut(&'a self) -> &'a BytesMut { + self + } +} + +impl<'a> BytesMutGetter<'a> for Socks5UdpMessage { + fn get_bytes_mut(&'a self) -> &'a BytesMut { + &self.data + } +} + +impl Stream for UdpFramedWrapper +where + F: Stream>, + for<'b> M: BytesMutGetter<'b> + std::fmt::Debug, + E: std::error::Error + Into, +{ + type Item = ResultType<(BytesMut, SocketAddr)>; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.project().0.poll_next(cx) { + Poll::Ready(Some(Ok((msg, addr)))) => { + Poll::Ready(Some(Ok((msg.get_bytes_mut().clone(), addr)))) + } + Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(anyhow!(e)))), + Poll::Ready(None) => Poll::Ready(None), + Poll::Pending => Poll::Pending, + } + } +} + +impl Sink<(Bytes, SocketAddr)> for UdpFramedWrapper +where + F: Sink<(Bytes, SocketAddr)>, +{ + type Error = >::Error; + + fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().0.poll_ready(cx) + } + + fn start_send(self: Pin<&mut Self>, item: (Bytes, SocketAddr)) -> Result<(), Self::Error> { + self.project().0.start_send(item) + } + + #[allow(unused_mut)] + fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().0.poll_flush(cx) + } + + fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project().0.poll_close(cx) + } +} diff --git a/src/client.rs b/src/client.rs index c3096cb53..c37413ffb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -13,8 +13,8 @@ use hbb_common::{ message_proto::*, protobuf::Message as _, rendezvous_proto::*, + socket_client, sodiumoxide::crypto::{box_, secretbox, sign}, - tcp::FramedStream, timeout, tokio::time::Duration, AddrMangle, ResultType, Stream, @@ -107,10 +107,10 @@ impl Client { let any_addr = Config::get_any_listen_addr(); let rendezvous_server = crate::get_rendezvous_server(1_000).await; log::info!("rendezvous server: {}", rendezvous_server); - let mut socket = FramedStream::new(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT) - .await - .with_context(|| "Failed to connect to rendezvous server")?; - let my_addr = socket.get_ref().local_addr()?; + + let mut socket = + socket_client::connect_tcp(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT).await?; + let my_addr = socket.local_addr(); let mut pk = Vec::new(); let mut relay_server = "".to_owned(); @@ -262,7 +262,8 @@ impl Client { } log::info!("peer address: {}, timeout: {}", peer, connect_timeout); let start = std::time::Instant::now(); - let mut conn = FramedStream::new(peer, local_addr, connect_timeout).await; + // NOTICE: Socks5 is be used event in intranet. Which may be not a good way. + let mut conn = socket_client::connect_tcp(peer, local_addr, connect_timeout).await; let direct = !conn.is_err(); if conn.is_err() { if !relay_server.is_empty() { @@ -393,9 +394,11 @@ impl Client { let mut uuid = "".to_owned(); for i in 1..=3 { // use different socket due to current hbbs implement requiring different nat address for each attempt - let mut socket = FramedStream::new(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT) - .await - .with_context(|| "Failed to connect to rendezvous server")?; + let mut socket = + socket_client::connect_tcp(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT) + .await + .with_context(|| "Failed to connect to rendezvous server")?; + let mut msg_out = RendezvousMessage::new(); uuid = Uuid::new_v4().to_string(); log::info!( @@ -438,7 +441,7 @@ impl Client { relay_server: String, conn_type: ConnType, ) -> ResultType { - let mut conn = FramedStream::new( + let mut conn = socket_client::connect_tcp( crate::check_port(relay_server, RELAY_PORT), Config::get_any_listen_addr(), CONNECT_TIMEOUT, diff --git a/src/common.rs b/src/common.rs index 921516311..75a619c31 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,20 +1,29 @@ +use std::net::SocketAddr; + pub use arboard::Clipboard as ClipboardContext; use hbb_common::{ - allow_err, bail, + allow_err, + anyhow::bail, + bytes::{Bytes, BytesMut}, compress::{compress as compress_func, decompress}, config::{Config, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT}, + futures_core::Stream, + futures_sink::Sink, log, message_proto::*, protobuf::Message as _, protobuf::ProtobufEnum, rendezvous_proto::*, - sleep, - tcp::FramedStream, - tokio, ResultType, + sleep, socket_client, tokio, + udp::FramedSocket, + ResultType, }; #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))] use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all}; -use std::sync::{Arc, Mutex}; +use std::{ + future::Future, + sync::{Arc, Mutex}, +}; pub const CLIPBOARD_NAME: &'static str = "clipboard"; pub const CLIPBOARD_INTERVAL: u64 = 333; @@ -259,13 +268,13 @@ async fn test_nat_type_() -> ResultType { let mut port2 = 0; let mut addr = Config::get_any_listen_addr(); for i in 0..2 { - let mut socket = FramedStream::new( + let mut socket = socket_client::connect_tcp( if i == 0 { &server1 } else { &server2 }, addr, RENDEZVOUS_TIMEOUT, ) .await?; - addr = socket.get_ref().local_addr()?; + addr = socket.local_addr(); socket.send(&msg_out).await?; if let Some(Ok(bytes)) = socket.next_timeout(3000).await { if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { @@ -302,12 +311,12 @@ async fn test_nat_type_() -> ResultType { } #[cfg(any(target_os = "android", target_os = "ios"))] -pub async fn get_rendezvous_server(_ms_timeout: u64) -> std::net::SocketAddr { +pub async fn get_rendezvous_server(_ms_timeout: u64) -> SocketAddr { Config::get_rendezvous_server() } #[cfg(not(any(target_os = "android", target_os = "ios")))] -pub async fn get_rendezvous_server(ms_timeout: u64) -> std::net::SocketAddr { +pub async fn get_rendezvous_server(ms_timeout: u64) -> SocketAddr { crate::ipc::get_rendezvous_server(ms_timeout).await } @@ -330,7 +339,7 @@ async fn test_rendezvous_server_() { for host in servers { futs.push(tokio::spawn(async move { let tm = std::time::Instant::now(); - if FramedStream::new( + if socket_client::connect_tcp( &crate::check_port(&host, RENDEZVOUS_PORT), Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, @@ -437,8 +446,37 @@ pub fn check_software_update() { #[tokio::main(flavor = "current_thread")] async fn _check_software_update() -> hbb_common::ResultType<()> { sleep(3.).await; + let rendezvous_server = get_rendezvous_server(1_000).await; - let mut socket = hbb_common::udp::FramedSocket::new(Config::get_any_listen_addr()).await?; + let socks5_conf = socket_client::get_socks5_conf(); + if socks5_conf.is_some() { + let conn_fn = |bind_addr: SocketAddr| async move { + socket_client::connect_udp_socks5( + rendezvous_server, + bind_addr, + &socks5_conf, + RENDEZVOUS_TIMEOUT, + ) + .await + }; + _inner_check_software_update(conn_fn, rendezvous_server).await + } else { + _inner_check_software_update(socket_client::connect_udp_socket, rendezvous_server).await + } +} + +pub async fn _inner_check_software_update<'a, F, Fut, Frm>( + conn_fn: F, + rendezvous_server: SocketAddr, +) -> ResultType<()> +where + F: FnOnce(SocketAddr) -> Fut, + Fut: Future, Option)>>, + Frm: Unpin + Stream> + Sink<(Bytes, SocketAddr)>, + >::Error: Sync + Send + std::error::Error + 'static, +{ + sleep(3.).await; + let (mut socket, _) = conn_fn(Config::get_any_listen_addr()).await?; let mut msg_out = RendezvousMessage::new(); msg_out.set_software_update(SoftwareUpdate { url: crate::VERSION.to_owned(), diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index 3719b353d..ffa2d565a 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -1,13 +1,16 @@ use crate::server::{check_zombie, new as new_server, ServerPtr}; use hbb_common::{ allow_err, + anyhow::bail, + bytes::{Bytes, BytesMut}, config::{Config, RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT}, futures::future::join_all, + futures_core::Stream, + futures_sink::Sink, log, protobuf::Message as _, rendezvous_proto::*, - sleep, - tcp::FramedStream, + sleep, socket_client, tokio::{ self, select, time::{interval, Duration}, @@ -16,6 +19,7 @@ use hbb_common::{ AddrMangle, ResultType, }; use std::{ + future::Future, net::SocketAddr, sync::{Arc, Mutex}, time::SystemTime, @@ -59,7 +63,35 @@ impl RendezvousMediator { let server = server.clone(); let servers = servers.clone(); futs.push(tokio::spawn(async move { - allow_err!(Self::start(server, host, servers).await); + let socks5_conf = socket_client::get_socks5_conf(); + if socks5_conf.is_some() { + let target = format!("{}:{}", host, RENDEZVOUS_PORT); + let conn_fn = |bind_addr: SocketAddr| { + let target = target.clone(); + let conf_ref = &socks5_conf; + async move { + socket_client::connect_udp_socks5( + target, + bind_addr, + conf_ref, + RENDEZVOUS_TIMEOUT, + ) + .await + } + }; + allow_err!(Self::start(server, host, servers, conn_fn, true).await); + } else { + allow_err!( + Self::start( + server, + host, + servers, + socket_client::connect_udp_socket, + false, + ) + .await + ); + } })); } join_all(futs).await; @@ -68,11 +100,19 @@ impl RendezvousMediator { } } - pub async fn start( + pub async fn start<'a, F, Fut, Frm>( server: ServerPtr, host: String, rendezvous_servers: Vec, - ) -> ResultType<()> { + conn_fn: F, + socks5: bool, + ) -> ResultType<()> + where + F: Fn(SocketAddr) -> Fut, + Fut: Future, Option)>>, + Frm: Unpin + Stream> + Sink<(Bytes, SocketAddr)>, + >::Error: Sync + Send + std::error::Error + 'static, + { log::info!("start rendezvous mediator of {}", host); let host_prefix: String = host .split(".") @@ -93,7 +133,12 @@ impl RendezvousMediator { last_id_pk_registry: "".to_owned(), }; allow_err!(rz.dns_check()); - let mut socket = FramedSocket::new(Config::get_any_listen_addr()).await?; + + let bind_addr = Config::get_any_listen_addr(); + let (mut socket, target_addr) = conn_fn(bind_addr).await?; + if let Some(addr) = target_addr { + rz.addr = addr; + } const TIMER_OUT: Duration = Duration::from_secs(1); let mut timer = interval(TIMER_OUT); let mut last_timer = SystemTime::UNIX_EPOCH; @@ -136,60 +181,68 @@ impl RendezvousMediator { } }; select! { - Some(Ok((bytes, _))) = socket.next() => { - if let Ok(msg_in) = Message::parse_from_bytes(&bytes) { - match msg_in.union { - Some(rendezvous_message::Union::register_peer_response(rpr)) => { - update_latency(); - if rpr.request_pk { - log::info!("request_pk received from {}", host); - allow_err!(rz.register_pk(&mut socket).await); - continue; - } - } - Some(rendezvous_message::Union::register_pk_response(rpr)) => { - update_latency(); - match rpr.result.enum_value_or_default() { - register_pk_response::Result::OK => { - Config::set_key_confirmed(true); - Config::set_host_key_confirmed(&rz.host_prefix, true); - *SOLVING_PK_MISMATCH.lock().unwrap() = "".to_owned(); + n = socket.next() => { + match n { + Some(Ok((bytes, _))) => { + if let Ok(msg_in) = Message::parse_from_bytes(&bytes) { + match msg_in.union { + Some(rendezvous_message::Union::register_peer_response(rpr)) => { + update_latency(); + if rpr.request_pk { + log::info!("request_pk received from {}", host); + allow_err!(rz.register_pk(&mut socket).await); + continue; + } } - register_pk_response::Result::UUID_MISMATCH => { - allow_err!(rz.handle_uuid_mismatch(&mut socket).await); + Some(rendezvous_message::Union::register_pk_response(rpr)) => { + update_latency(); + match rpr.result.enum_value_or_default() { + register_pk_response::Result::OK => { + Config::set_key_confirmed(true); + Config::set_host_key_confirmed(&rz.host_prefix, true); + *SOLVING_PK_MISMATCH.lock().unwrap() = "".to_owned(); + } + register_pk_response::Result::UUID_MISMATCH => { + allow_err!(rz.handle_uuid_mismatch(&mut socket).await); + } + _ => {} + } + } + Some(rendezvous_message::Union::punch_hole(ph)) => { + let rz = rz.clone(); + let server = server.clone(); + tokio::spawn(async move { + allow_err!(rz.handle_punch_hole(ph, server).await); + }); + } + Some(rendezvous_message::Union::request_relay(rr)) => { + let rz = rz.clone(); + let server = server.clone(); + tokio::spawn(async move { + allow_err!(rz.handle_request_relay(rr, server).await); + }); + } + Some(rendezvous_message::Union::fetch_local_addr(fla)) => { + let rz = rz.clone(); + let server = server.clone(); + tokio::spawn(async move { + allow_err!(rz.handle_intranet(fla, server).await); + }); + } + Some(rendezvous_message::Union::configure_update(cu)) => { + Config::set_option("rendezvous-servers".to_owned(), cu.rendezvous_servers.join(",")); + Config::set_serial(cu.serial); } _ => {} } + } else { + log::debug!("Non-protobuf message bytes received: {:?}", bytes); } - Some(rendezvous_message::Union::punch_hole(ph)) => { - let rz = rz.clone(); - let server = server.clone(); - tokio::spawn(async move { - allow_err!(rz.handle_punch_hole(ph, server).await); - }); - } - Some(rendezvous_message::Union::request_relay(rr)) => { - let rz = rz.clone(); - let server = server.clone(); - tokio::spawn(async move { - allow_err!(rz.handle_request_relay(rr, server).await); - }); - } - Some(rendezvous_message::Union::fetch_local_addr(fla)) => { - let rz = rz.clone(); - let server = server.clone(); - tokio::spawn(async move { - allow_err!(rz.handle_intranet(fla, server).await); - }); - } - Some(rendezvous_message::Union::configure_update(cu)) => { - Config::set_option("rendezvous-servers".to_owned(), cu.rendezvous_servers.join(",")); - Config::set_serial(cu.serial); - } - _ => {} - } - } else { - log::debug!("Non-protobuf message bytes received: {:?}", bytes); + }, + Some(Err(e)) => bail!("Failed to receive next {}", e), // maybe socks5 tcp disconnected + None => { + // unreachable!() + }, } }, _ = timer.tick() => { @@ -200,13 +253,21 @@ impl RendezvousMediator { break; } if rz.addr.port() == 0 { - allow_err!(rz.dns_check()); - if rz.addr.port() == 0 { - continue; - } else { - // have to do this for osx, to avoid "Can't assign requested address" - // when socket created before OS network ready - socket = FramedSocket::new(Config::get_any_listen_addr()).await?; + // tcp is established to help connecting socks5 + if !socks5 { + allow_err!(rz.dns_check()); + if rz.addr.port() == 0 { + continue; + } else { + // have to do this for osx, to avoid "Can't assign requested address" + // when socket created before OS network ready + + let r = conn_fn(bind_addr).await?; + socket = r.0; + if let Some(addr) = r.1 { + rz.addr = addr; + } + } } } let now = SystemTime::now(); @@ -226,10 +287,18 @@ impl RendezvousMediator { Config::update_latency(&host, -1); old_latency = 0; if now.duration_since(last_dns_check).map(|d| d.as_millis() as i64).unwrap_or(0) > DNS_INTERVAL { - if let Ok(_) = rz.dns_check() { + // tcp is established to help connecting socks5 + if !socks5 { + if let Ok(_) = rz.dns_check() { // in some case of network reconnect (dial IP network), // old UDP socket not work any more after network recover - socket = FramedSocket::new(Config::get_any_listen_addr()).await?; + + let r = conn_fn(bind_addr).await?; + socket = r.0; + if let Some(addr) = r.1 { + rz.addr = addr; + } + } } last_dns_check = now; } @@ -280,8 +349,14 @@ impl RendezvousMediator { uuid, secure, ); - let mut socket = - FramedStream::new(self.addr, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT).await?; + + let mut socket = socket_client::connect_tcp( + format!("{}:{}", self.host, RENDEZVOUS_PORT), + Config::get_any_listen_addr(), + RENDEZVOUS_TIMEOUT, + ) + .await?; + let mut msg_out = Message::new(); let mut rr = RelayResponse { socket_addr, @@ -303,15 +378,15 @@ impl RendezvousMediator { async fn handle_intranet(&self, fla: FetchLocalAddr, server: ServerPtr) -> ResultType<()> { let peer_addr = AddrMangle::decode(&fla.socket_addr); log::debug!("Handle intranet from {:?}", peer_addr); - let (mut socket, port) = { - let socket = - FramedStream::new(self.addr, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT) - .await?; - let port = socket.get_ref().local_addr()?.port(); - (socket, port) - }; - let local_addr = socket.get_ref().local_addr()?; - let local_addr: SocketAddr = format!("{}:{}", local_addr.ip(), port).parse()?; + let mut socket = socket_client::connect_tcp( + format!("{}:{}", self.host, RENDEZVOUS_PORT), + Config::get_any_listen_addr(), + RENDEZVOUS_TIMEOUT, + ) + .await?; + let local_addr = socket.local_addr(); + let local_addr: SocketAddr = + format!("{}:{}", local_addr.ip(), local_addr.port()).parse()?; let mut msg_out = Message::new(); let mut relay_server = Config::get_option("relay-server"); if relay_server.is_empty() { @@ -347,10 +422,14 @@ impl RendezvousMediator { let peer_addr = AddrMangle::decode(&ph.socket_addr); log::debug!("Punch hole to {:?}", peer_addr); let mut socket = { - let socket = - FramedStream::new(self.addr, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT) - .await?; - allow_err!(FramedStream::new(peer_addr, socket.get_ref().local_addr()?, 300).await); + let socket = socket_client::connect_tcp( + format!("{}:{}", self.host, RENDEZVOUS_PORT), + Config::get_any_listen_addr(), + RENDEZVOUS_TIMEOUT, + ) + .await?; + let local_addr = socket.local_addr(); + allow_err!(socket_client::connect_tcp(peer_addr, local_addr, 300).await); socket }; let mut msg_out = Message::new(); @@ -370,7 +449,11 @@ impl RendezvousMediator { Ok(()) } - async fn register_pk(&mut self, socket: &mut FramedSocket) -> ResultType<()> { + async fn register_pk(&mut self, socket: &mut FramedSocket) -> ResultType<()> + where + Frm: Unpin + Stream + Sink<(Bytes, SocketAddr)>, + >::Error: Sync + Send + std::error::Error + 'static, + { let mut msg_out = Message::new(); let pk = Config::get_key_pair().1; let uuid = if let Ok(id) = machine_uid::get() { @@ -391,7 +474,11 @@ impl RendezvousMediator { Ok(()) } - async fn handle_uuid_mismatch(&mut self, socket: &mut FramedSocket) -> ResultType<()> { + async fn handle_uuid_mismatch(&mut self, socket: &mut FramedSocket) -> ResultType<()> + where + Frm: Unpin + Stream + Sink<(Bytes, SocketAddr)>, + >::Error: Sync + Send + std::error::Error + 'static, + { if self.last_id_pk_registry != Config::get_id() { return Ok(()); } @@ -409,7 +496,11 @@ impl RendezvousMediator { self.register_pk(socket).await } - async fn register_peer(&mut self, socket: &mut FramedSocket) -> ResultType<()> { + async fn register_peer(&mut self, socket: &mut FramedSocket) -> ResultType<()> + where + Frm: Unpin + Stream + Sink<(Bytes, SocketAddr)>, + >::Error: Sync + Send + std::error::Error + 'static, + { if !SOLVING_PK_MISMATCH.lock().unwrap().is_empty() { return Ok(()); } diff --git a/src/server.rs b/src/server.rs index 270b8075e..451c18e1b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,5 +1,5 @@ use crate::ipc::Data; -pub use connection::*; +use connection::{ConnInner, Connection}; use hbb_common::{ allow_err, anyhow::{anyhow, Context}, @@ -11,8 +11,8 @@ use hbb_common::{ rendezvous_proto::*, sleep, sodiumoxide::crypto::{box_, secretbox, sign}, - tcp::FramedStream, timeout, tokio, ResultType, Stream, + socket_client, }; use service::{GenericService, Service, ServiceTmpl, Subscriber}; use std::{ @@ -61,7 +61,7 @@ pub fn new() -> ServerPtr { } async fn accept_connection_(server: ServerPtr, socket: Stream, secure: bool) -> ResultType<()> { - let local_addr = socket.get_ref().local_addr()?; + let local_addr = socket.local_addr(); drop(socket); // even we drop socket, below still may fail if not use reuse_addr, // there is TIME_WAIT before socket really released, so sometimes we @@ -69,7 +69,8 @@ async fn accept_connection_(server: ServerPtr, socket: Stream, secure: bool) -> let listener = new_listener(local_addr, true).await?; log::info!("Server listening on: {}", &listener.local_addr()?); if let Ok((stream, addr)) = timeout(CONNECT_TIMEOUT, listener.accept()).await? { - create_tcp_connection(server, Stream::from(stream), addr, secure).await?; + let stream_addr = stream.local_addr()?; + create_tcp_connection(server, Stream::from(stream, stream_addr), addr, secure).await?; } Ok(()) } @@ -183,8 +184,8 @@ async fn create_relay_connection_( peer_addr: SocketAddr, secure: bool, ) -> ResultType<()> { - let mut stream = FramedStream::new( - &crate::check_port(relay_server, RELAY_PORT), + let mut stream = socket_client::connect_tcp( + crate::check_port(relay_server, RELAY_PORT), Config::get_any_listen_addr(), CONNECT_TIMEOUT, ) From 875570e040ff5e0ef055e99aa32054687faa9954 Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 4 Jan 2022 00:44:50 +0800 Subject: [PATCH 46/77] refactor udp framed Signed-off-by: fufesou --- Cargo.lock | 4 - libs/hbb_common/Cargo.toml | 4 - libs/hbb_common/src/config.rs | 13 +++ libs/hbb_common/src/lib.rs | 2 - libs/hbb_common/src/socket_client.rs | 54 ++++----- libs/hbb_common/src/udp.rs | 167 ++++++--------------------- src/common.rs | 52 ++------- src/rendezvous_mediator.rs | 145 ++++++++++------------- 8 files changed, 140 insertions(+), 301 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16159ab24..c5afa5031 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1553,7 +1553,6 @@ name = "hbb_common" version = "0.1.0" dependencies = [ "anyhow", - "async-trait", "bytes", "confy", "directories-next", @@ -1561,13 +1560,10 @@ dependencies = [ "env_logger 0.9.0", "filetime", "futures", - "futures-core", - "futures-sink", "futures-util", "lazy_static", "log", "mac_address", - "pin-project", "protobuf", "protobuf-codegen-pure", "quinn", diff --git a/libs/hbb_common/Cargo.toml b/libs/hbb_common/Cargo.toml index dbebe8206..4dc7dcf86 100644 --- a/libs/hbb_common/Cargo.toml +++ b/libs/hbb_common/Cargo.toml @@ -29,10 +29,6 @@ dirs-next = "2.0" filetime = "0.2" sodiumoxide = "0.2" tokio-socks = { git = "https://github.com/fufesou/tokio-socks" } -futures-core = "0.3" -futures-sink = "0.3" -async-trait = "0.1" -pin-project = "1" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] mac_address = "1.1" diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index fb558eef1..49b12f4b0 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -55,6 +55,12 @@ pub const RENDEZVOUS_SERVERS: &'static [&'static str] = &[ pub const RENDEZVOUS_PORT: i32 = 21116; pub const RELAY_PORT: i32 = 21117; +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum NetworkType { + Direct, + ProxySocks, +} + #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct Config { #[serde(default)] @@ -642,6 +648,13 @@ impl Config { pub fn get_socks() -> Option { CONFIG2.read().unwrap().socks.clone() } + + pub fn get_network_type() -> NetworkType { + match &CONFIG2.read().unwrap().socks { + None => NetworkType::Direct, + Some(_) => NetworkType::ProxySocks, + } + } } const PEERS: &str = "peers"; diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 4bc90d198..dd685f77b 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -24,8 +24,6 @@ pub mod bytes_codec; #[cfg(feature = "quic")] pub mod quic; pub use anyhow::{self, bail}; -pub use futures_core; -pub use futures_sink; pub use futures_util; pub mod config; pub mod fs; diff --git a/libs/hbb_common/src/socket_client.rs b/libs/hbb_common/src/socket_client.rs index 596a96eaf..2fd9bcff1 100644 --- a/libs/hbb_common/src/socket_client.rs +++ b/libs/hbb_common/src/socket_client.rs @@ -1,22 +1,21 @@ use crate::{ - config::{Config, Socks5Server}, + config::{Config, NetworkType}, tcp::FramedStream, - udp::{FramedSocket, UdpFramedWrapper}, + udp::FramedSocket, ResultType, }; use anyhow::{bail, Context}; use std::net::SocketAddr; use tokio::net::ToSocketAddrs; -use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr}; -use tokio_util::{codec::BytesCodec, udp::UdpFramed}; +use tokio_socks::IntoTargetAddr; -pub fn get_socks5_conf() -> Option { - // Config::set_socks(Some(Socks5Server { - // proxy: "139.186.136.143:1080".to_owned(), - // ..Default::default() - // })); - Config::get_socks() -} +// fn get_socks5_conf() -> Option { +// // Config::set_socks(Some(Socks5Server { +// // proxy: "139.186.136.143:1080".to_owned(), +// // ..Default::default() +// // })); +// Config::get_socks() +// } pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( target: T, @@ -25,7 +24,7 @@ pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( ) -> ResultType { let target_addr = target.into_target_addr()?; - if let Some(conf) = get_socks5_conf() { + if let Some(conf) = Config::get_socks() { FramedStream::connect( conf.proxy.as_str(), target_addr, @@ -48,26 +47,13 @@ pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( } } -// TODO: merge connect_udp and connect_udp_socks5 -pub async fn connect_udp_socket( - local: T1, -) -> ResultType<( - FramedSocket>>, - Option, -)> { - Ok((FramedSocket::new(local).await?, None)) -} - -pub async fn connect_udp_socks5<'t, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( +pub async fn connect_udp<'t, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( target: T1, local: T2, - socks5: &Option, ms_timeout: u64, -) -> ResultType<( - FramedSocket>, - Option, -)> { - match socks5 { +) -> ResultType<(FramedSocket, Option)> { + match Config::get_socks() { + None => Ok((FramedSocket::new(local).await?, None)), Some(conf) => { let (socket, addr) = FramedSocket::connect( conf.proxy.as_str(), @@ -80,8 +66,12 @@ pub async fn connect_udp_socks5<'t, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( .await?; Ok((socket, Some(addr))) } - None => { - bail!("Nil socks5 server config") - } + } +} + +pub async fn reconnect_udp(local: T) -> ResultType> { + match Config::get_network_type() { + NetworkType::Direct => Ok(Some(FramedSocket::new(local).await?)), + _ => Ok(None), } } diff --git a/libs/hbb_common/src/udp.rs b/libs/hbb_common/src/udp.rs index 8203c47d0..719cea076 100644 --- a/libs/hbb_common/src/udp.rs +++ b/libs/hbb_common/src/udp.rs @@ -2,59 +2,16 @@ use crate::{bail, ResultType}; use anyhow::anyhow; use bytes::{Bytes, BytesMut}; use futures::{SinkExt, StreamExt}; -use futures_core::Stream; -use futures_sink::Sink; -use pin_project::pin_project; use protobuf::Message; use socket2::{Domain, Socket, Type}; -use std::{ - net::SocketAddr, - ops::{Deref, DerefMut}, - pin::Pin, - task::{Context, Poll}, -}; +use std::net::SocketAddr; use tokio::net::{ToSocketAddrs, UdpSocket}; -use tokio_socks::{ - udp::{Socks5UdpFramed, Socks5UdpMessage}, - IntoTargetAddr, TargetAddr, ToProxyAddrs, -}; +use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr, TargetAddr, ToProxyAddrs}; use tokio_util::{codec::BytesCodec, udp::UdpFramed}; -pub struct FramedSocket(F); - -#[pin_project] -pub struct UdpFramedWrapper(#[pin] F); - -pub trait BytesMutGetter<'a> { - fn get_bytes_mut(&'a self) -> &'a BytesMut; -} - -impl Deref for FramedSocket { - type Target = F; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for FramedSocket { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Deref for UdpFramedWrapper { - type Target = F; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for UdpFramedWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } +pub enum FramedSocket { + Direct(UdpFramed), + ProxySocks(Socks5UdpFramed), } fn new_socket(addr: SocketAddr, reuse: bool) -> Result { @@ -74,29 +31,24 @@ fn new_socket(addr: SocketAddr, reuse: bool) -> Result { Ok(socket) } -impl FramedSocket>> { +impl FramedSocket { pub async fn new(addr: T) -> ResultType { let socket = UdpSocket::bind(addr).await?; - Ok(Self(UdpFramedWrapper(UdpFramed::new( - socket, - BytesCodec::new(), - )))) + Ok(Self::Direct(UdpFramed::new(socket, BytesCodec::new()))) } #[allow(clippy::never_loop)] pub async fn new_reuse(addr: T) -> ResultType { for addr in addr.to_socket_addrs()? { let socket = new_socket(addr, true)?.into_udp_socket(); - return Ok(Self(UdpFramedWrapper(UdpFramed::new( + return Ok(Self::Direct(UdpFramed::new( UdpSocket::from_std(socket)?, BytesCodec::new(), - )))); + ))); } bail!("could not resolve to any address"); } -} -impl FramedSocket> { pub async fn connect<'a, 't, P: ToProxyAddrs, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( proxy: P, target: T1, @@ -134,43 +86,48 @@ impl FramedSocket> { framed.local_addr().unwrap(), &addr ); - Ok((Self(UdpFramedWrapper(framed)), addr)) - } -} - -// TODO: simplify this constraint -impl FramedSocket -where - F: Unpin + Stream + Sink<(Bytes, SocketAddr)>, - >::Error: Sync + Send + std::error::Error + 'static, -{ - pub async fn new_with(self) -> ResultType { - Ok(self) + Ok((Self::ProxySocks(framed), addr)) } #[inline] pub async fn send(&mut self, msg: &impl Message, addr: SocketAddr) -> ResultType<()> { - self.0 - .send((Bytes::from(msg.write_to_bytes().unwrap()), addr)) - .await?; + let send_data = (Bytes::from(msg.write_to_bytes().unwrap()), addr); + let _ = match self { + Self::Direct(f) => f.send(send_data).await?, + Self::ProxySocks(f) => f.send(send_data).await?, + }; Ok(()) } #[inline] pub async fn send_raw(&mut self, msg: &'static [u8], addr: SocketAddr) -> ResultType<()> { - self.0.send((Bytes::from(msg), addr)).await?; + let _ = match self { + Self::Direct(f) => f.send((Bytes::from(msg), addr)).await?, + Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?, + }; Ok(()) } #[inline] - pub async fn next(&mut self) -> Option<::Item> { - self.0.next().await + pub async fn next(&mut self) -> Option> { + match self { + Self::Direct(f) => match f.next().await { + Some(Ok((data, addr))) => Some(Ok((data, addr))), + Some(Err(e)) => Some(Err(anyhow!(e))), + None => None, + }, + Self::ProxySocks(f) => match f.next().await { + Some(Ok((data, addr))) => Some(Ok((data.data, addr))), + Some(Err(e)) => Some(Err(anyhow!(e))), + None => None, + }, + } } #[inline] - pub async fn next_timeout(&mut self, ms: u64) -> Option<::Item> { + pub async fn next_timeout(&mut self, ms: u64) -> Option> { if let Ok(res) = - tokio::time::timeout(std::time::Duration::from_millis(ms), self.0.next()).await + tokio::time::timeout(std::time::Duration::from_millis(ms), self.next()).await { res } else { @@ -178,59 +135,3 @@ where } } } - -impl<'a> BytesMutGetter<'a> for BytesMut { - fn get_bytes_mut(&'a self) -> &'a BytesMut { - self - } -} - -impl<'a> BytesMutGetter<'a> for Socks5UdpMessage { - fn get_bytes_mut(&'a self) -> &'a BytesMut { - &self.data - } -} - -impl Stream for UdpFramedWrapper -where - F: Stream>, - for<'b> M: BytesMutGetter<'b> + std::fmt::Debug, - E: std::error::Error + Into, -{ - type Item = ResultType<(BytesMut, SocketAddr)>; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match self.project().0.poll_next(cx) { - Poll::Ready(Some(Ok((msg, addr)))) => { - Poll::Ready(Some(Ok((msg.get_bytes_mut().clone(), addr)))) - } - Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(anyhow!(e)))), - Poll::Ready(None) => Poll::Ready(None), - Poll::Pending => Poll::Pending, - } - } -} - -impl Sink<(Bytes, SocketAddr)> for UdpFramedWrapper -where - F: Sink<(Bytes, SocketAddr)>, -{ - type Error = >::Error; - - fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().0.poll_ready(cx) - } - - fn start_send(self: Pin<&mut Self>, item: (Bytes, SocketAddr)) -> Result<(), Self::Error> { - self.project().0.start_send(item) - } - - #[allow(unused_mut)] - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().0.poll_flush(cx) - } - - fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.project().0.poll_close(cx) - } -} diff --git a/src/common.rs b/src/common.rs index 75a619c31..dcef673ed 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,27 +1,20 @@ -use std::net::SocketAddr; - pub use arboard::Clipboard as ClipboardContext; use hbb_common::{ allow_err, anyhow::bail, - bytes::{Bytes, BytesMut}, compress::{compress as compress_func, decompress}, - config::{Config, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT}, - futures_core::Stream, - futures_sink::Sink, + config::{Config, NetworkType, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT}, log, message_proto::*, protobuf::Message as _, protobuf::ProtobufEnum, rendezvous_proto::*, - sleep, socket_client, tokio, - udp::FramedSocket, - ResultType, + sleep, socket_client, tokio, ResultType, }; #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))] use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all}; use std::{ - future::Future, + net::SocketAddr, sync::{Arc, Mutex}, }; @@ -274,7 +267,9 @@ async fn test_nat_type_() -> ResultType { RENDEZVOUS_TIMEOUT, ) .await?; - addr = socket.local_addr(); + if Config::get_network_type() == NetworkType::Direct { + addr = socket.local_addr(); + } socket.send(&msg_out).await?; if let Some(Ok(bytes)) = socket.next_timeout(3000).await { if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) { @@ -448,35 +443,12 @@ async fn _check_software_update() -> hbb_common::ResultType<()> { sleep(3.).await; let rendezvous_server = get_rendezvous_server(1_000).await; - let socks5_conf = socket_client::get_socks5_conf(); - if socks5_conf.is_some() { - let conn_fn = |bind_addr: SocketAddr| async move { - socket_client::connect_udp_socks5( - rendezvous_server, - bind_addr, - &socks5_conf, - RENDEZVOUS_TIMEOUT, - ) - .await - }; - _inner_check_software_update(conn_fn, rendezvous_server).await - } else { - _inner_check_software_update(socket_client::connect_udp_socket, rendezvous_server).await - } -} - -pub async fn _inner_check_software_update<'a, F, Fut, Frm>( - conn_fn: F, - rendezvous_server: SocketAddr, -) -> ResultType<()> -where - F: FnOnce(SocketAddr) -> Fut, - Fut: Future, Option)>>, - Frm: Unpin + Stream> + Sink<(Bytes, SocketAddr)>, - >::Error: Sync + Send + std::error::Error + 'static, -{ - sleep(3.).await; - let (mut socket, _) = conn_fn(Config::get_any_listen_addr()).await?; + let (mut socket, _) = socket_client::connect_udp( + rendezvous_server, + Config::get_any_listen_addr(), + RENDEZVOUS_TIMEOUT, + ) + .await?; let mut msg_out = RendezvousMessage::new(); msg_out.set_software_update(SoftwareUpdate { url: crate::VERSION.to_owned(), diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index ffa2d565a..dc27126c5 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -2,11 +2,8 @@ use crate::server::{check_zombie, new as new_server, ServerPtr}; use hbb_common::{ allow_err, anyhow::bail, - bytes::{Bytes, BytesMut}, config::{Config, RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT}, futures::future::join_all, - futures_core::Stream, - futures_sink::Sink, log, protobuf::Message as _, rendezvous_proto::*, @@ -19,7 +16,6 @@ use hbb_common::{ AddrMangle, ResultType, }; use std::{ - future::Future, net::SocketAddr, sync::{Arc, Mutex}, time::SystemTime, @@ -63,35 +59,36 @@ impl RendezvousMediator { let server = server.clone(); let servers = servers.clone(); futs.push(tokio::spawn(async move { - let socks5_conf = socket_client::get_socks5_conf(); - if socks5_conf.is_some() { - let target = format!("{}:{}", host, RENDEZVOUS_PORT); - let conn_fn = |bind_addr: SocketAddr| { - let target = target.clone(); - let conf_ref = &socks5_conf; - async move { - socket_client::connect_udp_socks5( - target, - bind_addr, - conf_ref, - RENDEZVOUS_TIMEOUT, - ) - .await - } - }; - allow_err!(Self::start(server, host, servers, conn_fn, true).await); - } else { - allow_err!( - Self::start( - server, - host, - servers, - socket_client::connect_udp_socket, - false, - ) - .await - ); - } + allow_err!(Self::start(server, host, servers).await); + // let socks5_conf = socket_client::get_socks5_conf(); + // if socks5_conf.is_some() { + // let target = format!("{}:{}", host, RENDEZVOUS_PORT); + // let conn_fn = |bind_addr: SocketAddr| { + // let target = target.clone(); + // let conf_ref = &socks5_conf; + // async move { + // socket_client::connect_udp_socks5( + // target, + // bind_addr, + // conf_ref, + // RENDEZVOUS_TIMEOUT, + // ) + // .await + // } + // }; + // allow_err!(Self::start(server, host, servers, conn_fn, true).await); + // } else { + // allow_err!( + // Self::start( + // server, + // host, + // servers, + // socket_client::connect_udp_socket, + // false, + // ) + // .await + // ); + // } })); } join_all(futs).await; @@ -100,19 +97,11 @@ impl RendezvousMediator { } } - pub async fn start<'a, F, Fut, Frm>( + pub async fn start( server: ServerPtr, host: String, rendezvous_servers: Vec, - conn_fn: F, - socks5: bool, - ) -> ResultType<()> - where - F: Fn(SocketAddr) -> Fut, - Fut: Future, Option)>>, - Frm: Unpin + Stream> + Sink<(Bytes, SocketAddr)>, - >::Error: Sync + Send + std::error::Error + 'static, - { + ) -> ResultType<()> { log::info!("start rendezvous mediator of {}", host); let host_prefix: String = host .split(".") @@ -132,12 +121,17 @@ impl RendezvousMediator { rendezvous_servers, last_id_pk_registry: "".to_owned(), }; - allow_err!(rz.dns_check()); + let mut host_addr = rz.addr; + allow_err!(rz.dns_check(&mut host_addr)); let bind_addr = Config::get_any_listen_addr(); - let (mut socket, target_addr) = conn_fn(bind_addr).await?; + let target = format!("{}:{}", host, RENDEZVOUS_PORT); + let (mut socket, target_addr) = + socket_client::connect_udp(target, bind_addr, RENDEZVOUS_TIMEOUT).await?; if let Some(addr) = target_addr { rz.addr = addr; + } else { + rz.addr = host_addr; } const TIMER_OUT: Duration = Duration::from_secs(1); let mut timer = interval(TIMER_OUT); @@ -254,20 +248,16 @@ impl RendezvousMediator { } if rz.addr.port() == 0 { // tcp is established to help connecting socks5 - if !socks5 { - allow_err!(rz.dns_check()); - if rz.addr.port() == 0 { - continue; - } else { - // have to do this for osx, to avoid "Can't assign requested address" - // when socket created before OS network ready - - let r = conn_fn(bind_addr).await?; - socket = r.0; - if let Some(addr) = r.1 { - rz.addr = addr; - } - } + allow_err!(rz.dns_check(&mut host_addr)); + if host_addr.port() == 0 { + continue; + } else { + // have to do this for osx, to avoid "Can't assign requested address" + // when socket created before OS network ready + if let Some(s) = socket_client::reconnect_udp(bind_addr).await? { + socket = s; + rz.addr = host_addr; + }; } } let now = SystemTime::now(); @@ -287,18 +277,13 @@ impl RendezvousMediator { Config::update_latency(&host, -1); old_latency = 0; if now.duration_since(last_dns_check).map(|d| d.as_millis() as i64).unwrap_or(0) > DNS_INTERVAL { - // tcp is established to help connecting socks5 - if !socks5 { - if let Ok(_) = rz.dns_check() { + if let Ok(_) = rz.dns_check(&mut host_addr) { // in some case of network reconnect (dial IP network), // old UDP socket not work any more after network recover - - let r = conn_fn(bind_addr).await?; - socket = r.0; - if let Some(addr) = r.1 { - rz.addr = addr; - } - } + if let Some(s) = socket_client::reconnect_udp(bind_addr).await? { + socket = s; + rz.addr = host_addr; + }; } last_dns_check = now; } @@ -314,8 +299,8 @@ impl RendezvousMediator { Ok(()) } - fn dns_check(&mut self) -> ResultType<()> { - self.addr = hbb_common::to_socket_addr(&crate::check_port(&self.host, RENDEZVOUS_PORT))?; + fn dns_check(&self, addr: &mut SocketAddr) -> ResultType<()> { + *addr = hbb_common::to_socket_addr(&crate::check_port(&self.host, RENDEZVOUS_PORT))?; log::debug!("Lookup dns of {}", self.host); Ok(()) } @@ -449,11 +434,7 @@ impl RendezvousMediator { Ok(()) } - async fn register_pk(&mut self, socket: &mut FramedSocket) -> ResultType<()> - where - Frm: Unpin + Stream + Sink<(Bytes, SocketAddr)>, - >::Error: Sync + Send + std::error::Error + 'static, - { + async fn register_pk(&mut self, socket: &mut FramedSocket) -> ResultType<()> { let mut msg_out = Message::new(); let pk = Config::get_key_pair().1; let uuid = if let Ok(id) = machine_uid::get() { @@ -474,11 +455,7 @@ impl RendezvousMediator { Ok(()) } - async fn handle_uuid_mismatch(&mut self, socket: &mut FramedSocket) -> ResultType<()> - where - Frm: Unpin + Stream + Sink<(Bytes, SocketAddr)>, - >::Error: Sync + Send + std::error::Error + 'static, - { + async fn handle_uuid_mismatch(&mut self, socket: &mut FramedSocket) -> ResultType<()> { if self.last_id_pk_registry != Config::get_id() { return Ok(()); } @@ -496,11 +473,7 @@ impl RendezvousMediator { self.register_pk(socket).await } - async fn register_peer(&mut self, socket: &mut FramedSocket) -> ResultType<()> - where - Frm: Unpin + Stream + Sink<(Bytes, SocketAddr)>, - >::Error: Sync + Send + std::error::Error + 'static, - { + async fn register_peer(&mut self, socket: &mut FramedSocket) -> ResultType<()> { if !SOLVING_PK_MISMATCH.lock().unwrap().is_empty() { return Ok(()); } From cbcad03bc6ad68c1ae9d27ece1ea9a846de2dde5 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 4 Jan 2022 11:22:09 +0800 Subject: [PATCH 47/77] fix style --- src/ui/header.css | 10 ++++++++++ src/ui/index.tis | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ui/header.css b/src/ui/header.css index 4efeba514..e444c1f56 100644 --- a/src/ui/header.css +++ b/src/ui/header.css @@ -46,10 +46,20 @@ header span:hover { background: #f7f7f7; } +@media platform != "OSX" { +header span:hover { + background: #d9d9d9; +} +} + header #screen:hover { background: #d9d9d9; } +header #secure:hover { + background: unset; +} + header span:active, header #screen:active { color: black; background: color(gray-bg); diff --git a/src/ui/index.tis b/src/ui/index.tis index 89b6fa063..0ad2b17d8 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -303,7 +303,7 @@ class InstallMe: Reactor.Component { return
    {translate('install_tip')}
    - +
    ; } From fb392b81cbd39b51e2f7fbf9393e14d77b3d9e67 Mon Sep 17 00:00:00 2001 From: open-trade Date: Tue, 4 Jan 2022 17:44:06 +0800 Subject: [PATCH 48/77] rendezvous_mediator: ensure once one exits, the others also exit. --- src/rendezvous_mediator.rs | 41 ++++++++++---------------------------- 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index dc27126c5..bf83ca56c 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -17,7 +17,10 @@ use hbb_common::{ }; use std::{ net::SocketAddr, - sync::{Arc, Mutex}, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, Mutex, + }, time::SystemTime, }; use uuid::Uuid; @@ -27,6 +30,7 @@ type Message = RendezvousMessage; lazy_static::lazy_static! { pub static ref SOLVING_PK_MISMATCH: Arc> = Default::default(); } +static EXITED: AtomicBool = AtomicBool::new(false); #[derive(Clone)] pub struct RendezvousMediator { @@ -55,40 +59,14 @@ impl RendezvousMediator { } let mut futs = Vec::new(); let servers = Config::get_rendezvous_servers(); + EXITED.store(false, Ordering::SeqCst); for host in servers.clone() { let server = server.clone(); let servers = servers.clone(); futs.push(tokio::spawn(async move { allow_err!(Self::start(server, host, servers).await); - // let socks5_conf = socket_client::get_socks5_conf(); - // if socks5_conf.is_some() { - // let target = format!("{}:{}", host, RENDEZVOUS_PORT); - // let conn_fn = |bind_addr: SocketAddr| { - // let target = target.clone(); - // let conf_ref = &socks5_conf; - // async move { - // socket_client::connect_udp_socks5( - // target, - // bind_addr, - // conf_ref, - // RENDEZVOUS_TIMEOUT, - // ) - // .await - // } - // }; - // allow_err!(Self::start(server, host, servers, conn_fn, true).await); - // } else { - // allow_err!( - // Self::start( - // server, - // host, - // servers, - // socket_client::connect_udp_socket, - // false, - // ) - // .await - // ); - // } + // EXITED here is to ensure once one exits, the others also exit. + EXITED.store(true, Ordering::SeqCst); })); } join_all(futs).await; @@ -246,6 +224,9 @@ impl RendezvousMediator { if !Config::get_option("stop-service").is_empty() { break; } + if EXITED.load(Ordering::SeqCst) { + break; + } if rz.addr.port() == 0 { // tcp is established to help connecting socks5 allow_err!(rz.dns_check(&mut host_addr)); From 533efd04d765ed10975f510dbca9d90cb4774db1 Mon Sep 17 00:00:00 2001 From: open-trade Date: Tue, 4 Jan 2022 17:45:52 +0800 Subject: [PATCH 49/77] rename --- src/rendezvous_mediator.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index bf83ca56c..128cef6c2 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -30,7 +30,7 @@ type Message = RendezvousMessage; lazy_static::lazy_static! { pub static ref SOLVING_PK_MISMATCH: Arc> = Default::default(); } -static EXITED: AtomicBool = AtomicBool::new(false); +static SHOULD_EXIT: AtomicBool = AtomicBool::new(false); #[derive(Clone)] pub struct RendezvousMediator { @@ -59,14 +59,14 @@ impl RendezvousMediator { } let mut futs = Vec::new(); let servers = Config::get_rendezvous_servers(); - EXITED.store(false, Ordering::SeqCst); + SHOULD_EXIT.store(false, Ordering::SeqCst); for host in servers.clone() { let server = server.clone(); let servers = servers.clone(); futs.push(tokio::spawn(async move { allow_err!(Self::start(server, host, servers).await); - // EXITED here is to ensure once one exits, the others also exit. - EXITED.store(true, Ordering::SeqCst); + // SHOULD_EXIT here is to ensure once one exits, the others also exit. + SHOULD_EXIT.store(true, Ordering::SeqCst); })); } join_all(futs).await; @@ -224,7 +224,7 @@ impl RendezvousMediator { if !Config::get_option("stop-service").is_empty() { break; } - if EXITED.load(Ordering::SeqCst) { + if SHOULD_EXIT.load(Ordering::SeqCst) { break; } if rz.addr.port() == 0 { From 3e590b8212090095a5134639c21d9ded4922cad3 Mon Sep 17 00:00:00 2001 From: open-trade Date: Tue, 4 Jan 2022 19:49:44 +0800 Subject: [PATCH 50/77] refactor to_socket_addr and dns_check --- libs/hbb_common/src/config.rs | 4 +-- libs/hbb_common/src/lib.rs | 13 ++------- libs/hbb_common/src/socket_client.rs | 34 +++++++++++++++++----- libs/hbb_common/src/udp.rs | 2 +- src/common.rs | 7 +++-- src/ipc.rs | 4 +-- src/rendezvous_mediator.rs | 43 ++++++++++++---------------- 7 files changed, 57 insertions(+), 50 deletions(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 49b12f4b0..fa2db12cd 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -349,7 +349,7 @@ impl Config { format!("{}:0", BIND_INTERFACE).parse().unwrap() } - pub fn get_rendezvous_server() -> SocketAddr { + pub async fn get_rendezvous_server() -> SocketAddr { let mut rendezvous_server = Self::get_option("custom-rendezvous-server"); if rendezvous_server.is_empty() { rendezvous_server = CONFIG2.write().unwrap().rendezvous_server.clone(); @@ -363,7 +363,7 @@ impl Config { if !rendezvous_server.contains(":") { rendezvous_server = format!("{}:{}", rendezvous_server, RENDEZVOUS_PORT); } - if let Ok(addr) = crate::to_socket_addr(&rendezvous_server) { + if let Ok(addr) = crate::to_socket_addr(&rendezvous_server).await { addr } else { Self::get_any_listen_addr() diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index dd685f77b..367507243 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -9,15 +9,15 @@ pub use protobuf; use std::{ fs::File, io::{self, BufRead}, - net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs}, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, path::Path, time::{self, SystemTime, UNIX_EPOCH}, }; pub use tokio; pub use tokio_util; +pub mod socket_client; pub mod tcp; pub mod udp; -pub mod socket_client; pub use env_logger; pub use log; pub mod bytes_codec; @@ -27,6 +27,7 @@ pub use anyhow::{self, bail}; pub use futures_util; pub mod config; pub mod fs; +pub use socket_client::to_socket_addr; pub use sodiumoxide; pub use tokio_socks; @@ -149,14 +150,6 @@ pub fn get_version_from_url(url: &str) -> String { "".to_owned() } -pub fn to_socket_addr(host: &str) -> ResultType { - let addrs: Vec = host.to_socket_addrs()?.collect(); - if addrs.is_empty() { - bail!("Failed to solve {}", host); - } - Ok(addrs[0]) -} - pub fn gen_version() { let mut file = File::create("./src/version.rs").unwrap(); for line in read_lines("Cargo.toml").unwrap() { diff --git a/libs/hbb_common/src/socket_client.rs b/libs/hbb_common/src/socket_client.rs index 2fd9bcff1..e38ea5ed6 100644 --- a/libs/hbb_common/src/socket_client.rs +++ b/libs/hbb_common/src/socket_client.rs @@ -1,5 +1,5 @@ use crate::{ - config::{Config, NetworkType}, + config::{Config, NetworkType, RENDEZVOUS_TIMEOUT}, tcp::FramedStream, udp::FramedSocket, ResultType, @@ -47,15 +47,35 @@ pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( } } -pub async fn connect_udp<'t, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( +fn native_to_socket_addr(host: &str) -> ResultType { + use std::net::ToSocketAddrs; + let addrs: Vec = host.to_socket_addrs()?.collect(); + if addrs.is_empty() { + bail!("Failed to solve {}", host); + } + Ok(addrs[0]) +} + +pub async fn to_socket_addr(host: &str) -> ResultType { + Ok( + new_udp(host, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT) + .await? + .1, + ) +} + +pub async fn new_udp<'t, T1: IntoTargetAddr<'t> + std::fmt::Display, T2: ToSocketAddrs>( target: T1, local: T2, ms_timeout: u64, -) -> ResultType<(FramedSocket, Option)> { +) -> ResultType<(FramedSocket, SocketAddr)> { match Config::get_socks() { - None => Ok((FramedSocket::new(local).await?, None)), + None => Ok(( + FramedSocket::new(local).await?, + native_to_socket_addr(&target.to_string())?, + )), Some(conf) => { - let (socket, addr) = FramedSocket::connect( + let (socket, addr) = FramedSocket::new_proxy( conf.proxy.as_str(), target, local, @@ -64,12 +84,12 @@ pub async fn connect_udp<'t, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( ms_timeout, ) .await?; - Ok((socket, Some(addr))) + Ok((socket, addr)) } } } -pub async fn reconnect_udp(local: T) -> ResultType> { +pub async fn rebind(local: T) -> ResultType> { match Config::get_network_type() { NetworkType::Direct => Ok(Some(FramedSocket::new(local).await?)), _ => Ok(None), diff --git a/libs/hbb_common/src/udp.rs b/libs/hbb_common/src/udp.rs index 719cea076..f5d088623 100644 --- a/libs/hbb_common/src/udp.rs +++ b/libs/hbb_common/src/udp.rs @@ -49,7 +49,7 @@ impl FramedSocket { bail!("could not resolve to any address"); } - pub async fn connect<'a, 't, P: ToProxyAddrs, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( + pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( proxy: P, target: T1, local: T2, diff --git a/src/common.rs b/src/common.rs index dcef673ed..03256ce4c 100644 --- a/src/common.rs +++ b/src/common.rs @@ -415,12 +415,13 @@ pub fn is_modifier(evt: &KeyEvent) -> bool { } } -pub fn test_if_valid_server(host: String) -> String { +#[tokio::main(flavor = "current_thread")] +pub async fn test_if_valid_server(host: String) -> String { let mut host = host; if !host.contains(":") { host = format!("{}:{}", host, 0); } - match hbb_common::to_socket_addr(&host) { + match hbb_common::to_socket_addr(&host).await { Err(err) => err.to_string(), Ok(_) => "".to_owned(), } @@ -443,7 +444,7 @@ async fn _check_software_update() -> hbb_common::ResultType<()> { sleep(3.).await; let rendezvous_server = get_rendezvous_server(1_000).await; - let (mut socket, _) = socket_client::connect_udp( + let (mut socket, _) = socket_client::new_udp( rendezvous_server, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, diff --git a/src/ipc.rs b/src/ipc.rs index 0474e457f..cd69ccfb3 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -202,7 +202,7 @@ async fn handle(data: Data, stream: &mut Connection) { } else if name == "salt" { value = Some(Config::get_salt()); } else if name == "rendezvous_server" { - value = Some(Config::get_rendezvous_server().to_string()); + value = Some(Config::get_rendezvous_server().await.to_string()); } else { value = None; } @@ -403,7 +403,7 @@ pub async fn get_rendezvous_server(ms_timeout: u64) -> SocketAddr { return v; } } - return Config::get_rendezvous_server(); + return Config::get_rendezvous_server().await; } async fn get_options_(ms_timeout: u64) -> ResultType> { diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index 128cef6c2..123a1e016 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -99,18 +99,13 @@ impl RendezvousMediator { rendezvous_servers, last_id_pk_registry: "".to_owned(), }; - let mut host_addr = rz.addr; - allow_err!(rz.dns_check(&mut host_addr)); - - let bind_addr = Config::get_any_listen_addr(); - let target = format!("{}:{}", host, RENDEZVOUS_PORT); - let (mut socket, target_addr) = - socket_client::connect_udp(target, bind_addr, RENDEZVOUS_TIMEOUT).await?; - if let Some(addr) = target_addr { - rz.addr = addr; - } else { - rz.addr = host_addr; - } + let (mut socket, target_addr) = socket_client::new_udp( + crate::check_port(&host, RENDEZVOUS_PORT), + Config::get_any_listen_addr(), + RENDEZVOUS_TIMEOUT, + ) + .await?; + rz.addr = target_addr; const TIMER_OUT: Duration = Duration::from_secs(1); let mut timer = interval(TIMER_OUT); let mut last_timer = SystemTime::UNIX_EPOCH; @@ -228,16 +223,14 @@ impl RendezvousMediator { break; } if rz.addr.port() == 0 { - // tcp is established to help connecting socks5 - allow_err!(rz.dns_check(&mut host_addr)); - if host_addr.port() == 0 { + allow_err!(rz.dns_check().await); + if rz.addr.port() == 0 { continue; } else { // have to do this for osx, to avoid "Can't assign requested address" // when socket created before OS network ready - if let Some(s) = socket_client::reconnect_udp(bind_addr).await? { + if let Some(s) = socket_client::rebind(Config::get_any_listen_addr()).await? { socket = s; - rz.addr = host_addr; }; } } @@ -258,12 +251,11 @@ impl RendezvousMediator { Config::update_latency(&host, -1); old_latency = 0; if now.duration_since(last_dns_check).map(|d| d.as_millis() as i64).unwrap_or(0) > DNS_INTERVAL { - if let Ok(_) = rz.dns_check(&mut host_addr) { + if let Ok(_) = rz.dns_check().await { // in some case of network reconnect (dial IP network), // old UDP socket not work any more after network recover - if let Some(s) = socket_client::reconnect_udp(bind_addr).await? { + if let Some(s) = socket_client::rebind(Config::get_any_listen_addr()).await? { socket = s; - rz.addr = host_addr; }; } last_dns_check = now; @@ -280,8 +272,9 @@ impl RendezvousMediator { Ok(()) } - fn dns_check(&self, addr: &mut SocketAddr) -> ResultType<()> { - *addr = hbb_common::to_socket_addr(&crate::check_port(&self.host, RENDEZVOUS_PORT))?; + async fn dns_check(&mut self) -> ResultType<()> { + self.addr = + hbb_common::to_socket_addr(&crate::check_port(&self.host, RENDEZVOUS_PORT)).await?; log::debug!("Lookup dns of {}", self.host); Ok(()) } @@ -317,7 +310,7 @@ impl RendezvousMediator { ); let mut socket = socket_client::connect_tcp( - format!("{}:{}", self.host, RENDEZVOUS_PORT), + self.addr, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, ) @@ -345,7 +338,7 @@ impl RendezvousMediator { let peer_addr = AddrMangle::decode(&fla.socket_addr); log::debug!("Handle intranet from {:?}", peer_addr); let mut socket = socket_client::connect_tcp( - format!("{}:{}", self.host, RENDEZVOUS_PORT), + self.addr, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, ) @@ -389,7 +382,7 @@ impl RendezvousMediator { log::debug!("Punch hole to {:?}", peer_addr); let mut socket = { let socket = socket_client::connect_tcp( - format!("{}:{}", self.host, RENDEZVOUS_PORT), + self.addr, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, ) From 1d8cdb5e932fe52a21417514fa3ccda4602f5594 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 5 Jan 2022 13:21:14 +0800 Subject: [PATCH 51/77] refactor target address --- Cargo.lock | 14 ++--- libs/hbb_common/src/config.rs | 13 ++--- libs/hbb_common/src/lib.rs | 3 +- libs/hbb_common/src/socket_client.rs | 81 ++++++++++++++-------------- libs/hbb_common/src/udp.rs | 73 +++++++++++++------------ src/client.rs | 9 ++-- src/common.rs | 50 +++++++---------- src/ipc.rs | 13 +++-- src/rendezvous_mediator.rs | 73 +++++++++++-------------- src/ui.rs | 2 +- 10 files changed, 157 insertions(+), 174 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5afa5031..f783a63a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,9 +389,9 @@ dependencies = [ [[package]] name = "clipboard-win" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8340083d28acb43451166543b98c838299b7e0863621be53a338adceea0ed" +checksum = "1951fb8aa063a2ee18b4b4d217e4aa2ec9cc4f2430482983f607fa10cd36d7aa" dependencies = [ "error-code", "str-buf", @@ -586,9 +586,9 @@ dependencies = [ [[package]] name = "cstr_core" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ba9efe9e1e736671d5a03f006afc4e7e3f32503e2077e0bcaf519c0c8c1d3" +checksum = "644828c273c063ab0d39486ba42a5d1f3a499d35529c759e763a9c6cb8a0fb08" dependencies = [ "cty", "memchr", @@ -1238,9 +1238,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", @@ -3667,7 +3667,7 @@ dependencies = [ [[package]] name = "tokio-socks" version = "0.5.1" -source = "git+https://github.com/fufesou/tokio-socks#121a780c7e6a31c3aac70e7234f5c62eecaf0629" +source = "git+https://github.com/fufesou/tokio-socks#83e9e9202b85b887999375e4d86e437e33d0535c" dependencies = [ "bytes", "either", diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index fa2db12cd..23576d98f 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -6,14 +6,13 @@ use sodiumoxide::crypto::sign; use std::{ collections::HashMap, fs, - net::SocketAddr, + net::{IpAddr, Ipv4Addr, SocketAddr}, path::{Path, PathBuf}, sync::{Arc, Mutex, RwLock}, time::SystemTime, }; pub const APP_NAME: &str = "RustDesk"; -pub const BIND_INTERFACE: &str = "0.0.0.0"; pub const RENDEZVOUS_TIMEOUT: u64 = 12_000; pub const CONNECT_TIMEOUT: u64 = 18_000; pub const COMPRESS_LEVEL: i32 = 3; @@ -346,10 +345,10 @@ impl Config { #[inline] pub fn get_any_listen_addr() -> SocketAddr { - format!("{}:0", BIND_INTERFACE).parse().unwrap() + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0) } - pub async fn get_rendezvous_server() -> SocketAddr { + pub fn get_rendezvous_server() -> String { let mut rendezvous_server = Self::get_option("custom-rendezvous-server"); if rendezvous_server.is_empty() { rendezvous_server = CONFIG2.write().unwrap().rendezvous_server.clone(); @@ -363,11 +362,7 @@ impl Config { if !rendezvous_server.contains(":") { rendezvous_server = format!("{}:{}", rendezvous_server, RENDEZVOUS_PORT); } - if let Ok(addr) = crate::to_socket_addr(&rendezvous_server).await { - addr - } else { - Self::get_any_listen_addr() - } + rendezvous_server } pub fn get_rendezvous_servers() -> Vec { diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 367507243..38487a1a4 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -27,9 +27,10 @@ pub use anyhow::{self, bail}; pub use futures_util; pub mod config; pub mod fs; -pub use socket_client::to_socket_addr; pub use sodiumoxide; pub use tokio_socks; +pub use tokio_socks::IntoTargetAddr; +pub use tokio_socks::TargetAddr; #[cfg(feature = "quic")] pub type Stream = quic::Connection; diff --git a/libs/hbb_common/src/socket_client.rs b/libs/hbb_common/src/socket_client.rs index e38ea5ed6..d00b5e759 100644 --- a/libs/hbb_common/src/socket_client.rs +++ b/libs/hbb_common/src/socket_client.rs @@ -1,5 +1,5 @@ use crate::{ - config::{Config, NetworkType, RENDEZVOUS_TIMEOUT}, + config::{Config, NetworkType}, tcp::FramedStream, udp::FramedSocket, ResultType, @@ -7,15 +7,43 @@ use crate::{ use anyhow::{bail, Context}; use std::net::SocketAddr; use tokio::net::ToSocketAddrs; -use tokio_socks::IntoTargetAddr; +use tokio_socks::{IntoTargetAddr, TargetAddr}; -// fn get_socks5_conf() -> Option { -// // Config::set_socks(Some(Socks5Server { -// // proxy: "139.186.136.143:1080".to_owned(), -// // ..Default::default() -// // })); -// Config::get_socks() -// } +fn to_socket_addr(host: &str) -> ResultType { + use std::net::ToSocketAddrs; + let addrs: Vec = host.to_socket_addrs()?.collect(); + if addrs.is_empty() { + bail!("Failed to solve {}", host); + } + Ok(addrs[0]) +} + +pub fn get_target_addr(host: &str) -> ResultType> { + let addr = match Config::get_network_type() { + NetworkType::Direct => to_socket_addr(&host)?.into_target_addr()?, + NetworkType::ProxySocks => host.into_target_addr()?, + } + .to_owned(); + Ok(addr) +} + +pub fn test_if_valid_server(host: &str) -> String { + let mut host = host.to_owned(); + if !host.contains(":") { + host = format!("{}:{}", host, 0); + } + + match Config::get_network_type() { + NetworkType::Direct => match to_socket_addr(&host) { + Err(err) => err.to_string(), + Ok(_) => "".to_owned(), + }, + NetworkType::ProxySocks => match &host.into_target_addr() { + Err(err) => err.to_string(), + Ok(_) => "".to_owned(), + }, + } +} pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( target: T, @@ -47,49 +75,24 @@ pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( } } -fn native_to_socket_addr(host: &str) -> ResultType { - use std::net::ToSocketAddrs; - let addrs: Vec = host.to_socket_addrs()?.collect(); - if addrs.is_empty() { - bail!("Failed to solve {}", host); - } - Ok(addrs[0]) -} - -pub async fn to_socket_addr(host: &str) -> ResultType { - Ok( - new_udp(host, Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT) - .await? - .1, - ) -} - -pub async fn new_udp<'t, T1: IntoTargetAddr<'t> + std::fmt::Display, T2: ToSocketAddrs>( - target: T1, - local: T2, - ms_timeout: u64, -) -> ResultType<(FramedSocket, SocketAddr)> { +pub async fn new_udp(local: T, ms_timeout: u64) -> ResultType { match Config::get_socks() { - None => Ok(( - FramedSocket::new(local).await?, - native_to_socket_addr(&target.to_string())?, - )), + None => Ok(FramedSocket::new(local).await?), Some(conf) => { - let (socket, addr) = FramedSocket::new_proxy( + let socket = FramedSocket::new_proxy( conf.proxy.as_str(), - target, local, conf.username.as_str(), conf.password.as_str(), ms_timeout, ) .await?; - Ok((socket, addr)) + Ok(socket) } } } -pub async fn rebind(local: T) -> ResultType> { +pub async fn rebind_udp(local: T) -> ResultType> { match Config::get_network_type() { NetworkType::Direct => Ok(Some(FramedSocket::new(local).await?)), _ => Ok(None), diff --git a/libs/hbb_common/src/udp.rs b/libs/hbb_common/src/udp.rs index f5d088623..acf0bb222 100644 --- a/libs/hbb_common/src/udp.rs +++ b/libs/hbb_common/src/udp.rs @@ -49,75 +49,79 @@ impl FramedSocket { bail!("could not resolve to any address"); } - pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T1: IntoTargetAddr<'t>, T2: ToSocketAddrs>( + pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T: ToSocketAddrs>( proxy: P, - target: T1, - local: T2, + local: T, username: &'a str, password: &'a str, ms_timeout: u64, - ) -> ResultType<(Self, SocketAddr)> { + ) -> ResultType { let framed = if username.trim().is_empty() { - super::timeout( - ms_timeout, - Socks5UdpFramed::connect(proxy, target, Some(local)), - ) - .await?? + super::timeout(ms_timeout, Socks5UdpFramed::connect(proxy, Some(local))).await?? } else { super::timeout( ms_timeout, - Socks5UdpFramed::connect_with_password( - proxy, - target, - Some(local), - username, - password, - ), + Socks5UdpFramed::connect_with_password(proxy, Some(local), username, password), ) .await?? }; - let addr = if let TargetAddr::Ip(c) = framed.target_addr() { - c - } else { - unreachable!() - }; log::trace!( "Socks5 udp connected, local addr: {}, target addr: {}", framed.local_addr().unwrap(), - &addr + framed.socks_addr() ); - Ok((Self::ProxySocks(framed), addr)) + Ok(Self::ProxySocks(framed)) } #[inline] - pub async fn send(&mut self, msg: &impl Message, addr: SocketAddr) -> ResultType<()> { - let send_data = (Bytes::from(msg.write_to_bytes().unwrap()), addr); + pub async fn send( + &mut self, + msg: &impl Message, + addr: impl IntoTargetAddr<'_>, + ) -> ResultType<()> { + let addr = addr.into_target_addr()?.to_owned(); + let send_data = Bytes::from(msg.write_to_bytes().unwrap()); let _ = match self { - Self::Direct(f) => f.send(send_data).await?, - Self::ProxySocks(f) => f.send(send_data).await?, + Self::Direct(f) => match addr { + TargetAddr::Ip(addr) => f.send((send_data, addr)).await?, + _ => unreachable!(), + }, + Self::ProxySocks(f) => f.send((send_data, addr)).await?, }; Ok(()) } + // https://stackoverflow.com/a/68733302/1926020 #[inline] - pub async fn send_raw(&mut self, msg: &'static [u8], addr: SocketAddr) -> ResultType<()> { + pub async fn send_raw( + &mut self, + msg: &'static [u8], + addr: impl IntoTargetAddr<'static>, + ) -> ResultType<()> { + let addr = addr.into_target_addr()?.to_owned(); + let _ = match self { - Self::Direct(f) => f.send((Bytes::from(msg), addr)).await?, + Self::Direct(f) => match addr { + TargetAddr::Ip(addr) => f.send((Bytes::from(msg), addr)).await?, + _ => unreachable!(), + }, Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?, }; Ok(()) } #[inline] - pub async fn next(&mut self) -> Option> { + pub async fn next(&mut self) -> Option)>> { match self { Self::Direct(f) => match f.next().await { - Some(Ok((data, addr))) => Some(Ok((data, addr))), + Some(Ok((data, addr))) => { + Some(Ok((data, addr.into_target_addr().unwrap().to_owned()))) + } Some(Err(e)) => Some(Err(anyhow!(e))), None => None, }, Self::ProxySocks(f) => match f.next().await { - Some(Ok((data, addr))) => Some(Ok((data.data, addr))), + Some(Ok((data, _))) => Some(Ok((data.data, data.dst_addr))), Some(Err(e)) => Some(Err(anyhow!(e))), None => None, }, @@ -125,7 +129,10 @@ impl FramedSocket { } #[inline] - pub async fn next_timeout(&mut self, ms: u64) -> Option> { + pub async fn next_timeout( + &mut self, + ms: u64, + ) -> Option)>> { if let Ok(res) = tokio::time::timeout(std::time::Duration::from_millis(ms), self.next()).await { diff --git a/src/client.rs b/src/client.rs index c37413ffb..ff4603776 100644 --- a/src/client.rs +++ b/src/client.rs @@ -109,7 +109,8 @@ impl Client { log::info!("rendezvous server: {}", rendezvous_server); let mut socket = - socket_client::connect_tcp(rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT).await?; + socket_client::connect_tcp(&*rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT) + .await?; let my_addr = socket.local_addr(); let mut pk = Vec::new(); let mut relay_server = "".to_owned(); @@ -205,7 +206,7 @@ impl Client { peer, pk, &relay_server, - rendezvous_server, + &rendezvous_server, time_used, peer_nat_type, my_nat_type, @@ -221,7 +222,7 @@ impl Client { peer_id: &str, pk: Vec, relay_server: &str, - rendezvous_server: SocketAddr, + rendezvous_server: &str, punch_time_used: u64, peer_nat_type: NatType, my_nat_type: i32, @@ -385,7 +386,7 @@ impl Client { async fn request_relay( peer: &str, relay_server: String, - rendezvous_server: SocketAddr, + rendezvous_server: &str, secure: bool, conn_type: ConnType, ) -> ResultType { diff --git a/src/common.rs b/src/common.rs index 03256ce4c..b674c385b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -13,10 +13,7 @@ use hbb_common::{ }; #[cfg(any(target_os = "android", target_os = "ios", feature = "cli"))] use hbb_common::{config::RENDEZVOUS_PORT, futures::future::join_all}; -use std::{ - net::SocketAddr, - sync::{Arc, Mutex}, -}; +use std::sync::{Arc, Mutex}; pub const CLIPBOARD_NAME: &'static str = "clipboard"; pub const CLIPBOARD_INTERVAL: u64 = 333; @@ -244,13 +241,15 @@ async fn test_nat_type_() -> ResultType { let start = std::time::Instant::now(); let rendezvous_server = get_rendezvous_server(100).await; let server1 = rendezvous_server; - let mut server2 = server1; - if server1.port() == 0 { - // offline - // avoid overflow crash - bail!("Offline"); + let tmp: Vec<&str> = server1.split(":").collect(); + if tmp.len() != 2 { + bail!("Invalid server address: {}", server1); } - server2.set_port(server1.port() - 1); + let port: u16 = tmp[1].parse()?; + if port == 0 { + bail!("Invalid server address: {}", server1); + } + let server2 = format!("{}:{}", tmp[0], port); let mut msg_out = RendezvousMessage::new(); let serial = Config::get_serial(); msg_out.set_test_nat_request(TestNatRequest { @@ -262,7 +261,11 @@ async fn test_nat_type_() -> ResultType { let mut addr = Config::get_any_listen_addr(); for i in 0..2 { let mut socket = socket_client::connect_tcp( - if i == 0 { &server1 } else { &server2 }, + if i == 0 { + server1.clone() + } else { + server2.clone() + }, addr, RENDEZVOUS_TIMEOUT, ) @@ -306,12 +309,12 @@ async fn test_nat_type_() -> ResultType { } #[cfg(any(target_os = "android", target_os = "ios"))] -pub async fn get_rendezvous_server(_ms_timeout: u64) -> SocketAddr { +pub async fn get_rendezvous_server(_ms_timeout: u64) -> String { Config::get_rendezvous_server() } #[cfg(not(any(target_os = "android", target_os = "ios")))] -pub async fn get_rendezvous_server(ms_timeout: u64) -> SocketAddr { +pub async fn get_rendezvous_server(ms_timeout: u64) -> String { crate::ipc::get_rendezvous_server(ms_timeout).await } @@ -415,18 +418,6 @@ pub fn is_modifier(evt: &KeyEvent) -> bool { } } -#[tokio::main(flavor = "current_thread")] -pub async fn test_if_valid_server(host: String) -> String { - let mut host = host; - if !host.contains(":") { - host = format!("{}:{}", host, 0); - } - match hbb_common::to_socket_addr(&host).await { - Err(err) => err.to_string(), - Ok(_) => "".to_owned(), - } -} - pub fn get_version_number(v: &str) -> i64 { let mut n = 0; for x in v.split(".") { @@ -444,12 +435,9 @@ async fn _check_software_update() -> hbb_common::ResultType<()> { sleep(3.).await; let rendezvous_server = get_rendezvous_server(1_000).await; - let (mut socket, _) = socket_client::new_udp( - rendezvous_server, - Config::get_any_listen_addr(), - RENDEZVOUS_TIMEOUT, - ) - .await?; + let mut socket = + socket_client::new_udp(Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT).await?; + let mut msg_out = RendezvousMessage::new(); msg_out.set_software_update(SoftwareUpdate { url: crate::VERSION.to_owned(), diff --git a/src/ipc.rs b/src/ipc.rs index cd69ccfb3..1c5a0cc15 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -13,7 +13,7 @@ use parity_tokio_ipc::{ Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes, }; use serde_derive::{Deserialize, Serialize}; -use std::{collections::HashMap, net::SocketAddr}; +use std::collections::HashMap; #[cfg(not(windows))] use std::{fs::File, io::prelude::*}; @@ -202,7 +202,7 @@ async fn handle(data: Data, stream: &mut Connection) { } else if name == "salt" { value = Some(Config::get_salt()); } else if name == "rendezvous_server" { - value = Some(Config::get_rendezvous_server().await.to_string()); + value = Some(Config::get_rendezvous_server()); } else { value = None; } @@ -397,13 +397,12 @@ pub fn get_password() -> String { } } -pub async fn get_rendezvous_server(ms_timeout: u64) -> SocketAddr { +pub async fn get_rendezvous_server(ms_timeout: u64) -> String { if let Ok(Some(v)) = get_config_async("rendezvous_server", ms_timeout).await { - if let Ok(v) = v.parse() { - return v; - } + v + } else { + Config::get_rendezvous_server() } - return Config::get_rendezvous_server().await; } async fn get_options_(ms_timeout: u64) -> ResultType> { diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index 123a1e016..2e035fed6 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -13,7 +13,7 @@ use hbb_common::{ time::{interval, Duration}, }, udp::FramedSocket, - AddrMangle, ResultType, + AddrMangle, IntoTargetAddr, ResultType, TargetAddr, }; use std::{ net::SocketAddr, @@ -32,15 +32,26 @@ lazy_static::lazy_static! { } static SHOULD_EXIT: AtomicBool = AtomicBool::new(false); -#[derive(Clone)] pub struct RendezvousMediator { - addr: SocketAddr, + addr: TargetAddr<'static>, host: String, host_prefix: String, rendezvous_servers: Vec, last_id_pk_registry: String, } +impl Clone for RendezvousMediator { + fn clone(&self) -> Self { + Self { + addr: self.addr.to_owned(), + host: self.host.clone(), + host_prefix: self.host_prefix.clone(), + rendezvous_servers: self.rendezvous_servers.clone(), + last_id_pk_registry: self.last_id_pk_registry.clone(), + } + } +} + impl RendezvousMediator { pub async fn start_all() { let mut nat_tested = false; @@ -93,19 +104,17 @@ impl RendezvousMediator { }) .unwrap_or(host.to_owned()); let mut rz = Self { - addr: Config::get_any_listen_addr(), + addr: Config::get_any_listen_addr().into_target_addr()?, host: host.clone(), host_prefix, rendezvous_servers, last_id_pk_registry: "".to_owned(), }; - let (mut socket, target_addr) = socket_client::new_udp( - crate::check_port(&host, RENDEZVOUS_PORT), - Config::get_any_listen_addr(), - RENDEZVOUS_TIMEOUT, - ) - .await?; - rz.addr = target_addr; + + rz.addr = socket_client::get_target_addr(&crate::check_port(&host, RENDEZVOUS_PORT))?; + let any_addr = Config::get_any_listen_addr(); + let mut socket = socket_client::new_udp(any_addr, RENDEZVOUS_TIMEOUT).await?; + const TIMER_OUT: Duration = Duration::from_secs(1); let mut timer = interval(TIMER_OUT); let mut last_timer = SystemTime::UNIX_EPOCH; @@ -222,18 +231,6 @@ impl RendezvousMediator { if SHOULD_EXIT.load(Ordering::SeqCst) { break; } - if rz.addr.port() == 0 { - allow_err!(rz.dns_check().await); - if rz.addr.port() == 0 { - continue; - } else { - // have to do this for osx, to avoid "Can't assign requested address" - // when socket created before OS network ready - if let Some(s) = socket_client::rebind(Config::get_any_listen_addr()).await? { - socket = s; - }; - } - } let now = SystemTime::now(); if now.duration_since(last_timer).map(|d| d < TIMER_OUT).unwrap_or(false) { // a workaround of tokio timer bug @@ -251,13 +248,12 @@ impl RendezvousMediator { Config::update_latency(&host, -1); old_latency = 0; if now.duration_since(last_dns_check).map(|d| d.as_millis() as i64).unwrap_or(0) > DNS_INTERVAL { - if let Ok(_) = rz.dns_check().await { - // in some case of network reconnect (dial IP network), - // old UDP socket not work any more after network recover - if let Some(s) = socket_client::rebind(Config::get_any_listen_addr()).await? { - socket = s; - }; - } + rz.addr = socket_client::get_target_addr(&crate::check_port(&host, RENDEZVOUS_PORT))?; + // in some case of network reconnect (dial IP network), + // old UDP socket not work any more after network recover + if let Some(s) = socket_client::rebind_udp(any_addr).await? { + socket = s; + }; last_dns_check = now; } } else if fails > MAX_FAILS1 { @@ -272,13 +268,6 @@ impl RendezvousMediator { Ok(()) } - async fn dns_check(&mut self) -> ResultType<()> { - self.addr = - hbb_common::to_socket_addr(&crate::check_port(&self.host, RENDEZVOUS_PORT)).await?; - log::debug!("Lookup dns of {}", self.host); - Ok(()) - } - async fn handle_request_relay(&self, rr: RequestRelay, server: ServerPtr) -> ResultType<()> { self.create_relay( rr.socket_addr, @@ -310,7 +299,7 @@ impl RendezvousMediator { ); let mut socket = socket_client::connect_tcp( - self.addr, + self.addr.to_owned(), Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, ) @@ -338,7 +327,7 @@ impl RendezvousMediator { let peer_addr = AddrMangle::decode(&fla.socket_addr); log::debug!("Handle intranet from {:?}", peer_addr); let mut socket = socket_client::connect_tcp( - self.addr, + self.addr.to_owned(), Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, ) @@ -382,7 +371,7 @@ impl RendezvousMediator { log::debug!("Punch hole to {:?}", peer_addr); let mut socket = { let socket = socket_client::connect_tcp( - self.addr, + self.addr.to_owned(), Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, ) @@ -425,7 +414,7 @@ impl RendezvousMediator { pk, ..Default::default() }); - socket.send(&msg_out, self.addr).await?; + socket.send(&msg_out, self.addr.to_owned()).await?; Ok(()) } @@ -471,7 +460,7 @@ impl RendezvousMediator { serial, ..Default::default() }); - socket.send(&msg_out, self.addr).await?; + socket.send(&msg_out, self.addr.to_owned()).await?; Ok(()) } } diff --git a/src/ui.rs b/src/ui.rs index da7141284..f0e8ecd48 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -315,7 +315,7 @@ impl UI { } fn test_if_valid_server(&self, host: String) -> String { - crate::common::test_if_valid_server(host) + hbb_common::socket_client::test_if_valid_server(&host) } fn get_sound_inputs(&self) -> Value { From 78097f4006bbace0d9743cf9899d8436a0b94634 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 14:38:38 +0800 Subject: [PATCH 52/77] refactort --- Cargo.lock | 6 +++--- src/rendezvous_mediator.rs | 13 +------------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f783a63a7..a11d68fea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3340,9 +3340,9 @@ dependencies = [ [[package]] name = "signature" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" +checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" [[package]] name = "siphasher" @@ -3667,7 +3667,7 @@ dependencies = [ [[package]] name = "tokio-socks" version = "0.5.1" -source = "git+https://github.com/fufesou/tokio-socks#83e9e9202b85b887999375e4d86e437e33d0535c" +source = "git+https://github.com/fufesou/tokio-socks#63e27388e4d569316945c1c24353010d86f342a6" dependencies = [ "bytes", "either", diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index 2e035fed6..ec2822474 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -32,6 +32,7 @@ lazy_static::lazy_static! { } static SHOULD_EXIT: AtomicBool = AtomicBool::new(false); +#[derive(Clone)] pub struct RendezvousMediator { addr: TargetAddr<'static>, host: String, @@ -40,18 +41,6 @@ pub struct RendezvousMediator { last_id_pk_registry: String, } -impl Clone for RendezvousMediator { - fn clone(&self) -> Self { - Self { - addr: self.addr.to_owned(), - host: self.host.clone(), - host_prefix: self.host_prefix.clone(), - rendezvous_servers: self.rendezvous_servers.clone(), - last_id_pk_registry: self.last_id_pk_registry.clone(), - } - } -} - impl RendezvousMediator { pub async fn start_all() { let mut nat_tested = false; From 5631ffac4c234579889b09bbee9c6a094c7ac982 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 15:09:36 +0800 Subject: [PATCH 53/77] fix --- libs/hbb_common/src/udp.rs | 8 ++++---- src/common.rs | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libs/hbb_common/src/udp.rs b/libs/hbb_common/src/udp.rs index acf0bb222..d1896bdbc 100644 --- a/libs/hbb_common/src/udp.rs +++ b/libs/hbb_common/src/udp.rs @@ -66,8 +66,8 @@ impl FramedSocket { .await?? }; log::trace!( - "Socks5 udp connected, local addr: {}, target addr: {}", - framed.local_addr().unwrap(), + "Socks5 udp connected, local addr: {:?}, target addr: {}", + framed.local_addr(), framed.socks_addr() ); Ok(Self::ProxySocks(framed)) @@ -80,7 +80,7 @@ impl FramedSocket { addr: impl IntoTargetAddr<'_>, ) -> ResultType<()> { let addr = addr.into_target_addr()?.to_owned(); - let send_data = Bytes::from(msg.write_to_bytes().unwrap()); + let send_data = Bytes::from(msg.write_to_bytes()?); let _ = match self { Self::Direct(f) => match addr { TargetAddr::Ip(addr) => f.send((send_data, addr)).await?, @@ -115,7 +115,7 @@ impl FramedSocket { match self { Self::Direct(f) => match f.next().await { Some(Ok((data, addr))) => { - Some(Ok((data, addr.into_target_addr().unwrap().to_owned()))) + Some(Ok((data, addr.into_target_addr().ok()?.to_owned()))) } Some(Err(e)) => Some(Err(anyhow!(e))), None => None, diff --git a/src/common.rs b/src/common.rs index b674c385b..6a96db464 100644 --- a/src/common.rs +++ b/src/common.rs @@ -258,6 +258,8 @@ async fn test_nat_type_() -> ResultType { }); let mut port1 = 0; let mut port2 = 0; + let server1 = socket_client::get_target_addr(&server1)?; + let server2 = socket_client::get_target_addr(&server2)?; let mut addr = Config::get_any_listen_addr(); for i in 0..2 { let mut socket = socket_client::connect_tcp( @@ -434,7 +436,7 @@ pub fn check_software_update() { async fn _check_software_update() -> hbb_common::ResultType<()> { sleep(3.).await; - let rendezvous_server = get_rendezvous_server(1_000).await; + let rendezvous_server = socket_client::get_target_addr(&get_rendezvous_server(1_000).await)?; let mut socket = socket_client::new_udp(Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT).await?; From 5f61c2442a02393ad46677cfeb61edf4b5d8acc1 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 15:47:04 +0800 Subject: [PATCH 54/77] bug fix --- libs/hbb_common/src/socket_client.rs | 6 ++---- src/common.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libs/hbb_common/src/socket_client.rs b/libs/hbb_common/src/socket_client.rs index d00b5e759..a797acf33 100644 --- a/libs/hbb_common/src/socket_client.rs +++ b/libs/hbb_common/src/socket_client.rs @@ -4,7 +4,7 @@ use crate::{ udp::FramedSocket, ResultType, }; -use anyhow::{bail, Context}; +use anyhow::bail; use std::net::SocketAddr; use tokio::net::ToSocketAddrs; use tokio_socks::{IntoTargetAddr, TargetAddr}; @@ -69,9 +69,7 @@ pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( bail!("Invalid target addr"); }; - FramedStream::new(addrs[0], local, ms_timeout) - .await - .with_context(|| "Failed to connect to rendezvous server") + Ok(FramedStream::new(addrs[0], local, ms_timeout).await?) } } diff --git a/src/common.rs b/src/common.rs index 6a96db464..13f013540 100644 --- a/src/common.rs +++ b/src/common.rs @@ -249,7 +249,7 @@ async fn test_nat_type_() -> ResultType { if port == 0 { bail!("Invalid server address: {}", server1); } - let server2 = format!("{}:{}", tmp[0], port); + let server2 = format!("{}:{}", tmp[0], port - 1); let mut msg_out = RendezvousMessage::new(); let serial = Config::get_serial(); msg_out.set_test_nat_request(TestNatRequest { From 6767dda246fa4488531a61ff96615c37c43aa07d Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 15:59:01 +0800 Subject: [PATCH 55/77] refactor --- libs/hbb_common/src/socket_client.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/libs/hbb_common/src/socket_client.rs b/libs/hbb_common/src/socket_client.rs index a797acf33..e0dac0fb0 100644 --- a/libs/hbb_common/src/socket_client.rs +++ b/libs/hbb_common/src/socket_client.rs @@ -4,18 +4,14 @@ use crate::{ udp::FramedSocket, ResultType, }; -use anyhow::bail; +use anyhow::{bail, Context}; use std::net::SocketAddr; use tokio::net::ToSocketAddrs; use tokio_socks::{IntoTargetAddr, TargetAddr}; fn to_socket_addr(host: &str) -> ResultType { use std::net::ToSocketAddrs; - let addrs: Vec = host.to_socket_addrs()?.collect(); - if addrs.is_empty() { - bail!("Failed to solve {}", host); - } - Ok(addrs[0]) + host.to_socket_addrs()?.next().context("Failed to solve") } pub fn get_target_addr(host: &str) -> ResultType> { @@ -63,13 +59,10 @@ pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>( ) .await } else { - let addrs: Vec = - std::net::ToSocketAddrs::to_socket_addrs(&target_addr)?.collect(); - if addrs.is_empty() { - bail!("Invalid target addr"); - }; - - Ok(FramedStream::new(addrs[0], local, ms_timeout).await?) + let addr = std::net::ToSocketAddrs::to_socket_addrs(&target_addr)? + .next() + .context("Invalid target addr")?; + Ok(FramedStream::new(addr, local, ms_timeout).await?) } } From b24e16d6c152d5891c3477e9a6413f99f3b6194f Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 16:32:45 +0800 Subject: [PATCH 56/77] bug fix for msgbox, todo: test more for msgbox in file_transfer.tis --- libs/hbb_common/src/socket_client.rs | 2 +- src/common.rs | 1 + src/ui/common.tis | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/hbb_common/src/socket_client.rs b/libs/hbb_common/src/socket_client.rs index e0dac0fb0..0375b713e 100644 --- a/libs/hbb_common/src/socket_client.rs +++ b/libs/hbb_common/src/socket_client.rs @@ -4,7 +4,7 @@ use crate::{ udp::FramedSocket, ResultType, }; -use anyhow::{bail, Context}; +use anyhow::Context; use std::net::SocketAddr; use tokio::net::ToSocketAddrs; use tokio_socks::{IntoTargetAddr, TargetAddr}; diff --git a/src/common.rs b/src/common.rs index 13f013540..2d5fa5073 100644 --- a/src/common.rs +++ b/src/common.rs @@ -273,6 +273,7 @@ async fn test_nat_type_() -> ResultType { ) .await?; if Config::get_network_type() == NetworkType::Direct { + // to-do: should set NatType::UNKNOWN for proxy addr = socket.local_addr(); } socket.send(&msg_out).await?; diff --git a/src/ui/common.tis b/src/ui/common.tis index 09ffae08c..2ce6214e2 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -261,8 +261,8 @@ function msgbox_(type, title, text, callback, height, width, retry, contentStyle } else if (res == "!alive") { // do nothing } else if (res.type == "input-password") { - if (!is_port_forward) msgbox("connecting", "Connecting...", "Logging in..."); handler.login(res.password, res.remember); + if (!is_port_forward) msgbox("connecting", "Connecting...", "Logging in..."); } else if (res.reconnect) { if (!is_port_forward) connecting(); handler.reconnect(); From 9c55e1efc88076c18e5074ab207c7b91df509982 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 16:48:09 +0800 Subject: [PATCH 57/77] fix on msgbox --- src/lang/cn.rs | 1 + src/lang/fr.rs | 1 + src/lang/it.rs | 1 + src/ui/file_transfer.tis | 10 +++++----- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 2616e8ed2..184b09d36 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -191,5 +191,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Add to Favorites", "加入到收藏"), ("Remove from Favorites", "从收藏中删除"), ("Empty", "空空如也"), + ("Invalid folder name", "无效文件夹名称"), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 711d2e20a..0abe576ef 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -186,5 +186,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Password missed", "Mot de passe manqué"), ("Wrong credentials", "Identifiant ou mot de passe erroné"), ("Edit Tag", "Modifier la balise"), + ("Invalid folder name", "Nom de dossier invalide"), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 0b6f2ee15..83426a908 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -186,6 +186,7 @@ lazy_static::lazy_static! { ("Password missed", "Password dimenticata"), ("Wrong credentials", "Credenziali errate"), ("Edit Tag", "Modifica tag"), + ("Invalid folder name", "Nome della cartella non valido"), ].iter().cloned().collect(); } \ No newline at end of file diff --git a/src/ui/file_transfer.tis b/src/ui/file_transfer.tis index 83365d0ee..786eef8cf 100644 --- a/src/ui/file_transfer.tis +++ b/src/ui/file_transfer.tis @@ -440,7 +440,7 @@ class FolderView : Reactor.Component { var name = res.name.trim(); if (!name) return; if (name.indexOf(me.sep()) >= 0) { - msgbox("custom-error", "Create Folder", "Invalid folder name"); + handler.msgbox("custom-error", "Create Folder", "Invalid folder name"); return; } var path = me.joinPath(name); @@ -576,16 +576,16 @@ handler.jobDone = function(id, file_num = -1) { handler.jobError = function(id, err, file_num = -1) { var job = deleting_single_file_jobs[id]; if (job) { - msgbox("custom-error", "Delete File", err); + handler.msgbox("custom-error", "Delete File", err); return; } job = create_dir_jobs[id]; if (job) { - msgbox("custom-error", "Create Folder", err); + handler.msgbox("custom-error", "Create Folder", err); return; } if (file_num < 0) { - msgbox("custom-error", "Failed", err); + handler.msgbox("custom-error", "Failed", err); } file_transfer.job_table.updateJobStatus(id, file_num, err); } @@ -619,7 +619,7 @@ handler.confirmDeleteFiles = function(id, i, name) { if (i >= n) return; var file_path = job.path; if (name) file_path += handler.get_path_sep(job.is_remote) + name; - msgbox("custom-skip", "Confirm Delete", "
    \ + handler.msgbox("custom-skip", "Confirm Delete", "
    \
    " + translate('Deleting') + " #" + (i + 1) + " / " + n + " " + translate('files') + ".
    \
    " + translate('Are you sure you want to delete this file?') + "
    \ " + name + "
    \ From 7bde8a3713bebfe08bc8e7e5c27159478b581077 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 16:53:37 +0800 Subject: [PATCH 58/77] remove some unnessary handler.msgbox --- src/ui/file_transfer.tis | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/file_transfer.tis b/src/ui/file_transfer.tis index 786eef8cf..3623eaff5 100644 --- a/src/ui/file_transfer.tis +++ b/src/ui/file_transfer.tis @@ -576,12 +576,12 @@ handler.jobDone = function(id, file_num = -1) { handler.jobError = function(id, err, file_num = -1) { var job = deleting_single_file_jobs[id]; if (job) { - handler.msgbox("custom-error", "Delete File", err); + msgbox("custom-error", "Delete File", err); return; } job = create_dir_jobs[id]; if (job) { - handler.msgbox("custom-error", "Create Folder", err); + msgbox("custom-error", "Create Folder", err); return; } if (file_num < 0) { @@ -619,7 +619,7 @@ handler.confirmDeleteFiles = function(id, i, name) { if (i >= n) return; var file_path = job.path; if (name) file_path += handler.get_path_sep(job.is_remote) + name; - handler.msgbox("custom-skip", "Confirm Delete", "
    \ + msgbox("custom-skip", "Confirm Delete", "
    \
    " + translate('Deleting') + " #" + (i + 1) + " / " + n + " " + translate('files') + ".
    \
    " + translate('Are you sure you want to delete this file?') + "
    \ " + name + "
    \ From 12ab22e0485d52fc223a0bee13ff27bf27a34002 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 17:10:12 +0800 Subject: [PATCH 59/77] bug fix --- src/ui/ab.tis | 2 +- src/ui/index.tis | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 6400426ad..6cdd496e0 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -287,4 +287,4 @@ class MultipleSessions: Reactor.Component { } } -view.on("size", function() { app.multipleSessions.onSize(); }); \ No newline at end of file +view.on("size", function() { if (app.multipleSessions) app.multipleSessions.onSize(); }); \ No newline at end of file diff --git a/src/ui/index.tis b/src/ui/index.tis index 0ad2b17d8..974640831 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -668,7 +668,7 @@ function checkConnectStatus() { } if (handler.recent_sessions_updated()) { stdout.println("recent sessions updated"); - app.multipleSessions.update(); + app.update(); } checkConnectStatus(); }); From c0b63671375f716e1476bdb115d2c196273e8ab8 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 18:34:30 +0800 Subject: [PATCH 60/77] sock5 gui part --- src/common.rs | 7 +++--- src/ipc.rs | 50 ++++++++++++++++++++++++++++++++++++++ src/lang/cn.rs | 1 + src/rendezvous_mediator.rs | 6 ++++- src/ui.rs | 27 +++++++++++++++++++- src/ui/common.tis | 3 ++- src/ui/index.tis | 23 ++++++++++++++++++ 7 files changed, 111 insertions(+), 6 deletions(-) diff --git a/src/common.rs b/src/common.rs index 2d5fa5073..a29273397 100644 --- a/src/common.rs +++ b/src/common.rs @@ -3,7 +3,7 @@ use hbb_common::{ allow_err, anyhow::bail, compress::{compress as compress_func, decompress}, - config::{Config, NetworkType, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT}, + config::{Config, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT}, log, message_proto::*, protobuf::Message as _, @@ -238,8 +238,9 @@ pub fn test_nat_type() { #[tokio::main(flavor = "current_thread")] async fn test_nat_type_() -> ResultType { log::info!("Testing nat ..."); + let is_direct = crate::ipc::get_socks_async(1_000).await.is_none(); // sync socks BTW let start = std::time::Instant::now(); - let rendezvous_server = get_rendezvous_server(100).await; + let rendezvous_server = get_rendezvous_server(1_000).await; let server1 = rendezvous_server; let tmp: Vec<&str> = server1.split(":").collect(); if tmp.len() != 2 { @@ -272,7 +273,7 @@ async fn test_nat_type_() -> ResultType { RENDEZVOUS_TIMEOUT, ) .await?; - if Config::get_network_type() == NetworkType::Direct { + if is_direct { // to-do: should set NatType::UNKNOWN for proxy addr = socket.local_addr(); } diff --git a/src/ipc.rs b/src/ipc.rs index 1c5a0cc15..841dd37ef 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -89,6 +89,7 @@ pub enum Data { NatType(Option), ConfirmedKey(Option<(Vec, Vec)>), RawMessage(Vec), + Socks(Option), FS(FS), Test, } @@ -192,6 +193,20 @@ async fn handle(data: Data, stream: &mut Connection) { }; allow_err!(stream.send(&Data::ConfirmedKey(out)).await); } + Data::Socks(s) => match s { + None => { + allow_err!(stream.send(&Data::Socks(Config::get_socks())).await); + } + Some(data) => { + if data.proxy.is_empty() { + Config::set_socks(None); + } else { + Config::set_socks(Some(data)); + } + crate::rendezvous_mediator::RendezvousMediator::restart(); + log::info!("socks updated"); + } + }, Data::Config((name, value)) => match value { None => { let value; @@ -467,6 +482,41 @@ pub async fn get_nat_type(ms_timeout: u64) -> i32 { .unwrap_or(Config::get_nat_type()) } +#[inline] +async fn get_socks_(ms_timeout: u64) -> ResultType> { + let mut c = connect(ms_timeout, "").await?; + c.send(&Data::Socks(None)).await?; + if let Some(Data::Socks(value)) = c.next_timeout(ms_timeout).await? { + Config::set_socks(value.clone()); + Ok(value) + } else { + Ok(Config::get_socks()) + } +} + +pub async fn get_socks_async(ms_timeout: u64) -> Option { + get_socks_(ms_timeout).await.unwrap_or(Config::get_socks()) +} + +#[tokio::main(flavor = "current_thread")] +pub async fn get_socks() -> Option { + get_socks_async(1_000).await +} + +#[tokio::main(flavor = "current_thread")] +pub async fn set_socks(value: config::Socks5Server) -> ResultType<()> { + Config::set_socks(if value.proxy.is_empty() { + None + } else { + Some(value.clone()) + }); + connect(1_000, "") + .await? + .send(&Data::Socks(Some(value))) + .await?; + Ok(()) +} + /* static mut SHARED_MEMORY: *mut i64 = std::ptr::null_mut(); diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 184b09d36..33dbb8f3a 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -192,5 +192,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Remove from Favorites", "从收藏中删除"), ("Empty", "空空如也"), ("Invalid folder name", "无效文件夹名称"), + ("Socks5 Proxy", "Socks5 代理") ].iter().cloned().collect(); } diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index ec2822474..b994b4b91 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -28,7 +28,7 @@ use uuid::Uuid; type Message = RendezvousMessage; lazy_static::lazy_static! { - pub static ref SOLVING_PK_MISMATCH: Arc> = Default::default(); + static ref SOLVING_PK_MISMATCH: Arc> = Default::default(); } static SHOULD_EXIT: AtomicBool = AtomicBool::new(false); @@ -42,6 +42,10 @@ pub struct RendezvousMediator { } impl RendezvousMediator { + pub fn restart() { + SHOULD_EXIT.store(true, Ordering::SeqCst); + } + pub async fn start_all() { let mut nat_tested = false; check_zombie(); diff --git a/src/ui.rs b/src/ui.rs index f0e8ecd48..dcf97b298 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -8,7 +8,7 @@ use crate::common::SOFTWARE_UPDATE_URL; use crate::ipc; use hbb_common::{ allow_err, - config::{Config, Fav, PeerConfig, APP_NAME, ICON}, + config::{self, Config, Fav, PeerConfig, APP_NAME, ICON}, log, sleep, tokio::{self, time}, }; @@ -372,6 +372,29 @@ impl UI { return "".to_owned(); } + fn get_socks(&self) -> Value { + let s = ipc::get_socks(); + match s { + None => Value::null(), + Some(s) => { + let mut v = Value::array(0); + v.push(s.proxy); + v.push(s.username); + v.push(s.password); + v + } + } + } + + fn set_socks(&self, proxy: String, username: String, password: String) { + ipc::set_socks(config::Socks5Server { + proxy, + username, + password, + }) + .ok(); + } + fn is_installed(&mut self) -> bool { crate::platform::is_installed() } @@ -628,6 +651,8 @@ impl sciter::EventHandler for UI { fn get_msgbox(); fn install_me(String); fn is_installed(); + fn set_socks(String, String, String); + fn get_socks(); fn is_installed_lower_version(); fn install_path(); fn goto_install(); diff --git a/src/ui/common.tis b/src/ui/common.tis index 2ce6214e2..b4e0bf190 100644 --- a/src/ui/common.tis +++ b/src/ui/common.tis @@ -360,8 +360,9 @@ class PasswordComponent: Reactor.Component { var start = el.xcall(#selectionStart) || 0; var end = el.xcall(#selectionEnd); this.update({ visible: !this.visible }); + var me = this; self.timer(30ms, function() { - var el = this.$(input); + var el = me.$(input); view.focus = el; el.value = value; el.xcall(#setSelection, start, end); diff --git a/src/ui/index.tis b/src/ui/index.tis index 974640831..f8d8f4921 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -135,6 +135,7 @@ class MyIdMenu: Reactor.Component {
  • {translate('IP Whitelisting')}
  • {translate('ID/Relay Server')}
  • +
  • {translate('Socks5 Proxy')}
  • {svg_checkmark}{translate("Enable Service")}
  • @@ -211,6 +212,28 @@ class MyIdMenu: Reactor.Component { configOptions["relay-server"] = relay; handler.set_options(configOptions); }, 240); + } else if (me.id == "socks5-server") { + var socks5 = handler.get_socks() || {}; + var old_proxy = socks5[0] || ""; + var old_username = socks5[1] || ""; + var old_password = socks5[2] || ""; + msgbox("custom-server", "Socks5 Proxy",
    +
    {translate("Hostname")}
    +
    {translate("Username")}
    +
    {translate("Password")}
    +
    + , function(res=null) { + if (!res) return; + var proxy = (res.proxy || "").trim(); + var username = (res.username || "").trim(); + var password = (res.password || "").trim(); + if (proxy == old_proxy && username == old_username && password == old_password) return; + if (proxy) { + var err = handler.test_if_valid_server(proxy); + if (err) return translate("Server") + ": " + err; + } + handler.set_socks(proxy, username, password); + }, 240); } else if (me.id == "stop-service") { handler.set_option("stop-service", service_stopped ? "" : "Y"); } else if (me.id == "about") { From 1b61b77fbeb2b3ce056a6617856cb5d9d73dca53 Mon Sep 17 00:00:00 2001 From: open-trade Date: Wed, 5 Jan 2022 18:38:40 +0800 Subject: [PATCH 61/77] more trans --- src/lang/cn.rs | 3 ++- src/lang/fr.rs | 1 + src/lang/it.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 33dbb8f3a..60fb0d22f 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -192,6 +192,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Remove from Favorites", "从收藏中删除"), ("Empty", "空空如也"), ("Invalid folder name", "无效文件夹名称"), - ("Socks5 Proxy", "Socks5 代理") + ("Socks5 Proxy", "Socks5 代理"), + ("Hostname", "主机名"), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 0abe576ef..f114ab252 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -187,5 +187,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Wrong credentials", "Identifiant ou mot de passe erroné"), ("Edit Tag", "Modifier la balise"), ("Invalid folder name", "Nom de dossier invalide"), + ("Hostname", "nom d'hôte"), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 83426a908..cc8a617a5 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -187,6 +187,7 @@ lazy_static::lazy_static! { ("Wrong credentials", "Credenziali errate"), ("Edit Tag", "Modifica tag"), ("Invalid folder name", "Nome della cartella non valido"), + ("Hostname", "Nome host"), ].iter().cloned().collect(); } \ No newline at end of file From 32c5437c5db4dd629b2ecafbc259aea267350b88 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 5 Jan 2022 21:12:07 +0800 Subject: [PATCH 62/77] more equal check in config --- libs/hbb_common/src/config.rs | 11 ++++++++++- src/ui/ab.tis | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 23576d98f..d248f0c28 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -76,7 +76,7 @@ pub struct Config { keys_confirmed: HashMap, } -#[derive(Debug, Default, Serialize, Deserialize, Clone)] +#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)] pub struct Socks5Server { #[serde(default)] pub proxy: String, @@ -502,6 +502,9 @@ impl Config { pub fn set_key_pair(pair: (Vec, Vec)) { let mut config = CONFIG.write().unwrap(); + if config.key_pair == pair { + return; + } config.key_pair = pair; config.store(); } @@ -534,6 +537,9 @@ impl Config { pub fn set_options(v: HashMap) { let mut config = CONFIG2.write().unwrap(); + if config.options == v { + return; + } config.options = v; config.store(); } @@ -636,6 +642,9 @@ impl Config { pub fn set_socks(socks: Option) { let mut config = CONFIG2.write().unwrap(); + if config.socks == socks { + return; + } config.socks = socks; config.store(); } diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 6cdd496e0..22dc17f3d 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -287,4 +287,4 @@ class MultipleSessions: Reactor.Component { } } -view.on("size", function() { if (app.multipleSessions) app.multipleSessions.onSize(); }); \ No newline at end of file +view.on("size", function() { if (app && app.multipleSessions) app.multipleSessions.onSize(); }); From 1931cb8c7c57c8093ec742978e134c0cd898a6d2 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Wed, 5 Jan 2022 23:50:13 +0800 Subject: [PATCH 63/77] https://github.com/rustdesk/rustdesk/issues/356 --- Cargo.lock | 1 + libs/hbb_common/Cargo.toml | 1 + libs/hbb_common/src/lib.rs | 1 + src/client.rs | 25 ++++++++++++++++++++ src/common.rs | 9 ++++++- src/ipc.rs | 3 +++ src/rendezvous_mediator.rs | 48 ++++++++++++++++++++++++++++++++++++-- src/server/connection.rs | 2 +- src/ui/common.css | 5 ++++ src/ui/index.tis | 20 ++++++++++++++++ 10 files changed, 111 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a11d68fea..d8c112fd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1568,6 +1568,7 @@ dependencies = [ "protobuf-codegen-pure", "quinn", "rand 0.8.4", + "regex", "serde 1.0.133", "serde_derive", "serde_json 1.0.74", diff --git a/libs/hbb_common/Cargo.toml b/libs/hbb_common/Cargo.toml index 4dc7dcf86..d1868f5b5 100644 --- a/libs/hbb_common/Cargo.toml +++ b/libs/hbb_common/Cargo.toml @@ -28,6 +28,7 @@ confy = { git = "https://github.com/open-trade/confy" } dirs-next = "2.0" filetime = "0.2" sodiumoxide = "0.2" +regex = "1.4" tokio-socks = { git = "https://github.com/fufesou/tokio-socks" } [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] diff --git a/libs/hbb_common/src/lib.rs b/libs/hbb_common/src/lib.rs index 38487a1a4..f84221b70 100644 --- a/libs/hbb_common/src/lib.rs +++ b/libs/hbb_common/src/lib.rs @@ -27,6 +27,7 @@ pub use anyhow::{self, bail}; pub use futures_util; pub mod config; pub mod fs; +pub use regex; pub use sodiumoxide; pub use tokio_socks; pub use tokio_socks::IntoTargetAddr; diff --git a/src/client.rs b/src/client.rs index ff4603776..29e2585b1 100644 --- a/src/client.rs +++ b/src/client.rs @@ -103,8 +103,33 @@ impl Drop for OboePlayer { impl Client { pub async fn start(peer: &str, conn_type: ConnType) -> ResultType<(Stream, bool)> { + match Self::_start(peer, conn_type).await { + Err(err) => { + let err_str = err.to_string(); + if err_str.starts_with("Failed") { + bail!(err_str + ": Please try later"); + } else { + return Err(err); + } + } + Ok(x) => Ok(x), + } + } + + async fn _start(peer: &str, conn_type: ConnType) -> ResultType<(Stream, bool)> { // to-do: remember the port for each peer, so that we can retry easier let any_addr = Config::get_any_listen_addr(); + if crate::is_ip(peer) { + return Ok(( + socket_client::connect_tcp( + crate::check_port(peer, RELAY_PORT + 1), + any_addr, + RENDEZVOUS_TIMEOUT, + ) + .await?, + true, + )); + } let rendezvous_server = crate::get_rendezvous_server(1_000).await; log::info!("rendezvous server: {}", rendezvous_server); diff --git a/src/common.rs b/src/common.rs index a29273397..13599045e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -342,7 +342,7 @@ async fn test_rendezvous_server_() { futs.push(tokio::spawn(async move { let tm = std::time::Instant::now(); if socket_client::connect_tcp( - &crate::check_port(&host, RENDEZVOUS_PORT), + crate::check_port(&host, RENDEZVOUS_PORT), Config::get_any_listen_addr(), RENDEZVOUS_TIMEOUT, ) @@ -461,3 +461,10 @@ async fn _check_software_update() -> hbb_common::ResultType<()> { } Ok(()) } + +pub fn is_ip(id: &str) -> bool { + hbb_common::regex::Regex::new(r"^\d+\.\d+\.\d+\.\d+$") + .unwrap() + .is_match(id) +} + diff --git a/src/ipc.rs b/src/ipc.rs index 841dd37ef..e197d804d 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -218,6 +218,8 @@ async fn handle(data: Data, stream: &mut Connection) { value = Some(Config::get_salt()); } else if name == "rendezvous_server" { value = Some(Config::get_rendezvous_server()); + } else if name == "rendezvous_servers" { + value = Some(Config::get_rendezvous_servers().join(",")); } else { value = None; } @@ -225,6 +227,7 @@ async fn handle(data: Data, stream: &mut Connection) { } Some(value) => { if name == "id" { + Config::set_key_confirmed(false); Config::set_id(&value); } else if name == "password" { Config::set_password(&value); diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index b994b4b91..d46344517 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -31,6 +31,7 @@ lazy_static::lazy_static! { static ref SOLVING_PK_MISMATCH: Arc> = Default::default(); } static SHOULD_EXIT: AtomicBool = AtomicBool::new(false); +const REG_INTERVAL: i64 = 12_000; #[derive(Clone)] pub struct RendezvousMediator { @@ -54,6 +55,10 @@ impl RendezvousMediator { crate::common::test_nat_type(); nat_tested = true; } + let server_cloned = server.clone(); + tokio::spawn(async move { + allow_err!(direct_server(server_cloned).await); + }); loop { Config::reset_online(); if Config::get_option("stop-service").is_empty() { @@ -111,7 +116,6 @@ impl RendezvousMediator { const TIMER_OUT: Duration = Duration::from_secs(1); let mut timer = interval(TIMER_OUT); let mut last_timer = SystemTime::UNIX_EPOCH; - const REG_INTERVAL: i64 = 12_000; const REG_TIMEOUT: i64 = 3_000; const MAX_FAILS1: i64 = 3; const MAX_FAILS2: i64 = 6; @@ -246,7 +250,7 @@ impl RendezvousMediator { // old UDP socket not work any more after network recover if let Some(s) = socket_client::rebind_udp(any_addr).await? { socket = s; - }; + } last_dns_check = now; } } else if fails > MAX_FAILS1 { @@ -457,3 +461,43 @@ impl RendezvousMediator { Ok(()) } } + +async fn direct_server(server: ServerPtr) -> ResultType<()> { + let port = RENDEZVOUS_PORT + 2; + let addr = format!("0.0.0.0:{}", port); + let mut listener = None; + loop { + if !Config::get_option("direct-server").is_empty() && listener.is_none() { + listener = Some(hbb_common::tcp::new_listener(&addr, false).await?); + log::info!( + "Direct server listening on: {}", + &listener.as_ref().unwrap().local_addr()? + ); + } + if let Some(l) = listener.as_mut() { + if let Ok(Ok((stream, addr))) = hbb_common::timeout(1000, l.accept()).await { + if Config::get_option("direct-server").is_empty() { + continue; + } + log::info!("direct access from {}", addr); + let local_addr = stream.local_addr()?; + let server = server.clone(); + tokio::spawn(async move { + allow_err!( + crate::server::create_tcp_connection( + server, + hbb_common::Stream::from(stream, local_addr), + addr, + false, + ) + .await + ); + }); + } else { + sleep(0.1).await; + } + } else { + sleep(1.).await; + } + } +} diff --git a/src/server/connection.rs b/src/server/connection.rs index 482a9f654..75a9071f8 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -589,7 +589,7 @@ impl Connection { } _ => {} } - if lr.username != Config::get_id() { + if !crate::is_ip(&lr.username) && lr.username != Config::get_id() { self.send_login_error("Offline").await; } else if lr.password.is_empty() { self.try_start_cm(lr.my_id, lr.my_name, false).await; diff --git a/src/ui/common.css b/src/ui/common.css index 574fbb1a5..7e7eb6bf1 100644 --- a/src/ui/common.css +++ b/src/ui/common.css @@ -4,6 +4,7 @@ html { var(gray-bg): #eee; var(bg): white; var(border): #ccc; + var(hover-border): #999; var(text): #222; var(placeholder): #aaa; var(lighter-text): #888; @@ -52,6 +53,10 @@ button.button:active, button.active { border-color: color(accent); } +button.button:hover, button.outline:hover { + border-color: color(hover-border); +} + input[type=text], input[type=password], input[type=number] { width: *; font-size: 1.5em; diff --git a/src/ui/index.tis b/src/ui/index.tis index f8d8f4921..a69e5b014 100644 --- a/src/ui/index.tis +++ b/src/ui/index.tis @@ -62,6 +62,24 @@ function createNewConnect(id, type) { handler.new_remote(id, type); } +var direct_server; +class DirectServer: Reactor.Component { + function this() { + direct_server = this; + } + + function render() { + var text = translate("Enable Direct IP Access"); + var cls = handler.get_option("direct-server") == "Y" ? "selected" : "line-through"; + return
  • {svg_checkmark}{text}
  • ; + } + + function onClick() { + handler.set_option("direct-server", handler.get_option("direct-server") == "Y" ? "" : "Y"); + this.update(); + } +} + var myIdMenu; var audioInputMenu; class AudioInputs: Reactor.Component { @@ -138,6 +156,7 @@ class MyIdMenu: Reactor.Component {
  • {translate('Socks5 Proxy')}
  • {svg_checkmark}{translate("Enable Service")}
  • +
  • {translate('About')} {" "} {handler.get_app_name()}
  • @@ -147,6 +166,7 @@ class MyIdMenu: Reactor.Component { event click $(svg#menu) (_, me) { audioInputMenu.update({ show: true }); this.toggleMenuState(); + if (direct_server) direct_server.update(); var menu = $(menu#config-options); me.popup(menu); } From e82f040d6d89597f2ba4897ccb82fd1b794ac1e0 Mon Sep 17 00:00:00 2001 From: open-trade Date: Fri, 7 Jan 2022 13:59:21 +0800 Subject: [PATCH 64/77] kick start international keyboard --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + src/ui/ab.tis | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index d8c112fd6..22dfdc6f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3091,6 +3091,7 @@ dependencies = [ "sha2", "sys-locale", "systray", + "tigervnc", "uuid", "whoami", "winapi 0.3.9", @@ -3603,6 +3604,15 @@ dependencies = [ "weezl", ] +[[package]] +name = "tigervnc" +version = "1.0.0" +source = "git+https://github.com/open-trade/tigervnc#2007dbb0f47ac72069a529182ce73c954ab70d38" +dependencies = [ + "cc", + "cfg-if 1.0.0", +] + [[package]] name = "time" version = "0.3.5" diff --git a/Cargo.toml b/Cargo.toml index d5029532f..69b3673ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" ctrlc = "3.2" arboard = "2.0" clipboard-master = "3.1" +tigervnc = { git = "https://github.com/open-trade/tigervnc" } [target.'cfg(target_os = "windows")'.dependencies] systray = { git = "https://github.com/liyue201/systray-rs" } diff --git a/src/ui/ab.tis b/src/ui/ab.tis index 22dc17f3d..84cfcef4f 100644 --- a/src/ui/ab.tis +++ b/src/ui/ab.tis @@ -95,7 +95,7 @@ class SessionList: Reactor.Component { function render() { var sessions = this.getSessions(); if (sessions.length == 0) { - return
    {translate("Empty")}
    ; + return
    {translate("Empty")}
    ; } var me = this; sessions = sessions.map(function(x) { return me.getSession(x); }); From 9df1fcb783dbb2616a873260ad18291410c137fb Mon Sep 17 00:00:00 2001 From: open-trade Date: Fri, 7 Jan 2022 16:21:56 +0800 Subject: [PATCH 65/77] update tigervnc --- Cargo.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 22dfdc6f4..dc1244525 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -254,9 +254,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "bytemuck" @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.46" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b858541263efe664aead4a5209a4ae5c5d2811167d4ed4ee0944503f8d2089" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" dependencies = [ "cc", ] @@ -1015,9 +1015,9 @@ dependencies = [ [[package]] name = "flexi_logger" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11be38a063886b7be57de89636d65c07d318c1f9bd985cd8ab2c343786a910bc" +checksum = "a2917b8937f4d36d9df8b15a51428b6a1b2726ec57402b0c94b4dfc393a409e5" dependencies = [ "ansi_term", "atty", @@ -3310,9 +3310,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6" +checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" dependencies = [ "cfg-if 1.0.0", "cpufeatures", @@ -3459,9 +3459,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b" +checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7" dependencies = [ "proc-macro2", "quote", @@ -3606,8 +3606,8 @@ dependencies = [ [[package]] name = "tigervnc" -version = "1.0.0" -source = "git+https://github.com/open-trade/tigervnc#2007dbb0f47ac72069a529182ce73c954ab70d38" +version = "1.0.1" +source = "git+https://github.com/open-trade/tigervnc#254ad243c5a22887ddf0e79def58b8251b108d08" dependencies = [ "cc", "cfg-if 1.0.0", @@ -4160,18 +4160,18 @@ dependencies = [ [[package]] name = "zstd" -version = "0.9.1+zstd.1.5.1" +version = "0.9.2+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "538b8347df9257b7fbce37677ef7535c00a3c7bf1f81023cc328ed7fe4b41de8" +checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.2+zstd.1.5.1" +version = "4.1.3+zstd.1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb4cfe2f6e6d35c5d27ecd9d256c4b6f7933c4895654917460ec56c29336cc1" +checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" dependencies = [ "libc", "zstd-sys", From 26d161f8275766f52c61baed69430f18fcdf6fc8 Mon Sep 17 00:00:00 2001 From: open-trade Date: Fri, 7 Jan 2022 18:03:55 +0800 Subject: [PATCH 66/77] working on keysym --- libs/enigo/src/lib.rs | 2 ++ libs/enigo/src/linux.rs | 3 ++ libs/enigo/src/macos/macos_impl.rs | 1 + libs/enigo/src/win/win_impl.rs | 1 + libs/hbb_common/protos/message.proto | 1 + src/client.rs | 5 +-- src/server/input_service.rs | 47 ++++++++++++++++++++++------ 7 files changed, 48 insertions(+), 12 deletions(-) diff --git a/libs/enigo/src/lib.rs b/libs/enigo/src/lib.rs index 893f5918c..10c5da4a7 100644 --- a/libs/enigo/src/lib.rs +++ b/libs/enigo/src/lib.rs @@ -418,6 +418,8 @@ pub enum Key { Layout(char), /// raw keycode eg 0x38 Raw(u16), + /// VNC keysym + KeySym(u32), } /// Representing an interface and a set of keyboard functions every diff --git a/libs/enigo/src/linux.rs b/libs/enigo/src/linux.rs index 24628c1f9..2fe5d2205 100644 --- a/libs/enigo/src/linux.rs +++ b/libs/enigo/src/linux.rs @@ -181,6 +181,9 @@ impl MouseControllable for Enigo { } } fn keysequence<'a>(key: Key) -> Cow<'a, str> { + if let Key::KeySym(sym) = key { + return Cow::Owned(""); + } if let Key::Layout(c) = key { return Cow::Owned(format!("U{:X}", c as u32)); } diff --git a/libs/enigo/src/macos/macos_impl.rs b/libs/enigo/src/macos/macos_impl.rs index 0ee038012..93b78c6d8 100644 --- a/libs/enigo/src/macos/macos_impl.rs +++ b/libs/enigo/src/macos/macos_impl.rs @@ -426,6 +426,7 @@ impl Enigo { Key::Raw(raw_keycode) => raw_keycode, Key::Layout(c) => self.map_key_board(c), + Key::KeySym(sym) => 0 as _, Key::Super | Key::Command | Key::Windows | Key::Meta => kVK_Command, _ => 0, diff --git a/libs/enigo/src/win/win_impl.rs b/libs/enigo/src/win/win_impl.rs index 3a6b6215f..3f83dc951 100644 --- a/libs/enigo/src/win/win_impl.rs +++ b/libs/enigo/src/win/win_impl.rs @@ -340,6 +340,7 @@ impl Enigo { Key::Raw(raw_keycode) => raw_keycode, Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()), Key::Super | Key::Command | Key::Windows | Key::Meta => EVK_LWIN, + Key::KeySym(sym) => 0, } } diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index 24bc189b2..47c526dd1 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -172,6 +172,7 @@ message KeyEvent { uint32 chr = 4; uint32 unicode = 5; string seq = 6; + uint32 keysym = 7; } repeated ControlKey modifiers = 8; } diff --git a/src/client.rs b/src/client.rs index 29e2585b1..35e4ccdb5 100644 --- a/src/client.rs +++ b/src/client.rs @@ -134,8 +134,7 @@ impl Client { log::info!("rendezvous server: {}", rendezvous_server); let mut socket = - socket_client::connect_tcp(&*rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT) - .await?; + socket_client::connect_tcp(&*rendezvous_server, any_addr, RENDEZVOUS_TIMEOUT).await?; let my_addr = socket.local_addr(); let mut pk = Vec::new(); let mut relay_server = "".to_owned(); @@ -682,6 +681,7 @@ pub struct LoginConfigHandler { pub port_forward: (String, i32), pub support_press: bool, pub support_refresh: bool, + pub internation_keyboard: bool, } impl Deref for LoginConfigHandler { @@ -938,6 +938,7 @@ impl LoginConfigHandler { if !pi.version.is_empty() { self.support_press = true; self.support_refresh = true; + self.internation_keyboard = crate::get_version_number(&pi.version) > 1001008; } let serde = PeerInfoSerde { username, diff --git a/src/server/input_service.rs b/src/server/input_service.rs index ba34772a5..ef06f2348 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -40,7 +40,8 @@ struct Input { time: i64, } -const KEY_CHAR_START: i32 = 9999; +const KEY_CHAR_START: u64 = 0xFFFF; +const KEY_SYM_START: u64 = 0xFFFFFFFF; #[derive(Clone, Default)] pub struct MouseCursorSub { @@ -163,7 +164,7 @@ fn run_cursor(sp: MouseCursorService, state: &mut StateCursor) -> ResultType<()> lazy_static::lazy_static! { static ref ENIGO: Arc> = Arc::new(Mutex::new(Enigo::new())); - static ref KEYS_DOWN: Arc>> = Default::default(); + static ref KEYS_DOWN: Arc>> = Default::default(); static ref LATEST_INPUT: Arc> = Default::default(); } static EXITING: AtomicBool = AtomicBool::new(false); @@ -256,13 +257,15 @@ fn fix_key_down_timeout(force: bool) { if force || value.elapsed().as_millis() >= 3_000 { KEYS_DOWN.lock().unwrap().remove(&key); let key = if key < KEY_CHAR_START { - if let Some(key) = KEY_MAP.get(&key) { + if let Some(key) = KEY_MAP.get(&(key as _)) { Some(*key) } else { None } - } else { + } else if key < KEY_SYM_START { Some(Key::Layout(((key - KEY_CHAR_START) as u8) as _)) + } else { + Some(Key::KeySym((key - KEY_SYM_START) as u32)) }; if let Some(key) = key { let func = move || { @@ -352,7 +355,10 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { modifier_sleep(); to_release.push(key); } else { - KEYS_DOWN.lock().unwrap().insert(ck.value(), Instant::now()); + KEYS_DOWN + .lock() + .unwrap() + .insert(ck.value() as _, Instant::now()); } } } @@ -572,7 +578,10 @@ fn handle_key_(evt: &KeyEvent) { modifier_sleep(); to_release.push(key); } else { - KEYS_DOWN.lock().unwrap().insert(ck.value(), Instant::now()); + KEYS_DOWN + .lock() + .unwrap() + .insert(ck.value() as _, Instant::now()); } } } @@ -606,10 +615,13 @@ fn handle_key_(evt: &KeyEvent) { } if evt.down { allow_err!(en.key_down(key.clone())); - KEYS_DOWN.lock().unwrap().insert(ck.value(), Instant::now()); + KEYS_DOWN + .lock() + .unwrap() + .insert(ck.value() as _, Instant::now()); } else { en.key_up(key.clone()); - KEYS_DOWN.lock().unwrap().remove(&ck.value()); + KEYS_DOWN.lock().unwrap().remove(&(ck.value() as _)); } } else if ck.value() == ControlKey::CtrlAltDel.value() { // have to spawn new thread because send_sas is tokio_main, the caller can not be tokio_main. @@ -627,13 +639,28 @@ fn handle_key_(evt: &KeyEvent) { KEYS_DOWN .lock() .unwrap() - .insert(chr as i32 + KEY_CHAR_START, Instant::now()); + .insert(chr as u64 + KEY_CHAR_START, Instant::now()); } else { en.key_up(Key::Layout(chr as u8 as _)); KEYS_DOWN .lock() .unwrap() - .remove(&(chr as i32 + KEY_CHAR_START)); + .remove(&(chr as u64 + KEY_CHAR_START)); + } + } + Some(key_event::Union::keysym(sym)) => { + if evt.down { + allow_err!(en.key_down(Key::KeySym(sym))); + KEYS_DOWN + .lock() + .unwrap() + .insert(sym as u64 + KEY_SYM_START, Instant::now()); + } else { + en.key_up(Key::KeySym(sym)); + KEYS_DOWN + .lock() + .unwrap() + .remove(&(sym as u64 + KEY_SYM_START)); } } Some(key_event::Union::unicode(chr)) => { From a7a4cd7eacbef5b50984d92c4ff6ff4acf3ee88a Mon Sep 17 00:00:00 2001 From: open-trade Date: Fri, 7 Jan 2022 18:05:33 +0800 Subject: [PATCH 67/77] CI --- libs/enigo/src/linux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/enigo/src/linux.rs b/libs/enigo/src/linux.rs index 2fe5d2205..be21a2c70 100644 --- a/libs/enigo/src/linux.rs +++ b/libs/enigo/src/linux.rs @@ -182,7 +182,7 @@ impl MouseControllable for Enigo { } fn keysequence<'a>(key: Key) -> Cow<'a, str> { if let Key::KeySym(sym) = key { - return Cow::Owned(""); + return Cow::Owned("".to_owned()); } if let Key::Layout(c) = key { return Cow::Owned(format!("U{:X}", c as u32)); From 54269b6f5d0e6f199df3fb605797446e780504e5 Mon Sep 17 00:00:00 2001 From: fufesou Date: Fri, 7 Jan 2022 21:30:13 +0800 Subject: [PATCH 68/77] fix audio play with sample rate 48000 Signed-off-by: fufesou --- src/client.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.rs b/src/client.rs index 29e2585b1..ef6b00d76 100644 --- a/src/client.rs +++ b/src/client.rs @@ -586,7 +586,7 @@ impl AudioHandler { ); audio_buffer.lock().unwrap().extend(buffer); } else { - audio_buffer.lock().unwrap().extend(buffer.iter().cloned()); + audio_buffer.lock().unwrap().extend(buffer[0..n].iter().cloned()); } } #[cfg(any(target_os = "android"))] From 29f15aabedbf0512db89e623c2480f92cbb24000 Mon Sep 17 00:00:00 2001 From: chenbaiyu Date: Sat, 8 Jan 2022 01:39:54 +0800 Subject: [PATCH 69/77] fix security problem caused server hang and unexpected input behavior at pre-login window when macOS version on Big Sur or above --- .cargo/config.toml | 4 ++++ src/server/connection.rs | 8 +++----- 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 .cargo/config.toml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000..f19d0f027 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,4 @@ +[target.'cfg(target_os="macos")'] +rustflags = [ + "-C", "link-args=-sectcreate __CGPreLoginApp __cgpreloginapp /dev/null", +] \ No newline at end of file diff --git a/src/server/connection.rs b/src/server/connection.rs index 75a9071f8..ac971aafd 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -904,12 +904,10 @@ async fn start_ipc( mut rx_to_cm: mpsc::UnboundedReceiver, tx_from_cm: mpsc::UnboundedSender, ) -> ResultType<()> { - loop { - if !crate::platform::is_prelogin() { - break; - } - sleep(1.).await; + if crate::platform::is_prelogin() { + return Ok(()); } + let mut stream = None; if let Ok(s) = crate::ipc::connect(1000, "_cm").await { stream = Some(s); From 0a294d9ff318e9c9ea3ceda6820c686d664ec800 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 9 Jan 2022 19:56:24 +0800 Subject: [PATCH 70/77] https://github.com/rustdesk/rustdesk/issues/292 --- Cargo.lock | 121 ++++++++--- Cargo.toml | 5 +- libs/hbb_common/protos/message.proto | 1 + src/ui/grid.tis | 11 +- src/ui/remote.rs | 306 ++++++++++++++++++--------- src/ui/remote.tis | 45 +--- 6 files changed, 325 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc1244525..b66313127 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -94,7 +94,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d76e1fe0171b6d0857afca5671db12a44e71e80823db13ab39f776fb09ad079" dependencies = [ "clipboard-win", - "core-graphics", + "core-graphics 0.22.3", "image", "log", "objc", @@ -416,6 +416,21 @@ dependencies = [ "cc", ] +[[package]] +name = "cocoa" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667fdc068627a2816b9ff831201dd9864249d6ee8d190b9532357f1fc0f61ea7" +dependencies = [ + "bitflags", + "block", + "core-foundation 0.9.2", + "core-graphics 0.21.0", + "foreign-types", + "libc", + "objc", +] + [[package]] name = "cocoa" version = "0.24.0" @@ -425,8 +440,8 @@ dependencies = [ "bitflags", "block", "cocoa-foundation", - "core-foundation", - "core-graphics", + "core-foundation 0.9.2", + "core-graphics 0.22.3", "foreign-types", "libc", "objc", @@ -440,7 +455,7 @@ checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" dependencies = [ "bitflags", "block", - "core-foundation", + "core-foundation 0.9.2", "core-graphics-types", "foreign-types", "libc", @@ -473,22 +488,62 @@ dependencies = [ "toml", ] +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + [[package]] name = "core-foundation" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", ] +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + [[package]] name = "core-foundation-sys" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a67c4378cf203eace8fb6567847eb641fd6ff933c1145a115c6ee820ebb978" +dependencies = [ + "bitflags", + "core-foundation 0.9.2", + "foreign-types", + "libc", +] + [[package]] name = "core-graphics" version = "0.22.3" @@ -496,7 +551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.2", "core-graphics-types", "foreign-types", "libc", @@ -509,7 +564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" dependencies = [ "bitflags", - "core-foundation", + "core-foundation 0.9.2", "foreign-types", "libc", ] @@ -539,7 +594,7 @@ version = "0.13.4" source = "git+https://github.com/open-trade/cpal#3a30569687271c2d5d67279c4883d63f4003d34c" dependencies = [ "alsa", - "core-foundation-sys", + "core-foundation-sys 0.8.3", "coreaudio-rs", "jni", "js-sys", @@ -922,7 +977,7 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" name = "enigo" version = "0.0.14" dependencies = [ - "core-graphics", + "core-graphics 0.22.3", "libc", "log", "objc", @@ -2891,6 +2946,21 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "rdev" +version = "0.5.0" +source = "git+https://github.com/open-trade/rdev#faeef84bf2edfa457e9e32c0c96b63f44e494fff" +dependencies = [ + "cocoa 0.22.0", + "core-foundation 0.7.0", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.2", + "lazy_static", + "libc", + "winapi 0.3.9", + "x11", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -3055,9 +3125,9 @@ dependencies = [ "cfg-if 1.0.0", "clap", "clipboard-master", - "cocoa", - "core-foundation", - "core-graphics", + "cocoa 0.24.0", + "core-foundation 0.9.2", + "core-graphics 0.22.3", "cpal", "crc32fast", "ctrlc", @@ -3077,6 +3147,7 @@ dependencies = [ "objc", "parity-tokio-ipc", "psutil", + "rdev", "repng", "rpassword 5.0.1", "rubato", @@ -3091,7 +3162,6 @@ dependencies = [ "sha2", "sys-locale", "systray", - "tigervnc", "uuid", "whoami", "winapi 0.3.9", @@ -3243,8 +3313,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ "bitflags", - "core-foundation", - "core-foundation-sys", + "core-foundation 0.9.2", + "core-foundation-sys 0.8.3", "libc", "security-framework-sys", ] @@ -3255,7 +3325,7 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" dependencies = [ - "core-foundation-sys", + "core-foundation-sys 0.8.3", "libc", ] @@ -3604,15 +3674,6 @@ dependencies = [ "weezl", ] -[[package]] -name = "tigervnc" -version = "1.0.1" -source = "git+https://github.com/open-trade/tigervnc#254ad243c5a22887ddf0e79def58b8251b108d08" -dependencies = [ - "cc", - "cfg-if 1.0.0", -] - [[package]] name = "time" version = "0.3.5" @@ -4126,6 +4187,16 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "x11" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd0565fa8bfba8c5efe02725b14dff114c866724eff2cfd44d76cea74bcd87a" +dependencies = [ + "libc", + "pkg-config", +] + [[package]] name = "x11-clipboard" version = "0.5.3" diff --git a/Cargo.toml b/Cargo.toml index 69b3673ab..db0133937 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,10 @@ sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" ctrlc = "3.2" arboard = "2.0" clipboard-master = "3.1" -tigervnc = { git = "https://github.com/open-trade/tigervnc" } +#tigervnc = { path = "../tigervnc" } +#tigervnc = { git = "https://github.com/open-trade/tigervnc" } +#rdev = { path = "../rdev" } +rdev = { git = "https://github.com/open-trade/rdev" } [target.'cfg(target_os = "windows")'.dependencies] systray = { git = "https://github.com/liyue201/systray-rs" } diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index 47c526dd1..d436fe128 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -83,6 +83,7 @@ message MouseEvent { } enum ControlKey { + Unknown = 0; Alt = 1; Backspace = 2; CapsLock = 3; diff --git a/src/ui/grid.tis b/src/ui/grid.tis index f33b4ef35..cf7cf3a38 100644 --- a/src/ui/grid.tis +++ b/src/ui/grid.tis @@ -1,3 +1,12 @@ +var last_key_time = 0; +var keymap = {}; +for (var (k, v) in Event) { + k = k + "" + if (k[0] == "V" && k[1] == "K") { + keymap[v] = k; + } +} + class Grid: Behavior { const TABLE_HEADER_CLICK = 0x81; const TABLE_ROW_CLICK = 0x82; @@ -144,7 +153,7 @@ class Grid: Behavior { function onKey(evt) { - + last_key_time = getTime(); if (evt.type != Event.KEY_DOWN) return false; diff --git a/src/ui/remote.rs b/src/ui/remote.rs index d4fde3f38..e732bcbb3 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -48,6 +48,10 @@ fn get_key_state(key: enigo::Key) -> bool { ENIGO.lock().unwrap().get_key_state(key) } +static mut IS_IN: bool = false; +static mut KEYBOARD_HOOKED: bool = false; +static mut KEYBOARD_ENABLED: bool = true; + #[derive(Default)] pub struct HandlerInner { element: Option, @@ -153,7 +157,8 @@ impl sciter::EventHandler for Handler { fn login(String, bool); fn new_rdp(); fn send_mouse(i32, i32, i32, bool, bool, bool, bool); - fn key_down_or_up(bool, String, i32, bool, bool, bool, bool, bool); + fn enter(); + fn leave(); fn ctrl_alt_del(); fn transfer_file(); fn tunnel(); @@ -214,6 +219,130 @@ impl Handler { me } + fn start_keyboard_hook(&self) { + if self.is_port_forward() || self.is_file_transfer() { + return; + } + if unsafe { KEYBOARD_HOOKED } { + return; + } + unsafe { + KEYBOARD_HOOKED = true; + } + log::info!("keyboard hooked"); + let mut me = self.clone(); + let peer = self.peer_platform(); + let is_win = peer == "Windows"; + std::thread::spawn(move || { + // This will block. + std::env::set_var("KEYBOARD_ONLY", "y"); // pass to rdev + use rdev::{EventType::*, *}; + let func = move |evt: Event| { + if unsafe { !IS_IN || !KEYBOARD_ENABLED } { + return; + } + let (key, down) = match evt.event_type { + KeyPress(k) => (k, 1), + KeyRelease(k) => (k, 0), + _ => return, + }; + let alt = get_key_state(enigo::Key::Alt); + let ctrl = get_key_state(enigo::Key::Control); + let shift = get_key_state(enigo::Key::Shift); + let command = get_key_state(enigo::Key::Meta); + let control_key = match key { + Key::Alt => Some(ControlKey::Alt), + Key::AltGr => Some(ControlKey::RAlt), + Key::Backspace => Some(ControlKey::Backspace), + Key::ControlLeft => Some(ControlKey::Control), + Key::ControlRight => Some(ControlKey::RControl), + Key::DownArrow => Some(ControlKey::DownArrow), + Key::Escape => Some(ControlKey::Escape), + Key::F1 => Some(ControlKey::F1), + Key::F10 => Some(ControlKey::F10), + Key::F11 => Some(ControlKey::F11), + Key::F12 => Some(ControlKey::F12), + Key::F2 => Some(ControlKey::F2), + Key::F3 => Some(ControlKey::F3), + Key::F4 => Some(ControlKey::F4), + Key::F5 => Some(ControlKey::F5), + Key::F6 => Some(ControlKey::F6), + Key::F7 => Some(ControlKey::F7), + Key::F8 => Some(ControlKey::F8), + Key::F9 => Some(ControlKey::F9), + Key::LeftArrow => Some(ControlKey::LeftArrow), + Key::MetaLeft => Some(ControlKey::Meta), + Key::MetaRight => Some(ControlKey::RWin), + Key::Return => Some(ControlKey::Return), + Key::RightArrow => Some(ControlKey::RightArrow), + Key::ShiftLeft => Some(ControlKey::Shift), + Key::ShiftRight => Some(ControlKey::RShift), + Key::Space => Some(ControlKey::Space), + Key::Tab => Some(ControlKey::Tab), + Key::UpArrow => Some(ControlKey::UpArrow), + Key::Delete | Key::KpDelete => { + if is_win && ctrl && alt { + me.ctrl_alt_del(); + return; + } + Some(ControlKey::Delete) + } + Key::Apps => Some(ControlKey::Apps), + Key::Cancel => Some(ControlKey::Cancel), + Key::Clear => Some(ControlKey::Clear), + Key::Kana => Some(ControlKey::Kana), + Key::Hangul => Some(ControlKey::Hangul), + Key::Junja => Some(ControlKey::Junja), + Key::Final => Some(ControlKey::Final), + Key::Hanja => Some(ControlKey::Hanja), + Key::Hanji => Some(ControlKey::Hanja), + Key::Convert => Some(ControlKey::Convert), + Key::Print => Some(ControlKey::Print), + Key::Select => Some(ControlKey::Select), + Key::Execute => Some(ControlKey::Execute), + Key::Snapshot => Some(ControlKey::Snapshot), + Key::Help => Some(ControlKey::Help), + Key::Sleep => Some(ControlKey::Sleep), + Key::Separator => Some(ControlKey::Separator), + Key::KpReturn => Some(ControlKey::NumpadEnter), + Key::CapsLock | Key::NumLock | Key::ScrollLock => { + return; + } + _ => None, + }; + let mut key_event = KeyEvent::new(); + if let Some(k) = control_key { + key_event.set_control_key(k); + } else { + let chr = match evt.name { + Some(ref s) => { + if s.len() == 1 { + s.chars().next().unwrap() + } else { + '\0' + } + } + _ => '\0', + }; + if chr != '\0' { + if chr == 'l' && is_win && command { + me.lock_screen(); + return; + } + key_event.set_chr(chr as _); + } else { + log::error!("Unknown key {:?}", evt); + return; + } + } + me.key_down_or_up(down, key_event, alt, ctrl, shift, command); + }; + if let Err(error) = rdev::listen(func) { + log::error!("rdev: {:?}", error); + } + }); + } + fn get_view_style(&mut self) -> String { return self.lc.read().unwrap().view_style.clone(); } @@ -632,6 +761,18 @@ impl Handler { self.send(Data::NewRDP); } + fn enter(&mut self) { + unsafe { + IS_IN = true; + } + } + + fn leave(&mut self) { + unsafe { + IS_IN = false; + } + } + fn send_mouse( &mut self, mask: i32, @@ -814,18 +955,20 @@ impl Handler { fn ctrl_alt_del(&mut self) { if self.peer_platform() == "Windows" { - let del = "CTRL_ALT_DEL".to_owned(); - self.key_down_or_up(1, del, 0, false, false, false, false, false); + let mut key_event = KeyEvent::new(); + key_event.set_control_key(ControlKey::CtrlAltDel); + self.key_down_or_up(1, key_event, false, false, false, false); } else { - let del = "VK_DELETE".to_owned(); - self.key_down_or_up(1, del.clone(), 0, true, true, false, false, false); - self.key_down_or_up(0, del, 0, true, true, false, false, false); + let mut key_event = KeyEvent::new(); + key_event.set_control_key(ControlKey::Delete); + self.key_down_or_up(3, key_event, true, true, false, false); } } fn lock_screen(&mut self) { - let lock = "LOCK_SCREEN".to_owned(); - self.key_down_or_up(1, lock, 0, false, false, false, false, false); + let mut key_event = KeyEvent::new(); + key_event.set_control_key(ControlKey::LockScreen); + self.key_down_or_up(1, key_event, false, false, false, false); } fn transfer_file(&mut self) { @@ -847,106 +990,61 @@ impl Handler { fn key_down_or_up( &mut self, down_or_up: i32, - name: String, - code: i32, + evt: KeyEvent, alt: bool, ctrl: bool, shift: bool, command: bool, - extended: bool, ) { - if self.peer_platform() == "Windows" { - if ctrl && alt && name == "VK_DELETE" { - self.ctrl_alt_del(); - return; - } - if command && name == "VK_L" { - self.lock_screen(); + let mut key_event = evt; + + if alt + && !crate::is_control_key(&key_event, &ControlKey::Alt) + && !crate::is_control_key(&key_event, &ControlKey::RAlt) + { + key_event.modifiers.push(ControlKey::Alt.into()); + } + if shift + && !crate::is_control_key(&key_event, &ControlKey::Shift) + && !crate::is_control_key(&key_event, &ControlKey::RShift) + { + key_event.modifiers.push(ControlKey::Shift.into()); + } + if ctrl + && !crate::is_control_key(&key_event, &ControlKey::Control) + && !crate::is_control_key(&key_event, &ControlKey::RControl) + { + key_event.modifiers.push(ControlKey::Control.into()); + } + if command + && !crate::is_control_key(&key_event, &ControlKey::Meta) + && !crate::is_control_key(&key_event, &ControlKey::RWin) + { + key_event.modifiers.push(ControlKey::Meta.into()); + } + /* + if crate::is_control_key(&key_event, &ControlKey::CapsLock) { + return; + } else if get_key_state(enigo::Key::CapsLock) && common::valid_for_capslock(&key_event) { + key_event.modifiers.push(ControlKey::CapsLock.into()); + } + if self.peer_platform() != "Mac OS" { + if crate::is_control_key(&key_event, &ControlKey::NumLock) { return; + } else if get_key_state(enigo::Key::NumLock) && common::valid_for_numlock(&key_event) { + key_event.modifiers.push(ControlKey::NumLock.into()); } } - - // extended: e.g. ctrl key on right side, https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-keybd_event - // not found api of osx and xdo - log::debug!( - "{:?} {} {} {} {} {} {} {} {}", - std::time::SystemTime::now(), - down_or_up, - name, - code, - alt, - ctrl, - shift, - command, - extended, - ); - - let mut name = name; - #[cfg(target_os = "linux")] - if code == 65383 { - // VK_MENU - name = "Apps".to_owned(); - } - - if extended { - match name.as_ref() { - "VK_CONTROL" => name = "RControl".to_owned(), - "VK_MENU" => name = "RAlt".to_owned(), - "VK_SHIFT" => name = "RShift".to_owned(), - _ => {} - } - } - - if let Some(mut key_event) = self.get_key_event(down_or_up, &name, code) { - if alt - && !crate::is_control_key(&key_event, &ControlKey::Alt) - && !crate::is_control_key(&key_event, &ControlKey::RAlt) - { - key_event.modifiers.push(ControlKey::Alt.into()); - } - if shift - && !crate::is_control_key(&key_event, &ControlKey::Shift) - && !crate::is_control_key(&key_event, &ControlKey::RShift) - { - key_event.modifiers.push(ControlKey::Shift.into()); - } - if ctrl - && !crate::is_control_key(&key_event, &ControlKey::Control) - && !crate::is_control_key(&key_event, &ControlKey::RControl) - { - key_event.modifiers.push(ControlKey::Control.into()); - } - if command - && !crate::is_control_key(&key_event, &ControlKey::Meta) - && !crate::is_control_key(&key_event, &ControlKey::RWin) - { - key_event.modifiers.push(ControlKey::Meta.into()); - } - if crate::is_control_key(&key_event, &ControlKey::CapsLock) { - return; - } else if get_key_state(enigo::Key::CapsLock) && common::valid_for_capslock(&key_event) - { - key_event.modifiers.push(ControlKey::CapsLock.into()); - } - if self.peer_platform() != "Mac OS" { - if crate::is_control_key(&key_event, &ControlKey::NumLock) { - return; - } else if get_key_state(enigo::Key::NumLock) - && common::valid_for_numlock(&key_event) - { - key_event.modifiers.push(ControlKey::NumLock.into()); - } - } - if down_or_up == 1 { - key_event.down = true; - } else if down_or_up == 3 { - key_event.press = true; - } - let mut msg_out = Message::new(); - msg_out.set_key_event(key_event); - log::debug!("{:?}", msg_out); - self.send(Data::Message(msg_out)); + */ + if down_or_up == 1 { + key_event.down = true; + } else if down_or_up == 3 { + key_event.press = true; } + let mut msg_out = Message::new(); + msg_out.set_key_event(key_event); + log::debug!("{:?}", msg_out); + self.send(Data::Message(msg_out)); } #[inline] @@ -1123,6 +1221,9 @@ impl Remote { }; match Client::start(&self.handler.id, conn_type).await { Ok((mut peer, direct)) => { + unsafe { + KEYBOARD_ENABLED = true; + } self.handler .call("setConnectionType", &make_args!(peer.is_secured(), direct)); loop { @@ -1182,6 +1283,9 @@ impl Remote { if let Some(stop) = stop_clipboard { stop.send(()).ok(); } + unsafe { + KEYBOARD_ENABLED = false; + } } fn handle_job_status(&mut self, id: i32, file_num: i32, err: Option) { @@ -1577,6 +1681,9 @@ impl Remote { log::info!("Change permission {:?} -> {}", p.permission, p.enabled); match p.permission.enum_value_or_default() { Permission::Keyboard => { + unsafe { + KEYBOARD_ENABLED = p.enabled; + } self.handler .call("setPermission", &make_args!("keyboard", p.enabled)); } @@ -1729,6 +1836,7 @@ impl Interface for Handler { crate::platform::windows::add_recent_document(&path); } } + self.start_keyboard_hook(); } async fn handle_hash(&mut self, hash: Hash, peer: &mut Stream) { diff --git a/src/ui/remote.tis b/src/ui/remote.tis index af936e112..0afbe13f3 100644 --- a/src/ui/remote.tis +++ b/src/ui/remote.tis @@ -1,5 +1,4 @@ var cursor_img = $(img#cursor); -var last_key_time = 0; is_file_transfer = handler.is_file_transfer(); var is_port_forward = handler.is_port_forward(); var display_width = 0; @@ -72,46 +71,14 @@ function adaptDisplay() { // https://sciter.com/docs/content/sciter/Event.htm var entered = false; - -var keymap = {}; -for (var (k, v) in Event) { - k = k + "" - if (k[0] == "V" && k[1] == "K") { - keymap[v] = k; +if (!is_file_transfer && !is_port_forward) { + self.onKey = function(evt) { + if (!entered) return false; + // so that arrow key not move scrollbar + return true; } } -// VK_ENTER = VK_RETURN -// somehow, handler.onKey and view.onKey not working -function self.onKey(evt) { - last_key_time = getTime(); - if (is_file_transfer || is_port_forward) return false; - if (!entered) return false; - if (!keyboard_enabled) return false; - switch (evt.type) { - case Event.KEY_DOWN: - handler.key_down_or_up(1, keymap[evt.keyCode] || "", evt.keyCode, evt.altKey, - evt.ctrlKey, evt.shiftKey, evt.commandKey, evt.extendedKey); - if (is_osx && evt.commandKey) { - handler.key_down_or_up(0, keymap[evt.keyCode] || "", evt.keyCode, evt.altKey, - evt.ctrlKey, evt.shiftKey, evt.commandKey, evt.extendedKey); - } - break; - case Event.KEY_UP: - handler.key_down_or_up(0, keymap[evt.keyCode] || "", evt.keyCode, evt.altKey, - evt.ctrlKey, evt.shiftKey, evt.commandKey, evt.extendedKey); - break; - case Event.KEY_CHAR: - // the keypress event is fired when the element receives character value. Event.keyCode is a UNICODE code point of the character - handler.key_down_or_up(2, "", evt.keyCode, evt.altKey, - evt.ctrlKey, evt.shiftKey, evt.commandKey, evt.extendedKey); - break; - default: - return false; - } - return true; -} - var wait_window_toolbar = false; var last_mouse_mask; var acc_wheel_delta_x = 0; @@ -284,10 +251,12 @@ function handler.onMouse(evt) case Event.MOUSE_ENTER: entered = true; stdout.println("enter"); + handler.enter(); return keyboard_enabled; case Event.MOUSE_LEAVE: entered = false; stdout.println("leave"); + handler.leave(); return keyboard_enabled; default: return false; From a0c704f36e1367b9482d802bb3b4c42be45ec24c Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 9 Jan 2022 20:56:56 +0800 Subject: [PATCH 71/77] string len is num of bytes --- src/ui/remote.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ui/remote.rs b/src/ui/remote.rs index e732bcbb3..34888aba9 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -315,13 +315,7 @@ impl Handler { key_event.set_control_key(k); } else { let chr = match evt.name { - Some(ref s) => { - if s.len() == 1 { - s.chars().next().unwrap() - } else { - '\0' - } - } + Some(ref s) => s.chars().next().unwrap_or('\0'), _ => '\0', }; if chr != '\0' { From 3f56c82c7bda81f76d52bbec2c3b620625736024 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 9 Jan 2022 21:05:00 +0800 Subject: [PATCH 72/77] revert keysym back, enigo's Layout can do this --- libs/enigo/src/lib.rs | 2 -- libs/enigo/src/linux.rs | 3 -- libs/enigo/src/macos/macos_impl.rs | 1 - libs/enigo/src/win/win_impl.rs | 1 - libs/hbb_common/protos/message.proto | 1 - src/server/input_service.rs | 47 ++++++---------------------- 6 files changed, 10 insertions(+), 45 deletions(-) diff --git a/libs/enigo/src/lib.rs b/libs/enigo/src/lib.rs index 10c5da4a7..893f5918c 100644 --- a/libs/enigo/src/lib.rs +++ b/libs/enigo/src/lib.rs @@ -418,8 +418,6 @@ pub enum Key { Layout(char), /// raw keycode eg 0x38 Raw(u16), - /// VNC keysym - KeySym(u32), } /// Representing an interface and a set of keyboard functions every diff --git a/libs/enigo/src/linux.rs b/libs/enigo/src/linux.rs index be21a2c70..24628c1f9 100644 --- a/libs/enigo/src/linux.rs +++ b/libs/enigo/src/linux.rs @@ -181,9 +181,6 @@ impl MouseControllable for Enigo { } } fn keysequence<'a>(key: Key) -> Cow<'a, str> { - if let Key::KeySym(sym) = key { - return Cow::Owned("".to_owned()); - } if let Key::Layout(c) = key { return Cow::Owned(format!("U{:X}", c as u32)); } diff --git a/libs/enigo/src/macos/macos_impl.rs b/libs/enigo/src/macos/macos_impl.rs index 93b78c6d8..0ee038012 100644 --- a/libs/enigo/src/macos/macos_impl.rs +++ b/libs/enigo/src/macos/macos_impl.rs @@ -426,7 +426,6 @@ impl Enigo { Key::Raw(raw_keycode) => raw_keycode, Key::Layout(c) => self.map_key_board(c), - Key::KeySym(sym) => 0 as _, Key::Super | Key::Command | Key::Windows | Key::Meta => kVK_Command, _ => 0, diff --git a/libs/enigo/src/win/win_impl.rs b/libs/enigo/src/win/win_impl.rs index 3f83dc951..3a6b6215f 100644 --- a/libs/enigo/src/win/win_impl.rs +++ b/libs/enigo/src/win/win_impl.rs @@ -340,7 +340,6 @@ impl Enigo { Key::Raw(raw_keycode) => raw_keycode, Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()), Key::Super | Key::Command | Key::Windows | Key::Meta => EVK_LWIN, - Key::KeySym(sym) => 0, } } diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index d436fe128..3d892877f 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -173,7 +173,6 @@ message KeyEvent { uint32 chr = 4; uint32 unicode = 5; string seq = 6; - uint32 keysym = 7; } repeated ControlKey modifiers = 8; } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index ef06f2348..ba34772a5 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -40,8 +40,7 @@ struct Input { time: i64, } -const KEY_CHAR_START: u64 = 0xFFFF; -const KEY_SYM_START: u64 = 0xFFFFFFFF; +const KEY_CHAR_START: i32 = 9999; #[derive(Clone, Default)] pub struct MouseCursorSub { @@ -164,7 +163,7 @@ fn run_cursor(sp: MouseCursorService, state: &mut StateCursor) -> ResultType<()> lazy_static::lazy_static! { static ref ENIGO: Arc> = Arc::new(Mutex::new(Enigo::new())); - static ref KEYS_DOWN: Arc>> = Default::default(); + static ref KEYS_DOWN: Arc>> = Default::default(); static ref LATEST_INPUT: Arc> = Default::default(); } static EXITING: AtomicBool = AtomicBool::new(false); @@ -257,15 +256,13 @@ fn fix_key_down_timeout(force: bool) { if force || value.elapsed().as_millis() >= 3_000 { KEYS_DOWN.lock().unwrap().remove(&key); let key = if key < KEY_CHAR_START { - if let Some(key) = KEY_MAP.get(&(key as _)) { + if let Some(key) = KEY_MAP.get(&key) { Some(*key) } else { None } - } else if key < KEY_SYM_START { - Some(Key::Layout(((key - KEY_CHAR_START) as u8) as _)) } else { - Some(Key::KeySym((key - KEY_SYM_START) as u32)) + Some(Key::Layout(((key - KEY_CHAR_START) as u8) as _)) }; if let Some(key) = key { let func = move || { @@ -355,10 +352,7 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) { modifier_sleep(); to_release.push(key); } else { - KEYS_DOWN - .lock() - .unwrap() - .insert(ck.value() as _, Instant::now()); + KEYS_DOWN.lock().unwrap().insert(ck.value(), Instant::now()); } } } @@ -578,10 +572,7 @@ fn handle_key_(evt: &KeyEvent) { modifier_sleep(); to_release.push(key); } else { - KEYS_DOWN - .lock() - .unwrap() - .insert(ck.value() as _, Instant::now()); + KEYS_DOWN.lock().unwrap().insert(ck.value(), Instant::now()); } } } @@ -615,13 +606,10 @@ fn handle_key_(evt: &KeyEvent) { } if evt.down { allow_err!(en.key_down(key.clone())); - KEYS_DOWN - .lock() - .unwrap() - .insert(ck.value() as _, Instant::now()); + KEYS_DOWN.lock().unwrap().insert(ck.value(), Instant::now()); } else { en.key_up(key.clone()); - KEYS_DOWN.lock().unwrap().remove(&(ck.value() as _)); + KEYS_DOWN.lock().unwrap().remove(&ck.value()); } } else if ck.value() == ControlKey::CtrlAltDel.value() { // have to spawn new thread because send_sas is tokio_main, the caller can not be tokio_main. @@ -639,28 +627,13 @@ fn handle_key_(evt: &KeyEvent) { KEYS_DOWN .lock() .unwrap() - .insert(chr as u64 + KEY_CHAR_START, Instant::now()); + .insert(chr as i32 + KEY_CHAR_START, Instant::now()); } else { en.key_up(Key::Layout(chr as u8 as _)); KEYS_DOWN .lock() .unwrap() - .remove(&(chr as u64 + KEY_CHAR_START)); - } - } - Some(key_event::Union::keysym(sym)) => { - if evt.down { - allow_err!(en.key_down(Key::KeySym(sym))); - KEYS_DOWN - .lock() - .unwrap() - .insert(sym as u64 + KEY_SYM_START, Instant::now()); - } else { - en.key_up(Key::KeySym(sym)); - KEYS_DOWN - .lock() - .unwrap() - .remove(&(sym as u64 + KEY_SYM_START)); + .remove(&(chr as i32 + KEY_CHAR_START)); } } Some(key_event::Union::unicode(chr)) => { From d07ae9f2c609c8b5e3dbb5b5905048b21b6843c0 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Sun, 9 Jan 2022 23:59:30 +0800 Subject: [PATCH 73/77] numpad --- Cargo.lock | 21 +++++++++++++++------ Cargo.toml | 2 -- src/ui/remote.rs | 19 +++++++++++++++++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b66313127..4695b175c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1044,6 +1044,15 @@ dependencies = [ "backtrace", ] +[[package]] +name = "fastrand" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2" +dependencies = [ + "instant", +] + [[package]] name = "filetime" version = "0.2.15" @@ -1070,9 +1079,9 @@ dependencies = [ [[package]] name = "flexi_logger" -version = "0.22.1" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2917b8937f4d36d9df8b15a51428b6a1b2726ec57402b0c94b4dfc393a409e5" +checksum = "0b51b4517f4422bfa0515dafcc10b4cc4cd3953d69a19608fd74afb3b19e227c" dependencies = [ "ansi_term", "atty", @@ -2949,7 +2958,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0" -source = "git+https://github.com/open-trade/rdev#faeef84bf2edfa457e9e32c0c96b63f44e494fff" +source = "git+https://github.com/open-trade/rdev#f0ffc49b502c884956a47b8a1830fc5f55bf9faf" dependencies = [ "cocoa 0.22.0", "core-foundation 0.7.0", @@ -3604,13 +3613,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if 1.0.0", + "fastrand", "libc", - "rand 0.8.4", "redox_syscall", "remove_dir_all", "winapi 0.3.9", diff --git a/Cargo.toml b/Cargo.toml index db0133937..6a9325e25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,8 +54,6 @@ sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" ctrlc = "3.2" arboard = "2.0" clipboard-master = "3.1" -#tigervnc = { path = "../tigervnc" } -#tigervnc = { git = "https://github.com/open-trade/tigervnc" } #rdev = { path = "../rdev" } rdev = { git = "https://github.com/open-trade/rdev" } diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 34888aba9..0ca61eb3a 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -280,7 +280,7 @@ impl Handler { Key::Space => Some(ControlKey::Space), Key::Tab => Some(ControlKey::Tab), Key::UpArrow => Some(ControlKey::UpArrow), - Key::Delete | Key::KpDelete => { + Key::Delete => { if is_win && ctrl && alt { me.ctrl_alt_del(); return; @@ -305,6 +305,21 @@ impl Handler { Key::Sleep => Some(ControlKey::Sleep), Key::Separator => Some(ControlKey::Separator), Key::KpReturn => Some(ControlKey::NumpadEnter), + Key::Kp0 => Some(ControlKey::Numpad0), + Key::Kp1 => Some(ControlKey::Numpad1), + Key::Kp2 => Some(ControlKey::Numpad2), + Key::Kp3 => Some(ControlKey::Numpad3), + Key::Kp4 => Some(ControlKey::Numpad4), + Key::Kp5 => Some(ControlKey::Numpad5), + Key::Kp6 => Some(ControlKey::Numpad6), + Key::Kp7 => Some(ControlKey::Numpad7), + Key::Kp8 => Some(ControlKey::Numpad8), + Key::Kp9 => Some(ControlKey::Numpad9), + Key::KpDivide => Some(ControlKey::Divide), + Key::KpMultiply => Some(ControlKey::Subtract), + Key::KpDecimal => Some(ControlKey::Decimal), + Key::KpMinus => Some(ControlKey::Subtract), + Key::KpPlus => Some(ControlKey::Add), Key::CapsLock | Key::NumLock | Key::ScrollLock => { return; } @@ -1022,6 +1037,7 @@ impl Handler { } else if get_key_state(enigo::Key::CapsLock) && common::valid_for_capslock(&key_event) { key_event.modifiers.push(ControlKey::CapsLock.into()); } + */ if self.peer_platform() != "Mac OS" { if crate::is_control_key(&key_event, &ControlKey::NumLock) { return; @@ -1029,7 +1045,6 @@ impl Handler { key_event.modifiers.push(ControlKey::NumLock.into()); } } - */ if down_or_up == 1 { key_event.down = true; } else if down_or_up == 3 { From 3212290f6e333db792ac8b1a6f188b78a32a96ff Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 10 Jan 2022 00:33:31 +0800 Subject: [PATCH 74/77] fix on rdev --- Cargo.lock | 2 +- src/ui/remote.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4695b175c..f0a69c2c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2958,7 +2958,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0" -source = "git+https://github.com/open-trade/rdev#f0ffc49b502c884956a47b8a1830fc5f55bf9faf" +source = "git+https://github.com/open-trade/rdev#bc1d62c9966a56eecc5de61b1dee43dfc80ec141" dependencies = [ "cocoa 0.22.0", "core-foundation 0.7.0", diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 0ca61eb3a..33d3a013b 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -300,7 +300,7 @@ impl Handler { Key::Print => Some(ControlKey::Print), Key::Select => Some(ControlKey::Select), Key::Execute => Some(ControlKey::Execute), - Key::Snapshot => Some(ControlKey::Snapshot), + Key::PrintScreen => Some(ControlKey::Snapshot), Key::Help => Some(ControlKey::Help), Key::Sleep => Some(ControlKey::Sleep), Key::Separator => Some(ControlKey::Separator), From ae79a36f7bc2cfe1cd74118277705c800a65c443 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 10 Jan 2022 01:06:31 +0800 Subject: [PATCH 75/77] remove valid_for_capslock --- src/common.rs | 10 ---------- src/server/input_service.rs | 8 +++----- src/ui/remote.rs | 10 ++-------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/src/common.rs b/src/common.rs index 13599045e..d5390fe69 100644 --- a/src/common.rs +++ b/src/common.rs @@ -40,15 +40,6 @@ pub fn valid_for_numlock(evt: &KeyEvent) -> bool { } } -#[inline] -pub fn valid_for_capslock(evt: &KeyEvent) -> bool { - if let Some(key_event::Union::chr(ch)) = evt.union { - ch >= 'a' as u32 && ch <= 'z' as u32 - } else { - false - } -} - pub fn create_clipboard_msg(content: String) -> Message { let bytes = content.into_bytes(); let compressed = compress_func(&bytes, COMPRESS_LEVEL); @@ -467,4 +458,3 @@ pub fn is_ip(id: &str) -> bool { .unwrap() .is_match(id) } - diff --git a/src/server/input_service.rs b/src/server/input_service.rs index ba34772a5..657790aa2 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -580,11 +580,9 @@ fn handle_key_(evt: &KeyEvent) { } } #[cfg(not(target_os = "macos"))] - if crate::common::valid_for_capslock(evt) { - if has_cap != en.get_key_state(Key::CapsLock) { - en.key_down(Key::CapsLock).ok(); - en.key_up(Key::CapsLock); - } + if has_cap != en.get_key_state(Key::CapsLock) { + en.key_down(Key::CapsLock).ok(); + en.key_up(Key::CapsLock); } #[cfg(windows)] if crate::common::valid_for_numlock(evt) { diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 33d3a013b..48efad17e 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -1031,17 +1031,11 @@ impl Handler { { key_event.modifiers.push(ControlKey::Meta.into()); } - /* - if crate::is_control_key(&key_event, &ControlKey::CapsLock) { - return; - } else if get_key_state(enigo::Key::CapsLock) && common::valid_for_capslock(&key_event) { + if get_key_state(enigo::Key::CapsLock) { key_event.modifiers.push(ControlKey::CapsLock.into()); } - */ if self.peer_platform() != "Mac OS" { - if crate::is_control_key(&key_event, &ControlKey::NumLock) { - return; - } else if get_key_state(enigo::Key::NumLock) && common::valid_for_numlock(&key_event) { + if get_key_state(enigo::Key::NumLock) && common::valid_for_numlock(&key_event) { key_event.modifiers.push(ControlKey::NumLock.into()); } } From 3a6dc19616a35e53cf242a8e21724189d8374c27 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 10 Jan 2022 01:29:50 +0800 Subject: [PATCH 76/77] to be compatible with 1.1.8 --- src/client.rs | 9 ++++++--- src/ui/remote.rs | 8 +++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/client.rs b/src/client.rs index e6a5d0afd..946b923d2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -585,7 +585,10 @@ impl AudioHandler { ); audio_buffer.lock().unwrap().extend(buffer); } else { - audio_buffer.lock().unwrap().extend(buffer[0..n].iter().cloned()); + audio_buffer + .lock() + .unwrap() + .extend(buffer[0..n].iter().cloned()); } } #[cfg(any(target_os = "android"))] @@ -681,7 +684,7 @@ pub struct LoginConfigHandler { pub port_forward: (String, i32), pub support_press: bool, pub support_refresh: bool, - pub internation_keyboard: bool, + pub version: i64, } impl Deref for LoginConfigHandler { @@ -938,7 +941,7 @@ impl LoginConfigHandler { if !pi.version.is_empty() { self.support_press = true; self.support_refresh = true; - self.internation_keyboard = crate::get_version_number(&pi.version) > 1001008; + self.version = crate::get_version_number(&pi.version); } let serde = PeerInfoSerde { username, diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 48efad17e..15cac16ce 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -233,6 +233,8 @@ impl Handler { let mut me = self.clone(); let peer = self.peer_platform(); let is_win = peer == "Windows"; + let version = self.lc.read().unwrap().version; + const OFFSET_CASE: u8 = 'a' as u8 - 'A' as u8; std::thread::spawn(move || { // This will block. std::env::set_var("KEYBOARD_ONLY", "y"); // pass to rdev @@ -329,7 +331,7 @@ impl Handler { if let Some(k) = control_key { key_event.set_control_key(k); } else { - let chr = match evt.name { + let mut chr = match evt.name { Some(ref s) => s.chars().next().unwrap_or('\0'), _ => '\0', }; @@ -338,6 +340,10 @@ impl Handler { me.lock_screen(); return; } + // <= 1.1.8, caps modifier only for 'a' -> 'z', so here adjust it + if version <= 1001008 && chr >= 'A' && chr <= 'Z' { + chr = (chr as u8 + OFFSET_CASE) as _; + } key_event.set_chr(chr as _); } else { log::error!("Unknown key {:?}", evt); From e2a879692d943cd3783d5bbfbe2f0d0f7630037f Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 10 Jan 2022 03:11:53 +0800 Subject: [PATCH 77/77] ignore modifiers for name --- Cargo.lock | 2 +- src/ui/remote.rs | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f0a69c2c3..1ea2e7c9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2958,7 +2958,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0" -source = "git+https://github.com/open-trade/rdev#bc1d62c9966a56eecc5de61b1dee43dfc80ec141" +source = "git+https://github.com/open-trade/rdev#2a3205a13102907da2442a369f8b704601eecc9d" dependencies = [ "cocoa 0.22.0", "core-foundation 0.7.0", diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 15cac16ce..48efad17e 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -233,8 +233,6 @@ impl Handler { let mut me = self.clone(); let peer = self.peer_platform(); let is_win = peer == "Windows"; - let version = self.lc.read().unwrap().version; - const OFFSET_CASE: u8 = 'a' as u8 - 'A' as u8; std::thread::spawn(move || { // This will block. std::env::set_var("KEYBOARD_ONLY", "y"); // pass to rdev @@ -331,7 +329,7 @@ impl Handler { if let Some(k) = control_key { key_event.set_control_key(k); } else { - let mut chr = match evt.name { + let chr = match evt.name { Some(ref s) => s.chars().next().unwrap_or('\0'), _ => '\0', }; @@ -340,10 +338,6 @@ impl Handler { me.lock_screen(); return; } - // <= 1.1.8, caps modifier only for 'a' -> 'z', so here adjust it - if version <= 1001008 && chr >= 'A' && chr <= 'Z' { - chr = (chr as u8 + OFFSET_CASE) as _; - } key_event.set_chr(chr as _); } else { log::error!("Unknown key {:?}", evt);
    Local Port{translate('Local Port')} - Remote HostRemote PortAction{translate('Remote Host')}{translate('Remote Port')}{translate('Action')}
    {svg_arrow}