mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-03-21 20:21:09 +03:00
Feat/macos clipboard file (#10939)
* feat: macos, clipboard file Signed-off-by: fufesou <linlong1266@gmail.com> * Can't reuse file transfer Signed-off-by: fufesou <linlong1266@gmail.com> * handle paste task Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
@@ -848,6 +848,10 @@ impl ClientClipboardHandler {
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
if let Some(urls) = check_clipboard_files(&mut self.ctx, ClipboardSide::Client, false) {
|
||||
if !urls.is_empty() {
|
||||
#[cfg(target_os = "macos")]
|
||||
if crate::clipboard::is_file_url_set_by_rustdesk(&urls) {
|
||||
return;
|
||||
}
|
||||
if self.is_file_required() {
|
||||
match clipboard::platform::unix::serv_files::sync_files(&urls) {
|
||||
Ok(()) => {
|
||||
|
||||
@@ -12,7 +12,10 @@ use crate::{
|
||||
};
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
use crate::{clipboard::try_empty_clipboard_files, clipboard_file::unix_file_clip};
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
all(target_os = "macos", feature = "unix-file-copy-paste")
|
||||
))]
|
||||
use clipboard::ContextSend;
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
@@ -1956,9 +1959,9 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
|
||||
#[cfg(any(target_os = "windows", feature = "unix-file-copy-paste"))]
|
||||
async fn handle_cliprdr_msg(
|
||||
&self,
|
||||
&mut self,
|
||||
clip: hbb_common::message_proto::Cliprdr,
|
||||
_peer: &mut Stream,
|
||||
peer: &mut Stream,
|
||||
) {
|
||||
log::debug!("handling cliprdr msg from server peer");
|
||||
#[cfg(feature = "flutter")]
|
||||
@@ -1982,7 +1985,10 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
"Process clipboard message from server peer, stop: {}, is_stopping_allowed: {}, file_transfer_enabled: {}",
|
||||
stop, is_stopping_allowed, file_transfer_enabled);
|
||||
if !stop {
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(any(
|
||||
target_os = "windows",
|
||||
all(target_os = "macos", feature = "unix-file-copy-paste")
|
||||
))]
|
||||
if let Err(e) = ContextSend::make_sure_enabled() {
|
||||
log::error!("failed to restart clipboard context: {}", e);
|
||||
};
|
||||
@@ -1996,12 +2002,36 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
if crate::is_support_file_copy_paste_num(self.handler.lc.read().unwrap().version) {
|
||||
if let Some(msg) = unix_file_clip::serve_clip_messages(
|
||||
ClipboardSide::Client,
|
||||
clip,
|
||||
self.client_conn_id,
|
||||
) {
|
||||
allow_err!(_peer.send(&msg).await);
|
||||
let mut out_msg = None;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
if clipboard::platform::unix::macos::should_handle_msg(&clip) {
|
||||
if let Err(e) = ContextSend::proc(|context| -> ResultType<()> {
|
||||
context
|
||||
.server_clip_file(self.client_conn_id, clip)
|
||||
.map_err(|e| e.into())
|
||||
}) {
|
||||
log::error!("failed to handle cliprdr msg: {}", e);
|
||||
}
|
||||
} else {
|
||||
out_msg = unix_file_clip::serve_clip_messages(
|
||||
ClipboardSide::Client,
|
||||
clip,
|
||||
self.client_conn_id,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
out_msg = unix_file_clip::serve_clip_messages(
|
||||
ClipboardSide::Client,
|
||||
clip,
|
||||
self.client_conn_id,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(msg) = out_msg {
|
||||
allow_err!(peer.send(&msg).await);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,24 @@ pub fn check_clipboard(
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unix-file-copy-paste", target_os = "macos"))]
|
||||
pub fn is_file_url_set_by_rustdesk(url: &Vec<String>) -> bool {
|
||||
if url.len() != 1 {
|
||||
return false;
|
||||
}
|
||||
url.iter()
|
||||
.next()
|
||||
.map(|s| {
|
||||
for prefix in &["file:///tmp/.rustdesk_", "//tmp/.rustdesk_"] {
|
||||
if s.starts_with(prefix) {
|
||||
return s[prefix.len()..].parse::<uuid::Uuid>().is_ok();
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
pub fn check_clipboard_files(
|
||||
ctx: &mut Option<ClipboardContext>,
|
||||
@@ -110,7 +128,6 @@ pub fn update_clipboard_files(files: Vec<String>, side: ClipboardSide) {
|
||||
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
pub fn try_empty_clipboard_files(_side: ClipboardSide, _conn_id: i32) {
|
||||
#[cfg(target_os = "linux")]
|
||||
std::thread::spawn(move || {
|
||||
let mut ctx = CLIPBOARD_CTX.lock().unwrap();
|
||||
if ctx.is_none() {
|
||||
@@ -125,9 +142,22 @@ pub fn try_empty_clipboard_files(_side: ClipboardSide, _conn_id: i32) {
|
||||
}
|
||||
}
|
||||
if let Some(mut ctx) = ctx.as_mut() {
|
||||
use clipboard::platform::unix;
|
||||
if unix::fuse::empty_local_files(_side == ClipboardSide::Client, _conn_id) {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
use clipboard::platform::unix;
|
||||
if unix::fuse::empty_local_files(_side == ClipboardSide::Client, _conn_id) {
|
||||
ctx.try_empty_clipboard_files(_side);
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
ctx.try_empty_clipboard_files(_side);
|
||||
// No need to make sure the context is enabled.
|
||||
clipboard::ContextSend::proc(|context| -> ResultType<()> {
|
||||
context.empty_clipboard(_conn_id).ok();
|
||||
Ok(())
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -351,27 +381,43 @@ impl ClipboardContext {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unix-file-copy-paste", target_os = "macos"))]
|
||||
fn get_file_urls_set_by_rustdesk(
|
||||
data: Vec<ClipboardData>,
|
||||
_side: ClipboardSide,
|
||||
) -> Vec<String> {
|
||||
for item in data.into_iter() {
|
||||
if let ClipboardData::FileUrl(urls) = item {
|
||||
if is_file_url_set_by_rustdesk(&urls) {
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unix-file-copy-paste", target_os = "linux"))]
|
||||
fn get_file_urls_set_by_rustdesk(data: Vec<ClipboardData>, side: ClipboardSide) -> Vec<String> {
|
||||
let exclude_path =
|
||||
clipboard::platform::unix::fuse::get_exclude_paths(side == ClipboardSide::Client);
|
||||
data.into_iter()
|
||||
.filter_map(|c| match c {
|
||||
ClipboardData::FileUrl(urls) => Some(
|
||||
urls.into_iter()
|
||||
.filter(|s| s.starts_with(&*exclude_path))
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
fn try_empty_clipboard_files(&mut self, side: ClipboardSide) {
|
||||
let _lock = ARBOARD_MTX.lock().unwrap();
|
||||
if let Ok(data) = self.get_formats(&[ClipboardFormat::FileUrl]) {
|
||||
#[cfg(target_os = "linux")]
|
||||
let exclude_path =
|
||||
clipboard::platform::unix::fuse::get_exclude_paths(side == ClipboardSide::Client);
|
||||
#[cfg(target_os = "macos")]
|
||||
let exclude_path: Arc<String> = Default::default();
|
||||
let urls = data
|
||||
.into_iter()
|
||||
.filter_map(|c| match c {
|
||||
ClipboardData::FileUrl(urls) => Some(
|
||||
urls.into_iter()
|
||||
.filter(|s| s.starts_with(&*exclude_path))
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
let urls = Self::get_file_urls_set_by_rustdesk(data, side);
|
||||
if !urls.is_empty() {
|
||||
// FIXME:
|
||||
// The host-side clear file clipboard `let _ = self.inner.clear();`,
|
||||
|
||||
@@ -139,6 +139,10 @@ pub fn is_support_file_copy_paste_num(ver: i64) -> bool {
|
||||
ver >= hbb_common::get_version_number("1.3.8")
|
||||
}
|
||||
|
||||
pub fn is_support_file_paste_if_macos(ver: &str) -> bool {
|
||||
hbb_common::get_version_number(ver) >= hbb_common::get_version_number("1.3.9")
|
||||
}
|
||||
|
||||
// is server process, with "--server" args
|
||||
#[inline]
|
||||
pub fn is_server() -> bool {
|
||||
|
||||
@@ -115,6 +115,10 @@ impl Handler {
|
||||
fn check_clipboard_file(&mut self) {
|
||||
if let Some(urls) = check_clipboard_files(&mut self.ctx, ClipboardSide::Host, false) {
|
||||
if !urls.is_empty() {
|
||||
#[cfg(target_os = "macos")]
|
||||
if crate::clipboard::is_file_url_set_by_rustdesk(&urls) {
|
||||
return;
|
||||
}
|
||||
match clipboard::platform::unix::serv_files::sync_files(&urls) {
|
||||
Ok(()) => {
|
||||
// Use `send_data()` here to reuse `handle_file_clip()` in `connection.rs`.
|
||||
|
||||
@@ -1267,11 +1267,13 @@ impl Connection {
|
||||
let is_unix_and_peer_supported = crate::is_support_file_copy_paste(&self.lr.version);
|
||||
#[cfg(not(feature = "unix-file-copy-paste"))]
|
||||
let is_unix_and_peer_supported = false;
|
||||
// to-do: add file clipboard support for macos
|
||||
let is_both_macos = cfg!(target_os = "macos")
|
||||
&& self.lr.my_platform == whoami::Platform::MacOS.to_string();
|
||||
let has_file_clipboard =
|
||||
is_both_windows || (is_unix_and_peer_supported && !is_both_macos);
|
||||
let is_peer_support_paste_if_macos =
|
||||
crate::is_support_file_paste_if_macos(&self.lr.version);
|
||||
let has_file_clipboard = is_both_windows
|
||||
|| (is_unix_and_peer_supported
|
||||
&& (!is_both_macos || is_peer_support_paste_if_macos));
|
||||
platform_additions.insert("has_file_clipboard".into(), json!(has_file_clipboard));
|
||||
}
|
||||
|
||||
@@ -2195,11 +2197,38 @@ impl Connection {
|
||||
}
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
if crate::is_support_file_copy_paste(&self.lr.version) {
|
||||
if let Some(msg) = unix_file_clip::serve_clip_messages(
|
||||
ClipboardSide::Host,
|
||||
clip,
|
||||
self.inner.id(),
|
||||
) {
|
||||
let mut out_msg = None;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
if clipboard::platform::unix::macos::should_handle_msg(&clip) {
|
||||
if let Err(e) = clipboard::ContextSend::make_sure_enabled() {
|
||||
log::error!("failed to restart clipboard context: {}", e);
|
||||
} else {
|
||||
let _ =
|
||||
clipboard::ContextSend::proc(|context| -> ResultType<()> {
|
||||
context
|
||||
.server_clip_file(self.inner.id(), clip)
|
||||
.map_err(|e| e.into())
|
||||
});
|
||||
}
|
||||
} else {
|
||||
out_msg = unix_file_clip::serve_clip_messages(
|
||||
ClipboardSide::Host,
|
||||
clip,
|
||||
self.inner.id(),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
out_msg = unix_file_clip::serve_clip_messages(
|
||||
ClipboardSide::Host,
|
||||
clip,
|
||||
self.inner.id(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(msg) = out_msg {
|
||||
self.send(msg).await;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user