diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 4d1632292..9f9e7cda9 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -68,7 +68,7 @@ lazy_static::lazy_static! { } #[inline] -pub async fn get_rx_cliprdr_client<'a>( +pub fn get_rx_cliprdr_client<'a>( peer_id: &str, ) -> (i32, Arc>>) { let mut lock = VEC_MSG_CHANNEL.write().unwrap(); @@ -92,7 +92,7 @@ pub async fn get_rx_cliprdr_client<'a>( } #[inline] -pub async fn get_rx_cliprdr_server<'a>( +pub fn get_rx_cliprdr_server<'a>( conn_id: i32, ) -> Arc>> { let mut lock = VEC_MSG_CHANNEL.write().unwrap(); diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index a415576c8..d7a0995c8 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -44,6 +44,8 @@ pub struct Remote { first_frame: bool, #[cfg(windows)] clipboard_file_context: Option>, + #[cfg(windows)] + client_conn_id: i32, // used for clipboard data_count: Arc, frame_count: Arc, video_format: CodecFormat, @@ -73,6 +75,8 @@ impl Remote { first_frame: false, #[cfg(windows)] clipboard_file_context: None, + #[cfg(windows)] + client_conn_id: 0, data_count: Arc::new(AtomicUsize::new(0)), frame_count, video_format: CodecFormat::Unknown, @@ -107,7 +111,14 @@ impl Remote { #[cfg(not(windows))] let (_tx_holder, mut rx_clip_client) = mpsc::unbounded_channel::(); #[cfg(windows)] - let mut rx_clip_client = clipboard::get_rx_clip_client().lock().await; + let (client_conn_id, rx_clip_client1) = + clipboard::get_rx_cliprdr_client(&self.handler.id); + #[cfg(windows)] + let mut rx_clip_client = rx_clip_client1.lock().await; + #[cfg(windows)] + { + self.client_conn_id = client_conn_id; + } let mut status_timer = time::interval(Duration::new(1, 0)); @@ -152,7 +163,7 @@ impl Remote { _msg = rx_clip_client.recv() => { #[cfg(windows)] match _msg { - Some((_, clip)) => { + Some(clip) => { allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await); } None => { @@ -781,7 +792,7 @@ impl Remote { if !self.handler.lc.read().unwrap().disable_clipboard { if let Some(context) = &mut self.clipboard_file_context { if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) { - clipboard::server_clip_file(context, 0, clip); + clipboard::server_clip_file(context, self.client_conn_id, clip); } } } diff --git a/src/clipboard_file.rs b/src/clipboard_file.rs index b6c0513e8..6ae211eeb 100644 --- a/src/clipboard_file.rs +++ b/src/clipboard_file.rs @@ -3,14 +3,10 @@ use hbb_common::message_proto::*; pub fn clip_2_msg(clip: ClipbaordFile) -> Message { match clip { - ClipbaordFile::ServerFormatList { - conn_id, - format_list, - } => { + ClipbaordFile::FormatList { format_list } => { let mut formats: Vec = Vec::new(); for v in format_list.iter() { formats.push(CliprdrFormat { - conn_id: 0, id: v.0, format: v.1.clone(), ..Default::default() @@ -19,7 +15,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FormatList(CliprdrServerFormatList { - conn_id, formats, ..Default::default() })), @@ -28,11 +23,10 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { ..Default::default() } } - ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags } => Message { + ClipbaordFile::FormatListResponse { msg_flags } => Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FormatListResponse( CliprdrServerFormatListResponse { - conn_id, msg_flags, ..Default::default() }, @@ -41,14 +35,12 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { })), ..Default::default() }, - ClipbaordFile::ServerFormatDataRequest { - conn_id, + ClipbaordFile::FormatDataRequest { requested_format_id, } => Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FormatDataRequest( CliprdrServerFormatDataRequest { - conn_id, requested_format_id, ..Default::default() }, @@ -57,15 +49,13 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { })), ..Default::default() }, - ClipbaordFile::ServerFormatDataResponse { - conn_id, + ClipbaordFile::FormatDataResponse { msg_flags, format_data, } => Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FormatDataResponse( CliprdrServerFormatDataResponse { - conn_id, msg_flags, format_data: format_data.into(), ..Default::default() @@ -76,7 +66,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { ..Default::default() }, ClipbaordFile::FileContentsRequest { - conn_id, stream_id, list_index, dw_flags, @@ -89,7 +78,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FileContentsRequest( CliprdrFileContentsRequest { - conn_id, stream_id, list_index, dw_flags, @@ -106,7 +94,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { ..Default::default() }, ClipbaordFile::FileContentsResponse { - conn_id, msg_flags, stream_id, requested_data, @@ -114,7 +101,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FileContentsResponse( CliprdrFileContentsResponse { - conn_id, msg_flags, stream_id, requested_data: requested_data.into(), @@ -135,33 +121,20 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option { for v in data.formats.iter() { format_list.push((v.id, v.format.clone())); } - Some(ClipbaordFile::ServerFormatList { - conn_id: data.conn_id, - format_list, - }) - } - Some(cliprdr::Union::FormatListResponse(data)) => { - Some(ClipbaordFile::ServerFormatListResponse { - conn_id: data.conn_id, - msg_flags: data.msg_flags, - }) - } - Some(cliprdr::Union::FormatDataRequest(data)) => { - Some(ClipbaordFile::ServerFormatDataRequest { - conn_id: data.conn_id, - requested_format_id: data.requested_format_id, - }) - } - Some(cliprdr::Union::FormatDataResponse(data)) => { - Some(ClipbaordFile::ServerFormatDataResponse { - conn_id: data.conn_id, - msg_flags: data.msg_flags, - format_data: data.format_data.into(), - }) + Some(ClipbaordFile::FormatList { format_list }) } + Some(cliprdr::Union::FormatListResponse(data)) => Some(ClipbaordFile::FormatListResponse { + msg_flags: data.msg_flags, + }), + Some(cliprdr::Union::FormatDataRequest(data)) => Some(ClipbaordFile::FormatDataRequest { + requested_format_id: data.requested_format_id, + }), + Some(cliprdr::Union::FormatDataResponse(data)) => Some(ClipbaordFile::FormatDataResponse { + msg_flags: data.msg_flags, + format_data: data.format_data.into(), + }), Some(cliprdr::Union::FileContentsRequest(data)) => { Some(ClipbaordFile::FileContentsRequest { - conn_id: data.conn_id, stream_id: data.stream_id, list_index: data.list_index, dw_flags: data.dw_flags, @@ -174,7 +147,6 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option { } Some(cliprdr::Union::FileContentsResponse(data)) => { Some(ClipbaordFile::FileContentsResponse { - conn_id: data.conn_id, msg_flags: data.msg_flags, stream_id: data.stream_id, requested_data: data.requested_data.into(), diff --git a/src/flutter.rs b/src/flutter.rs index 2b95f9cfb..c651c9fbe 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -22,7 +22,7 @@ pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer"; pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward"; lazy_static::lazy_static! { - pub static ref SESSIONS: RwLock>> = Default::default(); + pub static ref SESSIONS: RwLock>> = Default::default(); pub static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel } diff --git a/src/ui/cm.rs b/src/ui/cm.rs index e5a46817a..3472a184e 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -2,11 +2,6 @@ use crate::ipc::start_pa; use crate::ui_cm_interface::{start_ipc, ConnectionManager, InvokeUiCM}; -#[cfg(windows)] -use clipboard::{ - create_cliprdr_context, empty_clipboard, get_rx_clip_client, server_clip_file, set_conn_enabled, -}; - use hbb_common::{allow_err, log}; use sciter::{make_args, Element, Value, HELEMENT}; use std::sync::Mutex; diff --git a/src/ui/remote.rs b/src/ui/remote.rs index dfd6394a5..ce10827c4 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -14,12 +14,6 @@ use sciter::{ Value, }; -#[cfg(windows)] -use clipboard::{ - cliprdr::CliprdrClientContext, create_cliprdr_context as create_clipboard_file_context, - get_rx_clip_client, server_clip_file, -}; - use hbb_common::{ allow_err, fs::TransferJobMeta, log, message_proto::*, rendezvous_proto::ConnType, }; diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 96fb84b6d..886babe0f 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -8,6 +8,8 @@ use std::{ }, }; +use clipboard::empty_clipboard; +use hbb_common::chrono::Duration; use serde_derive::Serialize; use crate::ipc::Data; @@ -47,7 +49,7 @@ pub struct Client { } lazy_static::lazy_static! { - static ref CLIENTS: RwLock> = Default::default(); + static ref CLIENTS: RwLock> = Default::default(); static ref CLICK_TIME: AtomicI64 = AtomicI64::new(0); } @@ -215,22 +217,182 @@ pub fn get_clients_length() -> usize { clients.len() } +#[derive(Debug)] pub enum ClipboardFileData { #[cfg(windows)] - Clip((i32, ipc::ClipbaordFile)), + Clip(ipc::ClipbaordFile), Enable((i32, bool)), } +async fn cm_ipc_task_wait_login( + mut stream: Connection, + cm: ConnectionManager, + tx: mpsc::UnboundedSender, +) -> (Connection, ConnectionManager, Option<(i32, bool)>) { + let mut ret = None; + loop { + tokio::select! { + res = stream.next() => { + match res { + Err(err) => { + log::info!("cm ipc connection closed: {}", err); + break; + } + Ok(Some(data)) => { + match data { + Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled, restart, recording} => { + log::debug!("conn_id: {}", id); + cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, tx); + ret = Some((id, file_transfer_enabled)); + break; + } + Data::Close => { + log::info!("cm ipc connection closed from connection request"); + break; + } + Data::Disconnected => { + log::info!("cm ipc connection disconnect"); + break; + } + _ => { + + } + } + } + _ => {} + } + } + } + } + (stream, cm, ret) +} + +#[cfg(windows)] +fn create_cliprdr_context_(enabled: bool) -> Option> { + if enabled { + match clipboard::create_cliprdr_context(true, false) { + Ok(context) => { + log::info!("clipboard context for file transfer created."); + Some(context) + } + Err(err) => { + log::error!( + "Create clipboard context for file transfer: {}", + err.to_string() + ); + None + } + } + } else { + None + } +} + +async fn cm_ipc_task_loop( + mut stream: Connection, + cm: ConnectionManager, + tx: mpsc::UnboundedSender, + mut rx: mpsc::UnboundedReceiver, + mut conn_id: i32, + #[cfg(windows)] file_transfer_enabled: bool, +) { + use hbb_common::config::LocalConfig; + + // for tmp use, without real conn id + let conn_id_tmp = -1; + let mut write_jobs: Vec = Vec::new(); + let mut close = true; + + let (tx_file, _rx_file) = mpsc::unbounded_channel::(); + #[cfg(windows)] + std::thread::spawn(move || { + start_clipboard_file(conn_id, _rx_file); + }); + #[cfg(windows)] + allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, file_transfer_enabled)))); + + loop { + tokio::select! { + res = stream.next() => { + match res { + Err(err) => { + log::info!("cm ipc connection closed: {}", err); + break; + } + Ok(Some(data)) => { + match data { + Data::Close => { + allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, false)))); + log::info!("cm ipc connection closed from connection request"); + break; + } + Data::Disconnected => { + close = false; + allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, false)))); + log::info!("cm ipc connection disconnect"); + break; + } + Data::PrivacyModeState((id, _)) => { + conn_id = conn_id_tmp; + allow_err!(tx.send(data)); + } + Data::ClickTime(ms) => { + CLICK_TIME.store(ms, Ordering::SeqCst); + } + Data::ChatMessage { text } => { + cm.new_message(conn_id, text); + } + Data::FS(fs) => { + handle_fs(fs, &mut write_jobs, &tx).await; + } + #[cfg(windows)] + Data::ClipbaordFile(_clip) => { + allow_err!(tx_file.send(ClipboardFileData::Clip(_clip))); + } + #[cfg(windows)] + Data::ClipboardFileEnabled(enabled) => { + allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, enabled)))); + } + Data::Theme(dark) => { + cm.change_theme(dark); + } + Data::Language(lang) => { + LocalConfig::set_option("lang".to_owned(), lang); + cm.change_language(); + } + _ => { + + } + } + } + _ => {} + } + } + Some(data) = rx.recv() => { + if stream.send(&data).await.is_err() { + break; + } + } + } + } + if conn_id != conn_id_tmp { + cm.remove_connection(conn_id, close); + } +} + +async fn cm_ipc_task(stream: Connection, cm: ConnectionManager) { + let (tx, rx) = mpsc::unbounded_channel::(); + let (stream, cm, wait_res) = cm_ipc_task_wait_login(stream, cm, tx.clone()).await; + if let Some((conn_id, file_transfer_enabled)) = wait_res { + cm_ipc_task_loop(stream, cm, tx, rx, conn_id, file_transfer_enabled).await; + } +} + #[cfg(not(any(target_os = "android", target_os = "ios")))] #[tokio::main(flavor = "current_thread")] pub async fn start_ipc(cm: ConnectionManager) { - use hbb_common::config::LocalConfig; - - let (tx_file, _rx_file) = mpsc::unbounded_channel::(); #[cfg(windows)] let cm_clip = cm.clone(); - #[cfg(windows)] - std::thread::spawn(move || start_clipboard_file(cm_clip, _rx_file)); #[cfg(windows)] std::thread::spawn(move || { @@ -253,94 +415,7 @@ pub async fn start_ipc(cm: ConnectionManager) { match result { Ok(stream) => { log::debug!("Got new connection"); - let mut stream = Connection::new(stream); - let cm = cm.clone(); - let tx_file = tx_file.clone(); - tokio::spawn(async move { - // for tmp use, without real conn id - let conn_id_tmp = -1; - let mut conn_id: i32 = 0; - let (tx, mut rx) = mpsc::unbounded_channel::(); - let mut write_jobs: Vec = Vec::new(); - let mut close = true; - loop { - tokio::select! { - res = stream.next() => { - match res { - Err(err) => { - log::info!("cm ipc connection closed: {}", err); - break; - } - Ok(Some(data)) => { - match data { - Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled, restart, recording} => { - log::debug!("conn_id: {}", id); - conn_id = id; - tx_file.send(ClipboardFileData::Enable((id, file_transfer_enabled))).ok(); - cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, tx.clone()); - } - Data::Close => { - tx_file.send(ClipboardFileData::Enable((conn_id, false))).ok(); - log::info!("cm ipc connection closed from connection request"); - break; - } - Data::Disconnected => { - close = false; - tx_file.send(ClipboardFileData::Enable((conn_id, false))).ok(); - log::info!("cm ipc connection disconnect"); - break; - } - Data::PrivacyModeState((id, _)) => { - conn_id = conn_id_tmp; - allow_err!(tx.send(data)); - } - Data::ClickTime(ms) => { - CLICK_TIME.store(ms, Ordering::SeqCst); - } - Data::ChatMessage { text } => { - cm.new_message(conn_id, text); - } - Data::FS(fs) => { - handle_fs(fs, &mut write_jobs, &tx).await; - } - #[cfg(windows)] - Data::ClipbaordFile(_clip) => { - tx_file - .send(ClipboardFileData::Clip((conn_id, _clip))) - .ok(); - } - #[cfg(windows)] - Data::ClipboardFileEnabled(enabled) => { - tx_file - .send(ClipboardFileData::Enable((conn_id, enabled))) - .ok(); - } - Data::Theme(dark) => { - cm.change_theme(dark); - } - Data::Language(lang) => { - LocalConfig::set_option("lang".to_owned(), lang); - cm.change_language(); - } - _ => { - - } - } - } - _ => {} - } - } - Some(data) = rx.recv() => { - if stream.send(&data).await.is_err() { - break; - } - } - } - } - if conn_id != conn_id_tmp { - cm.remove_connection(conn_id, close); - } - }); + tokio::spawn(cm_ipc_task(Connection::new(stream), cm.clone())); } Err(err) => { log::error!("Couldn't get cm client: {:?}", err); @@ -643,17 +718,18 @@ fn send_raw(msg: Message, tx: &UnboundedSender) { #[cfg(windows)] #[tokio::main(flavor = "current_thread")] -pub async fn start_clipboard_file( - cm: ConnectionManager, +pub async fn start_clipboard_file( + conn_id: i32, mut rx: mpsc::UnboundedReceiver, ) { let mut cliprdr_context = None; - let mut rx_clip_client = clipboard::get_rx_clip_client().lock().await; + let rx_clip_client1 = clipboard::get_rx_cliprdr_server(conn_id); + let mut rx_clip_client = rx_clip_client1.lock().await; loop { tokio::select! { clip_file = rx_clip_client.recv() => match clip_file { - Some((conn_id, clip)) => { + Some(clip) => { cmd_inner_send( conn_id, Data::ClipbaordFile(clip) @@ -664,7 +740,7 @@ pub async fn start_clipboard_file( } }, server_msg = rx.recv() => match server_msg { - Some(ClipboardFileData::Clip((conn_id, clip))) => { + Some(ClipboardFileData::Clip(clip)) => { if let Some(ctx) = cliprdr_context.as_mut() { clipboard::server_clip_file(ctx, conn_id, clip); }