From f8092f924ab571069e174ccaf63ff3bd723fda2b Mon Sep 17 00:00:00 2001 From: solokot Date: Sat, 28 Oct 2023 06:29:50 +0300 Subject: [PATCH 01/17] Update ru.rs --- src/lang/ru.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/ru.rs b/src/lang/ru.rs index f43df683c..1ea714bf4 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -570,7 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Big tiles", "Большие значки"), ("Small tiles", "Маленькие значки"), ("List", "Список"), - ("Virtual display", ""), - ("Plug out all", ""), + ("Virtual display", "Виртуальный дисплей"), + ("Plug out all", "Отключить все"), ].iter().cloned().collect(); } From dc96b473cd2c5e52bdb5f96d210f31d5be453b5b Mon Sep 17 00:00:00 2001 From: jxd1337 Date: Sat, 28 Oct 2023 10:50:39 +0200 Subject: [PATCH 02/17] lang.py PEP8 improvements --- res/lang.py | 102 ++++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/res/lang.py b/res/lang.py index 74492818a..2ed549fe1 100644 --- a/res/lang.py +++ b/res/lang.py @@ -5,20 +5,22 @@ import glob import sys import csv + def get_lang(lang): - out = {} - for ln in open('./src/lang/%s.rs'%lang, encoding='utf8'): - ln = ln.strip() - if ln.startswith('("'): - k, v = line_split(ln) - out[k] = v - return out + out = {} + for ln in open('./src/lang/%s.rs' % lang, encoding='utf8'): + ln = ln.strip() + if ln.startswith('("'): + k, v = line_split(ln) + out[k] = v + return out + def line_split(line): toks = line.split('", "') if len(toks) != 2: print(line) - assert(0) + assert (0) # Replace fixed position. # Because toks[1] may be v") or v"), k = toks[0][toks[0].find('"') + 1:] @@ -27,62 +29,62 @@ def line_split(line): def main(): - if len(sys.argv) == 1: - expand() - elif sys.argv[1] == '1': - to_csv() - else: - to_rs(sys.argv[1]) + if len(sys.argv) == 1: + expand() + elif sys.argv[1] == '1': + to_csv() + else: + to_rs(sys.argv[1]) def expand(): - for fn in glob.glob('./src/lang/*.rs'): - lang = os.path.basename(fn)[:-3] - if lang in ['en','template']: continue - print(lang) - dict = get_lang(lang) - fw = open("./src/lang/%s.rs"%lang, "wt", encoding='utf8') - for line in open('./src/lang/template.rs', encoding='utf8'): - line_strip = line.strip() - if line_strip.startswith('("'): - k, v = line_split(line_strip) - if k in dict: - # embraced with " to avoid empty v - line = line.replace('"%s"'%v, '"%s"'%dict[k]) - else: - line = line.replace(v, "") - fw.write(line) - else: - fw.write(line) - fw.close() + for fn in glob.glob('./src/lang/*.rs'): + lang = os.path.basename(fn)[:-3] + if lang in ['en', 'template']: continue + print(lang) + dict = get_lang(lang) + fw = open("./src/lang/%s.rs" % lang, "wt", encoding='utf8') + for line in open('./src/lang/template.rs', encoding='utf8'): + line_strip = line.strip() + if line_strip.startswith('("'): + k, v = line_split(line_strip) + if k in dict: + # embraced with " to avoid empty v + line = line.replace('"%s"' % v, '"%s"' % dict[k]) + else: + line = line.replace(v, "") + fw.write(line) + else: + fw.write(line) + fw.close() def to_csv(): - for fn in glob.glob('./src/lang/*.rs'): - lang = os.path.basename(fn)[:-3] - csvfile = open('./src/lang/%s.csv'%lang, "wt", encoding='utf8') - csvwriter = csv.writer(csvfile) - for line in open(fn, encoding='utf8'): - line_strip = line.strip() - if line_strip.startswith('("'): - k, v = line_split(line_strip) - csvwriter.writerow([k, v]) - csvfile.close() + for fn in glob.glob('./src/lang/*.rs'): + lang = os.path.basename(fn)[:-3] + csvfile = open('./src/lang/%s.csv' % lang, "wt", encoding='utf8') + csvwriter = csv.writer(csvfile) + for line in open(fn, encoding='utf8'): + line_strip = line.strip() + if line_strip.startswith('("'): + k, v = line_split(line_strip) + csvwriter.writerow([k, v]) + csvfile.close() def to_rs(lang): - csvfile = open('%s.csv'%lang, "rt", encoding='utf8') - fw = open("./src/lang/%s.rs"%lang, "wt", encoding='utf8') - fw.write('''lazy_static::lazy_static! { + csvfile = open('%s.csv' % lang, "rt", encoding='utf8') + fw = open("./src/lang/%s.rs" % lang, "wt", encoding='utf8') + fw.write('''lazy_static::lazy_static! { pub static ref T: std::collections::HashMap<&'static str, &'static str> = [ ''') - for row in csv.reader(csvfile): - fw.write(' ("%s", "%s"),\n'%(row[0].replace('"', '\"'), row[1].replace('"', '\"'))) - fw.write(''' ].iter().cloned().collect(); + for row in csv.reader(csvfile): + fw.write(' ("%s", "%s"),\n' % (row[0].replace('"', '\"'), row[1].replace('"', '\"'))) + fw.write(''' ].iter().cloned().collect(); } ''') - fw.close() + fw.close() main() From f61fd02ac7378172d4112f23c9c21dcfbdbd67e1 Mon Sep 17 00:00:00 2001 From: jxd1337 Date: Sat, 28 Oct 2023 10:57:50 +0200 Subject: [PATCH 03/17] build.py, generate.py improvements --- build.py | 11 ++++++++--- libs/portable/generate.py | 5 +++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/build.py b/build.py index 42dc8d6de..f65b3a4aa 100755 --- a/build.py +++ b/build.py @@ -24,18 +24,21 @@ else: flutter_build_dir_2 = f'flutter/{flutter_build_dir}' skip_cargo = False + def get_arch() -> str: custom_arch = os.environ.get("ARCH") if custom_arch is None: return "amd64" return custom_arch + def system2(cmd): err = os.system(cmd) if err != 0: print(f"Error occurred when executing: {cmd}. Exiting.") sys.exit(-1) + def get_version(): with open("Cargo.toml", encoding="utf-8") as fh: for line in fh: @@ -196,9 +199,9 @@ def download_extract_features(features, res_dir): for (feat, feat_info) in features.items(): includes = feat_info['include'] if 'include' in feat_info and feat_info['include'] else [] - includes = [ re.compile(p) for p in includes ] + includes = [re.compile(p) for p in includes] excludes = feat_info['exclude'] if 'exclude' in feat_info and feat_info['exclude'] else [] - excludes = [ re.compile(p) for p in excludes ] + excludes = [re.compile(p) for p in excludes] print(f'{feat} download begin') download_filename = feat_info['zip_url'].split('/')[-1] @@ -350,6 +353,7 @@ def build_flutter_deb(version, features): os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version) os.chdir("..") + def build_deb_from_folder(version, binary_folder): os.chdir('flutter') system2('mkdir -p tmpdeb/usr/bin/') @@ -388,6 +392,7 @@ def build_deb_from_folder(version, binary_folder): os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version) os.chdir("..") + def build_flutter_dmg(version, features): if not skip_cargo: # set minimum osx build target, now is 10.14, which is the same as the flutter xcode project @@ -577,7 +582,7 @@ def main(): else: print('Not signed') else: - # buid deb package + # build deb package system2( 'mv target/release/bundle/deb/rustdesk*.deb ./rustdesk.deb') system2('dpkg-deb -R rustdesk.deb tmpdeb') diff --git a/libs/portable/generate.py b/libs/portable/generate.py index 640f2ae6a..61d8c78f7 100644 --- a/libs/portable/generate.py +++ b/libs/portable/generate.py @@ -1,4 +1,3 @@ -from ast import parse import os import optparse from hashlib import md5 @@ -47,7 +46,7 @@ def write_metadata(md5_table: dict, output_folder: str, exe: str): f.write((len(path)).to_bytes(length=length_count, byteorder='big')) f.write(path) # data length & compressed data - f.write((data_length).to_bytes( + f.write(data_length.to_bytes( length=length_count, byteorder='big')) f.write(compressed_data) # md5 code @@ -65,6 +64,8 @@ def build_portable(output_folder: str): # Linux: python3 generate.py -f ../rustdesk-portable-packer/test -o . -e ./test/main.py # Windows: python3 .\generate.py -f ..\rustdesk\flutter\build\windows\runner\Debug\ -o . -e ..\rustdesk\flutter\build\windows\runner\Debug\rustdesk.exe + + if __name__ == '__main__': parser = optparse.OptionParser() parser.add_option("-f", "--folder", dest="folder", From 55412b94d2386f309ccc0cbe351891ba12bbb59f Mon Sep 17 00:00:00 2001 From: jxd1337 Date: Sat, 28 Oct 2023 10:59:33 +0200 Subject: [PATCH 04/17] assert without redundant () --- res/lang.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/lang.py b/res/lang.py index 2ed549fe1..4655d2cbe 100644 --- a/res/lang.py +++ b/res/lang.py @@ -20,7 +20,7 @@ def line_split(line): toks = line.split('", "') if len(toks) != 2: print(line) - assert (0) + assert 0 # Replace fixed position. # Because toks[1] may be v") or v"), k = toks[0][toks[0].find('"') + 1:] From f6ee61f29e17153c8a11e4aeda19e2cc30f21102 Mon Sep 17 00:00:00 2001 From: Mr-Update <37781396+Mr-Update@users.noreply.github.com> Date: Sat, 28 Oct 2023 20:19:17 +0200 Subject: [PATCH 05/17] Update de.rs --- src/lang/de.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/de.rs b/src/lang/de.rs index fde9d132c..3fcd2fada 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -570,7 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Big tiles", "Große Kacheln"), ("Small tiles", "Kleine Kacheln"), ("List", "Liste"), - ("Virtual display", ""), - ("Plug out all", ""), + ("Virtual display", "Virtueller Bildschirm"), + ("Plug out all", "Alle ausschalten"), ].iter().cloned().collect(); } From f8d64528b5c20a21ce3d84925246e010ba8d40bd Mon Sep 17 00:00:00 2001 From: Andrzej Rudnik Date: Sat, 28 Oct 2023 20:19:50 +0200 Subject: [PATCH 06/17] Update pl.rs --- src/lang/pl.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 9c4101dfa..fbb04387d 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -274,7 +274,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Chat", "Czat"), ("Total", "Łącznie"), ("items", "elementów"), - ("Selected", "Zaznaczonych"), + ("Selected", "zaznaczonych"), ("Screen Capture", "Przechwytywanie ekranu"), ("Input Control", "Kontrola wejścia"), ("Audio Capture", "Przechwytywanie dźwięku"), @@ -564,13 +564,13 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("elevated_switch_display_msg", "Przełącz się na ekran główny, ponieważ wyświetlanie kilku ekranów nie jest obsługiwane przy podniesionych uprawnieniach."), ("Open in new window", "Otwórz w nowym oknie"), ("Show displays as individual windows", "Pokaż ekrany w osobnych oknach"), - ("Use all my displays for the remote session", ""), - ("selinux_tip", ""), - ("Change view", ""), - ("Big tiles", ""), - ("Small tiles", ""), - ("List", ""), - ("Virtual display", ""), - ("Plug out all", ""), + ("Use all my displays for the remote session", "Użyj wszystkich moich ekranów do zdalnej sesji"), + ("selinux_tip", "SELinux jest włączony na Twoim urządzeniu, co może przeszkodzić w uruchomieniu RustDesk po stronie kontrolowanej."), + ("Change view", "Zmień widok"), + ("Big tiles", "Duże kafelki"), + ("Small tiles", "Małe kafelki"), + ("List", "Lista"), + ("Virtual display", "Witualne ekrany"), + ("Plug out all", "Odłącz wszystko"), ].iter().cloned().collect(); } From 0b82874a5232a7defac3bc5c8eaa81dd048a107f Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Sun, 29 Oct 2023 11:45:00 +0800 Subject: [PATCH 07/17] patch: lossen x11 clipboard timeout this should make the clipboard reading more stable Signed-off-by: ClSlaid --- libs/clipboard/src/platform/unix/x11.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/clipboard/src/platform/unix/x11.rs b/libs/clipboard/src/platform/unix/x11.rs index e137deac2..72fa018e0 100644 --- a/libs/clipboard/src/platform/unix/x11.rs +++ b/libs/clipboard/src/platform/unix/x11.rs @@ -16,8 +16,7 @@ use super::{encode_path_to_uri, parse_plain_uri_list, SysClipboard}; static X11_CLIPBOARD: OnceCell = OnceCell::new(); -// this is tested on an Arch Linux with X11 -const X11_CLIPBOARD_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(70); +const X11_CLIPBOARD_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(130); fn get_clip() -> Result<&'static Clipboard, CliprdrError> { X11_CLIPBOARD.get_or_try_init(|| Clipboard::new().map_err(|_| CliprdrError::CliprdrInit)) @@ -68,7 +67,14 @@ impl X11Clipboard { match res { Ok(res) => Ok(res), Err(x11_clipboard::error::Error::UnexpectedType(_)) => Ok(vec![]), - Err(_) => Err(CliprdrError::ClipboardInternalError), + Err(x11_clipboard::error::Error::Timeout) => { + log::debug!("x11 clipboard get content timeout."); + Err(CliprdrError::ClipboardInternalError) + } + Err(e) => { + log::debug!("x11 clipboard get content fail: {:?}", e); + Err(CliprdrError::ClipboardInternalError) + } } } From fd1dc155768ac72a98e9b6c1ac09f22a10f5869b Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Sun, 29 Oct 2023 12:07:21 +0800 Subject: [PATCH 08/17] patch: re apply time limited api in common clipboard when no content in text clipboard, it will wait forever Signed-off-by: ClSlaid --- libs/clipboard/src/platform/unix/x11.rs | 4 +--- src/common.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/clipboard/src/platform/unix/x11.rs b/libs/clipboard/src/platform/unix/x11.rs index 72fa018e0..9f4c9e4c6 100644 --- a/libs/clipboard/src/platform/unix/x11.rs +++ b/libs/clipboard/src/platform/unix/x11.rs @@ -16,8 +16,6 @@ use super::{encode_path_to_uri, parse_plain_uri_list, SysClipboard}; static X11_CLIPBOARD: OnceCell = OnceCell::new(); -const X11_CLIPBOARD_TIMEOUT: std::time::Duration = std::time::Duration::from_millis(130); - fn get_clip() -> Result<&'static Clipboard, CliprdrError> { X11_CLIPBOARD.get_or_try_init(|| Clipboard::new().map_err(|_| CliprdrError::CliprdrInit)) } @@ -63,7 +61,7 @@ impl X11Clipboard { // NOTE: // # why not use `load_wait` // load_wait is likely to wait forever, which is not what we want - let res = get_clip()?.load(clip, target, prop, X11_CLIPBOARD_TIMEOUT); + let res = get_clip()?.load_wait(clip, target, prop); match res { Ok(res) => Ok(res), Err(x11_clipboard::error::Error::UnexpectedType(_)) => Ok(vec![]), diff --git a/src/common.rs b/src/common.rs index 7435f4c6e..4287d5aa3 100644 --- a/src/common.rs +++ b/src/common.rs @@ -87,7 +87,7 @@ impl ClipboardContext { let clip = self.clip; let prop = self.prop; - const TIMEOUT: std::time::Duration = std::time::Duration::from_millis(100); + const TIMEOUT: std::time::Duration = std::time::Duration::from_millis(120); let text_content = get_clipboard()? .load(clip, self.string_getter, prop, TIMEOUT) From a168fc37190d669403e1dd281fd763972ba53673 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Sun, 29 Oct 2023 08:57:49 +0100 Subject: [PATCH 09/17] Update Italian language --- src/lang/it.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/it.rs b/src/lang/it.rs index 87964f39a..b0a5218aa 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -570,7 +570,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Big tiles", "Icone grandi"), ("Small tiles", "Icone piccole"), ("List", "Elenco"), - ("Virtual display", ""), - ("Plug out all", ""), + ("Virtual display", "Scehrmo virtuale"), + ("Plug out all", "Scollega tutto"), ].iter().cloned().collect(); } From dc02ce3f979f70f0eaf673377535eaf0d7969ed7 Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Sun, 29 Oct 2023 19:50:31 +0800 Subject: [PATCH 10/17] patch: only enable file copy and paste under features Signed-off-by: ClSlaid --- Cargo.toml | 17 +++++--- libs/clipboard/Cargo.toml | 31 ++++++++++----- libs/clipboard/src/lib.rs | 5 ++- libs/clipboard/src/platform/mod.rs | 62 +++++++++++++++++------------- 4 files changed, 73 insertions(+), 42 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2f5d48c44..1670b4fbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,13 @@ linux_headless = ["pam" ] virtual_display_driver = ["virtual_display"] plugin_framework = [] linux-pkg-config = ["magnum-opus/linux-pkg-config", "scrap/linux-pkg-config"] +unix-file-copy-paste = [ + "dep:x11-clipboard", + "dep:x11rb", + "dep:percent-encoding", + "dep:once_cell", + "clipboard/unix-file-copy-paste", +] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -84,7 +91,7 @@ mac_address = "1.1" sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" } sys-locale = "0.3" enigo = { path = "libs/enigo", features = [ "with_serde" ] } -clipboard = { path = "libs/clipboard" } +clipboard = { path = "libs/clipboard", default-features = false } ctrlc = "3.2" arboard = "3.2" system_shutdown = "4.0" @@ -132,10 +139,10 @@ dbus = "0.9" dbus-crossroads = "0.5" pam = { git="https://github.com/fufesou/pam", optional = true } users = { version = "0.11" } -x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch"} -x11rb = {version = "0.12", features = ["all-extensions"]} -percent-encoding = "2.3" -once_cell = "1.18" +x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch", optional = true} +x11rb = {version = "0.12", features = ["all-extensions"], optional = true} +percent-encoding = {version = "2.3", optional = true} +once_cell = {version = "1.18", optional = true} [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.13" diff --git a/libs/clipboard/Cargo.toml b/libs/clipboard/Cargo.toml index 3de02f768..ef2755661 100644 --- a/libs/clipboard/Cargo.toml +++ b/libs/clipboard/Cargo.toml @@ -9,6 +9,19 @@ build = "build.rs" [build-dependencies] cc = "1.0" +[features] +default = ["unix-file-copy-paste"] +unix-file-copy-paste = [ +"dep:x11rb", +"dep:x11-clipboard", +"dep:rand", +"dep:fuser", +"dep:libc", +"dep:dashmap", +"dep:percent-encoding", +"dep:utf16string" +] + [dependencies] thiserror = "1.0" lazy_static = "1.4" @@ -18,12 +31,12 @@ hbb_common = { path = "../hbb_common" } parking_lot = {version = "0.12"} [target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies] -once_cell = "1.18" -x11rb = {version = "0.12", features = ["all-extensions"]} -rand = {version = "0.8"} -fuser = {version = "0.13"} -libc = {version = "0.2"} -dashmap = "5.5" -percent-encoding = "2.3" -utf16string = "0.2" -x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch"} +once_cell = {version = "1.18", optional = true} +x11rb = {version = "0.12", features = ["all-extensions"], optional = true} +rand = {version = "0.8", optional = true} +fuser = {version = "0.13", optional = true} +libc = {version = "0.2", optional = true} +dashmap = {version ="5.5", optional = true} +percent-encoding = {version ="2.3", optional = true} +utf16string = {version = "0.2", optional = true} +x11-clipboard = {git="https://github.com/clslaid/x11-clipboard", branch = "feat/store-batch", optional = true} diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 822d83a10..0e80cda2d 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -108,6 +108,7 @@ pub enum ClipboardFile { struct MsgChannel { peer_id: String, conn_id: i32, + #[allow(dead_code)] sender: UnboundedSender, receiver: Arc>>, } @@ -193,6 +194,7 @@ pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc crate::ResultType> { - use std::{fs::Permissions, os::unix::prelude::PermissionsExt}; + #[cfg(feature = "unix-file-copy-paste")] + { + use std::{fs::Permissions, os::unix::prelude::PermissionsExt}; - use hbb_common::{config::APP_NAME, log}; + use hbb_common::{config::APP_NAME, log}; - if !enable_files { - return Ok(Box::new(DummyCliprdrContext {}) as Box<_>); + if !_enable_files { + return Ok(Box::new(DummyCliprdrContext {}) as Box<_>); + } + + let timeout = std::time::Duration::from_secs(_response_wait_timeout_secs as u64); + + let app_name = APP_NAME.read().unwrap().clone(); + + let mnt_path = format!("/tmp/{}/{}", app_name, "cliprdr"); + + // this function must be called after the main IPC is up + std::fs::create_dir(&mnt_path).ok(); + std::fs::set_permissions(&mnt_path, Permissions::from_mode(0o777)).ok(); + + log::info!("clear previously mounted cliprdr FUSE"); + if let Err(e) = std::process::Command::new("umount").arg(&mnt_path).status() { + log::warn!("umount {:?} may fail: {:?}", mnt_path, e); + } + + let linux_ctx = unix::ClipboardContext::new(timeout, mnt_path.parse().unwrap())?; + log::debug!("start cliprdr FUSE"); + linux_ctx.run().expect("failed to start cliprdr FUSE"); + + Ok(Box::new(linux_ctx) as Box<_>) } - - let timeout = std::time::Duration::from_secs(response_wait_timeout_secs as u64); - - let app_name = APP_NAME.read().unwrap().clone(); - - let mnt_path = format!("/tmp/{}/{}", app_name, "cliprdr"); - - // this function must be called after the main IPC is up - std::fs::create_dir(&mnt_path).ok(); - std::fs::set_permissions(&mnt_path, Permissions::from_mode(0o777)).ok(); - - log::info!("clear previously mounted cliprdr FUSE"); - if let Err(e) = std::process::Command::new("umount").arg(&mnt_path).status() { - log::warn!("umount {:?} may fail: {:?}", mnt_path, e); - } - - let linux_ctx = unix::ClipboardContext::new(timeout, mnt_path.parse().unwrap())?; - log::debug!("start cliprdr FUSE"); - linux_ctx.run().expect("failed to start cliprdr FUSE"); - - Ok(Box::new(linux_ctx) as Box<_>) + #[cfg(not(feature = "unix-file-copy-paste"))] + return Ok(Box::new(DummyCliprdrContext {}) as Box<_>); } struct DummyCliprdrContext {} @@ -73,6 +80,7 @@ impl CliprdrServiceContext for DummyCliprdrContext { } } +#[cfg(feature = "unix-file-copy-paste")] // begin of epoch used by microsoft // 1601-01-01 00:00:00 + LDAP_EPOCH_DELTA*(100 ns) = 1970-01-01 00:00:00 #[cfg(target_os = "linux")] From 79f6b5c181b5869cfe741ba461b07fd423ab9c43 Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Sun, 29 Oct 2023 20:10:39 +0800 Subject: [PATCH 11/17] patch: forbid enable cliprdr without feature Signed-off-by: ClSlaid --- libs/clipboard/Cargo.toml | 3 ++- src/client/io_loop.rs | 5 ++++- src/common.rs | 12 ++++++------ src/ui_cm_interface.rs | 10 ++++------ src/ui_interface.rs | 4 +++- src/ui_session_interface.rs | 5 ++++- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/libs/clipboard/Cargo.toml b/libs/clipboard/Cargo.toml index ef2755661..6978ceb9a 100644 --- a/libs/clipboard/Cargo.toml +++ b/libs/clipboard/Cargo.toml @@ -19,7 +19,8 @@ unix-file-copy-paste = [ "dep:libc", "dep:dashmap", "dep:percent-encoding", -"dep:utf16string" +"dep:utf16string", +"dep:once_cell" ] [dependencies] diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index c4ca8dfa4..36cf38715 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -1704,7 +1704,10 @@ impl Remote { } fn check_clipboard_file_context(&self) { - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any( + target_os = "windows", + all(feature = "unix-file-copy-paste", target_os = "linux") + ))] { let enabled = *self.handler.server_file_transfer_enabled.read().unwrap() && self.handler.lc.read().unwrap().enable_file_transfer.v; diff --git a/src/common.rs b/src/common.rs index 4287d5aa3..27e32c98a 100644 --- a/src/common.rs +++ b/src/common.rs @@ -14,22 +14,22 @@ pub enum GrabState { #[cfg(not(any( target_os = "android", target_os = "ios", - all(target_os = "linux", not(feature = "wayland")) + all(target_os = "linux", feature = "unix-file-copy-paste") )))] pub use arboard::Clipboard as ClipboardContext; -#[cfg(all(target_os = "linux", not(feature = "wayland")))] +#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))] static X11_CLIPBOARD: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); -#[cfg(all(target_os = "linux", not(feature = "wayland")))] +#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))] fn get_clipboard() -> Result<&'static x11_clipboard::Clipboard, String> { X11_CLIPBOARD .get_or_try_init(|| x11_clipboard::Clipboard::new()) .map_err(|e| e.to_string()) } -#[cfg(all(target_os = "linux", not(feature = "wayland")))] +#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))] pub struct ClipboardContext { string_setter: x11rb::protocol::xproto::Atom, string_getter: x11rb::protocol::xproto::Atom, @@ -39,7 +39,7 @@ pub struct ClipboardContext { prop: x11rb::protocol::xproto::Atom, } -#[cfg(all(target_os = "linux", not(feature = "wayland")))] +#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))] fn parse_plain_uri_list(v: Vec) -> Result { let text = String::from_utf8(v).map_err(|_| "ConversionFailure".to_owned())?; let mut list = String::new(); @@ -56,7 +56,7 @@ fn parse_plain_uri_list(v: Vec) -> Result { Ok(list) } -#[cfg(all(target_os = "linux", not(feature = "wayland")))] +#[cfg(all(target_os = "linux", feature = "unix-file-copy-paste"))] impl ClipboardContext { pub fn new() -> Result { let clipboard = get_clipboard()?; diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 5baa852c3..5308305d1 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -575,12 +575,10 @@ pub async fn start_ipc(cm: ConnectionManager) { } }); - log::debug!( - "start_ipc enable context_send: {}", - Config::get_option("enable-file-transfer").is_empty() - ); - - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any( + target_os = "windows", + all(target_os = "linux", feature = "unix-file-copy-paste"), + ))] ContextSend::enable(Config::get_option("enable-file-transfer").is_empty()); match ipc::new_listener("_cm").await { diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 3e0de80db..39dd92158 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1030,7 +1030,9 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver Session { #[tokio::main(flavor = "current_thread")] pub async fn io_loop(handler: Session, round: u32) { // It is ok to call this function multiple times. - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any( + target_os = "windows", + all(target_os = "linux", feature = "unix-file-copy-paste") + ))] if !handler.is_file_transfer() && !handler.is_port_forward() { clipboard::ContextSend::enable(true); } From 80200a998390217bf2719a41f5751e6476909858 Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Sun, 29 Oct 2023 20:49:43 +0800 Subject: [PATCH 12/17] patch: add `has_file_clipboard` field to PeerInfo Signed-off-by: ClSlaid --- libs/hbb_common/protos/message.proto | 1 + src/client/io_loop.rs | 5 ++++- src/server/connection.rs | 7 +++++++ src/server/display_service.rs | 7 +++++++ src/ui_cm_interface.rs | 5 ++++- src/ui_interface.rs | 8 ++++++-- src/ui_session_interface.rs | 5 ++++- 7 files changed, 33 insertions(+), 5 deletions(-) diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index 454bc0d3d..438206966 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -104,6 +104,7 @@ message PeerInfo { // Use JSON's key-value format which is friendly for peer to handle. // NOTE: Only support one-level dictionaries (for peer to update), and the key is of type string. string platform_additions = 12; + bool has_file_clipboard = 13; } message LoginResponse { diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 36cf38715..2d46097ed 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -1706,7 +1706,10 @@ impl Remote { fn check_clipboard_file_context(&self) { #[cfg(any( target_os = "windows", - all(feature = "unix-file-copy-paste", target_os = "linux") + all( + feature = "unix-file-copy-paste", + any(target_os = "linux", target_os = "macos") + ) ))] { let enabled = *self.handler.server_file_transfer_enabled.read().unwrap() diff --git a/src/server/connection.rs b/src/server/connection.rs index d74f4815e..8927eaf11 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1019,6 +1019,13 @@ impl Connection { let mut pi = PeerInfo { username: username.clone(), version: VERSION.to_owned(), + has_file_clipboard: cfg!(any( + target_os = "windows", + all( + feature = "unix-file-copy-paste", + any(target_os = "linux", target_os = "macos") + ) + )), ..Default::default() }; diff --git a/src/server/display_service.rs b/src/server/display_service.rs index 30225e491..22103f790 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -153,6 +153,13 @@ pub fn new() -> GenericService { fn displays_to_msg(displays: Vec) -> Message { let mut pi = PeerInfo { + has_file_clipboard: cfg!(any( + target_os = "windows", + all( + feature = "unix-file-copy-paste", + any(target_os = "linux", target_os = "macos") + ) + )), ..Default::default() }; pi.displays = displays.clone(); diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 5308305d1..83c43d24b 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -577,7 +577,10 @@ pub async fn start_ipc(cm: ConnectionManager) { #[cfg(any( target_os = "windows", - all(target_os = "linux", feature = "unix-file-copy-paste"), + all( + any(target_os = "linux", target_os = "macos"), + feature = "unix-file-copy-paste" + ), ))] ContextSend::enable(Config::get_option("enable-file-transfer").is_empty()); diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 39dd92158..d60220634 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1030,8 +1030,12 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver(handler: Session, round: u32) { // It is ok to call this function multiple times. #[cfg(any( target_os = "windows", - all(target_os = "linux", feature = "unix-file-copy-paste") + all( + any(target_os = "linux", target_os = "macos"), + feature = "unix-file-copy-paste" + ) ))] if !handler.is_file_transfer() && !handler.is_port_forward() { clipboard::ContextSend::enable(true); From 7aee76f5dee626c7ceeb4044a1f2e3dae9c03afb Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Sun, 29 Oct 2023 23:11:30 +0800 Subject: [PATCH 13/17] patch: don't show enable file clipboard when anyone unsupporting Signed-off-by: ClSlaid --- flutter/lib/common/widgets/toolbar.dart | 4 +++- flutter/lib/consts.dart | 1 + libs/hbb_common/protos/message.proto | 1 - src/flutter_ffi.rs | 11 +++++++++++ src/server/connection.rs | 20 ++++++++++++-------- src/server/display_service.rs | 7 ------- src/ui/header.tis | 2 +- src/ui_interface.rs | 1 + 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/flutter/lib/common/widgets/toolbar.dart b/flutter/lib/common/widgets/toolbar.dart index 17c8883a5..0bead716f 100644 --- a/flutter/lib/common/widgets/toolbar.dart +++ b/flutter/lib/common/widgets/toolbar.dart @@ -436,7 +436,9 @@ Future> toolbarDisplayToggle( child: Text(translate('Mute')))); } // file copy and paste - if (perms['file'] != false) { + if (perms['file'] != false && + bind.mainHasFileClipboard() && + pi.platformAdditions.containsKey(kPlatformAdditionsHasFileClipboard)) { final option = 'enable-file-transfer'; final value = bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option); diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 073edbfec..460894c31 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -22,6 +22,7 @@ const String kPlatformAdditionsIsWayland = "is_wayland"; const String kPlatformAdditionsHeadless = "headless"; const String kPlatformAdditionsIsInstalled = "is_installed"; const String kPlatformAdditionsVirtualDisplays = "virtual_displays"; +const String kPlatformAdditionsHasFileClipboard = "has_file_clipboard"; const String kPeerPlatformWindows = "Windows"; const String kPeerPlatformLinux = "Linux"; diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index 438206966..454bc0d3d 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -104,7 +104,6 @@ message PeerInfo { // Use JSON's key-value format which is friendly for peer to handle. // NOTE: Only support one-level dictionaries (for peer to update), and the key is of type string. string platform_additions = 12; - bool has_file_clipboard = 13; } message LoginResponse { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 872d782d8..dc4a904d4 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1725,6 +1725,17 @@ pub fn main_use_texture_render() -> SyncReturn { } } +pub fn main_has_file_clipboard() -> SyncReturn { + let ret = cfg!(any( + target_os = "windows", + all( + feature = "unix-file-copy-paste", + any(target_os = "linux", target_os = "macos") + ) + )); + SyncReturn(ret) +} + pub fn cm_init() { #[cfg(not(any(target_os = "android", target_os = "ios")))] crate::flutter::connection_manager::cm_init(); diff --git a/src/server/connection.rs b/src/server/connection.rs index 8927eaf11..9601f3ca9 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1019,13 +1019,6 @@ impl Connection { let mut pi = PeerInfo { username: username.clone(), version: VERSION.to_owned(), - has_file_clipboard: cfg!(any( - target_os = "windows", - all( - feature = "unix-file-copy-paste", - any(target_os = "linux", target_os = "macos") - ) - )), ..Default::default() }; @@ -1069,7 +1062,18 @@ impl Connection { } } - #[cfg(any(target_os = "linux", target_os = "windows"))] + #[cfg(any( + target_os = "windows", + all( + any(target_os = "linux", target_os = "macos"), + feature = "unix-file-copy-paste" + ) + ))] + { + platform_additions.insert("has_file_clipboard".into(), json!(true)); + } + + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] if !platform_additions.is_empty() { pi.platform_additions = serde_json::to_string(&platform_additions).unwrap_or("".into()); } diff --git a/src/server/display_service.rs b/src/server/display_service.rs index 22103f790..30225e491 100644 --- a/src/server/display_service.rs +++ b/src/server/display_service.rs @@ -153,13 +153,6 @@ pub fn new() -> GenericService { fn displays_to_msg(displays: Vec) -> Message { let mut pi = PeerInfo { - has_file_clipboard: cfg!(any( - target_os = "windows", - all( - feature = "unix-file-copy-paste", - any(target_os = "linux", target_os = "macos") - ) - )), ..Default::default() }; pi.displays = displays.clone(); diff --git a/src/ui/header.tis b/src/ui/header.tis index e0af9eed7..b0b21bc5e 100644 --- a/src/ui/header.tis +++ b/src/ui/header.tis @@ -196,7 +196,7 @@ class Header: Reactor.Component { {!cursor_embedded &&
  • {svg_checkmark}{translate('Show remote cursor')}
  • }
  • {svg_checkmark}{translate('Show quality monitor')}
  • {audio_enabled ?
  • {svg_checkmark}{translate('Mute')}
  • : ""} - {((is_win && pi.platform == "Windows")||(is_linux && pi.platform == "Linux")) && file_enabled ?
  • {svg_checkmark}{translate('Allow file copy and paste')}
  • : ""} + {(is_win && pi.platform == "Windows") && file_enabled ?
  • {svg_checkmark}{translate('Allow file copy and paste')}
  • : ""} {keyboard_enabled && clipboard_enabled ?
  • {svg_checkmark}{translate('Disable clipboard')}
  • : ""} {keyboard_enabled ?
  • {svg_checkmark}{translate('Lock after session end')}
  • : ""} {keyboard_enabled && pi.platform == "Windows" ?
  • {svg_checkmark}{translate('Privacy mode')}
  • : ""} diff --git a/src/ui_interface.rs b/src/ui_interface.rs index d60220634..5379b4a55 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1008,6 +1008,7 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver Date: Sun, 29 Oct 2023 23:35:55 +0800 Subject: [PATCH 14/17] patch: make linux build ok Signed-off-by: ClSlaid --- libs/clipboard/src/platform/fuse.rs | 1 - libs/clipboard/src/platform/mod.rs | 9 +++---- libs/clipboard/src/platform/unix/mod.rs | 11 +++++++- src/client/io_loop.rs | 28 ++++++++++---------- src/lib.rs | 2 +- src/server/connection.rs | 14 +++++----- src/ui_cm_interface.rs | 34 ++++++++++++------------- src/ui_interface.rs | 4 +-- 8 files changed, 55 insertions(+), 48 deletions(-) diff --git a/libs/clipboard/src/platform/fuse.rs b/libs/clipboard/src/platform/fuse.rs index 9294ac1db..6c5bbcdd2 100644 --- a/libs/clipboard/src/platform/fuse.rs +++ b/libs/clipboard/src/platform/fuse.rs @@ -40,7 +40,6 @@ use utf16string::WStr; use crate::{send_data, ClipboardFile, CliprdrError}; -#[cfg(target_os = "linux")] use super::LDAP_EPOCH_DELTA; /// fuse server ready retry max times diff --git a/libs/clipboard/src/platform/mod.rs b/libs/clipboard/src/platform/mod.rs index 1d9a96644..9f76fa8bb 100644 --- a/libs/clipboard/src/platform/mod.rs +++ b/libs/clipboard/src/platform/mod.rs @@ -21,7 +21,7 @@ pub mod fuse; #[cfg(feature = "unix-file-copy-paste")] #[cfg(any(target_os = "linux", target_os = "macos"))] pub mod unix; -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "macos"))] pub fn create_cliprdr_context( _enable_files: bool, _enable_others: bool, @@ -52,11 +52,11 @@ pub fn create_cliprdr_context( log::warn!("umount {:?} may fail: {:?}", mnt_path, e); } - let linux_ctx = unix::ClipboardContext::new(timeout, mnt_path.parse().unwrap())?; + let unix_ctx = unix::ClipboardContext::new(timeout, mnt_path.parse().unwrap())?; log::debug!("start cliprdr FUSE"); - linux_ctx.run().expect("failed to start cliprdr FUSE"); + unix_ctx.run().expect("failed to start cliprdr FUSE"); - Ok(Box::new(linux_ctx) as Box<_>) + Ok(Box::new(unix_ctx) as Box<_>) } #[cfg(not(feature = "unix-file-copy-paste"))] return Ok(Box::new(DummyCliprdrContext {}) as Box<_>); @@ -83,5 +83,4 @@ impl CliprdrServiceContext for DummyCliprdrContext { #[cfg(feature = "unix-file-copy-paste")] // begin of epoch used by microsoft // 1601-01-01 00:00:00 + LDAP_EPOCH_DELTA*(100 ns) = 1970-01-01 00:00:00 -#[cfg(target_os = "linux")] const LDAP_EPOCH_DELTA: u64 = 116444772610000000; diff --git a/libs/clipboard/src/platform/unix/mod.rs b/libs/clipboard/src/platform/unix/mod.rs index b74c583c8..39b851e10 100644 --- a/libs/clipboard/src/platform/unix/mod.rs +++ b/libs/clipboard/src/platform/unix/mod.rs @@ -19,14 +19,17 @@ use crate::{ }; use self::local_file::LocalFile; +#[cfg(target_os = "linux")] use self::url::{encode_path_to_uri, parse_plain_uri_list}; use super::fuse::FuseServer; -#[cfg(not(feature = "wayland"))] +#[cfg(target_os = "linux")] pub mod x11; pub mod local_file; + +#[cfg(target_os = "linux")] pub mod url; // not actual format id, just a placeholder @@ -66,6 +69,7 @@ trait SysClipboard: Send + Sync { fn get_file_list(&self) -> Vec; } +#[cfg(target_os = "linux")] fn get_sys_clipboard(ignore_path: &PathBuf) -> Result, CliprdrError> { #[cfg(feature = "wayland")] { @@ -79,6 +83,11 @@ fn get_sys_clipboard(ignore_path: &PathBuf) -> Result, Cli } } +#[cfg(target_os = "macos")] +fn get_sys_clipboard(ignore_path: &PathBuf) -> Result, CliprdrError> { + unimplemented!() +} + #[derive(Debug)] enum FileContentsRequest { Size { diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 2d46097ed..377da85e3 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -7,14 +7,14 @@ use std::{ }, }; -#[cfg(any(target_os = "windows", target_os = "linux"))] +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] use clipboard::ContextSend; use crossbeam_queue::ArrayQueue; #[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::sleep; #[cfg(not(target_os = "ios"))] use hbb_common::tokio::sync::mpsc::error::TryRecvError; -#[cfg(any(target_os = "windows", target_os = "linux"))] +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] use hbb_common::tokio::sync::Mutex as TokioMutex; use hbb_common::{ allow_err, @@ -66,7 +66,7 @@ pub struct Remote { last_update_jobs_status: (Instant, HashMap), is_connected: bool, first_frame: bool, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] client_conn_id: i32, // used for file clipboard data_count: Arc, frame_count_map: Arc>>, @@ -101,7 +101,7 @@ impl Remote { last_update_jobs_status: (Instant::now(), Default::default()), is_connected: false, first_frame: false, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] client_conn_id: 0, data_count: Arc::new(AtomicUsize::new(0)), frame_count_map, @@ -146,14 +146,14 @@ impl Remote { } // just build for now - #[cfg(not(any(target_os = "windows", target_os = "linux")))] + #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))] let (_tx_holder, mut rx_clip_client) = mpsc::unbounded_channel::(); - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] let (_tx_holder, rx) = mpsc::unbounded_channel(); - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] let mut rx_clip_client_lock = Arc::new(TokioMutex::new(rx)); - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] { let is_conn_not_default = self.handler.is_file_transfer() || self.handler.is_port_forward() @@ -164,7 +164,7 @@ impl Remote { clipboard::get_rx_cliprdr_client(&self.handler.id); }; } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] let mut rx_clip_client = rx_clip_client_lock.lock().await; let mut status_timer = time::interval(Duration::new(1, 0)); @@ -210,7 +210,7 @@ impl Remote { } } _msg = rx_clip_client.recv() => { - #[cfg(any(target_os="windows", target_os="linux"))] + #[cfg(any(target_os="windows", target_os="linux", target_os = "macos"))] self.handle_local_clipboard_msg(&mut peer, _msg).await; } _ = self.timer.tick() => { @@ -278,7 +278,7 @@ impl Remote { Client::try_stop_clipboard(&self.handler.id); } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] if _set_disconnected_ok { let conn_id = self.client_conn_id; log::debug!("try empty cliprdr for conn_id {}", conn_id); @@ -289,7 +289,7 @@ impl Remote { } } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] async fn handle_local_clipboard_msg( &self, peer: &mut crate::client::FramedStream, @@ -1143,7 +1143,7 @@ impl Remote { } } } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] Some(message::Union::Cliprdr(clip)) => { self.handle_cliprdr_msg(clip); } @@ -1718,7 +1718,7 @@ impl Remote { } } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] fn handle_cliprdr_msg(&self, clip: hbb_common::message_proto::Cliprdr) { log::debug!("handling cliprdr msg from server peer"); #[cfg(feature = "flutter")] diff --git a/src/lib.rs b/src/lib.rs index 631766a2d..8aa520579 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,7 +58,7 @@ mod ui_session_interface; mod hbbs_http; -#[cfg(any(target_os = "windows", target_os = "linux"))] +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] pub mod clipboard_file; #[cfg(windows)] diff --git a/src/server/connection.rs b/src/server/connection.rs index 9601f3ca9..4bbfd6211 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -1,5 +1,5 @@ use super::{input_service::*, *}; -#[cfg(any(target_os = "windows", target_os = "linux"))] +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] use crate::clipboard_file::*; #[cfg(not(any(target_os = "android", target_os = "ios")))] use crate::common::update_clipboard; @@ -192,7 +192,7 @@ pub struct Connection { // by peer disable_audio: bool, // by peer - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] enable_file_transfer: bool, // by peer audio_sender: Option, @@ -330,7 +330,7 @@ impl Connection { show_remote_cursor: false, ip: "".to_owned(), disable_audio: false, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] enable_file_transfer: false, disable_clipboard: false, disable_keyboard: false, @@ -1032,7 +1032,7 @@ impl Connection { pi.hostname = DEVICE_NAME.lock().unwrap().clone(); pi.platform = "Android".into(); } - #[cfg(any(target_os = "linux", target_os = "windows"))] + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] let mut platform_additions = serde_json::Map::new(); #[cfg(target_os = "linux")] { @@ -1247,7 +1247,7 @@ impl Connection { self.audio && !self.disable_audio } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] fn file_transfer_enabled(&self) -> bool { self.file && self.enable_file_transfer } @@ -1817,7 +1817,7 @@ impl Connection { } Some(message::Union::Cliprdr(_clip)) => { - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] if let Some(clip) = msg_2_clip(_clip) { log::debug!("got clipfile from client peer"); self.send_to_cm(ipc::Data::ClipboardFile(clip)) @@ -2401,7 +2401,7 @@ impl Connection { } } } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] if let Ok(q) = o.enable_file_transfer.enum_value() { if q != BoolOption::NotSet { self.enable_file_transfer = q == BoolOption::Yes; diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 83c43d24b..a20997dc9 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -1,6 +1,6 @@ #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] use std::iter::FromIterator; -#[cfg(any(target_os = "windows", target_os = "linux"))] +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] use std::sync::Arc; use std::{ collections::HashMap, @@ -15,11 +15,11 @@ use std::{ use crate::ipc::Connection; #[cfg(not(any(target_os = "ios")))] use crate::ipc::{self, Data}; -#[cfg(any(target_os = "windows", target_os = "linux"))] +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] use clipboard::ContextSend; #[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::tokio::sync::mpsc::unbounded_channel; -#[cfg(any(target_os = "windows", target_os = "linux"))] +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] use hbb_common::tokio::sync::Mutex as TokioMutex; use hbb_common::{ allow_err, @@ -70,9 +70,9 @@ struct IpcTaskRunner { close: bool, running: bool, conn_id: i32, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] file_transfer_enabled: bool, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] file_transfer_enabled_peer: bool, } @@ -165,7 +165,7 @@ impl ConnectionManager { } #[inline] - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] fn is_authorized(&self, id: i32) -> bool { CLIENTS .read() @@ -186,7 +186,7 @@ impl ConnectionManager { .map(|c| c.disconnected = true); } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] { let _ = ContextSend::proc(|context| -> ResultType<()> { context.empty_clipboard(id)?; @@ -330,14 +330,14 @@ impl IpcTaskRunner { // for tmp use, without real conn id let mut write_jobs: Vec = Vec::new(); - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] let is_authorized = self.cm.is_authorized(self.conn_id); - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] let rx_clip1; let mut rx_clip; let _tx_clip; - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] if self.conn_id > 0 && is_authorized { log::debug!("Clipboard is enabled from client peer: type 1"); rx_clip1 = clipboard::get_rx_cliprdr_server(self.conn_id); @@ -349,12 +349,12 @@ impl IpcTaskRunner { rx_clip1 = Arc::new(TokioMutex::new(rx_clip2)); rx_clip = rx_clip1.lock().await; } - #[cfg(not(any(target_os = "windows", target_os = "linux")))] + #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))] { (_tx_clip, rx_clip) = unbounded_channel::(); } - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] { if ContextSend::is_enabled() { log::debug!("Clipboard is enabled"); @@ -382,7 +382,7 @@ impl IpcTaskRunner { log::debug!("conn_id: {}", id); self.cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, from_switch,self.tx.clone()); self.conn_id = id; - #[cfg(any(target_os = "linux", target_os = "windows"))] + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] { self.file_transfer_enabled = _file_transfer_enabled; } @@ -425,7 +425,7 @@ impl IpcTaskRunner { } #[cfg(not(any(target_os = "android", target_os = "ios")))] Data::ClipboardFile(_clip) => { - #[cfg(any(target_os = "windows", target_os="linux"))] + #[cfg(any(target_os = "windows", target_os="linux", target_os = "macos"))] { let is_stopping_allowed = _clip.is_stopping_allowed_from_peer(); let is_clipboard_enabled = ContextSend::is_enabled(); @@ -504,7 +504,7 @@ impl IpcTaskRunner { }, clip_file = rx_clip.recv() => match clip_file { Some(_clip) => { - #[cfg(any(target_os = "windows", target_os ="linux"))] + #[cfg(any(target_os = "windows", target_os ="linux", target_os = "macos"))] { let is_stopping_allowed = _clip.is_stopping_allowed(); let is_clipboard_enabled = ContextSend::is_enabled(); @@ -543,9 +543,9 @@ impl IpcTaskRunner { close: true, running: true, conn_id: 0, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] file_transfer_enabled: false, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] file_transfer_enabled_peer: false, }; diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 5379b4a55..7cabdf790 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -1007,7 +1007,7 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver Date: Mon, 30 Oct 2023 00:06:53 +0800 Subject: [PATCH 15/17] patch: add feature to build script Signed-off-by: ClSlaid --- build.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/build.py b/build.py index 42dc8d6de..1f54f3403 100755 --- a/build.py +++ b/build.py @@ -24,18 +24,21 @@ else: flutter_build_dir_2 = f'flutter/{flutter_build_dir}' skip_cargo = False + def get_arch() -> str: custom_arch = os.environ.get("ARCH") if custom_arch is None: return "amd64" return custom_arch + def system2(cmd): err = os.system(cmd) if err != 0: print(f"Error occurred when executing: {cmd}. Exiting.") sys.exit(-1) + def get_version(): with open("Cargo.toml", encoding="utf-8") as fh: for line in fh: @@ -123,6 +126,11 @@ def make_parser(): action='store_true', help='Build windows portable' ) + parser.add_argument( + '--unix-file-copy-paste', + action='store_true', + help='Build with unix file copy paste feature' + ) parser.add_argument( '--flatpak', action='store_true', @@ -185,6 +193,7 @@ def download_extract_features(features, res_dir): import re proxy = '' + def req(url): if not proxy: return url @@ -195,10 +204,12 @@ def download_extract_features(features, res_dir): return r for (feat, feat_info) in features.items(): - includes = feat_info['include'] if 'include' in feat_info and feat_info['include'] else [] - includes = [ re.compile(p) for p in includes ] - excludes = feat_info['exclude'] if 'exclude' in feat_info and feat_info['exclude'] else [] - excludes = [ re.compile(p) for p in excludes ] + includes = feat_info['include'] if 'include' in feat_info and feat_info['include'] else [ + ] + includes = [re.compile(p) for p in includes] + excludes = feat_info['exclude'] if 'exclude' in feat_info and feat_info['exclude'] else [ + ] + excludes = [re.compile(p) for p in excludes] print(f'{feat} download begin') download_filename = feat_info['zip_url'].split('/')[-1] @@ -272,6 +283,8 @@ def get_features(args): features.append('flatpak') if args.appimage: features.append('appimage') + if args.unix_file_copy_paste: + features.append('unix-file-copy-paste') print("features:", features) return features @@ -350,6 +363,7 @@ def build_flutter_deb(version, features): os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version) os.chdir("..") + def build_deb_from_folder(version, binary_folder): os.chdir('flutter') system2('mkdir -p tmpdeb/usr/bin/') @@ -388,10 +402,12 @@ def build_deb_from_folder(version, binary_folder): os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version) os.chdir("..") + def build_flutter_dmg(version, features): if not skip_cargo: # set minimum osx build target, now is 10.14, which is the same as the flutter xcode project - system2(f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --lib --release') + system2( + f'MACOSX_DEPLOYMENT_TARGET=10.14 cargo build --features {features} --lib --release') # copy dylib system2( "cp target/release/liblibrustdesk.dylib target/release/librustdesk.dylib") @@ -557,7 +573,8 @@ def main(): codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app/Contents/MacOS/* codesign -s "Developer ID Application: {0}" --force --options runtime ./target/release/bundle/osx/RustDesk.app '''.format(pa)) - system2('create-dmg "RustDesk %s.dmg" "target/release/bundle/osx/RustDesk.app"' % version) + system2( + 'create-dmg "RustDesk %s.dmg" "target/release/bundle/osx/RustDesk.app"' % version) os.rename('RustDesk %s.dmg' % version, 'rustdesk-%s.dmg' % version) if pa: From 43aa62e2129adf16b5b8fa3147511eaaa65bba6a Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Mon, 30 Oct 2023 12:00:44 +0800 Subject: [PATCH 16/17] patch: fix active enable of file copy paste Signed-off-by: ClSlaid --- libs/clipboard/src/context_send.rs | 13 ++++++++++ libs/clipboard/src/platform/unix/mod.rs | 3 +-- libs/clipboard/src/platform/unix/x11.rs | 33 ++++--------------------- src/client/io_loop.rs | 6 +++++ 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/libs/clipboard/src/context_send.rs b/libs/clipboard/src/context_send.rs index 64ab85983..f3606509f 100644 --- a/libs/clipboard/src/context_send.rs +++ b/libs/clipboard/src/context_send.rs @@ -47,6 +47,19 @@ impl ContextSend { } } + /// make sure the clipboard context is enabled. + pub fn make_sure_enabled() -> ResultType<()> { + let mut lock = CONTEXT_SEND.addr.lock().unwrap(); + if lock.is_some() { + return Ok(()); + } + + let ctx = crate::create_cliprdr_context(true, false, CLIPBOARD_RESPONSE_WAIT_TIMEOUT_SECS)?; + *lock = Some(ctx); + log::info!("clipboard context for file transfer recreated."); + Ok(()) + } + pub fn proc) -> ResultType<()>>( f: F, ) -> ResultType<()> { diff --git a/libs/clipboard/src/platform/unix/mod.rs b/libs/clipboard/src/platform/unix/mod.rs index 39b851e10..cd499d0d8 100644 --- a/libs/clipboard/src/platform/unix/mod.rs +++ b/libs/clipboard/src/platform/unix/mod.rs @@ -63,7 +63,6 @@ fn add_remote_format(local_name: &str, remote_id: i32) { trait SysClipboard: Send + Sync { fn start(&self); - fn stop(&self); fn set_file_list(&self, paths: &[PathBuf]) -> Result<(), CliprdrError>; fn get_file_list(&self) -> Vec; @@ -524,7 +523,7 @@ impl CliprdrServiceContext for ClipboardContext { if let Some(fuse_handle) = self.fuse_handle.lock().take() { fuse_handle.join(); } - self.clipboard.stop(); + // we don't stop the clipboard, keep listening in case of restart Ok(()) } diff --git a/libs/clipboard/src/platform/unix/x11.rs b/libs/clipboard/src/platform/unix/x11.rs index 9f4c9e4c6..4ca3a2c0b 100644 --- a/libs/clipboard/src/platform/unix/x11.rs +++ b/libs/clipboard/src/platform/unix/x11.rs @@ -1,8 +1,4 @@ -use std::{ - collections::BTreeSet, - path::PathBuf, - sync::atomic::{AtomicBool, Ordering}, -}; +use std::{collections::BTreeSet, path::PathBuf}; use hbb_common::log; use once_cell::sync::OnceCell; @@ -21,7 +17,6 @@ fn get_clip() -> Result<&'static Clipboard, CliprdrError> { } pub struct X11Clipboard { - stop: AtomicBool, ignore_path: PathBuf, text_uri_list: Atom, gnome_copied_files: Atom, @@ -47,7 +42,6 @@ impl X11Clipboard { .map_err(|_| CliprdrError::CliprdrInit)?; Ok(Self { ignore_path: ignore_path.to_owned(), - stop: AtomicBool::new(false), text_uri_list, gnome_copied_files, nautilus_clipboard, @@ -85,22 +79,12 @@ impl X11Clipboard { } fn wait_file_list(&self) -> Result>, CliprdrError> { - if self.stop.load(Ordering::Relaxed) { - return Ok(None); - } let v = self.load(self.text_uri_list)?; let p = parse_plain_uri_list(v)?; Ok(Some(p)) } } -impl X11Clipboard { - #[inline] - fn is_stopped(&self) -> bool { - self.stop.load(Ordering::Relaxed) - } -} - impl SysClipboard for X11Clipboard { fn set_file_list(&self, paths: &[PathBuf]) -> Result<(), CliprdrError> { *self.former_file_list.lock() = paths.to_vec(); @@ -118,13 +102,11 @@ impl SysClipboard for X11Clipboard { .map_err(|_| CliprdrError::ClipboardInternalError) } - fn stop(&self) { - self.stop.store(true, Ordering::Relaxed); - } - fn start(&self) { - self.stop.store(false, Ordering::Relaxed); - + { + // clear cached file list + *self.former_file_list.lock() = vec![]; + } loop { let sth = match self.wait_file_list() { Ok(sth) => sth, @@ -135,11 +117,6 @@ impl SysClipboard for X11Clipboard { } }; - if self.is_stopped() { - std::thread::sleep(std::time::Duration::from_millis(100)); - continue; - } - let Some(paths) = sth else { // just sleep std::thread::sleep(std::time::Duration::from_millis(100)); diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 377da85e3..ca5ffee3b 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -317,6 +317,9 @@ impl Remote { if stop { ContextSend::set_is_stopped(); } else { + if let Err(e) = ContextSend::make_sure_enabled() { + log::error!("failed to restart clipboard context: {}", e); + }; log::debug!("Send system clipboard message to remote"); let msg = crate::clipboard_file::clip_2_msg(clip); allow_err!(peer.send(&msg).await); @@ -1742,6 +1745,9 @@ impl Remote { "Process clipboard message from server peer, stop: {}, is_stopping_allowed: {}, file_transfer_enabled: {}", stop, is_stopping_allowed, file_transfer_enabled); if !stop { + if let Err(e) = ContextSend::make_sure_enabled() { + log::error!("failed to restart clipboard context: {}", e); + }; let _ = ContextSend::proc(|context| -> ResultType<()> { context .server_clip_file(self.client_conn_id, clip) From fdc4d6dda9c2060f104324bcd7cd192660deafd1 Mon Sep 17 00:00:00 2001 From: ClSlaid Date: Mon, 30 Oct 2023 15:09:39 +0800 Subject: [PATCH 17/17] patch: remove redundant features Signed-off-by: ClSlaid --- Cargo.toml | 2 +- libs/clipboard/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1670b4fbb..dbeaf68ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,7 +91,7 @@ mac_address = "1.1" sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" } sys-locale = "0.3" enigo = { path = "libs/enigo", features = [ "with_serde" ] } -clipboard = { path = "libs/clipboard", default-features = false } +clipboard = { path = "libs/clipboard" } ctrlc = "3.2" arboard = "3.2" system_shutdown = "4.0" diff --git a/libs/clipboard/Cargo.toml b/libs/clipboard/Cargo.toml index 6978ceb9a..182e73002 100644 --- a/libs/clipboard/Cargo.toml +++ b/libs/clipboard/Cargo.toml @@ -10,7 +10,7 @@ build = "build.rs" cc = "1.0" [features] -default = ["unix-file-copy-paste"] +default = [] unix-file-copy-paste = [ "dep:x11rb", "dep:x11-clipboard",