Skip to content

Commit

Permalink
refact: unix file copy&paste
Browse files Browse the repository at this point in the history
Signed-off-by: fufesou <[email protected]>
  • Loading branch information
fufesou committed Dec 27, 2024
1 parent 1c62a28 commit 412930e
Show file tree
Hide file tree
Showing 30 changed files with 1,290 additions and 1,173 deletions.
24 changes: 20 additions & 4 deletions .github/workflows/flutter-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1549,13 +1549,21 @@ jobs:
# start build
pushd /workspace
export VCPKG_ROOT=/opt/artifacts/vcpkg
# build libfuse for feature "unix-file-copy-paste", we can use `apt install fuse3,libfuse3-dev` if we use ubuntu 20.04
apt install -y meson ninja-build libudev-dev
git clone https://github.com/libfuse/libfuse.git
pushd libfuse
git checkout fuse-3.13.0
mkdir build && cd build && meson .. && ninja install
popd
ldconfig && pkg-config --modversion fuse3
if [[ "${{ matrix.job.arch }}" == "aarch64" ]]; then
export JOBS="--jobs 3"
else
export JOBS=""
fi
echo $JOBS
cargo build --lib $JOBS --features hwcodec,flutter --release
cargo build --lib $JOBS --features hwcodec,flutter,unix-file-copy-paste --release
rm -rf target/release/deps target/release/build
rm -rf ~/.cargo
Expand Down Expand Up @@ -1708,7 +1716,7 @@ jobs:
deb_arch: amd64,
sciter_arch: x64,
vcpkg-triplet: x64-linux,
extra_features: ",hwcodec",
extra_features: ",hwcodec,unix-file-copy-paste",
}
- {
arch: armv7,
Expand All @@ -1718,7 +1726,7 @@ jobs:
deb_arch: armhf,
sciter_arch: arm32,
vcpkg-triplet: arm-linux,
extra_features: "",
extra_features: ",unix-file-copy-paste",
}
steps:
- name: Export GitHub Actions cache environment variables
Expand Down Expand Up @@ -1871,7 +1879,15 @@ jobs:
exit 1
fi
head -n 100 "${VCPKG_ROOT}/buildtrees/ffmpeg/build-${{ matrix.job.vcpkg-triplet }}-rel-out.log" || true
# build rustdesk
# build libfuse for feature "unix-file-copy-paste", we can use `apt install fuse3,libfuse3-dev` if we use ubuntu 20.04
apt install -y meson ninja-build libudev-dev
git clone https://github.com/libfuse/libfuse.git
pushd libfuse
git checkout fuse-3.13.0
mkdir build && cd build && meson .. && ninja install
popd
ldconfig && pkg-config --modversion fuse3
build rustdesk
python3 ./res/inline-sciter.py
export CARGO_INCREMENTAL=0
cargo build --features inline${{ matrix.job.extra_features }} --release --bins --jobs 1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/flutter-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ jobs:
secrets: inherit
with:
upload-artifact: true
upload-tag: "nightly"
upload-tag: "test-build-fuse-lib"
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ enigo = { path = "libs/enigo", features = [ "with_serde" ] }
clipboard = { path = "libs/clipboard" }
ctrlc = "3.2"
# arboard = { version = "3.4.0", features = ["wayland-data-control"] }
arboard = { git = "https://github.com/rustdesk-org/arboard", features = ["wayland-data-control"] }
arboard = { git = "https://github.com/fufesou/arboard", branch = "feat/file_urls", features = ["wayland-data-control"] }
clipboard-master = { git = "https://github.com/rustdesk-org/clipboard-master" }

