diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index 68ad2529c..5dd0629fb 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -43,7 +43,7 @@ class _FileManagerTabPageState extends State { void initState() { super.initState(); - tabController.onRemove = (_, id) => onRemoveId(id); + tabController.onRemoved = (_, id) => onRemoveId(id); rustDeskWinManager.setMethodHandler((call, fromWindowId) async { print( diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index 6d7390493..de3ba0d92 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -46,7 +46,7 @@ class _PortForwardTabPageState extends State { void initState() { super.initState(); - tabController.onRemove = (_, id) => onRemoveId(id); + tabController.onRemoved = (_, id) => onRemoveId(id); rustDeskWinManager.setMethodHandler((call, fromWindowId) async { debugPrint( diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index b73dacec2..93008de07 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -24,8 +24,9 @@ class ConnectionTabPage extends StatefulWidget { } class _ConnectionTabPageState extends State { - final tabController = - Get.put(DesktopTabController(tabType: DesktopTabType.remoteScreen)); + final tabController = Get.put(DesktopTabController( + tabType: DesktopTabType.remoteScreen, + onSelected: (_, id) => bind.setCurSessionId(id: id))); static const IconData selectedIcon = Icons.desktop_windows_sharp; static const IconData unselectedIcon = Icons.desktop_windows_outlined; @@ -59,11 +60,11 @@ class _ConnectionTabPageState extends State { void initState() { super.initState(); - tabController.onRemove = (_, id) => onRemoveId(id); + tabController.onRemoved = (_, id) => onRemoveId(id); rustDeskWinManager.setMethodHandler((call, fromWindowId) async { print( - "call ${call.method} with args ${call.arguments} from window ${fromWindowId}"); + "call ${call.method} with args ${call.arguments} from window $fromWindowId"); final RxBool fullscreen = Get.find(tag: 'fullscreen'); // for simplify, just replace connectionId diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 2211a0b0d..d04f7871f 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -30,7 +30,7 @@ class _DesktopServerPageState extends State void initState() { gFFI.ffiModel.updateEventListener(""); windowManager.addListener(this); - tabController.onRemove = (_, id) => onRemoveId(id); + tabController.onRemoved = (_, id) => onRemoveId(id); super.initState(); } @@ -99,7 +99,7 @@ class ConnectionManagerState extends State { @override void initState() { gFFI.serverModel.updateClientState(); - gFFI.serverModel.tabController.onSelected = (index) => + gFFI.serverModel.tabController.onSelected = (index, _) => gFFI.chatModel.changeCurrentID(gFFI.serverModel.clients[index].id); super.initState(); } diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 92c868c34..7fae47e69 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -70,10 +70,11 @@ class DesktopTabController { final DesktopTabType tabType; /// index, key - Function(int, String)? onRemove; - Function(int)? onSelected; + Function(int, String)? onRemoved; + Function(int, String)? onSelected; - DesktopTabController({required this.tabType}); + DesktopTabController( + {required this.tabType, this.onRemoved, this.onSelected}); int get length => state.value.tabs.length; @@ -114,7 +115,7 @@ class DesktopTabController { state.value.tabs.removeAt(index); state.value.scrollController.itemCount = state.value.tabs.length; jumpTo(toIndex); - onRemove?.call(index, key); + onRemoved?.call(index, key); } void jumpTo(int index) { @@ -134,7 +135,8 @@ class DesktopTabController { })); }); if (state.value.tabs.length > index) { - onSelected?.call(index); + final key = state.value.tabs[index].key; + onSelected?.call(index, key); } } @@ -146,7 +148,7 @@ class DesktopTabController { void closeBy(String? key) { if (!isDesktop) return; - assert(onRemove != null); + assert(onRemoved != null); if (key == null) { if (state.value.selected < state.value.tabs.length) { remove(state.value.selected); diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 8e5723588..aa9dfd8e2 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -28,7 +28,7 @@ import 'input_model.dart'; import 'platform_model.dart'; typedef HandleMsgBox = Function(Map evt, String id); -bool _waitForImage = false; +final _waitForImage = {}; class FfiModel with ChangeNotifier { PeerInfo _pi = PeerInfo(); @@ -92,7 +92,6 @@ class FfiModel with ChangeNotifier { clear() { _pi = PeerInfo(); _display = Display(); - _waitForImage = false; _secure = null; _direct = null; _inputBlocked = false; @@ -314,7 +313,7 @@ class FfiModel with ChangeNotifier { parent.target?.dialogManager.showLoading( translate('Connected, waiting for image...'), onCancel: closeConnection); - _waitForImage = true; + _waitForImage[peerId] = true; _reconnects = 1; } } @@ -354,8 +353,8 @@ class ImageModel with ChangeNotifier { ImageModel(this.parent); onRgba(Uint8List rgba) { - if (_waitForImage) { - _waitForImage = false; + if (_waitForImage[id]!) { + _waitForImage[id] = false; parent.target?.dialogManager.dismissAll(); } final pid = parent.target?.id; diff --git a/libs/clipboard/src/context_send.rs b/libs/clipboard/src/context_send.rs new file mode 100644 index 000000000..b19270a37 --- /dev/null +++ b/libs/clipboard/src/context_send.rs @@ -0,0 +1,59 @@ +use crate::cliprdr::*; +use hbb_common::log; +use std::sync::Mutex; + +lazy_static::lazy_static! { + static ref CONTEXT_SEND: ContextSend = ContextSend{addr: Mutex::new(0)}; +} + +pub struct ContextSend { + addr: Mutex, +} + +impl ContextSend { + pub fn is_enabled() -> bool { + *CONTEXT_SEND.addr.lock().unwrap() != 0 + } + + pub fn enable(enabled: bool) { + let mut lock = CONTEXT_SEND.addr.lock().unwrap(); + if enabled { + if *lock == 0 { + match crate::create_cliprdr_context(true, false, crate::ProcessSide::ClientSide) { + Ok(context) => { + log::info!("clipboard context for file transfer created."); + *lock = Box::into_raw(context) as _; + } + Err(err) => { + log::error!( + "Create clipboard context for file transfer: {}", + err.to_string() + ); + } + } + } + } else { + if *lock != 0 { + unsafe { + let _ = Box::from_raw(*lock as *mut CliprdrClientContext); + } + log::info!("clipboard context for file transfer destroyed."); + *lock = 0; + } + } + } + + pub fn proc) -> u32>(f: F) -> u32 { + let mut lock = CONTEXT_SEND.addr.lock().unwrap(); + if *lock != 0 { + unsafe { + let mut context = Box::from_raw(*lock as *mut CliprdrClientContext); + let res = f(&mut context); + *lock = Box::into_raw(context) as _; + res + } + } else { + 0 + } + } +} diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 7c6ccae0d..b992e39e3 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -1,6 +1,6 @@ use cliprdr::*; use hbb_common::{ - log, + allow_err, log, tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, @@ -12,33 +12,31 @@ use std::{ boxed::Box, collections::HashMap, ffi::{CStr, CString}, - sync::Mutex, + sync::{Arc, Mutex, RwLock}, }; pub mod cliprdr; +pub mod context_send; +pub use context_send::*; #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "t", content = "c")] pub enum ClipbaordFile { - ServerFormatList { - conn_id: i32, + MonitorReady, + FormatList { format_list: Vec<(i32, String)>, }, - ServerFormatListResponse { - conn_id: i32, + FormatListResponse { msg_flags: i32, }, - ServerFormatDataRequest { - conn_id: i32, + FormatDataRequest { requested_format_id: i32, }, - ServerFormatDataResponse { - conn_id: i32, + FormatDataResponse { msg_flags: i32, format_data: Vec, }, FileContentsRequest { - conn_id: i32, stream_id: i32, list_index: i32, dw_flags: i32, @@ -49,7 +47,6 @@ pub enum ClipbaordFile { clip_data_id: i32, }, FileContentsResponse { - conn_id: i32, msg_flags: i32, stream_id: i32, requested_data: Vec, @@ -61,18 +58,89 @@ struct ConnEnabled { conn_enabled: HashMap, } -lazy_static::lazy_static! { - static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(i32, ClipbaordFile)>, TokioMutex>) = { - let (tx, rx) = unbounded_channel(); - (tx, TokioMutex::new(rx)) - }; - - static ref CLIP_CONN_ENABLED: Mutex = Mutex::new(ConnEnabled::default()); +struct MsgChannel { + peer_id: String, + conn_id: i32, + sender: UnboundedSender, + receiver: Arc>>, } -#[inline(always)] -pub fn get_rx_clip_client<'a>() -> &'a TokioMutex> { - &MSG_CHANNEL_CLIENT.1 +#[derive(PartialEq)] +pub enum ProcessSide { + UnknownSide, + ClientSide, + ServerSide, +} + +lazy_static::lazy_static! { + static ref VEC_MSG_CHANNEL: RwLock> = Default::default(); + static ref CLIP_CONN_ENABLED: Mutex = Mutex::new(ConnEnabled::default()); + static ref PROCESS_SIDE: RwLock = RwLock::new(ProcessSide::UnknownSide); +} + +pub fn get_client_conn_id(peer_id: &str) -> Option { + VEC_MSG_CHANNEL + .read() + .unwrap() + .iter() + .find(|x| x.peer_id == peer_id.to_owned()) + .map(|x| x.conn_id) +} + +pub fn get_rx_cliprdr_client( + peer_id: &str, +) -> (i32, Arc>>) { + let mut lock = VEC_MSG_CHANNEL.write().unwrap(); + match lock.iter().find(|x| x.peer_id == peer_id.to_owned()) { + Some(msg_channel) => (msg_channel.conn_id, msg_channel.receiver.clone()), + None => { + let (sender, receiver) = unbounded_channel(); + let receiver = Arc::new(TokioMutex::new(receiver)); + let receiver2 = receiver.clone(); + let conn_id = lock.len() as i32 + 1; + let msg_channel = MsgChannel { + peer_id: peer_id.to_owned(), + conn_id, + sender, + receiver, + }; + lock.push(msg_channel); + (conn_id, receiver2) + } + } +} + +pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc>> { + let mut lock = VEC_MSG_CHANNEL.write().unwrap(); + match lock.iter().find(|x| x.conn_id == conn_id) { + Some(msg_channel) => msg_channel.receiver.clone(), + None => { + let (sender, receiver) = unbounded_channel(); + let receiver = Arc::new(TokioMutex::new(receiver)); + let receiver2 = receiver.clone(); + let msg_channel = MsgChannel { + peer_id: "".to_owned(), + conn_id, + sender, + receiver, + }; + lock.push(msg_channel); + receiver2 + } + } +} + +#[inline] +fn send_data(conn_id: i32, data: ClipbaordFile) { + // no need to handle result here + if let Some(msg_channel) = VEC_MSG_CHANNEL + .read() + .unwrap() + .iter() + .find(|x| x.conn_id == conn_id) + { + allow_err!(msg_channel.sender.send(data)); + } } pub fn set_conn_enabled(conn_id: i32, enabled: bool) { @@ -88,61 +156,46 @@ pub fn empty_clipboard(context: &mut Box, conn_id: i32) -> pub fn server_clip_file( context: &mut Box, - s_conn_id: i32, + conn_id: i32, msg: ClipbaordFile, ) -> u32 { match msg { - ClipbaordFile::ServerFormatList { - mut conn_id, - format_list, - } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } + ClipbaordFile::MonitorReady => { + log::debug!("server_monitor_ready called"); + let ret = server_monitor_ready(context, conn_id); + log::debug!("server_monitor_ready called, return {}", ret); + ret + } + ClipbaordFile::FormatList { format_list } => { log::debug!("server_format_list called"); let ret = server_format_list(context, conn_id, format_list); log::debug!("server_format_list called, return {}", ret); ret } - ClipbaordFile::ServerFormatListResponse { - mut conn_id, - msg_flags, - } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } + ClipbaordFile::FormatListResponse { msg_flags } => { log::debug!("format_list_response called"); let ret = server_format_list_response(context, conn_id, msg_flags); log::debug!("server_format_list_response called, return {}", ret); ret } - ClipbaordFile::ServerFormatDataRequest { - mut conn_id, + ClipbaordFile::FormatDataRequest { requested_format_id, } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } log::debug!("format_data_request called"); let ret = server_format_data_request(context, conn_id, requested_format_id); log::debug!("server_format_data_request called, return {}", ret); ret } - ClipbaordFile::ServerFormatDataResponse { - mut conn_id, + ClipbaordFile::FormatDataResponse { msg_flags, format_data, } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } log::debug!("format_data_response called"); let ret = server_format_data_response(context, conn_id, msg_flags, format_data); log::debug!("server_format_data_response called, return {}", ret); ret } ClipbaordFile::FileContentsRequest { - mut conn_id, stream_id, list_index, dw_flags, @@ -152,9 +205,6 @@ pub fn server_clip_file( have_clip_data_id, clip_data_id, } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } log::debug!("file_contents_request called"); let ret = server_file_contents_request( context, @@ -172,14 +222,10 @@ pub fn server_clip_file( ret } ClipbaordFile::FileContentsResponse { - mut conn_id, msg_flags, stream_id, requested_data, } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } log::debug!("file_contents_response called"); let ret = server_file_contents_response( context, @@ -194,6 +240,19 @@ pub fn server_clip_file( } } +pub fn server_monitor_ready(context: &mut Box, conn_id: i32) -> u32 { + unsafe { + let monitor_ready = CLIPRDR_MONITOR_READY { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: 0 as UINT16, + dataLen: 0 as UINT32, + }; + let ret = ((**context).MonitorReady.unwrap())(&mut (**context), &monitor_ready); + ret as u32 + } +} + pub fn server_format_list( context: &mut Box, conn_id: i32, @@ -243,6 +302,7 @@ pub fn server_format_list( ret as u32 } } + pub fn server_format_list_response( context: &mut Box, conn_id: i32, @@ -262,6 +322,7 @@ pub fn server_format_list_response( ret as u32 } } + pub fn server_format_data_request( context: &mut Box, conn_id: i32, @@ -280,6 +341,7 @@ pub fn server_format_data_request( ret as u32 } } + pub fn server_format_data_response( context: &mut Box, conn_id: i32, @@ -301,6 +363,7 @@ pub fn server_format_data_response( ret as u32 } } + pub fn server_file_contents_request( context: &mut Box, conn_id: i32, @@ -335,6 +398,7 @@ pub fn server_file_contents_request( ret as u32 } } + pub fn server_file_contents_response( context: &mut Box, conn_id: i32, @@ -363,7 +427,10 @@ pub fn server_file_contents_response( pub fn create_cliprdr_context( enable_files: bool, enable_others: bool, + process_side: ProcessSide, ) -> ResultType> { + *PROCESS_SIDE.write().unwrap() = process_side; + Ok(CliprdrClientContext::create( enable_files, enable_others, @@ -378,8 +445,11 @@ pub fn create_cliprdr_context( } extern "C" fn check_enabled(conn_id: UINT32) -> BOOL { - let lock = CLIP_CONN_ENABLED.lock().unwrap(); + if *PROCESS_SIDE.read().unwrap() == ProcessSide::ClientSide { + return TRUE; + } + let lock = CLIP_CONN_ENABLED.lock().unwrap(); let mut connd_enabled = false; if conn_id != 0 { if let Some(true) = lock.conn_enabled.get(&(conn_id as i32)) { @@ -422,12 +492,17 @@ extern "C" fn client_format_list( } conn_id = (*clip_format_list).connID as i32; } - let data = ClipbaordFile::ServerFormatList { - conn_id, - format_list, - }; + let data = ClipbaordFile::FormatList { format_list }; // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + if conn_id == 0 { + VEC_MSG_CHANNEL + .read() + .unwrap() + .iter() + .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone()))); + } else { + send_data(conn_id, data); + } 0 } @@ -444,9 +519,8 @@ extern "C" fn client_format_list_response( conn_id = (*format_list_response).connID as i32; msg_flags = (*format_list_response).msgFlags as i32; } - let data = ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags }; - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + let data = ClipbaordFile::FormatListResponse { msg_flags }; + send_data(conn_id, data); 0 } @@ -463,12 +537,11 @@ extern "C" fn client_format_data_request( conn_id = (*format_data_request).connID as i32; requested_format_id = (*format_data_request).requestedFormatId as i32; } - let data = ClipbaordFile::ServerFormatDataRequest { - conn_id, + let data = ClipbaordFile::FormatDataRequest { requested_format_id, }; // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + send_data(conn_id, data); 0 } @@ -495,13 +568,11 @@ extern "C" fn client_format_data_response( .to_vec(); } } - let data = ClipbaordFile::ServerFormatDataResponse { - conn_id, + let data = ClipbaordFile::FormatDataResponse { msg_flags, format_data, }; - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + send_data(conn_id, data); 0 } @@ -544,7 +615,6 @@ extern "C" fn client_file_contents_request( } let data = ClipbaordFile::FileContentsRequest { - conn_id, stream_id, list_index, dw_flags, @@ -554,8 +624,7 @@ extern "C" fn client_file_contents_request( have_clip_data_id, clip_data_id, }; - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + send_data(conn_id, data); 0 } @@ -585,13 +654,11 @@ extern "C" fn client_file_contents_response( } } let data = ClipbaordFile::FileContentsResponse { - conn_id, msg_flags, stream_id, requested_data, }; - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + send_data(conn_id, data); 0 } diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index f55eeb718..7374b27c1 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -135,14 +135,14 @@ typedef struct _FORMAT_IDS FORMAT_IDS; #define TAG "windows" -#ifdef WITH_DEBUG_CLIPRDR -#define DEBUG_CLIPRDR(...) printf(TAG, __VA_ARGS__) -#else -#define DEBUG_CLIPRDR(...) \ - do \ - { \ - } while (0) -#endif +// #ifdef WITH_DEBUG_CLIPRDR +#define DEBUG_CLIPRDR(fmt, ...) fprintf(stderr, "DEBUG %s[%d] %s() " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__);fflush(stderr) +// #else +// #define DEBUG_CLIPRDR(fmt, ...) \ +// do \ +// { \ +// } while (0) +// #endif typedef BOOL(WINAPI *fnAddClipboardFormatListener)(HWND hwnd); typedef BOOL(WINAPI *fnRemoveClipboardFormatListener)(HWND hwnd); @@ -193,6 +193,7 @@ struct _CliprdrDataObject ULONG m_nStreams; IStream **m_pStream; void *m_pData; + DWORD m_processID; UINT32 m_connID; }; typedef struct _CliprdrDataObject CliprdrDataObject; @@ -246,7 +247,7 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr); BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr); BOOL wf_do_empty_cliprdr(wfClipboard *clipboard); -static BOOL wf_create_file_obj(UINT32 connID, wfClipboard *cliprdrrdr, IDataObject **ppDataObject); +static BOOL wf_create_file_obj(UINT32 *connID, wfClipboard *clipboard, IDataObject **ppDataObject); static void wf_destroy_file_obj(IDataObject *instance); static UINT32 get_remote_format_id(wfClipboard *clipboard, UINT32 local_format); static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UINT32 format); @@ -673,6 +674,12 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO if (!pFormatEtc || !pMedium || !instance) return E_INVALIDARG; + // Not the same process id + if (instance->m_processID != GetCurrentProcessId()) + { + return E_INVALIDARG; + } + clipboard = (wfClipboard *)instance->m_pData; if (!clipboard->context->CheckEnabled(instance->m_connID)) { @@ -892,6 +899,7 @@ static CliprdrDataObject *CliprdrDataObject_New(UINT32 connID, FORMATETC *fmtetc instance->m_pData = data; instance->m_nStreams = 0; instance->m_pStream = NULL; + instance->m_processID = GetCurrentProcessId(); instance->m_connID = connID; if (count > 0) @@ -1340,7 +1348,7 @@ static BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard *clipboard, PUINT lpu return TRUE; } -static UINT cliprdr_send_format_list(wfClipboard *clipboard) +static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID) { UINT rc; int count = 0; @@ -1415,7 +1423,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) } } - formatList.connID = 0; + formatList.connID = connID; formatList.numFormats = numFormats; formatList.formats = formats; formatList.msgType = CB_FORMAT_LIST; @@ -1645,7 +1653,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM clipboard->hmem = NULL; } - cliprdr_send_format_list(clipboard); + cliprdr_send_format_list(clipboard, 0); } } @@ -1669,7 +1677,8 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM DEBUG_CLIPRDR("info: WM_RENDERFORMAT"); // https://docs.microsoft.com/en-us/windows/win32/dataxchg/wm-renderformat?redirectedfrom=MSDN - if (cliprdr_send_data_request(0, 0, clipboard, (UINT32)wParam) != 0) + // to-do: ensure usage of 0 + if (cliprdr_send_data_request(0, clipboard, (UINT32)wParam) != 0) { DEBUG_CLIPRDR("error: cliprdr_send_data_request failed."); break; @@ -1695,7 +1704,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM if ((GetClipboardOwner() != clipboard->hwnd) && (S_FALSE == OleIsCurrentClipboard(clipboard->data_obj))) { - cliprdr_send_format_list(clipboard); + cliprdr_send_format_list(clipboard, 0); } SendMessage(clipboard->hWndNextViewer, Msg, wParam, lParam); @@ -2128,9 +2137,14 @@ static UINT wf_cliprdr_send_client_capabilities(wfClipboard *clipboard) CLIPRDR_CAPABILITIES capabilities; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; - if (!clipboard || !clipboard->context || !clipboard->context->ClientCapabilities) + if (!clipboard || !clipboard->context) return ERROR_INTERNAL_ERROR; + // Ignore ClientCapabilities for now + if (!clipboard->context->ClientCapabilities) { + return CHANNEL_RC_OK; + } + capabilities.connID = 0; capabilities.cCapabilitiesSets = 1; capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET *)&(generalCapabilitySet); @@ -2162,7 +2176,7 @@ static UINT wf_cliprdr_monitor_ready(CliprdrClientContext *context, if (rc != CHANNEL_RC_OK) return rc; - return cliprdr_send_format_list(clipboard); + return cliprdr_send_format_list(clipboard, monitorReady->connID); } /** diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index 4bb015866..aaa02c327 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -360,38 +360,31 @@ message FileDirCreate { // main logic from freeRDP message CliprdrMonitorReady { - int32 conn_id = 1; } message CliprdrFormat { - int32 conn_id = 1; int32 id = 2; string format = 3; } message CliprdrServerFormatList { - int32 conn_id = 1; repeated CliprdrFormat formats = 2; } message CliprdrServerFormatListResponse { - int32 conn_id = 1; int32 msg_flags = 2; } message CliprdrServerFormatDataRequest { - int32 conn_id = 1; int32 requested_format_id = 2; } message CliprdrServerFormatDataResponse { - int32 conn_id = 1; int32 msg_flags = 2; bytes format_data = 3; } message CliprdrFileContentsRequest { - int32 conn_id = 1; int32 stream_id = 2; int32 list_index = 3; int32 dw_flags = 4; @@ -403,7 +396,6 @@ message CliprdrFileContentsRequest { } message CliprdrFileContentsResponse { - int32 conn_id = 1; int32 msg_flags = 3; int32 stream_id = 4; bytes requested_data = 5; diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index a415576c8..b108c1ad0 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -6,6 +6,9 @@ use crate::common; #[cfg(not(any(target_os = "android", target_os = "ios")))] use crate::common::{check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}; +#[cfg(windows)] +use clipboard::{cliprdr::CliprdrClientContext, ContextSend}; + use crate::ui_session_interface::{InvokeUiSession, Session}; use crate::{client::Data, client::Interface}; @@ -22,7 +25,11 @@ use hbb_common::tokio::{ sync::mpsc, time::{self, Duration, Instant, Interval}, }; -use hbb_common::{allow_err, message_proto::*, sleep}; +use hbb_common::{ + allow_err, + message_proto::{self, *}, + sleep, +}; use hbb_common::{fs, log, Stream}; use std::collections::HashMap; @@ -43,7 +50,7 @@ pub struct Remote { last_update_jobs_status: (Instant, HashMap), first_frame: bool, #[cfg(windows)] - clipboard_file_context: Option>, + client_conn_id: i32, // used for clipboard data_count: Arc, frame_count: Arc, video_format: CodecFormat, @@ -72,7 +79,7 @@ impl Remote { last_update_jobs_status: (Instant::now(), Default::default()), first_frame: false, #[cfg(windows)] - clipboard_file_context: None, + client_conn_id: 0, data_count: Arc::new(AtomicUsize::new(0)), frame_count, video_format: CodecFormat::Unknown, @@ -107,7 +114,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 +166,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 => { @@ -778,13 +792,7 @@ impl Remote { } #[cfg(windows)] Some(message::Union::Cliprdr(clip)) => { - 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); - } - } - } + self.handle_cliprdr_msg(clip); } Some(message::Union::FileResponse(fr)) => { match fr.union { @@ -1158,30 +1166,32 @@ impl Remote { true } - fn check_clipboard_file_context(&mut self) { + fn check_clipboard_file_context(&self) { #[cfg(windows)] { let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst) && self.handler.lc.read().unwrap().enable_file_transfer; - if enabled == self.clipboard_file_context.is_none() { - self.clipboard_file_context = 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 { - log::info!("clipboard context for file transfer destroyed."); - None - }; + ContextSend::enable(enabled); + } + } + + #[cfg(windows)] + fn handle_cliprdr_msg(&self, clip: message_proto::Cliprdr) { + if !self.handler.lc.read().unwrap().disable_clipboard { + #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] + if let Some(message_proto::cliprdr::Union::FormatList(_)) = &clip.union { + if self.client_conn_id + != clipboard::get_client_conn_id(&crate::flutter::get_cur_session_id()) + .unwrap_or(0) + { + return; + } + } + + if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) { + ContextSend::proc(|context: &mut Box| -> u32 { + clipboard::server_clip_file(context, self.client_conn_id, clip) + }); } } } diff --git a/src/clipboard_file.rs b/src/clipboard_file.rs index b6c0513e8..e6f40e215 100644 --- a/src/clipboard_file.rs +++ b/src/clipboard_file.rs @@ -3,14 +3,19 @@ use hbb_common::message_proto::*; pub fn clip_2_msg(clip: ClipbaordFile) -> Message { match clip { - ClipbaordFile::ServerFormatList { - conn_id, - format_list, - } => { + ClipbaordFile::MonitorReady => Message { + union: Some(message::Union::Cliprdr(Cliprdr { + union: Some(cliprdr::Union::Ready(CliprdrMonitorReady { + ..Default::default() + })), + ..Default::default() + })), + ..Default::default() + }, + 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 +24,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 +32,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 +44,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 +58,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 +75,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { ..Default::default() }, ClipbaordFile::FileContentsRequest { - conn_id, stream_id, list_index, dw_flags, @@ -89,7 +87,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 +103,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { ..Default::default() }, ClipbaordFile::FileContentsResponse { - conn_id, msg_flags, stream_id, requested_data, @@ -114,7 +110,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(), @@ -130,38 +125,26 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { pub fn msg_2_clip(msg: Cliprdr) -> Option { match msg.union { + Some(cliprdr::Union::Ready(_)) => Some(ClipbaordFile::MonitorReady), Some(cliprdr::Union::FormatList(data)) => { let mut format_list: Vec<(i32, String)> = Vec::new(); 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 +157,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..5e844f910 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -22,7 +22,8 @@ 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(); + static ref CUR_SESSION_ID: RwLock = Default::default(); + pub static ref SESSIONS: RwLock>> = Default::default(); pub static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel } @@ -564,3 +565,13 @@ pub fn make_fd_flutter(id: i32, entries: &Vec, only_count: bool) -> S m.insert("total_size".into(), json!(n as f64)); serde_json::to_string(&m).unwrap_or("".into()) } + +pub fn get_cur_session_id() -> String { + CUR_SESSION_ID.read().unwrap().clone() +} + +pub fn set_cur_session_id(id: String) { + if get_cur_session_id() != id { + *CUR_SESSION_ID.write().unwrap() = id; + } +} diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 5fdb3122c..cddaf4d79 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1052,6 +1052,10 @@ pub fn main_update_me() -> SyncReturn { SyncReturn(true) } +pub fn set_cur_session_id(id: String) { + super::flutter::set_cur_session_id(id) +} + pub fn install_show_run_without_install() -> SyncReturn { SyncReturn(show_run_without_install()) } diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 8cf1623c5..de304c459 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -249,8 +249,8 @@ pub(super) fn release_resouce() { if *write_lock != 0 { let cap_display_info: *mut CapDisplayInfo = *write_lock as _; unsafe { - let box_capturer = Box::from_raw((*cap_display_info).capturer.0); - let box_cap_display_info = Box::from_raw(cap_display_info); + let _box_capturer = Box::from_raw((*cap_display_info).capturer.0); + let _box_cap_display_info = Box::from_raw(cap_display_info); *write_lock = 0; } } diff --git a/src/ui.rs b/src/ui.rs index 63dc4704a..548bfad43 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -53,11 +53,8 @@ fn check_connect_status( ) { let status = Arc::new(Mutex::new((0, false, 0, "".to_owned()))); let options = Arc::new(Mutex::new(Config::get_options())); - let cloned = status.clone(); - let cloned_options = options.clone(); let (tx, rx) = mpsc::unbounded_channel::(); let password = Arc::new(Mutex::new(String::default())); - let cloned_password = password.clone(); std::thread::spawn(move || crate::ui_interface::check_connect_status_(reconnect, rx)); (status, options, tx, password) } @@ -514,17 +511,17 @@ impl UI { } fn get_lan_peers(&self) -> String { - let peers = get_lan_peers() - .into_iter() - .map(|mut peer| { - ( - peer.remove("id").unwrap_or_default(), - peer.remove("username").unwrap_or_default(), - peer.remove("hostname").unwrap_or_default(), - peer.remove("platform").unwrap_or_default(), - ) - }) - .collect::>(); + // let peers = get_lan_peers() + // .into_iter() + // .map(|mut peer| { + // ( + // peer.remove("id").unwrap_or_default(), + // peer.remove("username").unwrap_or_default(), + // peer.remove("hostname").unwrap_or_default(), + // peer.remove("platform").unwrap_or_default(), + // ) + // }) + // .collect::>(); serde_json::to_string(&get_lan_peers()).unwrap_or_default() } 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..7296f8738 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -1,17 +1,22 @@ -use std::ops::{Deref, DerefMut}; +#[cfg(windows)] +use std::sync::Arc; use std::{ collections::HashMap, iter::FromIterator, + ops::{Deref, DerefMut}, sync::{ atomic::{AtomicI64, Ordering}, RwLock, }, }; +#[cfg(windows)] +use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, ContextSend}; use serde_derive::Serialize; -use crate::ipc::Data; -use crate::ipc::{self, new_listener, Connection}; +use crate::ipc::{self, new_listener, Connection, Data}; +#[cfg(windows)] +use hbb_common::tokio::sync::Mutex as TokioMutex; use hbb_common::{ allow_err, config::Config, @@ -22,7 +27,7 @@ use hbb_common::{ protobuf::Message as _, tokio::{ self, - sync::mpsc::{self, UnboundedSender}, + sync::mpsc::{self, unbounded_channel, UnboundedSender}, task::spawn_blocking, }, }; @@ -46,8 +51,19 @@ pub struct Client { tx: UnboundedSender, } +struct IpcTaskRunner { + stream: Connection, + cm: ConnectionManager, + tx: mpsc::UnboundedSender, + rx: mpsc::UnboundedReceiver, + close: bool, + conn_id: i32, + #[cfg(windows)] + file_transfer_enabled: bool, +} + 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,23 +231,185 @@ pub fn get_clients_length() -> usize { clients.len() } -pub enum ClipboardFileData { +impl IpcTaskRunner { #[cfg(windows)] - Clip((i32, ipc::ClipbaordFile)), - Enable((i32, bool)), + async fn enable_cliprdr_file_context(&mut self, conn_id: i32, enabled: bool) { + if conn_id == 0 { + return; + } + + let pre_enabled = ContextSend::is_enabled(); + ContextSend::enable(enabled); + if !pre_enabled && ContextSend::is_enabled() { + allow_err!( + self.stream + .send(&Data::ClipbaordFile(clipboard::ClipbaordFile::MonitorReady)) + .await + ); + } + clipboard::set_conn_enabled(conn_id, enabled); + if !enabled { + ContextSend::proc(|context: &mut Box| -> u32 { + clipboard::empty_clipboard(context, conn_id); + 0 + }); + } + } + + async fn run(&mut self) { + use hbb_common::config::LocalConfig; + + // for tmp use, without real conn id + let mut write_jobs: Vec = Vec::new(); + + #[cfg(windows)] + if self.conn_id > 0 { + self.enable_cliprdr_file_context(self.conn_id, self.file_transfer_enabled) + .await; + } + + #[cfg(windows)] + let rx_clip1; + let mut rx_clip; + let _tx_clip; + #[cfg(windows)] + if self.conn_id > 0 { + rx_clip1 = clipboard::get_rx_cliprdr_server(self.conn_id); + rx_clip = rx_clip1.lock().await; + } else { + let rx_clip2; + (_tx_clip, rx_clip2) = unbounded_channel::(); + rx_clip1 = Arc::new(TokioMutex::new(rx_clip2)); + rx_clip = rx_clip1.lock().await; + } + #[cfg(not(windows))] + { + (_tx_clip, rx_clip) = unbounded_channel::(); + } + + loop { + tokio::select! { + res = self.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: _file_transfer_enabled, restart, recording} => { + log::debug!("conn_id: {}", id); + self.cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, self.tx.clone()); + self.conn_id = id; + #[cfg(windows)] + { + self.file_transfer_enabled = _file_transfer_enabled; + } + break; + } + Data::Close => { + #[cfg(windows)] + self.enable_cliprdr_file_context(self.conn_id, false).await; + log::info!("cm ipc connection closed from connection request"); + break; + } + Data::Disconnected => { + self.close = false; + #[cfg(windows)] + self.enable_cliprdr_file_context(self.conn_id, false).await; + log::info!("cm ipc connection disconnect"); + break; + } + Data::PrivacyModeState((_id, _)) => { + #[cfg(windows)] + cm_inner_send(_id, data); + } + Data::ClickTime(ms) => { + CLICK_TIME.store(ms, Ordering::SeqCst); + } + Data::ChatMessage { text } => { + self.cm.new_message(self.conn_id, text); + } + Data::FS(fs) => { + handle_fs(fs, &mut write_jobs, &self.tx).await; + } + Data::ClipbaordFile(_clip) => { + #[cfg(windows)] + { + let conn_id = self.conn_id; + ContextSend::proc(|context: &mut Box| -> u32 { + clipboard::server_clip_file(context, conn_id, _clip) + }); + } + } + #[cfg(windows)] + Data::ClipboardFileEnabled(_enabled) => { + #[cfg(windows)] + self.enable_cliprdr_file_context(self.conn_id, _enabled).await; + } + Data::Theme(dark) => { + self.cm.change_theme(dark); + } + Data::Language(lang) => { + LocalConfig::set_option("lang".to_owned(), lang); + self.cm.change_language(); + } + _ => { + + } + } + } + _ => {} + } + } + Some(data) = self.rx.recv() => { + if self.stream.send(&data).await.is_err() { + break; + } + } + clip_file = rx_clip.recv() => match clip_file { + Some(_clip) => { + #[cfg(windows)] + allow_err!(self.tx.send(Data::ClipbaordFile(_clip))); + } + None => { + // + } + }, + } + } + } + + async fn ipc_task(stream: Connection, cm: ConnectionManager) { + log::debug!("ipc task begin"); + let (tx, rx) = mpsc::unbounded_channel::(); + let mut task_runner = Self { + stream, + cm, + tx, + rx, + close: true, + conn_id: 0, + #[cfg(windows)] + file_transfer_enabled: false, + }; + + task_runner.run().await; + if task_runner.conn_id > 0 { + task_runner.run().await; + } + if task_runner.conn_id > 0 { + task_runner + .cm + .remove_connection(task_runner.conn_id, task_runner.close); + } + log::debug!("ipc task end"); + } } #[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 || { log::info!("try create privacy mode window"); @@ -253,94 +431,10 @@ 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(IpcTaskRunner::::ipc_task( + Connection::new(stream), + cm.clone(), + )); } Err(err) => { log::error!("Couldn't get cm client: {:?}", err); @@ -642,66 +736,7 @@ fn send_raw(msg: Message, tx: &UnboundedSender) { } #[cfg(windows)] -#[tokio::main(flavor = "current_thread")] -pub async fn start_clipboard_file( - cm: ConnectionManager, - mut rx: mpsc::UnboundedReceiver, -) { - let mut cliprdr_context = None; - let mut rx_clip_client = clipboard::get_rx_clip_client().lock().await; - - loop { - tokio::select! { - clip_file = rx_clip_client.recv() => match clip_file { - Some((conn_id, clip)) => { - cmd_inner_send( - conn_id, - Data::ClipbaordFile(clip) - ); - } - None => { - // - } - }, - server_msg = rx.recv() => match server_msg { - Some(ClipboardFileData::Clip((conn_id, clip))) => { - if let Some(ctx) = cliprdr_context.as_mut() { - clipboard::server_clip_file(ctx, conn_id, clip); - } - } - Some(ClipboardFileData::Enable((id, enabled))) => { - if enabled && cliprdr_context.is_none() { - cliprdr_context = Some(match clipboard::create_cliprdr_context(true, false) { - Ok(context) => { - log::info!("clipboard context for file transfer created."); - context - } - Err(err) => { - log::error!( - "Create clipboard context for file transfer: {}", - err.to_string() - ); - return; - } - }); - } - clipboard::set_conn_enabled(id, enabled); - if !enabled { - if let Some(ctx) = cliprdr_context.as_mut() { - clipboard::empty_clipboard(ctx, id); - } - } - } - None => { - break - } - } - } - } -} - -#[cfg(windows)] -fn cmd_inner_send(id: i32, data: Data) { +fn cm_inner_send(id: i32, data: Data) { let lock = CLIENTS.read().unwrap(); if id != 0 { if let Some(s) = lock.get(&id) { diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 142c9cb43..0f7db9a1d 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -76,11 +76,11 @@ pub fn goto_install() { } #[inline] -pub fn install_me(_options: String, _path: String, silent: bool, debug: bool) { +pub fn install_me(_options: String, _path: String, _silent: bool, _debug: bool) { #[cfg(windows)] std::thread::spawn(move || { allow_err!(crate::platform::windows::install_me( - &_options, _path, silent, debug + &_options, _path, _silent, _debug )); std::process::exit(0); }); diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index f95a743c2..a085e9822 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -6,6 +6,7 @@ use crate::client::{ load_config, send_mouse, start_video_audio_threads, FileManager, Key, LoginConfigHandler, QualityStatus, KEY_MAP, SERVER_KEYBOARD_ENABLED, }; +#[cfg(target_os = "linux")] use crate::common::IS_X11; use crate::{client::Data, client::Interface}; use async_trait::async_trait; @@ -812,6 +813,7 @@ impl Session { let keycode: u32 = keycode as u32; let scancode: u32 = scancode as u32; + #[cfg(not(target_os = "windows"))] let key = rdev::key_from_scancode(scancode) as RdevKey; // Windows requires special handling #[cfg(target_os = "windows")]