From 1a59a6ac2e9e66d6a8020aa0567c883b6bb4c652 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Mon, 21 Sep 2026 00:56:16 +0800 Subject: [PATCH] [refactor] build host information in the wire library --- .../devices/session_device_manager.cpp | 29 ++++- .../features/devices/session_device_manager.h | 10 +- .../src/gui/runtime/peer_data_callbacks.cpp | 5 +- .../src/gui/runtime/peer_event_handler.cpp | 110 ++++------------ .../src/gui/runtime/remote_action_codec.cpp | 120 ------------------ .../src/gui/runtime/remote_action_codec.h | 23 ---- docs/gui-architecture.md | 3 +- libs/wire/include/remote_action.h | 20 +++ libs/wire/src/remote_action.cpp | 39 ++++++ 9 files changed, 118 insertions(+), 241 deletions(-) delete mode 100644 apps/desktop/src/gui/runtime/remote_action_codec.cpp delete mode 100644 apps/desktop/src/gui/runtime/remote_action_codec.h diff --git a/apps/desktop/src/gui/features/devices/session_device_manager.cpp b/apps/desktop/src/gui/features/devices/session_device_manager.cpp index 66fb409c..3b2f403d 100644 --- a/apps/desktop/src/gui/features/devices/session_device_manager.cpp +++ b/apps/desktop/src/gui/features/devices/session_device_manager.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "platform.h" #include "rd_log.h" @@ -146,7 +147,7 @@ int SessionDeviceManager::InitializeScreenCapturer() { ? 30 : 60; LOG_INFO("Init screen capturer with {} fps", fps); - display_info_list_.clear(); + SetDisplayInfoList({}); registered_display_stream_count_ = 0; last_video_frame_stream_id_.clear(); invalid_video_stream_id_logged_ = false; @@ -256,11 +257,11 @@ int SessionDeviceManager::InitializeScreenCapturer() { if (init_ret == 0) { LOG_INFO("Init screen capturer success"); - const auto latest_display_info = screen_capturer_->GetDisplayInfoList(); + auto latest_display_info = screen_capturer_->GetDisplayInfoList(); + registered_display_stream_count_ = latest_display_info.size(); if (!latest_display_info.empty()) { - display_info_list_ = latest_display_info; + SetDisplayInfoList(std::move(latest_display_info)); } - registered_display_stream_count_ = display_info_list_.size(); return 0; } @@ -329,6 +330,11 @@ void SessionDeviceManager::StopSpeakerCapturer() { speaker_capture_.SetEnabled(false); } +void SessionDeviceManager::SetDisplayInfoList(std::vector displays) { + std::lock_guard lock(display_info_mutex_); + display_info_list_ = std::move(displays); +} + int SessionDeviceManager::StartMouseController() { #ifdef __APPLE__ if (!owner_.EnsureMacAccessibilityPermission()) { @@ -657,11 +663,22 @@ void SessionDeviceManager::ResetToInitialDisplay() { owner_.selected_display_ = 0; } -const std::vector & -SessionDeviceManager::display_info_list() const { +std::vector SessionDeviceManager::display_info_list() const { + std::lock_guard lock(display_info_mutex_); return display_info_list_; } +std::vector SessionDeviceManager::host_display_list() const { + std::lock_guard lock(display_info_mutex_); + std::vector displays; + displays.reserve(display_info_list_.size()); + for (const auto &display : display_info_list_) { + displays.push_back({display.name, display.left, display.top, display.right, + display.bottom}); + } + return displays; +} + void SessionDeviceManager::DestroyDevices() { speaker_capture_.Shutdown(); if (mouse_controller_) { diff --git a/apps/desktop/src/gui/features/devices/session_device_manager.h b/apps/desktop/src/gui/features/devices/session_device_manager.h index 28365c19..2b1a3bbb 100644 --- a/apps/desktop/src/gui/features/devices/session_device_manager.h +++ b/apps/desktop/src/gui/features/devices/session_device_manager.h @@ -74,7 +74,12 @@ public: int SwitchDisplay(int display_id); void ResetToInitialDisplay(); - const std::vector &display_info_list() const; + // Snapshot of the capture displays. The UI thread refreshes the list every + // tick while transport threads build host information and map mouse input + // from it, so callers get a copy taken under the lock. + std::vector display_info_list() const; + // The same snapshot in the wire's host information form. + std::vector host_display_list() const; private: struct CapturedKeyboardInput { @@ -91,6 +96,7 @@ private: bool ShouldSendCapturedFrame(std::chrono::steady_clock::time_point now, int fps); bool ShouldCaptureCursor() const; + void SetDisplayInfoList(std::vector displays); void RecordCaptureCadence(std::chrono::steady_clock::time_point now, int fps, bool from_secure_desktop); @@ -103,6 +109,8 @@ private: DeviceControllerFactory *device_controller_factory_ = nullptr; MouseController *mouse_controller_ = nullptr; KeyboardCapturer *keyboard_capturer_ = nullptr; + // Guards display_info_list_ (UI thread writes, transport threads read). + mutable std::mutex display_info_mutex_; std::vector display_info_list_; size_t registered_display_stream_count_ = 0; std::deque captured_keyboard_inputs_; diff --git a/apps/desktop/src/gui/runtime/peer_data_callbacks.cpp b/apps/desktop/src/gui/runtime/peer_data_callbacks.cpp index c6b79295..453c36d7 100644 --- a/apps/desktop/src/gui/runtime/peer_data_callbacks.cpp +++ b/apps/desktop/src/gui/runtime/peer_data_callbacks.cpp @@ -20,7 +20,6 @@ #include "platform.h" #include "rd_log.h" #include "runtime/gui_runtime.h" -#include "runtime/remote_action_codec.h" #if _WIN32 #include "interactive_state.h" @@ -288,7 +287,7 @@ void PeerEventHandler::OnReceiveDataBuffer( remote_action.i.right[i], remote_action.i.bottom[i])); } } - remote_action_codec::Free(remote_action); + FreeRemoteAction(remote_action); } else { // server mode std::string host_name(remote_action.i.host_name, @@ -302,7 +301,7 @@ void PeerEventHandler::OnReceiveDataBuffer( runtime->SetControllerPrivacySupport( remote_id, remote_action.i.supports_privacy_screen); } - remote_action_codec::Free(remote_action); + FreeRemoteAction(remote_action); } } else { // remote diff --git a/apps/desktop/src/gui/runtime/peer_event_handler.cpp b/apps/desktop/src/gui/runtime/peer_event_handler.cpp index 9fa1355d..0f191fcd 100644 --- a/apps/desktop/src/gui/runtime/peer_event_handler.cpp +++ b/apps/desktop/src/gui/runtime/peer_event_handler.cpp @@ -21,7 +21,6 @@ #include "platform/video_renderer.h" #include "rd_log.h" #include "runtime/gui_runtime.h" -#include "runtime/remote_action_codec.h" #if _WIN32 #include "interactive_state.h" @@ -265,52 +264,22 @@ void PeerEventHandler::OnConnectionStatus(ConnectionStatus status, props->cursor_presentation_ = {}; } { - RemoteAction remote_action{}; - remote_action.i.supports_privacy_screen = true; - remote_action.i.display_num = - runtime->devices_.display_info_list().size(); - remote_action.i.display_list = - (char**)malloc(remote_action.i.display_num * sizeof(char*)); - remote_action.i.left = - (int*)malloc(remote_action.i.display_num * sizeof(int)); - remote_action.i.top = - (int*)malloc(remote_action.i.display_num * sizeof(int)); - remote_action.i.right = - (int*)malloc(remote_action.i.display_num * sizeof(int)); - remote_action.i.bottom = - (int*)malloc(remote_action.i.display_num * sizeof(int)); - for (int i = 0; i < remote_action.i.display_num; i++) { + RemoteAction remote_action = MakeHostInformation( + GetHostName(), runtime->devices_.host_display_list(), + /*supports_privacy_screen=*/true); + for (std::size_t i = 0; i < remote_action.i.display_num; i++) { LOG_INFO("Local display [{}:{}]", i + 1, - runtime->devices_.display_info_list()[i].name); - remote_action.i.display_list[i] = (char*)malloc( - runtime->devices_.display_info_list()[i].name.length() + 1); - strncpy(remote_action.i.display_list[i], - runtime->devices_.display_info_list()[i].name.c_str(), - runtime->devices_.display_info_list()[i].name.length()); - remote_action.i - .display_list[i][runtime->devices_.display_info_list()[i] - .name.length()] = '\0'; - remote_action.i.left[i] = - runtime->devices_.display_info_list()[i].left; - remote_action.i.top[i] = - runtime->devices_.display_info_list()[i].top; - remote_action.i.right[i] = - runtime->devices_.display_info_list()[i].right; - remote_action.i.bottom[i] = - runtime->devices_.display_info_list()[i].bottom; + remote_action.i.display_list[i]); } - - std::string host_name = GetHostName(); - remote_action.type = ControlType::host_infomation; - memcpy(&remote_action.i.host_name, host_name.data(), - host_name.size()); - remote_action.i.host_name[host_name.size()] = '\0'; - remote_action.i.host_name_size = host_name.size(); - std::string msg = remote_action.to_json(); - int ret = SendReliableDataFrame(props->peer_, msg.data(), msg.size(), - runtime->control_data_label_.c_str()); - remote_action_codec::Free(remote_action); + const int ret = + SendReliableDataFrame(props->peer_, msg.data(), msg.size(), + runtime->control_data_label_.c_str()); + if (ret != 0) { + LOG_WARN("[{}] host information send failed, ret={}", remote_id, + ret); + } + FreeRemoteAction(remote_action); } if (!runtime->need_to_create_stream_window_) { @@ -413,53 +382,22 @@ void PeerEventHandler::OnConnectionStatus(ConnectionStatus status, runtime->last_windows_service_status_tick_ = 0; #endif { - RemoteAction remote_action{}; - remote_action.i.supports_privacy_screen = true; - remote_action.i.display_num = - runtime->devices_.display_info_list().size(); - remote_action.i.display_list = - (char**)malloc(remote_action.i.display_num * sizeof(char*)); - remote_action.i.left = - (int*)malloc(remote_action.i.display_num * sizeof(int)); - remote_action.i.top = - (int*)malloc(remote_action.i.display_num * sizeof(int)); - remote_action.i.right = - (int*)malloc(remote_action.i.display_num * sizeof(int)); - remote_action.i.bottom = - (int*)malloc(remote_action.i.display_num * sizeof(int)); - for (int i = 0; i < remote_action.i.display_num; i++) { + RemoteAction remote_action = MakeHostInformation( + GetHostName(), runtime->devices_.host_display_list(), + /*supports_privacy_screen=*/true); + for (std::size_t i = 0; i < remote_action.i.display_num; i++) { LOG_INFO("Local display [{}:{}]", i + 1, - runtime->devices_.display_info_list()[i].name); - remote_action.i.display_list[i] = (char*)malloc( - runtime->devices_.display_info_list()[i].name.length() + 1); - strncpy(remote_action.i.display_list[i], - runtime->devices_.display_info_list()[i].name.c_str(), - runtime->devices_.display_info_list()[i].name.length()); - remote_action.i - .display_list[i][runtime->devices_.display_info_list()[i] - .name.length()] = '\0'; - remote_action.i.left[i] = - runtime->devices_.display_info_list()[i].left; - remote_action.i.top[i] = - runtime->devices_.display_info_list()[i].top; - remote_action.i.right[i] = - runtime->devices_.display_info_list()[i].right; - remote_action.i.bottom[i] = - runtime->devices_.display_info_list()[i].bottom; + remote_action.i.display_list[i]); } - - std::string host_name = GetHostName(); - remote_action.type = ControlType::host_infomation; - memcpy(&remote_action.i.host_name, host_name.data(), - host_name.size()); - remote_action.i.host_name[host_name.size()] = '\0'; - remote_action.i.host_name_size = host_name.size(); - std::string msg = remote_action.to_json(); - int ret = + const int ret = SendReliableDataFrame(runtime->peer_, msg.data(), msg.size(), runtime->control_data_label_.c_str()); - remote_action_codec::Free(remote_action); + if (ret != 0) { + LOG_WARN("[{}] host information send failed, ret={}", remote_id, + ret); + } + FreeRemoteAction(remote_action); } runtime->need_to_destroy_server_window_.store( diff --git a/apps/desktop/src/gui/runtime/remote_action_codec.cpp b/apps/desktop/src/gui/runtime/remote_action_codec.cpp deleted file mode 100644 index 16cc6fb9..00000000 --- a/apps/desktop/src/gui/runtime/remote_action_codec.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "runtime/remote_action_codec.h" - -#include - -#include -#include - -namespace crossdesk::remote_action_codec { - -std::vector Serialize(const RemoteAction &action) { - std::vector buffer; - buffer.push_back(static_cast(action.type)); - - auto insert_bytes = [&](const void *ptr, size_t len) { - buffer.insert(buffer.end(), static_cast(ptr), - static_cast(ptr) + len); - }; - - if (action.type == ControlType::host_infomation) { - insert_bytes(&action.i.host_name_size, sizeof(size_t)); - insert_bytes(action.i.host_name, action.i.host_name_size); - - size_t num = action.i.display_num; - insert_bytes(&num, sizeof(size_t)); - - for (size_t i = 0; i < num; ++i) { - const size_t len = std::strlen(action.i.display_list[i]); - insert_bytes(&len, sizeof(size_t)); - insert_bytes(action.i.display_list[i], len); - } - - insert_bytes(action.i.left, sizeof(int) * num); - insert_bytes(action.i.top, sizeof(int) * num); - insert_bytes(action.i.right, sizeof(int) * num); - insert_bytes(action.i.bottom, sizeof(int) * num); - } - - return buffer; -} - -bool Deserialize(const char *data, size_t size, RemoteAction &out) { - size_t offset = 0; - auto read = [&](void *dst, size_t len) -> bool { - if (offset + len > size) { - return false; - } - std::memcpy(dst, data + offset, len); - offset += len; - return true; - }; - - if (size < 1) { - return false; - } - out.type = static_cast(data[offset++]); - - if (out.type == ControlType::host_infomation) { - out.i.supports_privacy_screen = false; - size_t name_len; - if (!read(&name_len, sizeof(size_t)) || - name_len >= sizeof(out.i.host_name)) { - return false; - } - if (!read(out.i.host_name, name_len)) { - return false; - } - out.i.host_name[name_len] = '\0'; - out.i.host_name_size = name_len; - - size_t num; - if (!read(&num, sizeof(size_t))) { - return false; - } - out.i.display_num = num; - - out.i.display_list = - static_cast(std::malloc(num * sizeof(char *))); - for (size_t i = 0; i < num; ++i) { - size_t len; - if (!read(&len, sizeof(size_t)) || offset + len > size) { - return false; - } - out.i.display_list[i] = static_cast(std::malloc(len + 1)); - std::memcpy(out.i.display_list[i], data + offset, len); - out.i.display_list[i][len] = '\0'; - offset += len; - } - - auto alloc_int_array = [&](int *&array) { - array = static_cast(std::malloc(num * sizeof(int))); - return read(array, num * sizeof(int)); - }; - - return alloc_int_array(out.i.left) && alloc_int_array(out.i.top) && - alloc_int_array(out.i.right) && alloc_int_array(out.i.bottom); - } - - return true; -} - -void Free(RemoteAction &action) { - if (action.type != ControlType::host_infomation) { - return; - } - - for (size_t i = 0; i < action.i.display_num; ++i) { - std::free(action.i.display_list[i]); - } - std::free(action.i.display_list); - std::free(action.i.left); - std::free(action.i.top); - std::free(action.i.right); - std::free(action.i.bottom); - - action.i.display_list = nullptr; - action.i.left = action.i.top = action.i.right = action.i.bottom = nullptr; - action.i.display_num = 0; -} - -} // namespace crossdesk::remote_action_codec diff --git a/apps/desktop/src/gui/runtime/remote_action_codec.h b/apps/desktop/src/gui/runtime/remote_action_codec.h deleted file mode 100644 index a92274fe..00000000 --- a/apps/desktop/src/gui/runtime/remote_action_codec.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * @Author: DI JUNKUN - * @Date: 2026-09-04 - * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. - */ - -#ifndef _REMOTE_ACTION_CODEC_H_ -#define _REMOTE_ACTION_CODEC_H_ - -#include -#include - -#include - -namespace crossdesk::remote_action_codec { - -std::vector Serialize(const RemoteAction &action); -bool Deserialize(const char *data, size_t size, RemoteAction &out); -void Free(RemoteAction &action); - -} // namespace crossdesk::remote_action_codec - -#endif \ No newline at end of file diff --git a/docs/gui-architecture.md b/docs/gui-architecture.md index f7c97f9d..d24177da 100644 --- a/docs/gui-architecture.md +++ b/docs/gui-architecture.md @@ -25,8 +25,7 @@ apps/desktop/src/gui/ │ ├── device_presence_cache.h # 设备在线状态缓存 │ ├── peer_event_handler.h/.cpp # 信令和连接状态回调 │ ├── peer_media_callbacks.cpp # 视频和音频回调 -│ ├── peer_data_callbacks.cpp # 控制、剪贴板和文件数据回调 -│ └── remote_action_codec.h/.cpp # RemoteAction 编解码 +│ └── peer_data_callbacks.cpp # 控制、剪贴板和文件数据回调 ├── features/ # 可独立演进的功能模块 │ ├── clipboard/ # 本地与远端剪贴板同步 │ ├── devices/ # 媒体及输入设备生命周期 diff --git a/libs/wire/include/remote_action.h b/libs/wire/include/remote_action.h index 8c994976..cf306049 100644 --- a/libs/wire/include/remote_action.h +++ b/libs/wire/include/remote_action.h @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -179,6 +180,25 @@ struct RemoteAction { // Other RemoteAction variants do not own memory and are left unchanged. void FreeRemoteAction(RemoteAction& action); +// One display as advertised in host information; bounds are virtual-desktop +// pixel coordinates. +struct HostDisplay { + std::string name; + int left = 0; + int top = 0; + int right = 0; + int bottom = 0; +}; + +// Builds the host_infomation message advertised on every new connection. +// |host_name| is truncated to the wire field size. The display arrays are +// heap-allocated with the same layout the decoder produces; release the +// result with FreeRemoteAction. An allocation failure yields an empty display +// list rather than a partially filled one. +RemoteAction MakeHostInformation(const std::string& host_name, + const std::vector& displays, + bool supports_privacy_screen); + } // namespace crossdesk #endif diff --git a/libs/wire/src/remote_action.cpp b/libs/wire/src/remote_action.cpp index fa11493e..e1417079 100644 --- a/libs/wire/src/remote_action.cpp +++ b/libs/wire/src/remote_action.cpp @@ -37,8 +37,47 @@ bool AllocateHostDisplays(HostInfo& info, std::size_t count) { info.bottom; } +char* DuplicateString(const std::string& value) { + char* copy = static_cast(std::malloc(value.size() + 1)); + if (copy == nullptr) return nullptr; + std::memcpy(copy, value.data(), value.size()); + copy[value.size()] = '\0'; + return copy; +} + } // namespace +RemoteAction MakeHostInformation(const std::string& host_name, + const std::vector& displays, + bool supports_privacy_screen) { + RemoteAction action{}; + action.type = ControlType::host_infomation; + ResetHostInfo(action.i); + + const std::size_t count = displays.size(); + if (AllocateHostDisplays(action.i, count)) { + action.i.display_num = count; + for (std::size_t index = 0; index < count; ++index) { + const HostDisplay& display = displays[index]; + action.i.display_list[index] = DuplicateString(display.name); + action.i.left[index] = display.left; + action.i.top[index] = display.top; + action.i.right[index] = display.right; + action.i.bottom[index] = display.bottom; + } + } else { + FreeRemoteAction(action); + } + + action.i.supports_privacy_screen = supports_privacy_screen; + const std::size_t name_size = + std::min(host_name.size(), sizeof(action.i.host_name) - 1); + std::memcpy(action.i.host_name, host_name.data(), name_size); + action.i.host_name[name_size] = '\0'; + action.i.host_name_size = name_size; + return action; +} + std::string RemoteAction::to_json() const { return ToJson(*this); } bool RemoteAction::from_json(const std::string& json_string) {