Refactor: Move FileManager to common, add macOS file management support

This commit is contained in:
yuanyuanxiang
2026-05-03 09:57:46 +02:00
parent a3611d9fc1
commit 36423b1c7c
11 changed files with 206 additions and 35 deletions

View File

@@ -45,6 +45,7 @@ find_library(CARBON_FRAMEWORK Carbon REQUIRED)
find_library(VIDEOTOOLBOX_FRAMEWORK VideoToolbox REQUIRED)
find_library(COREMEDIA_FRAMEWORK CoreMedia REQUIRED)
find_library(COREVIDEO_FRAMEWORK CoreVideo REQUIRED)
find_library(ICONV_LIBRARY iconv REQUIRED)
target_link_libraries(ghost PRIVATE
${COCOA_FRAMEWORK}
@@ -57,6 +58,7 @@ target_link_libraries(ghost PRIVATE
${VIDEOTOOLBOX_FRAMEWORK}
${COREMEDIA_FRAMEWORK}
${COREVIDEO_FRAMEWORK}
${ICONV_LIBRARY}
"${CMAKE_SOURCE_DIR}/lib/libzstd.a"
)

View File

@@ -3,6 +3,8 @@
#import "InputHandler.h"
#import "../client/IOCPClient.h"
#import "../common/commands.h"
#import "../common/FileTransferV2.h"
#import "../common/logger.h"
#import "Permissions.h"
#import <Cocoa/Cocoa.h>
#import <chrono>
@@ -280,6 +282,72 @@ void ScreenHandler::OnReceive(uint8_t* data, ULONG size)
}
break;
case COMMAND_GET_FILE:
// Server requests file download: [cmd:1][targetDir\0][file1\0file2\0...\0]
// Use V2 protocol to upload files
{
if (size < 3) break;
// Parse target directory (GBK encoding)
const char* ptr = (const char*)(data + 1);
const char* end = (const char*)(data + size);
std::string targetDirGbk = ptr;
std::string targetDir = FileTransferV2::gbkToUtf8(targetDirGbk);
ptr += targetDirGbk.length() + 1;
// Parse file list
std::vector<std::string> files;
while (ptr < end && *ptr != '\0') {
std::string fileGbk = ptr;
files.push_back(FileTransferV2::gbkToUtf8(fileGbk));
ptr += fileGbk.length() + 1;
}
// TODO: If no file list, get from clipboard (ClipboardHandler not implemented yet)
if (!files.empty() && !targetDir.empty()) {
NSLog(@">>> COMMAND_GET_FILE: %zu files -> %s", files.size(), targetDir.c_str());
// Use V2 protocol to send files
IOCPClient* client = m_client;
std::thread([files, targetDir, client]() {
// Collect all files (expand directories)
std::vector<std::string> allFiles;
std::vector<std::string> rootCandidates;
for (const auto& path : files) {
struct stat st;
if (stat(path.c_str(), &st) != 0) continue;
if (S_ISDIR(st.st_mode)) {
std::string dirPath = path;
if (dirPath.back() != '/') dirPath += '/';
size_t pos = dirPath.rfind('/', dirPath.length() - 2);
std::string parentPath = (pos != std::string::npos) ? dirPath.substr(0, pos + 1) : dirPath;
rootCandidates.push_back(parentPath);
FileTransferV2::CollectFiles(dirPath, allFiles);
} else {
rootCandidates.push_back(path);
allFiles.push_back(path);
}
}
if (allFiles.empty()) {
NSLog(@"*** No files to send");
return;
}
std::string commonRoot = FileTransferV2::GetCommonRoot(rootCandidates);
NSLog(@">>> Sending %zu files, root=%s", allFiles.size(), commonRoot.c_str());
FileTransferV2::SendFilesV2(allFiles, targetDir, commonRoot, client, g_myClientID);
}).detach();
} else {
NSLog(@"*** COMMAND_GET_FILE: no files or empty target");
}
}
break;
default:
break;
}

View File

@@ -22,7 +22,10 @@
#import "ScreenHandler.h"
#import "InputHandler.h"
#import "SystemManager.h"
#import "common/PTYHandler.h"
#import "../common/PTYHandler.h"
#import "../common/FileManager.h"
#import "../common/FileTransferV2.h"
#import "../common/logger.h"
// Global state
static std::atomic<bool> g_running(true);
@@ -664,6 +667,26 @@ void* ScreenworkingThread(void* param)
return NULL;
}
void* FileManagerworkingThread(void* param)
{
try {
std::unique_ptr<IOCPClient> ClientObject(new IOCPClient(g_bExit, true));
void* clientAddr = ClientObject.get();
Mprintf(">>> Enter FileManagerworkingThread [%p]\n", clientAddr);
if (!g_bExit && ClientObject->ConnectServer(g_SETTINGS.ServerIP(), g_SETTINGS.ServerPort())) {
std::unique_ptr<FileManager> handler(new FileManager(ClientObject.get()));
ClientObject->setManagerCallBack(handler.get(), IOCPManager::DataProcess, IOCPManager::ReconnectProcess);
Mprintf(">>> FileManagerworkingThread [%p] initialized\n", clientAddr);
while (ClientObject->IsRunning() && ClientObject->IsConnected() && S_CLIENT_NORMAL == g_bExit)
Sleep(1000);
}
Mprintf(">>> Leave FileManagerworkingThread [%p]\n", clientAddr);
} catch (const std::exception& e) {
Mprintf("*** FileManagerworkingThread exception: %s ***\n", e.what());
}
return NULL;
}
int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
{
if (szBuffer == nullptr || ulLength == 0)
@@ -682,7 +705,18 @@ int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
} else if (szBuffer[0] == COMMAND_SYSTEM) {
Mprintf("** [%p] Received 'SYSTEM' command ***\n", user);
} else if (szBuffer[0] == COMMAND_LIST_DRIVE) {
std::thread(FileManagerworkingThread, nullptr).detach();
Mprintf("** [%p] Received 'LIST_DRIVE' command ***\n", user);
} else if (szBuffer[0] == COMMAND_C2C_PREPARE) {
// C2C 准备接收通知
FileTransferV2::HandleC2CPrepare(szBuffer, ulLength, nullptr);
Mprintf("** [%p] C2C Prepare received ***\n", user);
} else if (szBuffer[0] == COMMAND_SEND_FILE_V2 || szBuffer[0] == COMMAND_FILE_COMPLETE_V2) {
// V2 文件接收
int result = FileTransferV2::RecvFileChunkV2(szBuffer, ulLength, g_myClientID);
if (result != 0) {
Mprintf("** [%p] V2 File recv error: %d ***\n", user, result);
}
} else if (szBuffer[0] == CMD_HEARTBEAT_ACK) {
if (ulLength >= 1 + sizeof(HeartbeatACK)) {
HeartbeatACK* ack = (HeartbeatACK*)(szBuffer + 1);