From de46e40e0c8c4d45f9baa706f31bf4df382be41c Mon Sep 17 00:00:00 2001 From: taynpg Date: Mon, 12 May 2025 22:07:06 +0800 Subject: [PATCH] =?UTF-8?q?debug=EF=BC=9A=E5=88=9D=E6=AD=A5=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E8=BF=9C=E7=AB=AF=E6=96=87=E4=BB=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ClientCore/CMakeLists.txt | 6 +++ ClientCore/ClientCore.cxx | 51 ++++++++++++++++++++ ClientCore/ClientCore.h | 22 +++++++-- ClientCore/ClientFile.cxx | 65 +++++++++++++++++++++++++ ClientCore/ClientFile.h | 21 ++++++++ Information/InfoDirFile.hpp | 41 ++++++++++++++++ Protocol/Communicate.h | 5 +- UserInterface/ControlManager.cxx | 4 +- UserInterface/HeaderControl.h | 2 + UserInterface/OnLineControl.cxx | 39 +++++++++++++++ UserInterface/OnLineControl.h | 9 ++++ UserInterface/RemoteControl.cxx | 82 +++++++++++++++++++++++++++++++- UserInterface/RemoteControl.h | 20 +++++++- 13 files changed, 358 insertions(+), 9 deletions(-) create mode 100644 ClientCore/ClientFile.cxx create mode 100644 ClientCore/ClientFile.h diff --git a/ClientCore/CMakeLists.txt b/ClientCore/CMakeLists.txt index 603e040..a6526e1 100644 --- a/ClientCore/CMakeLists.txt +++ b/ClientCore/CMakeLists.txt @@ -4,11 +4,17 @@ project(ClientCore LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) +if (MSVC) + add_compile_options(/utf-8) +endif() + find_package(wxWidgets CONFIG REQUIRED) set(MSOURCES ClientCore.h ClientCore.cxx +ClientFile.h +ClientFile.cxx ) add_library(ClientCore STATIC ${MSOURCES}) diff --git a/ClientCore/ClientCore.cxx b/ClientCore/ClientCore.cxx index 73e58d8..65aa968 100644 --- a/ClientCore/ClientCore.cxx +++ b/ClientCore/ClientCore.cxx @@ -52,6 +52,11 @@ wxString ClientCore::GetErr() const return err_; } +wxString ClientCore::GetOwnId() const +{ + return id_; +} + bool ClientCore::IsOk() { return socket_->IsConnected(); @@ -76,6 +81,16 @@ void ClientCore::ReqOnlineCallback(const std::function& callback) +{ + homeCall_ = callback; +} + +void ClientCore::SetDirFileCallback(const std::function& callback) +{ + dirFileCall_ = callback; +} + bool ClientCore::AskDirectory(const wxString& id, const wxString& path, DirFileInfoVec& dirInfoVec) { return false; @@ -121,6 +136,42 @@ void ClientCore::UseFrame(FrameBuffer* buf) InfoCommunicate info; break; } + case FBT_CLI_ASK_HOME: { + InfoCommunicate info; + wxString home = wxGetHomeDir(); + info.data = home.ToStdString(); + Send(info, FBT_CLI_ANS_HOME, buf->fid); + break; + } + case FBT_CLI_ANS_HOME: { + InfoCommunicate info; + ZeroCopyInput input(buf->dataMut, buf->len); + input.archive() >> info; + if (homeCall_) { + homeCall_(info.data); + } + break; + } + case FBT_CLI_ASK_DIRFILE: { + InfoCommunicate info; + ZeroCopyInput input(buf->dataMut, buf->len); + input.archive() >> info; + DirFileInfoVec vec; + if (!cf_.GetDirFiles(info.data, vec)) { + break; + } + Send(vec, FBT_CLI_ANS_DIRFILE, buf->fid); + break; + } + case FBT_CLI_ANS_DIRFILE: { + DirFileInfoVec vec; + ZeroCopyInput input(buf->dataMut, buf->len); + input.archive() >> vec; + if (dirFileCall_) { + dirFileCall_(vec); + } + break; + } default: break; } diff --git a/ClientCore/ClientCore.h b/ClientCore/ClientCore.h index 1f785f3..6693a4c 100644 --- a/ClientCore/ClientCore.h +++ b/ClientCore/ClientCore.h @@ -1,15 +1,16 @@ #ifndef CLIENTCORE_H #define CLIENTCORE_H +#include "ClientFile.h" #include #include #include #include #include -#include -#include -#include #include +#include +#include +#include #include #include @@ -27,12 +28,17 @@ public: public: wxString GetErr() const; + wxString GetOwnId() const; bool IsOk(); void SetLogCallback(const std::function& callback); bool ReqOnline(); - void ReqOnlineCallback(const std::function& callback); bool AskDirectory(const wxString& id, const wxString& path, DirFileInfoVec& dirInfoVec); +public: + void ReqOnlineCallback(const std::function& callback); + void SetHomeCallback(const std::function& callback); + void SetDirFileCallback(const std::function& callback); + private: void UseFrame(FrameBuffer* buf); @@ -42,7 +48,9 @@ private: private: void HeartBeat(); void Recv(); - template bool Send(const T& info, FrameBufferType type) + +public: + template bool Send(const T& info, FrameBufferType type, const wxString& remoteId = wxEmptyString) { std::stringstream ss; cereal::BinaryOutputArchive archive(ss); @@ -52,6 +60,7 @@ private: buf->dataConst = ss.view().data(); buf->len = ss.str().size(); buf->dataType = type; + buf->tid = remoteId.ToStdString(); return Send(buf.get()); } @@ -62,13 +71,16 @@ private: bool thRun_; MutBuffer buffer_; wxString err_; + ClientFile cf_; std::thread recvThread_; std::array buf_; wxSocketClient* socket_; private: + std::function dirFileCall_; std::function onlineCallback_; std::function logCall_; + std::function homeCall_; }; #endif // CLIENTCORE_H \ No newline at end of file diff --git a/ClientCore/ClientFile.cxx b/ClientCore/ClientFile.cxx new file mode 100644 index 0000000..85c5221 --- /dev/null +++ b/ClientCore/ClientFile.cxx @@ -0,0 +1,65 @@ +#include "ClientFile.h" +#include + +ClientFile::ClientFile() +{ +} + +bool ClientFile::GetDirFiles(const std::string& path, DirFileInfoVec& vec) +{ + if (!fs::exists(path)) { + lastErr_ = wxString::Format(_("Path does not exist: %s"), path); + return false; + } + + if (!fs::is_directory(path)) { + lastErr_ = wxString::Format(_("Not a directory: %s"), path); + return false; + } + + vec.vec.clear(); + + try { + // 遍历目录 + for (const auto& entry : fs::directory_iterator(path)) { + DirFileInfo info; + const auto& path = entry.path(); + + // 设置基本信息 + info.fullPath = path.string(); + info.name = path.filename().string(); + + // 设置类型 + if (entry.is_directory()) { + info.type = Dir; + info.size = 0; + } else if (entry.is_regular_file()) { + info.type = File; + info.size = entry.file_size(); + } else { + // 跳过符号链接、设备文件等 + continue; + } + + // 获取最后修改时间 + auto ftime = entry.last_write_time(); + auto sctp = std::chrono::time_point_cast( + ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); + info.lastModifyTime = std::chrono::system_clock::to_time_t(sctp); + vec.vec.push_back(info); + } + } catch (const fs::filesystem_error& e) { + lastErr_ = wxString::FromUTF8(e.what()); + return false; + } catch (const std::exception& e) { + lastErr_ = wxString::FromUTF8(e.what()); + return false; + } + + return true; +} + +wxString ClientFile::GetLastErr() const +{ + return lastErr_; +} diff --git a/ClientCore/ClientFile.h b/ClientCore/ClientFile.h new file mode 100644 index 0000000..c50f00d --- /dev/null +++ b/ClientCore/ClientFile.h @@ -0,0 +1,21 @@ +#ifndef CLIENTFILE_H +#define CLIENTFILE_H + +#include +#include + +namespace fs = std::filesystem; +class ClientFile +{ +public: + ClientFile(); + +public: + bool GetDirFiles(const std::string& path, DirFileInfoVec& vec); + wxString GetLastErr() const; + +private: + wxString lastErr_; +}; + +#endif // CLIENTFILE_H \ No newline at end of file diff --git a/Information/InfoDirFile.hpp b/Information/InfoDirFile.hpp index 2c4ef15..dcc6c11 100644 --- a/Information/InfoDirFile.hpp +++ b/Information/InfoDirFile.hpp @@ -17,6 +17,47 @@ enum FileType : uint32_t { }; struct DirFileInfo { + + static wxString GetFileSize(uint64_t size) + { + const uint64_t KB = 1024; + const uint64_t MB = KB * 1024; + const uint64_t GB = MB * 1024; + + if (size >= GB) { + return wxString::Format("%.2f GB", static_cast(size) / GB); + } else if (size >= MB) { + return wxString::Format("%.2f MB", static_cast(size) / MB); + } else if (size >= KB) { + return wxString::Format("%.2f KB", static_cast(size) / KB); + } else { + return wxString::Format("%llu B", size); + } + } + + static wxString GetStrTime(uint64_t time) + { + wxDateTime dt(static_cast(time)); + wxString dateStr = dt.Format("%Y/%m/%d %H:%M:%S"); + return dateStr; + } + + static wxString GetFileTypeName(FileType type) + { + switch (type) { + case None: + return _("None"); + case File: + return _("File"); + case Dir: + return _("Dir"); + case Link: + return _("Link"); + default: + return _("Unknown"); + } + } + std::string name; uint64_t size = 0; FileType type = None; diff --git a/Protocol/Communicate.h b/Protocol/Communicate.h index 94e0e98..3c0840c 100644 --- a/Protocol/Communicate.h +++ b/Protocol/Communicate.h @@ -12,7 +12,10 @@ enum FrameBufferType : uint16_t { FBT_SER_MSG_RESPONSE, FBT_CLI_BIN_FILEDATA = 31, FBT_CLI_MSG_COMMUNICATE, - FBT_CLI_INFO_DIRFILE + FBT_CLI_ASK_DIRFILE, + FBT_CLI_ANS_DIRFILE, + FBT_CLI_ASK_HOME, + FBT_CLI_ANS_HOME }; struct FrameBuffer { diff --git a/UserInterface/ControlManager.cxx b/UserInterface/ControlManager.cxx index bf2de16..c81f44a 100644 --- a/UserInterface/ControlManager.cxx +++ b/UserInterface/ControlManager.cxx @@ -10,13 +10,15 @@ void ControlManager::Init(std::shared_ptr& clientCore) log_ = new LogControl(parent_); header_ = new HeaderControl(parent_, clientCore); local_ = new LocalControl(parent_); - remote_ = new RemoteControl(parent_); + remote_ = new RemoteControl(parent_, clientCore); task_ = new TaskControl(parent_); online_ = new OnlineControl(parent_, clientCore); header_->SetLogControl(log_); online_->SetLogControl(log_); header_->SetOnlineControl(online_); + online_->SetRemoteControl(remote_); + remote_->SetLogControl(log_); clientCore->SetLogCallback([this](const wxString& msg) { log_->AddLog(msg); }); } \ No newline at end of file diff --git a/UserInterface/HeaderControl.h b/UserInterface/HeaderControl.h index 0d9ca8a..45f476a 100644 --- a/UserInterface/HeaderControl.h +++ b/UserInterface/HeaderControl.h @@ -7,6 +7,7 @@ class LogControl; class ClientCore; class OnlineControl; +class RemoteControl; class HeaderControl : public wxPanel { public: @@ -16,6 +17,7 @@ public: public: void SetLogControl(LogControl* logControl); void SetOnlineControl(OnlineControl* onlineControl); + void SetRemoteControl(RemoteControl* remoteControl); private: void Init(); diff --git a/UserInterface/OnLineControl.cxx b/UserInterface/OnLineControl.cxx index 478c933..e9e5b33 100644 --- a/UserInterface/OnLineControl.cxx +++ b/UserInterface/OnLineControl.cxx @@ -1,12 +1,14 @@ #include "OnLineControl.h" #include "HeaderControl.h" #include "LogControl.h" +#include "RemoteControl.h" #include OnlineControl::OnlineControl(wxWindow* parent, std::shared_ptr& clientCore) : wxPanel(parent), clientCore_(clientCore) { Init(); InitCall(); + BindEvent(); } OnlineControl::~OnlineControl() @@ -23,6 +25,11 @@ void OnlineControl::SetLogControl(LogControl* logControl) logControl_ = logControl; } +void OnlineControl::SetRemoteControl(RemoteControl* remoteControl) +{ + remoteControl_ = remoteControl; +} + void OnlineControl::Init() { btnFresh_ = new wxButton(this, wxID_ANY, _("Refresh")); @@ -30,6 +37,8 @@ void OnlineControl::Init() elbCurState_ = new wxStaticText(this, wxID_ANY, _("Disconnected")); elbCurState_->SetForegroundColour(*wxBLUE); onLineList_ = new wxListBox(this, wxID_ANY); + // 设置 onLineList_ 只能单选 + onLineList_->SetWindowStyle(wxLB_SINGLE); lbCurPoint_ = new wxStaticText(this, wxID_ANY, _("Commnunicate Point => ")); elbCurPoint_ = new wxStaticText(this, wxID_ANY, _("None")); @@ -51,7 +60,20 @@ void OnlineControl::Init() SetSizer(topSizer); Layout(); + menu_ = new wxMenu; + useId_ = wxNewId(); + menu_->Append(useId_, _("Use this client")); +} + +void OnlineControl::BindEvent() +{ Bind(wxEVT_BUTTON, &OnlineControl::OnFreshClients, this, btnFresh_->GetId()); + onLineList_->Bind(wxEVT_CONTEXT_MENU, [&](wxContextMenuEvent& event) { + auto p = event.GetPosition(); + p = onLineList_->ScreenToClient(p); + onLineList_->PopupMenu(menu_, p); + }); + Bind(wxEVT_MENU, &OnlineControl::UseThisClient, this, useId_); } void OnlineControl::SetConnectState(const wxString& state) @@ -98,3 +120,20 @@ void OnlineControl::OnFreshClientsCall(const InfoClientVec& infoClientVec) } logControl_->AddLog(_("Get online list success.")); } + +void OnlineControl::UseThisClient(wxCommandEvent& event) +{ + int selection = onLineList_->GetSelection(); + if (selection != wxNOT_FOUND) { + wxString selectedText = onLineList_->GetString(selection); + if (clientCore_->GetOwnId() == selectedText) { + wxMessageDialog dialog(this, _("You selected yourself, do you want to use yourself?"), _("Confirm"), + wxYES_NO | wxICON_QUESTION); + if (dialog.ShowModal() == wxID_YES) { + remoteControl_->setRemoteID(selectedText); + } + return; + } + remoteControl_->setRemoteID(selectedText); + } +} diff --git a/UserInterface/OnLineControl.h b/UserInterface/OnLineControl.h index b2905d8..97d8fbc 100644 --- a/UserInterface/OnLineControl.h +++ b/UserInterface/OnLineControl.h @@ -8,6 +8,7 @@ class HeaderControl; class LogControl; class ClientCore; +class RemoteControl; class OnlineControl : public wxPanel { public: @@ -16,6 +17,7 @@ public: public: void SetHeaderControl(HeaderControl* headerControl); + void SetRemoteControl(RemoteControl* remoteControl); void SetLogControl(LogControl* logControl); void SetConnectState(const wxString& state); void SetConnectServer(const wxString& server); @@ -24,10 +26,12 @@ public: private: void Init(); void InitCall(); + void BindEvent(); void OnFreshClients(wxCommandEvent& event); private: void OnFreshClientsCall(const InfoClientVec& infoClientVec); + void UseThisClient(wxCommandEvent& event); public: wxButton* btnFresh_; @@ -39,7 +43,12 @@ public: wxListBox* onLineList_; HeaderControl* headerControl_; LogControl* logControl_; + wxMenu* menu_; + RemoteControl* remoteControl_; std::shared_ptr clientCore_; + +private: + wxWindowID useId_; }; #endif // ONLINECONTROL_H \ No newline at end of file diff --git a/UserInterface/RemoteControl.cxx b/UserInterface/RemoteControl.cxx index d9406e5..5f7272f 100644 --- a/UserInterface/RemoteControl.cxx +++ b/UserInterface/RemoteControl.cxx @@ -1,9 +1,13 @@ #include "RemoteControl.h" +#include "LogControl.h" +#include +#include -RemoteControl::RemoteControl(wxWindow* parent) : wxPanel(parent) +RemoteControl::RemoteControl(wxWindow* parent, std::shared_ptr& clientCore) : wxPanel(parent), clientCore_(clientCore) { Init(); SetGrid(); + BindEvent(); } RemoteControl::~RemoteControl() @@ -19,6 +23,11 @@ void RemoteControl::Init() textCtrl_ = new wxTextCtrl(this, wxID_ANY); dirSizer->Add(textCtrl_, 1, wxALL | wxEXPAND, gBorder); + edRemoteId_ = new wxTextCtrl(this, wxID_ANY); + edRemoteId_->SetMinSize(wxSize(200, -1)); + edRemoteId_->SetEditable(false); + dirSizer->Add(edRemoteId_, 0, wxALL | wxCENTER, gBorder); + btnHome_ = new wxButton(this, wxID_ANY, _("Home")); dirSizer->Add(btnHome_, 0, wxALL | wxCENTER, gBorder); @@ -40,6 +49,66 @@ void RemoteControl::Init() Layout(); } +void RemoteControl::BindEvent() +{ + Bind(wxEVT_BUTTON, &RemoteControl::AskHome, this, btnHome_->GetId()); + clientCore_->SetHomeCallback([this](const wxString& home) { + textCtrl_->SetValue(home); + logControl_->AddLog(_("Remote Home: %s"), home); + }); + Bind(wxEVT_BUTTON, &RemoteControl::GetDirContent, this, btnGet_->GetId()); + clientCore_->SetDirFileCallback([this](const DirFileInfoVec& dirInfoVec) { + if (grid_->GetNumberRows() > 0) { + grid_->DeleteRows(0, grid_->GetNumberRows()); + } + for (auto& dirInfo : dirInfoVec.vec) { + grid_->AppendRows(); + auto wxPath = wxString::FromUTF8(dirInfo.fullPath); + grid_->SetCellValue(grid_->GetNumberRows() - 1, 0, wxPath); + grid_->SetCellValue(grid_->GetNumberRows() - 1, 1, DirFileInfo::GetFileSize(dirInfo.size)); + grid_->SetCellValue(grid_->GetNumberRows() - 1, 2, DirFileInfo::GetFileTypeName(dirInfo.type)); + grid_->SetCellValue(grid_->GetNumberRows() - 1, 3, DirFileInfo::GetStrTime(dirInfo.lastModifyTime)); + grid_->SetCellValue(grid_->GetNumberRows() - 1, 4, wxString::Format("%o", dirInfo.permission)); + } + }); +} + +void RemoteControl::AskHome(wxCommandEvent& event) +{ + auto remoteId = edRemoteId_->GetValue(); + if (remoteId.empty()) { + logControl_->AddLog(_("Remote ID is Empty.")); + return; + } + InfoCommunicate infoCommunicate; + if (!clientCore_->Send(infoCommunicate, FBT_CLI_ASK_HOME, remoteId)) { + logControl_->AddLog(_("Request ask %s's Home Failed"), remoteId); + } else { + logControl_->AddLog(_("Request ask %s's Home Success"), remoteId); + } +} + +void RemoteControl::GetDirContent(wxCommandEvent& event) +{ + auto remoteId = edRemoteId_->GetValue(); + if (remoteId.empty()) { + logControl_->AddLog(_("Remote ID is Empty.")); + return; + } + auto home = textCtrl_->GetValue(); + if (home.empty()) { + logControl_->AddLog(_("Remote Home is Empty.")); + return; + } + InfoCommunicate info; + info.data = home.ToStdString(); + if (!clientCore_->Send(info, FBT_CLI_ASK_DIRFILE, remoteId)) { + logControl_->AddLog(_("Request get %s's DirFile Failed"), home); + } else { + logControl_->AddLog(_("Request get %s's DirFile Success"), home); + } +} + void RemoteControl::SetGrid() { grid_->CreateGrid(10, 5); @@ -55,3 +124,14 @@ void RemoteControl::SetGrid() grid_->SetColSize(3, 150); grid_->SetColSize(4, 100); } + +void RemoteControl::setRemoteID(const wxString& id) +{ + logControl_->AddLog(_("You Selected Remote ID: ") + id); + edRemoteId_->SetValue(id); +} + +void RemoteControl::SetLogControl(LogControl* logControl) +{ + logControl_ = logControl; +} diff --git a/UserInterface/RemoteControl.h b/UserInterface/RemoteControl.h index d7bbd29..4759f8b 100644 --- a/UserInterface/RemoteControl.h +++ b/UserInterface/RemoteControl.h @@ -4,23 +4,41 @@ #include "InterfaceDefine.hpp" #include +class LogControl; +class ClientCore; class RemoteControl : public wxPanel { public: - RemoteControl(wxWindow* parent); + RemoteControl(wxWindow* parent, std::shared_ptr& clientCore); ~RemoteControl() override; +public: + void setRemoteID(const wxString& id); + +public: + void SetLogControl(LogControl* logControl); + private: void Init(); void SetGrid(); + void BindEvent(); + +private: + void AskHome(wxCommandEvent& event); + void GetDirContent(wxCommandEvent& event); public: wxGrid* grid_; wxTextCtrl* textCtrl_; + wxTextCtrl* edRemoteId_; wxButton* btnHome_; wxButton* btnGet_; wxButton* btnUpLevel_; wxButton* btnRefresh_; + +private: + LogControl* logControl_; + std::shared_ptr clientCore_; }; #endif // REMOTECONTROL_H \ No newline at end of file