mirror of
https://github.com/rustdesk/rustdesk.git
synced 2025-01-19 08:23:01 +08:00
feat(part): implement fuse support for linux clipboard
Signed-off-by: 蔡略 <cailue@bupt.edu.cn>
This commit is contained in:
parent
c25d648321
commit
4f7036a405
156
Cargo.lock
generated
156
Cargo.lock
generated
@ -243,7 +243,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"thiserror",
|
||||
"winapi 0.3.9",
|
||||
"x11rb",
|
||||
"x11rb 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -932,11 +932,20 @@ name = "clipboard"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"dashmap",
|
||||
"fuser",
|
||||
"hbb_common",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
"serde 1.0.163",
|
||||
"serde_derive",
|
||||
"thiserror",
|
||||
"utf16string",
|
||||
"x11-clipboard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1375,6 +1384,19 @@ dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "5.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"hashbrown 0.14.0",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dasp"
|
||||
version = "0.11.0"
|
||||
@ -2212,6 +2234,21 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||
|
||||
[[package]]
|
||||
name = "fuser"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21370f84640642c8ea36dfb2a6bfc4c55941f476fcf431f6fef25a5ddcf0169b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"memchr",
|
||||
"page_size",
|
||||
"pkg-config",
|
||||
"smallvec",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.28"
|
||||
@ -2422,6 +2459,16 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.9"
|
||||
@ -2842,6 +2889,12 @@ dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
|
||||
[[package]]
|
||||
name = "hbb_common"
|
||||
version = "0.1.0"
|
||||
@ -3122,7 +3175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3559,9 +3612,9 @@ checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"scopeguard",
|
||||
@ -4133,9 +4186,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
@ -4162,7 +4215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
|
||||
dependencies = [
|
||||
"dlv-list",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4210,6 +4263,16 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "page_size"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b7663cbd190cfd818d08efa8497f6cd383076688c49a391ef7c0d03cd12b561"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pam"
|
||||
version = "0.7.0"
|
||||
@ -4300,15 +4363,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.7"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
||||
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"redox_syscall 0.3.5",
|
||||
"smallvec",
|
||||
"windows-sys 0.45.0",
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4354,9 +4417,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
@ -6211,7 +6274,7 @@ dependencies = [
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"hashbrown",
|
||||
"hashbrown 0.12.3",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
"tokio",
|
||||
@ -6500,6 +6563,15 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16string"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b62a1e85e12d5d712bf47a85f426b73d303e2d00a90de5f3004df3596e9d216"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
@ -7194,6 +7266,15 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11-clipboard"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b41aca1115b1f195f21c541c5efb423470848d48143127d0f07f8b90c27440df"
|
||||
dependencies = [
|
||||
"x11rb 0.12.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11-dl"
|
||||
version = "2.21.0"
|
||||
@ -7211,11 +7292,24 @@ version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"gethostname 0.2.3",
|
||||
"nix 0.24.3",
|
||||
"winapi 0.3.9",
|
||||
"winapi-wsapoll",
|
||||
"x11rb-protocol",
|
||||
"x11rb-protocol 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a"
|
||||
dependencies = [
|
||||
"gethostname 0.3.0",
|
||||
"nix 0.26.2",
|
||||
"winapi 0.3.9",
|
||||
"winapi-wsapoll",
|
||||
"x11rb-protocol 0.12.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7227,6 +7321,15 @@ dependencies = [
|
||||
"nix 0.24.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb-protocol"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc"
|
||||
dependencies = [
|
||||
"nix 0.26.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xdg-home"
|
||||
version = "1.0.0"
|
||||
@ -7310,6 +7413,27 @@ dependencies = [
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3b9c234616391070b0b173963ebc65a9195068e7ed3731c6edac2ec45ebe106"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f7f3a471f98d0a61c34322fbbfd10c384b07687f680d4119813713f72308d91"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.63",
|
||||
"quote 1.0.27",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.5"
|
||||
|
@ -15,3 +15,14 @@ lazy_static = "1.4"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
hbb_common = { path = "../hbb_common" }
|
||||
parking_lot = {version = "0.12"}
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||
rand = {version = "0.8"}
|
||||
fuser = {version = "0.13"}
|
||||
libc = {version = "0.2"}
|
||||
rayon = {version = "1.7"}
|
||||
dashmap = "5.5"
|
||||
percent-encoding = "2.3"
|
||||
utf16string = "0.2"
|
||||
x11-clipboard = "0.8"
|
||||
|
@ -44,11 +44,9 @@ impl ContextSend {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let Some(_clp) = lock.take() {
|
||||
*lock = None;
|
||||
log::info!("clipboard context for file transfer destroyed.");
|
||||
}
|
||||
} else if let Some(_clp) = lock.take() {
|
||||
*lock = None;
|
||||
log::info!("clipboard context for file transfer destroyed.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,14 @@ pub enum CliprdrError {
|
||||
CliprdrOutOfMemory,
|
||||
#[error("cliprdr internal error")]
|
||||
ClipboardInternalError,
|
||||
#[error("cliprdr occupied")]
|
||||
ClipboardOccupied,
|
||||
#[error("content not available")]
|
||||
ContentNotAvailable,
|
||||
#[error("conversion failure")]
|
||||
ConversionFailure,
|
||||
#[error("unknown cliprdr error")]
|
||||
Unknown(u32),
|
||||
Unknown { description: String },
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
1383
libs/clipboard/src/platform/fuse.rs
Normal file
1383
libs/clipboard/src/platform/fuse.rs
Normal file
File diff suppressed because it is too large
Load Diff
135
libs/clipboard/src/platform/linux/mod.rs
Normal file
135
libs/clipboard/src/platform/linux/mod.rs
Normal file
@ -0,0 +1,135 @@
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::CliprdrError;
|
||||
|
||||
use super::fuse::{self, FuseServer};
|
||||
|
||||
#[cfg(not(feature = "wayland"))]
|
||||
pub mod x11;
|
||||
|
||||
trait SysClipboard {
|
||||
fn wait_file_list(&self) -> Result<Vec<PathBuf>, CliprdrError>;
|
||||
fn set_file_list(&self, paths: &[PathBuf]) -> Result<(), CliprdrError>;
|
||||
}
|
||||
|
||||
fn get_sys_clipboard() -> Box<dyn SysClipboard> {
|
||||
#[cfg(feature = "wayland")]
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
#[cfg(not(feature = "wayland"))]
|
||||
{
|
||||
pub use x11::*;
|
||||
X11Clipboard::new()
|
||||
}
|
||||
}
|
||||
|
||||
// on x11, path will be encode as
|
||||
// "/home/rustdesk/pictures/🖼️.png" -> "file:///home/rustdesk/pictures/%F0%9F%96%BC%EF%B8%8F.png"
|
||||
// url encode and decode is needed
|
||||
const ENCODE_SET: percent_encoding::AsciiSet = percent_encoding::CONTROLS.add(b' ').remove(b'/');
|
||||
|
||||
fn encode_path_to_uri(path: &PathBuf) -> String {
|
||||
let encoded = percent_encoding::percent_encode(path.to_str().unwrap().as_bytes(), &ENCODE_SET)
|
||||
.to_string();
|
||||
format!("file://{}", encoded)
|
||||
}
|
||||
|
||||
fn parse_uri_to_path(encoded_uri: &str) -> Result<PathBuf, CliprdrError> {
|
||||
let encoded_path = encoded_uri.trim_start_matches("file://");
|
||||
let path_str = percent_encoding::percent_decode_str(encoded_path)
|
||||
.decode_utf8()
|
||||
.map_err(|_| CliprdrError::ConversionFailure)?;
|
||||
let path_str = path_str.to_string();
|
||||
|
||||
Ok(Path::new(&path_str).to_path_buf())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod uri_test {
|
||||
#[test]
|
||||
fn test_conversion() {
|
||||
let path = std::path::PathBuf::from("/home/rustdesk/pictures/🖼️.png");
|
||||
let uri = super::encode_path_to_uri(&path);
|
||||
assert_eq!(
|
||||
uri,
|
||||
"file:///home/rustdesk/pictures/%F0%9F%96%BC%EF%B8%8F.png"
|
||||
);
|
||||
let convert_back = super::parse_uri_to_path(&uri).unwrap();
|
||||
assert_eq!(path, convert_back);
|
||||
}
|
||||
}
|
||||
|
||||
// helper parse function
|
||||
// convert 'text/uri-list' data to a list of valid Paths
|
||||
// # Note
|
||||
// - none utf8 data will lead to error
|
||||
fn parse_plain_uri_list(v: Vec<u8>) -> Result<Vec<PathBuf>, CliprdrError> {
|
||||
let text = String::from_utf8(v).map_err(|_| CliprdrError::ConversionFailure)?;
|
||||
parse_uri_list(&text)
|
||||
}
|
||||
|
||||
// helper parse function
|
||||
// convert "x-special/gnome-copied-files", "x-special/x-kde-cutselection" and "x-special/nautilus-clipboard" data to a list of valid Paths
|
||||
// # Note
|
||||
// - none utf8 data will lead to error
|
||||
fn parse_de_uri_list(v: Vec<u8>) -> Result<Vec<PathBuf>, CliprdrError> {
|
||||
let text = String::from_utf8(v).map_err(|_| CliprdrError::ConversionFailure)?;
|
||||
let plain_list = text
|
||||
.trim_start_matches("copy\n")
|
||||
.trim_start_matches("cut\n");
|
||||
parse_uri_list(plain_list)
|
||||
}
|
||||
|
||||
// helper parse function
|
||||
// convert 'text/uri-list' data to a list of valid Paths
|
||||
// # Note
|
||||
// - none utf8 data will lead to error
|
||||
fn parse_uri_list(text: &str) -> Result<Vec<PathBuf>, CliprdrError> {
|
||||
let mut list = Vec::new();
|
||||
|
||||
for line in text.lines() {
|
||||
let decoded = parse_uri_to_path(line)?;
|
||||
list.push(decoded)
|
||||
}
|
||||
Ok(list)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClipboardContext {
|
||||
pub stop: bool,
|
||||
pub fuse_mount_point: PathBuf,
|
||||
pub fuse_server: FuseServer,
|
||||
pub file_list: HashSet<PathBuf>,
|
||||
pub clipboard: Clipboard,
|
||||
|
||||
pub bkg_session: fuser::BackgroundSession,
|
||||
}
|
||||
|
||||
impl ClipboardContext {
|
||||
fn new(timeout: Duration, mount_path: PathBuf) -> Result<Self, CliprdrError> {
|
||||
// assert mount path exists
|
||||
let mountpoint = mount_path
|
||||
.canonicalize()
|
||||
.map_err(|e| CliprdrError::Unknown {
|
||||
description: format!("invalid mount point: {:?}", e),
|
||||
})?;
|
||||
let fuse_server = FuseServer::new(timeout);
|
||||
let mnt_opts = [
|
||||
fuser::MountOption::FSName("clipboard".to_string()),
|
||||
fuser::MountOption::NoAtime,
|
||||
fuser::MountOption::RO,
|
||||
fuser::MountOption::NoExec,
|
||||
];
|
||||
let bkg_session = fuser::spawn_mount2(fuse_server, mountpoint, &mnt_opts).map_err(|e| {
|
||||
CliprdrError::Unknown {
|
||||
description: format!("failed to mount fuse: {:?}", e),
|
||||
}
|
||||
})?;
|
||||
|
||||
log::debug!("mounting clipboard fuse to {}", mount_path.display());
|
||||
}
|
||||
}
|
7
libs/clipboard/src/platform/linux/x11.rs
Normal file
7
libs/clipboard/src/platform/linux/x11.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use super::SysClipboard;
|
||||
|
||||
pub struct X11Clipboard {}
|
||||
|
||||
impl SysClipboard for X11Clipboard {
|
||||
todo!()
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
use parking_lot::{Condvar, Mutex};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod windows;
|
||||
#[cfg(target_os = "windows")]
|
||||
@ -8,3 +10,17 @@ pub fn create_cliprdr_context(
|
||||
) -> crate::ResultType<Box<dyn crate::CliprdrServiceContext>> {
|
||||
windows::create_cliprdr_context(enable_files, enable_others, response_wait_timeout_secs)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
/// use FUSE for file pasting on these platforms
|
||||
pub mod fuse;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod linux;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn create_cliprdr_context(
|
||||
enable_files: bool,
|
||||
enable_others: bool,
|
||||
response_wait_timeout_secs: u32,
|
||||
) -> crate::ResultType<Box<dyn crate::CliprdrServiceContext>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user