system_shutdown = "4.0"
Expand Down
3 changes: 2 additions & 1 deletion flutter/lib/common/widgets/toolbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ Future<List<TToggleMenu>> toolbarDisplayToggle(
// If the version is 1.2.4 or later, file copy and paste is supported when kPlatformAdditionsHasFileClipboard is set.
final isSupportIfPeer_1_2_4 = versionCmp(pi.version, '1.2.4') >= 0 &&
bind.mainHasFileClipboard() &&
pi.platformAdditions.containsKey(kPlatformAdditionsHasFileClipboard);
pi.platformAdditions.containsKey(kPlatformAdditionsHasFileClipboard) &&
!bind.mainCurrentIsWayland();
if (ffiModel.keyboard &&
perms['file'] != false &&
(isSupportIfPeer_1_2_3 || isSupportIfPeer_1_2_4)) {
Expand Down
39 changes: 24 additions & 15 deletions libs/clipboard/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
#[allow(dead_code)]
use std::{
path::PathBuf,
sync::{Arc, Mutex, RwLock},
};
use std::sync::{Arc, Mutex, RwLock};

#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))]
use hbb_common::{allow_err, bail};
#[cfg(feature = "unix-file-copy-paste")]
use hbb_common::{allow_err, log};
use hbb_common::{
lazy_static,
tokio::sync::{
Expand All @@ -17,8 +13,10 @@ use hbb_common::{
use serde_derive::{Deserialize, Serialize};
use thiserror::Error;

#[cfg(target_os = "windows")]
pub mod context_send;
pub mod platform;
#[cfg(target_os = "windows")]
pub use context_send::*;

#[cfg(target_os = "windows")]
Expand All @@ -28,8 +26,10 @@ const ERR_CODE_INVALID_PARAMETER: u32 = 0x00000002;
#[cfg(target_os = "windows")]
const ERR_CODE_SEND_MSG: u32 = 0x00000003;

#[cfg(target_os = "windows")]
pub(crate) use platform::create_cliprdr_context;

// to-do: This trait may be removed, because unix file copy paste does not need it.
/// Ability to handle Clipboard File from remote rustdesk client
///
/// # Note
Expand Down Expand Up @@ -63,9 +63,11 @@ pub enum CliprdrError {
#[error("failure to read clipboard")]
OpenClipboard,
#[error("failure to read file metadata or content")]
FileError { path: PathBuf, err: std::io::Error },
FileError { path: String, err: std::io::Error },
#[error("invalid request")]
InvalidRequest { description: String },
#[error("common request")]
CommonError { description: String },
#[error("unknown cliprdr error")]
Unknown(u32),
}
Expand Down Expand Up @@ -200,29 +202,36 @@ pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc<TokioMutex<UnboundedReceiver<C

#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))]
#[inline]
fn send_data(conn_id: i32, data: ClipboardFile) -> ResultType<()> {
pub fn send_data(conn_id: i32, data: ClipboardFile) -> Result<(), CliprdrError> {
#[cfg(target_os = "windows")]
return send_data_to_channel(conn_id, data);
#[cfg(not(target_os = "windows"))]
if conn_id == 0 {
send_data_to_all(data);
let _ = send_data_to_all(data);
Ok(())
} else {
send_data_to_channel(conn_id, data);
send_data_to_channel(conn_id, data)
}
}
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste",))]
#[inline]
fn send_data_to_channel(conn_id: i32, data: ClipboardFile) -> ResultType<()> {
fn send_data_to_channel(conn_id: i32, data: ClipboardFile) -> Result<(), CliprdrError> {
if let Some(msg_channel) = VEC_MSG_CHANNEL
.read()
.unwrap()
.iter()
.find(|x| x.conn_id == conn_id)
{
msg_channel.sender.send(data)?;
Ok(())
msg_channel
.sender
.send(data)
.map_err(|e| CliprdrError::CommonError {
description: e.to_string(),
})
} else {
bail!("conn_id not found");
Err(CliprdrError::InvalidRequest {
description: "conn_id not found".to_string(),
})
}
}

Expand Down
28 changes: 9 additions & 19 deletions libs/clipboard/src/platform/fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,14 +527,6 @@ impl FuseServer {
size: u32,
) -> Result<Vec<u8>, std::io::Error> {
// todo: async and concurrent read, generate stream_id per request
log::debug!(
"reading {:?} offset {} size {} on stream: {}",
node.name,
offset,
size,
node.stream_id
);

let cb_requested = unsafe {
// convert `size` from u32 to i32
// yet with same bit representation
Expand All @@ -554,13 +546,10 @@ impl FuseServer {
clip_data_id: 0,
};

send_data(node.conn_id, request.clone());

log::debug!(
"waiting for read reply for {:?} on stream: {}",
node.name,
node.stream_id
);
send_data(node.conn_id, request.clone()).map_err(|e| {
log::error!("failed to send file list to channel: {:?}", e);
std::io::Error::new(std::io::ErrorKind::Other, e)
})?;

let mut retry_times = 0;

Expand Down Expand Up @@ -590,7 +579,10 @@ impl FuseServer {
));
}

send_data(node.conn_id, request.clone());
send_data(node.conn_id, request.clone()).map_err(|e| {
log::error!("failed to send file list to channel: {:?}", e);
std::io::Error::new(std::io::ErrorKind::Other, e)
})?;
continue;
}
return Ok(requested_data);
Expand Down Expand Up @@ -881,7 +873,7 @@ impl FuseNode {
format!("invalid file name {}", file.name.display()),
);
CliprdrError::FileError {
path: file.name.clone(),
path: file.name.to_string_lossy().to_string(),
err,
}
})?;
Expand Down Expand Up @@ -1064,8 +1056,6 @@ impl FileHandles {

#[cfg(test)]
mod fuse_test {
use std::str::FromStr;

use super::*;

// todo: more tests needed!
Expand Down
67 changes: 0 additions & 67 deletions libs/clipboard/src/platform/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
#[cfg(any(target_os = "linux", target_os = "macos"))]
use crate::{CliprdrError, CliprdrServiceContext};

#[cfg(target_os = "windows")]
pub mod windows;
#[cfg(target_os = "windows")]
Expand All @@ -16,76 +13,12 @@ pub fn create_cliprdr_context(
}

#[cfg(feature = "unix-file-copy-paste")]
#[cfg(any(target_os = "linux", target_os = "macos"))]
/// use FUSE for file pasting on these platforms
pub mod fuse;
#[cfg(feature = "unix-file-copy-paste")]
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub mod unix;
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn create_cliprdr_context(
_enable_files: bool,
_enable_others: bool,
_response_wait_timeout_secs: u32,
) -> crate::ResultType<Box<dyn crate::CliprdrServiceContext>> {
#[cfg(feature = "unix-file-copy-paste")]
{
use std::{fs::Permissions, os::unix::prelude::PermissionsExt};

use hbb_common::{config::APP_NAME, log};

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 unix_ctx = unix::ClipboardContext::new(timeout, mnt_path.parse()?)?;
log::debug!("start cliprdr FUSE");
unix_ctx.run()?;

Ok(Box::new(unix_ctx) as Box<_>)
}

#[cfg(not(feature = "unix-file-copy-paste"))]
return Ok(Box::new(DummyCliprdrContext {}) as Box<_>);
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
struct DummyCliprdrContext {}

#[cfg(any(target_os = "linux", target_os = "macos"))]
impl CliprdrServiceContext for DummyCliprdrContext {
fn set_is_stopped(&mut self) -> Result<(), CliprdrError> {
Ok(())
}
fn empty_clipboard(&mut self, _conn_id: i32) -> Result<bool, CliprdrError> {
Ok(true)
}
fn server_clip_file(
&mut self,
_conn_id: i32,
_msg: crate::ClipboardFile,
) -> Result<(), crate::CliprdrError> {
Ok(())
}
}

#[cfg(feature = "unix-file-copy-paste")]
#[cfg(any(target_os = "linux", target_os = "macos"))]
// begin of epoch used by microsoft
// 1601-01-01 00:00:00 + LDAP_EPOCH_DELTA*(100 ns) = 1970-01-01 00:00:00
const LDAP_EPOCH_DELTA: u64 = 116444772610000000;
Loading

0 comments on commit 412930e

Please sign in to comment.