patch: reduce logic in Fuse and SystemClipboard

1. also added more observability

Signed-off-by: ClSlaid <cailue@bupt.edu.cn>
This commit is contained in:
ClSlaid 2023-10-17 16:57:55 +08:00
parent 8f9ba44c2c
commit fbb1d9247f
No known key found for this signature in database
GPG Key ID: E0A5F564C51C056E
6 changed files with 133 additions and 322 deletions

View File

@ -181,7 +181,7 @@ impl FuseServer {
} }
impl FuseServer { impl FuseServer {
pub fn serve(&mut self, reply: ClipboardFile) -> Result<(), CliprdrError> { pub fn serve(&self, reply: ClipboardFile) -> Result<(), CliprdrError> {
self.tx.send(reply).map_err(|e| { self.tx.send(reply).map_err(|e| {
log::error!("failed to serve cliprdr reply from endpoint: {:?}", e); log::error!("failed to serve cliprdr reply from endpoint: {:?}", e);
CliprdrError::ClipboardInternalError CliprdrError::ClipboardInternalError
@ -190,6 +190,15 @@ impl FuseServer {
} }
} }
impl FuseServer {
pub fn load_file_list(&mut self, files: Vec<FileDescription>) -> Result<(), CliprdrError> {
let tree = FuseNode::build_tree(files)?;
self.files = tree;
self.generation.fetch_add(1, Ordering::Relaxed);
Ok(())
}
}
impl fuser::Filesystem for FuseServer { impl fuser::Filesystem for FuseServer {
fn init( fn init(
&mut self, &mut self,
@ -499,165 +508,11 @@ impl FuseServer {
paths paths
} }
/// fetch file list from remote
fn sync_file_system(
&mut self,
conn_id: i32,
file_group_format_id: i32,
_file_contents_format_id: i32,
) -> Result<bool, CliprdrError> {
let resp = self.send_sync_fs_request(conn_id, file_group_format_id, self.timeout)?;
let descs = match resp {
ClipboardFile::FormatDataResponse {
msg_flags,
format_data,
} => {
if msg_flags != 0x1 {
log::error!("clipboard FUSE server: received unexpected response flags");
return Err(CliprdrError::ClipboardInternalError);
}
let descs = FileDescription::parse_file_descriptors(format_data, conn_id)?;
descs
}
_ => {
log::error!("clipboard FUSE server: received unexpected response type");
return Err(CliprdrError::ClipboardInternalError);
}
};
let mut new_tree = FuseNode::build_tree(descs)?;
let res = new_tree
.iter_mut()
.filter(|f_node| f_node.is_file() && f_node.attributes.size == 0)
.try_for_each(|f_node| self.sync_node_size(f_node));
if let Err(err) = res {
log::error!(
"clipboard FUSE server: failed to fetch file size: {:?}",
err
);
return Err(CliprdrError::ClipboardInternalError);
}
// replace current file system
self.files = new_tree;
self.generation.fetch_add(1, Ordering::Relaxed);
Ok(true)
}
fn send_sync_fs_request(
&self,
conn_id: i32,
file_group_format_id: i32,
timeout: std::time::Duration,
) -> Result<ClipboardFile, CliprdrError> {
// request file list
let data = ClipboardFile::FormatDataRequest {
requested_format_id: file_group_format_id,
};
send_data(conn_id, data);
self.rx.recv_timeout(timeout).map_err(|e| {
log::error!("failed to receive file list from channel: {:?}", e);
CliprdrError::ClipboardInternalError
})
}
pub fn update_files(
&mut self,
conn_id: i32,
file_group_format_id: i32,
file_contents_format_id: i32,
) -> Result<bool, CliprdrError> {
self.sync_file_system(conn_id, file_group_format_id, file_contents_format_id)
}
/// allocate a new file descriptor /// allocate a new file descriptor
fn alloc_fd(&self) -> u64 { fn alloc_fd(&self) -> u64 {
self.file_handle_counter.fetch_add(1, Ordering::Relaxed) self.file_handle_counter.fetch_add(1, Ordering::Relaxed)
} }
// synchronize metadata with remote
fn sync_node_size(&self, node: &mut FuseNode) -> Result<(), std::io::Error> {
log::debug!(
"syncing metadata for {:?} on stream: {}",
node.name,
node.stream_id
);
let request = ClipboardFile::FileContentsRequest {
stream_id: node.stream_id,
list_index: node.inode as i32 - 2, // list index at least 2
dw_flags: 1,
n_position_low: 0,
n_position_high: 0,
cb_requested: 8,
have_clip_data_id: false,
clip_data_id: 0,
};
send_data(node.conn_id, request);
log::debug!(
"waiting for metadata sync reply for {:?} on channel {}",
node.name,
node.conn_id
);
let reply = self
.rx
.recv_timeout(self.timeout)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::TimedOut, e))?;
log::debug!(
"got metadata sync reply for {:?} on channel {}",
node.name,
node.conn_id
);
let size = match reply {
ClipboardFile::FileContentsResponse {
msg_flags,
stream_id,
requested_data,
} => {
if stream_id != node.stream_id {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"stream id mismatch",
));
}
if msg_flags & 1 == 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"failure request",
));
}
if requested_data.len() != 8 {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"invalid data length",
));
}
let little_endian_value = u64::from_le_bytes(requested_data.try_into().unwrap());
little_endian_value
}
_ => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"invalid reply",
));
}
};
log::debug!("got metadata sync reply for {:?}: size {}", node.name, size);
node.attributes.size = size;
Ok(())
}
fn read_node( fn read_node(
&self, &self,
node: &FuseNode, node: &FuseNode,
@ -916,6 +771,7 @@ impl FuseNode {
} }
} }
#[allow(unused)]
pub fn is_file(&self) -> bool { pub fn is_file(&self) -> bool {
self.attributes.kind == FileType::File self.attributes.kind == FileType::File
} }

