mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-02 22:21:29 +03:00
refact: file copy&paste, cross platform (no macOS) (#10671)
* feat: unix, file copy&paste Signed-off-by: fufesou <linlong1266@gmail.com> * refact: unix file c&p, check peer version Signed-off-by: fufesou <linlong1266@gmail.com> * Update pubspec.yaml --------- Signed-off-by: fufesou <linlong1266@gmail.com> Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com>
This commit is contained in:
@@ -189,3 +189,206 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option<ClipboardFile> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
pub mod unix_file_clip {
|
||||
use crate::clipboard::try_empty_clipboard_files;
|
||||
|
||||
use super::{
|
||||
super::clipboard::{update_clipboard_files, ClipboardSide},
|
||||
*,
|
||||
};
|
||||
#[cfg(target_os = "linux")]
|
||||
use clipboard::platform::unix::fuse;
|
||||
use clipboard::platform::unix::{
|
||||
get_local_format, serv_files, FILECONTENTS_FORMAT_ID, FILECONTENTS_FORMAT_NAME,
|
||||
FILEDESCRIPTORW_FORMAT_NAME, FILEDESCRIPTOR_FORMAT_ID,
|
||||
};
|
||||
use hbb_common::log;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref CLIPBOARD_CTX: Arc<Mutex<Option<crate::clipboard::ClipboardContext>>> = Arc::new(Mutex::new(None));
|
||||
}
|
||||
|
||||
pub fn get_format_list() -> ClipboardFile {
|
||||
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());
|
||||
ClipboardFile::FormatList {
|
||||
format_list: vec![
|
||||
(FILEDESCRIPTOR_FORMAT_ID, fd_format_name),
|
||||
(FILECONTENTS_FORMAT_ID, fc_format_name),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn msg_resp_format_data_failure() -> Message {
|
||||
clip_2_msg(ClipboardFile::FormatDataResponse {
|
||||
msg_flags: 0x2,
|
||||
format_data: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn resp_file_contents_fail(stream_id: i32) -> Message {
|
||||
clip_2_msg(ClipboardFile::FileContentsResponse {
|
||||
msg_flags: 0x2,
|
||||
stream_id,
|
||||
requested_data: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn serve_clip_messages(
|
||||
side: ClipboardSide,
|
||||
clip: ClipboardFile,
|
||||
conn_id: i32,
|
||||
) -> Option<Message> {
|
||||
log::debug!("got clipfile from client peer");
|
||||
match clip {
|
||||
ClipboardFile::MonitorReady => {
|
||||
log::debug!("client is ready for clipboard");
|
||||
}
|
||||
ClipboardFile::FormatList { format_list } => {
|
||||
if !format_list
|
||||
.iter()
|
||||
.find(|(_, name)| name == FILECONTENTS_FORMAT_NAME)
|
||||
.map(|(id, _)| *id)
|
||||
.is_some()
|
||||
{
|
||||
log::error!("no file contents format found");
|
||||
return None;
|
||||
};
|
||||
let Some(file_descriptor_id) = format_list
|
||||
.iter()
|
||||
.find(|(_, name)| name == FILEDESCRIPTORW_FORMAT_NAME)
|
||||
.map(|(id, _)| *id)
|
||||
else {
|
||||
log::error!("no file descriptor format found");
|
||||
return None;
|
||||
};
|
||||
// sync file system from peer
|
||||
let data = ClipboardFile::FormatDataRequest {
|
||||
requested_format_id: file_descriptor_id,
|
||||
};
|
||||
return Some(clip_2_msg(data));
|
||||
}
|
||||
ClipboardFile::FormatListResponse {
|
||||
msg_flags: _msg_flags,
|
||||
} => {}
|
||||
ClipboardFile::FormatDataRequest {
|
||||
requested_format_id: _requested_format_id,
|
||||
} => {
|
||||
log::debug!("requested format id: {}", _requested_format_id);
|
||||
let format_data = serv_files::get_file_list_pdu();
|
||||
if !format_data.is_empty() {
|
||||
return Some(clip_2_msg(ClipboardFile::FormatDataResponse {
|
||||
msg_flags: 1,
|
||||
format_data,
|
||||
}));
|
||||
}
|
||||
// empty file list, send failure message
|
||||
return Some(msg_resp_format_data_failure());
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
ClipboardFile::FormatDataResponse {
|
||||
msg_flags,
|
||||
format_data,
|
||||
} => {
|
||||
log::debug!("format data response: msg_flags: {}", msg_flags);
|
||||
|
||||
if msg_flags != 0x1 {
|
||||
// return failure message?
|
||||
}
|
||||
|
||||
log::debug!("parsing file descriptors");
|
||||
if fuse::init_fuse_context(true).is_ok() {
|
||||
match fuse::format_data_response_to_urls(
|
||||
side == ClipboardSide::Client,
|
||||
format_data,
|
||||
conn_id,
|
||||
) {
|
||||
Ok(files) => {
|
||||
update_clipboard_files(files, side);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("failed to parse file descriptors: {:?}", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// send error message to server
|
||||
}
|
||||
}
|
||||
ClipboardFile::FileContentsRequest {
|
||||
stream_id,
|
||||
list_index,
|
||||
dw_flags,
|
||||
n_position_low,
|
||||
n_position_high,
|
||||
cb_requested,
|
||||
..
|
||||
} => {
|
||||
log::debug!("file contents request: stream_id: {}, list_index: {}, dw_flags: {}, n_position_low: {}, n_position_high: {}, cb_requested: {}", stream_id, list_index, dw_flags, n_position_low, n_position_high, cb_requested);
|
||||
match serv_files::read_file_contents(
|
||||
conn_id,
|
||||
stream_id,
|
||||
list_index,
|
||||
dw_flags,
|
||||
n_position_low,
|
||||
n_position_high,
|
||||
cb_requested,
|
||||
) {
|
||||
Ok(data) => {
|
||||
return Some(clip_2_msg(data));
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("failed to read file contents: {:?}", e);
|
||||
return Some(resp_file_contents_fail(stream_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
ClipboardFile::FileContentsResponse {
|
||||
msg_flags,
|
||||
stream_id,
|
||||
..
|
||||
} => {
|
||||
log::debug!(
|
||||
"file contents response: msg_flags: {}, stream_id: {}",
|
||||
msg_flags,
|
||||
stream_id,
|
||||
);
|
||||
if fuse::init_fuse_context(true).is_ok() {
|
||||
hbb_common::allow_err!(fuse::handle_file_content_response(
|
||||
side == ClipboardSide::Client,
|
||||
clip
|
||||
));
|
||||
} else {
|
||||
// send error message to server
|
||||
}
|
||||
}
|
||||
ClipboardFile::NotifyCallback {
|
||||
r#type,
|
||||
title,
|
||||
text,
|
||||
} => {
|
||||
// unreachable, but still log it
|
||||
log::debug!(
|
||||
"notify callback: type: {}, title: {}, text: {}",
|
||||
r#type,
|
||||
title,
|
||||
text
|
||||
);
|
||||
}
|
||||
ClipboardFile::TryEmpty => {
|
||||
try_empty_clipboard_files(side, conn_id);
|
||||
}
|
||||
_ => {
|
||||
log::error!("unsupported clipboard file type");
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user