View File

@ -14,10 +14,12 @@ use hbb_common::{
log, log,
}; };
use lazy_static::lazy_static; use lazy_static::lazy_static;
use parking_lot::{Mutex, RwLock}; use parking_lot::Mutex;
use utf16string::WString; use utf16string::WString;
use crate::{send_data, ClipboardFile, CliprdrError, CliprdrServiceContext}; use crate::{
platform::fuse::FileDescription, send_data, ClipboardFile, CliprdrError, CliprdrServiceContext,
};
use super::{fuse::FuseServer, LDAP_EPOCH_DELTA}; use super::{fuse::FuseServer, LDAP_EPOCH_DELTA};
@ -44,13 +46,11 @@ fn add_remote_format(local_name: &str, remote_id: i32) {
} }
trait SysClipboard: Send + Sync { trait SysClipboard: Send + Sync {
fn set_file_list(&self, paths: &[PathBuf]) -> Result<(), CliprdrError>;
fn stop(&self);
fn start(&self); fn start(&self);
/// send to 0 will send to all channels fn stop(&self);
fn send_format_list(&self, conn_id: i32) -> Result<(), CliprdrError>;
/// send to 0 will send to all channels fn set_file_list(&self, paths: &[PathBuf]) -> Result<(), CliprdrError>;
fn send_file_list(&self, conn_id: i32) -> Result<(), CliprdrError>; fn get_file_list(&self) -> Result<Vec<LocalFile>, CliprdrError>;
} }
fn get_sys_clipboard(ignore_path: &PathBuf) -> Result<Box<dyn SysClipboard>, CliprdrError> { fn get_sys_clipboard(ignore_path: &PathBuf) -> Result<Box<dyn SysClipboard>, CliprdrError> {
@ -312,7 +312,6 @@ pub struct ClipboardContext {
fuse_server: Arc<Mutex<FuseServer>>, fuse_server: Arc<Mutex<FuseServer>>,
file_list: RwLock<Vec<LocalFile>>,
clipboard: Arc<dyn SysClipboard>, clipboard: Arc<dyn SysClipboard>,
} }
@ -328,13 +327,11 @@ impl ClipboardContext {
let clipboard = get_sys_clipboard(&fuse_mount_point)?; let clipboard = get_sys_clipboard(&fuse_mount_point)?;
let clipboard = Arc::from(clipboard) as Arc<_>; let clipboard = Arc::from(clipboard) as Arc<_>;
let file_list = RwLock::new(vec![]);
Ok(Self { Ok(Self {
fuse_mount_point, fuse_mount_point,
fuse_server, fuse_server,
fuse_handle: Mutex::new(None), fuse_handle: Mutex::new(None),
file_list,
clipboard, clipboard,
}) })
} }
@ -379,10 +376,6 @@ impl ClipboardContext {
Ok(()) Ok(())
} }
pub fn stop(&self) -> Result<(), CliprdrError> {
self.set_is_stopped()
}
/// set clipboard data from file list /// set clipboard data from file list
pub fn set_clipboard(&self, paths: &[PathBuf]) -> Result<(), CliprdrError> { pub fn set_clipboard(&self, paths: &[PathBuf]) -> Result<(), CliprdrError> {
let prefix = self.fuse_mount_point.clone(); let prefix = self.fuse_mount_point.clone();
@ -404,7 +397,7 @@ impl ClipboardContext {
stream_id, stream_id,
file_idx, file_idx,
} => { } => {
let file_list = self.file_list.read(); let file_list = self.clipboard.get_file_list()?;
let Some(file) = file_list.get(file_idx) else { let Some(file) = file_list.get(file_idx) else {
log::error!( log::error!(
"invalid file index {} requested from conn: {}", "invalid file index {} requested from conn: {}",
@ -436,7 +429,7 @@ impl ClipboardContext {
offset, offset,
length, length,
} => { } => {
let file_list = self.file_list.read(); let file_list = self.clipboard.get_file_list()?;
let Some(file) = file_list.get(file_idx) else { let Some(file) = file_list.get(file_idx) else {
log::error!( log::error!(
"invalid file index {} requested from conn: {}", "invalid file index {} requested from conn: {}",
@ -523,33 +516,6 @@ impl ClipboardContext {
self.fuse_handle.lock().is_none() self.fuse_handle.lock().is_none()
} }
pub fn set_is_stopped(&self) -> Result<(), CliprdrError> {
if self.is_stopped() {
log::debug!("cliprdr already stopped");
return Ok(());
}
// unmount the fuse
if let Some(fuse_handle) = self.fuse_handle.lock().take() {
fuse_handle.join();
}
self.clipboard.stop();
Ok(())
}
pub fn empty_clipboard(&self, conn_id: i32) -> Result<bool, CliprdrError> {
// gc all files, the clipboard is going to shutdown
if self.is_stopped() {
log::debug!("cliprdr stopped, skip emptying clipboard");
return Ok(true);
}
self.fuse_server.lock().update_files(
conn_id,
FILEDESCRIPTOR_FORMAT_ID,
FILECONTENTS_FORMAT_ID,
)
}
pub fn serve(&self, conn_id: i32, msg: ClipboardFile) -> Result<(), CliprdrError> { pub fn serve(&self, conn_id: i32, msg: ClipboardFile) -> Result<(), CliprdrError> {
if self.is_stopped() { if self.is_stopped() {
log::debug!("cliprdr stopped, restart it"); log::debug!("cliprdr stopped, restart it");
@ -562,9 +528,8 @@ impl ClipboardContext {
ClipboardFile::MonitorReady => { ClipboardFile::MonitorReady => {
log::debug!("server_monitor_ready called"); log::debug!("server_monitor_ready called");
// ignore capabilities for now self.send_file_list(conn_id)?;
self.clipboard.send_file_list(0)?;
Ok(()) Ok(())
} }
@ -595,17 +560,19 @@ impl ClipboardContext {
add_remote_format(FILECONTENTS_FORMAT_NAME, file_contents_id); add_remote_format(FILECONTENTS_FORMAT_NAME, file_contents_id);
add_remote_format(FILEDESCRIPTORW_FORMAT_NAME, file_descriptor_id); add_remote_format(FILEDESCRIPTORW_FORMAT_NAME, file_descriptor_id);
self.fuse_server.lock().update_files(
conn_id, // sync file system from peer
file_descriptor_id, let data = ClipboardFile::FormatDataRequest {
file_contents_id, requested_format_id: file_descriptor_id,
)?; };
send_data(conn_id, data);
Ok(()) Ok(())
} }
ClipboardFile::FormatListResponse { msg_flags } => { ClipboardFile::FormatListResponse { msg_flags } => {
log::debug!("server_format_list_response called"); log::debug!("server_format_list_response called");
if msg_flags != 0x1 { if msg_flags != 0x1 {
self.clipboard.send_format_list(conn_id) send_format_list(conn_id)
} else { } else {
Ok(()) Ok(())
} }
@ -625,7 +592,7 @@ impl ClipboardContext {
}; };
if format == FILEDESCRIPTORW_FORMAT_NAME { if format == FILEDESCRIPTORW_FORMAT_NAME {
self.clipboard.send_file_list(conn_id)?; self.send_file_list(conn_id)?;
} else if format == FILECONTENTS_FORMAT_NAME { } else if format == FILECONTENTS_FORMAT_NAME {
log::error!( log::error!(
"try to read file contents with FormatDataRequest from conn={}", "try to read file contents with FormatDataRequest from conn={}",
@ -642,13 +609,27 @@ impl ClipboardContext {
} }
Ok(()) Ok(())
} }
ClipboardFile::FormatDataResponse { .. } => { ClipboardFile::FormatDataResponse {
// we don't know its corresponding request, no resend can be performed msg_flags,
format_data,
} => {
log::debug!("server_format_data_response called"); log::debug!("server_format_data_response called");
let mut fuse_server = self.fuse_server.lock();
fuse_server.serve(msg)?; if msg_flags != 0x1 {
let paths = fuse_server.list_root(); resp_format_data_failure(conn_id);
return Ok(());
}
// this must be a file descriptor format data
let files = FileDescription::parse_file_descriptors(format_data.into(), conn_id)?;
let paths = {
let mut fuse_guard = self.fuse_server.lock();
fuse_guard.load_file_list(files)?;
fuse_guard.list_root()
};
self.set_clipboard(&paths)?; self.set_clipboard(&paths)?;
Ok(()) Ok(())
} }
@ -693,16 +674,30 @@ impl ClipboardContext {
} }
} }
} }
fn send_file_list(&self, conn_id: i32) -> Result<(), CliprdrError> {
let file_list = self.clipboard.get_file_list()?;
let paths = file_list.into_iter().map(|lf| lf.path).collect();
send_file_list(paths, conn_id)
}
} }
impl CliprdrServiceContext for ClipboardContext { impl CliprdrServiceContext for ClipboardContext {
fn set_is_stopped(&mut self) -> Result<(), CliprdrError> { fn set_is_stopped(&mut self) -> Result<(), CliprdrError> {
self.stop() // unmount the fuse
if let Some(fuse_handle) = self.fuse_handle.lock().take() {
fuse_handle.join();
}
self.clipboard.stop();
Ok(())
} }
fn empty_clipboard(&mut self, _conn_id: i32) -> Result<bool, CliprdrError> { fn empty_clipboard(&mut self, _conn_id: i32) -> Result<bool, CliprdrError> {
self.clipboard.set_file_list(&[])?; self.clipboard.set_file_list(&[])?;
Ok(true) Ok(true)
} }
fn server_clip_file(&mut self, conn_id: i32, msg: ClipboardFile) -> Result<(), CliprdrError> { fn server_clip_file(&mut self, conn_id: i32, msg: ClipboardFile) -> Result<(), CliprdrError> {
self.serve(conn_id, msg) self.serve(conn_id, msg)
} }
@ -715,3 +710,43 @@ fn resp_format_data_failure(conn_id: i32) {
}; };
send_data(conn_id, data) send_data(conn_id, data)
} }
fn send_format_list(conn_id: i32) -> Result<(), CliprdrError> {
log::debug!("send format list to remote, conn={}", conn_id);
let fd_format_name = get_local_format(FILEDESCRIPTOR_FORMAT_ID)
.unwrap_or(FILEDESCRIPTORW_FORMAT_NAME.to_string());
let fc_format_name =
get_local_format(FILECONTENTS_FORMAT_ID).unwrap_or(FILECONTENTS_FORMAT_NAME.to_string());
let format_list = ClipboardFile::FormatList {
format_list: vec![
(FILEDESCRIPTOR_FORMAT_ID, fd_format_name),
(FILECONTENTS_FORMAT_ID, fc_format_name),
],
};
send_data(conn_id, format_list);
log::debug!("format list to remote dispatched, conn={}", conn_id);
Ok(())
}
fn send_file_list(paths: Vec<PathBuf>, conn_id: i32) -> Result<(), CliprdrError> {
log::debug!("send file list to remote, conn={}", conn_id);
let files = construct_file_list(paths.as_slice())?;
let mut data = BytesMut::with_capacity(4 + 592 * files.len());
data.put_u32_le(paths.len() as u32);
for file in files.iter() {
data.put(file.as_bin().as_slice());
}
let format_data = data.to_vec();
send_data(
conn_id,
ClipboardFile::FormatDataResponse {
msg_flags: 1,
format_data,
},
);
Ok(())
}

View File

@ -4,21 +4,15 @@ use std::{
sync::atomic::{AtomicBool, Ordering}, sync::atomic::{AtomicBool, Ordering},
}; };
use hbb_common::{ use hbb_common::log;
bytes::{BufMut, BytesMut},
log,
};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use x11_clipboard::Clipboard; use x11_clipboard::Clipboard;
use x11rb::protocol::xproto::Atom; use x11rb::protocol::xproto::Atom;
use crate::{ use crate::{
platform::linux::{ platform::linux::{construct_file_list, send_format_list},
construct_file_list, FILECONTENTS_FORMAT_ID, FILECONTENTS_FORMAT_NAME, CliprdrError,
FILEDESCRIPTORW_FORMAT_NAME, FILEDESCRIPTOR_FORMAT_ID,
},
send_data, ClipboardFile, CliprdrError,
}; };
use super::{encode_path_to_uri, parse_plain_uri_list, SysClipboard}; use super::{encode_path_to_uri, parse_plain_uri_list, SysClipboard};
@ -175,89 +169,8 @@ impl SysClipboard for X11Clipboard {
log::debug!("stop listening file related atoms on clipboard"); log::debug!("stop listening file related atoms on clipboard");
} }
fn send_format_list(&self, conn_id: i32) -> Result<(), CliprdrError> { fn get_file_list(&self) -> Result<Vec<super::LocalFile>, CliprdrError> {
if self.is_stopped() { let paths = { self.former_file_list.lock().clone() };
log::debug!("clipboard stopped, skip sending"); construct_file_list(&paths)
return Ok(());
}
let Some(paths) = self.wait_file_list()? else {
log::debug!("no files in format list, skip sending");
return Ok(());
};
let filtered: Vec<_> = paths
.into_iter()
.filter(|pb| !pb.starts_with(&self.ignore_path))
.collect();
if filtered.is_empty() {
log::debug!("no files in format list, skip sending");
return Ok(());
}
send_format_list(conn_id)
}
fn send_file_list(&self, conn_id: i32) -> Result<(), CliprdrError> {
if self.is_stopped() {
log::debug!("clipboard stopped, skip sending");
return Ok(());
}
let Some(paths) = self.wait_file_list()? else {
log::debug!("no files in format list, skip sending");
return Ok(());
};
let filtered: Vec<_> = paths
.into_iter()
.filter(|pb| !pb.starts_with(&self.ignore_path))
.collect();
if filtered.is_empty() {
log::debug!("no files in format list, skip sending");
return Ok(());
}
send_file_list(filtered, conn_id)
} }
} }
fn send_format_list(conn_id: i32) -> Result<(), CliprdrError> {
log::debug!("send format list to remote, conn={}", conn_id);
let format_list = ClipboardFile::FormatList {
format_list: vec![
(
FILEDESCRIPTOR_FORMAT_ID,
FILEDESCRIPTORW_FORMAT_NAME.to_string(),
),
(FILECONTENTS_FORMAT_ID, FILECONTENTS_FORMAT_NAME.to_string()),
],
};
send_data(conn_id, format_list);
log::debug!("format list to remote dispatched, conn={}", conn_id);
Ok(())
}
fn send_file_list(paths: Vec<PathBuf>, conn_id: i32) -> Result<(), CliprdrError> {
log::debug!("send file list to remote, conn={}", conn_id);
let files = construct_file_list(paths.as_slice())?;
let mut data = BytesMut::with_capacity(4 + 592 * files.len());
data.put_u32_le(paths.len() as u32);
for file in files.iter() {
data.put(file.as_bin().as_slice());
}
let format_data = data.to_vec();
send_data(
conn_id,
ClipboardFile::FormatDataResponse {
msg_flags: 1,
format_data,
},
);
Ok(())
}

View File

@ -317,6 +317,7 @@ impl<T: InvokeUiSession> Remote<T> {
if stop { if stop {
ContextSend::set_is_stopped(); ContextSend::set_is_stopped();
} else { } else {
log::debug!("Send system clipboard message to remote");
let msg = crate::clipboard_file::clip_2_msg(clip); let msg = crate::clipboard_file::clip_2_msg(clip);
allow_err!(peer.send(&msg).await); allow_err!(peer.send(&msg).await);
} }
@ -1714,6 +1715,7 @@ impl<T: InvokeUiSession> Remote<T> {
#[cfg(any(target_os = "windows", target_os = "linux"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
fn handle_cliprdr_msg(&self, clip: hbb_common::message_proto::Cliprdr) { fn handle_cliprdr_msg(&self, clip: hbb_common::message_proto::Cliprdr) {
log::debug!("handling cliprdr msg from server peer");
#[cfg(feature = "flutter")] #[cfg(feature = "flutter")]
if let Some(hbb_common::message_proto::cliprdr::Union::FormatList(_)) = &clip.union { if let Some(hbb_common::message_proto::cliprdr::Union::FormatList(_)) = &clip.union {
if self.client_conn_id if self.client_conn_id
@ -1723,20 +1725,23 @@ impl<T: InvokeUiSession> Remote<T> {
} }
} }
if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) { let Some(clip) = crate::clipboard_file::msg_2_clip(clip) else {
let is_stopping_allowed = clip.is_stopping_allowed_from_peer(); log::warn!("failed to decode cliprdr msg from server peer");
let file_transfer_enabled = self.handler.lc.read().unwrap().enable_file_transfer.v; return;
let stop = is_stopping_allowed && !file_transfer_enabled; };
log::debug!(
let is_stopping_allowed = clip.is_stopping_allowed_from_peer();
let file_transfer_enabled = self.handler.lc.read().unwrap().enable_file_transfer.v;
let stop = is_stopping_allowed && !file_transfer_enabled;
log::debug!(
"Process clipboard message from server peer, stop: {}, is_stopping_allowed: {}, file_transfer_enabled: {}", "Process clipboard message from server peer, stop: {}, is_stopping_allowed: {}, file_transfer_enabled: {}",
stop, is_stopping_allowed, file_transfer_enabled); stop, is_stopping_allowed, file_transfer_enabled);
if !stop { if !stop {
let _ = ContextSend::proc(|context| -> ResultType<()> { let _ = ContextSend::proc(|context| -> ResultType<()> {
context context
.server_clip_file(self.client_conn_id, clip) .server_clip_file(self.client_conn_id, clip)
.map_err(|e| e.into()) .map_err(|e| e.into())
}); });
}
} }
} }
} }

View File

@ -480,6 +480,7 @@ impl Connection {
} }
#[cfg(any(target_os="windows", target_os="linux"))] #[cfg(any(target_os="windows", target_os="linux"))]
ipc::Data::ClipboardFile(clip) => { ipc::Data::ClipboardFile(clip) => {
log::debug!("got clipfile from rx_from_cm, send to stream: {:?}", clip);
allow_err!(conn.stream.send(&clip_2_msg(clip)).await); allow_err!(conn.stream.send(&clip_2_msg(clip)).await);
} }
ipc::Data::PrivacyModeState((_, state)) => { ipc::Data::PrivacyModeState((_, state)) => {
@ -1785,10 +1786,11 @@ impl Connection {
update_clipboard(_cb, None); update_clipboard(_cb, None);
} }
} }
Some(message::Union::Cliprdr(_clip)) => Some(message::Union::Cliprdr(_clip)) => {
{ log::debug!("got cliprdr file from connection:{:?}", _clip);
#[cfg(any(target_os = "windows", target_os = "linux"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
if let Some(clip) = msg_2_clip(_clip) { if let Some(clip) = msg_2_clip(_clip) {
log::debug!("send cliprdr file from connection to cm");
self.send_to_cm(ipc::Data::ClipboardFile(clip)) self.send_to_cm(ipc::Data::ClipboardFile(clip))
} }
} }

View File

@ -425,7 +425,7 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
Data::ClipboardFile(_clip) => { Data::ClipboardFile(_clip) => {
#[cfg(any(windows, linux))] #[cfg(any(target_os = "windows", target_os="linux"))]
{ {
let is_stopping_allowed = _clip.is_stopping_allowed_from_peer(); let is_stopping_allowed = _clip.is_stopping_allowed_from_peer();
let is_clipboard_enabled = ContextSend::is_enabled(); let is_clipboard_enabled = ContextSend::is_enabled();