From 185c36826f959fb8803f19838805395d97152d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonz=C3=A1lez?= <117672238+cg27shokworks@users.noreply.github.com> Date: Fri, 14 Feb 2025 15:06:11 +0100 Subject: [PATCH 1/2] feat: rename context (#116) * wip * chore: clean up * chore: clean up --- binding.gyp | 1 + include/logger/Logger.h | 2 +- .../RenameTransferContext.h | 25 +++ native-src/logger/Logger.cpp | 18 +- .../placeholders_interface/Planceholders.cpp | 1 - .../NotifyRename/NotifyRenameCallback.cpp | 165 +++++------------- .../NotifyRename/RenameTransferContext.cpp | 31 ++++ 7 files changed, 117 insertions(+), 126 deletions(-) create mode 100644 include/sync_root_interface/RenameTransferContext.h create mode 100644 native-src/sync_root_interface/callbacks/NotifyRename/RenameTransferContext.cpp diff --git a/binding.gyp b/binding.gyp index ad8ec2ef..d5767ea6 100644 --- a/binding.gyp +++ b/binding.gyp @@ -29,6 +29,7 @@ "native-src/sync_root_interface/callbacks/FetchPlaceholder/FetchPlaceholder.cpp", "native-src/sync_root_interface/callbacks/NotifyDelete/NotifyDeleteCallback.cpp", "native-src/sync_root_interface/callbacks/NotifyRename/NotifyRenameCallback.cpp", + "native-src/sync_root_interface/callbacks/NotifyRename/RenameTransferContext.cpp", "native-src/virtual_drive/Wrappers.cpp" ], "include_dirs": [ diff --git a/include/logger/Logger.h b/include/logger/Logger.h index 1cc062f9..50453bf3 100644 --- a/include/logger/Logger.h +++ b/include/logger/Logger.h @@ -31,7 +31,7 @@ class Logger { return instance; } - void log(const std::string &message, LogLevel level); + void log(const std::string &message, LogLevel level, WORD color = 0); Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete; diff --git a/include/sync_root_interface/RenameTransferContext.h b/include/sync_root_interface/RenameTransferContext.h new file mode 100644 index 00000000..0929e0ca --- /dev/null +++ b/include/sync_root_interface/RenameTransferContext.h @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include +#include +#include +#include "stdafx.h" + +struct RenameContext { + CF_CONNECTION_KEY connectionKey; + CF_TRANSFER_KEY transferKey; + std::wstring targetPath; + std::wstring fileIdentity; + + std::mutex mtx; + std::condition_variable cv; + bool ready = false; + bool callbackResult = false; +}; + +std::shared_ptr GetOrCreateRenameContext( + CF_CONNECTION_KEY connKey, + CF_TRANSFER_KEY transferKey); + +void RemoveRenameContext(CF_TRANSFER_KEY transferKey); diff --git a/native-src/logger/Logger.cpp b/native-src/logger/Logger.cpp index 6e12fa08..a6e9bf23 100644 --- a/native-src/logger/Logger.cpp +++ b/native-src/logger/Logger.cpp @@ -29,7 +29,7 @@ std::wstring Logger::fromUtf8ToWide(const std::string& utf8Str) { return std::wstring(wideStr.get()); } -void Logger::log(const std::string &message, LogLevel level) { +void Logger::log(const std::string &message, LogLevel level, WORD color) { std::lock_guard guard(log_mutex); auto now = std::chrono::system_clock::now(); @@ -45,7 +45,21 @@ void Logger::log(const std::string &message, LogLevel level) { std::transform(level_str.begin(), level_str.end(), level_str.begin(), ::tolower); log_file << "[" << time_stream.str() << "] [" << level_str << "] " << message << std::endl; + + HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO consoleInfo; + GetConsoleScreenBufferInfo(hConsole, &consoleInfo); + WORD saved_attributes = consoleInfo.wAttributes; + + if (color != 0) { + SetConsoleTextAttribute(hConsole, color); + } + printf("[%s] [%s] %s\n", time_stream.str().c_str(), level_str.c_str(), message.c_str()); + + if (color != 0) { + SetConsoleTextAttribute(hConsole, saved_attributes); + } } std::string Logger::toString(LogLevel level) { @@ -67,4 +81,4 @@ std::string Logger::fromWStringToString(const std::wstring wstr) { std::string strTo(size_needed, 0); WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL); return strTo; -} \ No newline at end of file +} diff --git a/native-src/placeholders_interface/Planceholders.cpp b/native-src/placeholders_interface/Planceholders.cpp index 67e9fcf1..ae749f53 100644 --- a/native-src/placeholders_interface/Planceholders.cpp +++ b/native-src/placeholders_interface/Planceholders.cpp @@ -597,7 +597,6 @@ bool Placeholders::IsFileValidForSync(const std::wstring &filePath) void Placeholders::ForceShellRefresh(const std::wstring &path) { - Logger::getInstance().log("Forcing shell refresh for path: " + Logger::fromWStringToString(path), LogLevel::INFO); SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, path.c_str(), nullptr); SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, path.c_str(), nullptr); } diff --git a/native-src/sync_root_interface/callbacks/NotifyRename/NotifyRenameCallback.cpp b/native-src/sync_root_interface/callbacks/NotifyRename/NotifyRenameCallback.cpp index f4081b1c..fa9691ab 100644 --- a/native-src/sync_root_interface/callbacks/NotifyRename/NotifyRenameCallback.cpp +++ b/native-src/sync_root_interface/callbacks/NotifyRename/NotifyRenameCallback.cpp @@ -7,118 +7,68 @@ #include #include #include -#include - -napi_threadsafe_function g_notify_rename_threadsafe_callback = nullptr; - -inline std::mutex mtx; -inline std::condition_variable cv; -inline bool ready = false; -inline bool callbackResult = false; - -napi_ref g_async_complete_ref = nullptr; - -struct NotifyRenameArgs -{ - std::wstring targetPathArg; - std::wstring fileIdentityArg; -}; +#include "RenameTransferContext.h" +napi_threadsafe_function g_notify_rename_tsfn = nullptr; napi_value response_callback_fn(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value argv[1]; napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); - if (argc < 1) - { - // Manejar error return nullptr; - } - bool response; napi_get_value_bool(env, argv[0], &response); - std::lock_guard lock(mtx); - ready = true; - callbackResult = response; - cv.notify_one(); - + void* data; + napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data); + RenameContext* renameCtx = static_cast(data); + { + Logger::getInstance().log("response_callback_fn: Setting callback result.", LogLevel::DEBUG, FOREGROUND_BLUE); + std::lock_guard lock(renameCtx->mtx); + renameCtx->ready = true; + renameCtx->callbackResult = response; + } + renameCtx->cv.notify_one(); return nullptr; } -void notify_rename_call(napi_env env, napi_value js_callback, void *context, void *data) +void notify_rename_call(napi_env env, napi_value js_callback, void* context, void* data) { - NotifyRenameArgs *args = static_cast(data); - napi_status status; - - std::u16string u16_targetPath(args->targetPathArg.begin(), args->targetPathArg.end()); - std::u16string u16_fileIdentity(args->fileIdentityArg.begin(), args->fileIdentityArg.end()); - + RenameContext* renameCtx = static_cast(data); napi_value js_targetPathArg, js_fileIdentityArg, undefined, result; + std::u16string u16_targetPath(renameCtx->targetPath.begin(), renameCtx->targetPath.end()); + std::u16string u16_fileIdentity(renameCtx->fileIdentity.begin(), renameCtx->fileIdentity.end()); - status = napi_create_string_utf16(env, u16_targetPath.c_str(), u16_targetPath.size(), &js_targetPathArg); + napi_status status = napi_create_string_utf16(env, u16_targetPath.c_str(), u16_targetPath.size(), &js_targetPathArg); if (status != napi_ok) - { - fprintf(stderr, "Failed to create targetPath string.\n"); return; - } - status = napi_create_string_utf16(env, u16_fileIdentity.c_str(), u16_fileIdentity.size(), &js_fileIdentityArg); if (status != napi_ok) - { - fprintf(stderr, "Failed to create fileIdentity string.\n"); return; - } - - // Crear la función C++ como un valor de N-API para pasar a JS napi_value js_response_callback_fn; - napi_create_function(env, "responseCallback", NAPI_AUTO_LENGTH, response_callback_fn, nullptr, &js_response_callback_fn); + napi_create_function(env, "responseCallback", NAPI_AUTO_LENGTH, response_callback_fn, renameCtx, &js_response_callback_fn); - napi_value args_to_js_callback[3] = {js_targetPathArg, js_fileIdentityArg, js_response_callback_fn}; + napi_value args_to_js_callback[3] = { js_targetPathArg, js_fileIdentityArg, js_response_callback_fn }; status = napi_get_undefined(env, &undefined); if (status != napi_ok) - { - fprintf(stderr, "Failed to get undefined value.\n"); return; - } - - { - std::lock_guard lock(mtx); - ready = false; - } - status = napi_call_function(env, undefined, js_callback, 3, args_to_js_callback, &result); if (status != napi_ok) - { - fprintf(stderr, "Failed to call JS function.\n"); Logger::getInstance().log("Failed to call JS function in notifyRenameCallback.", LogLevel::ERROR); - return; - } - - delete args; -} - -void setup_global_tsfn_rename(napi_threadsafe_function tsfn) -{ - g_notify_rename_threadsafe_callback = tsfn; } void register_threadsafe_notify_rename_callback(const std::string &resource_name, napi_env env, InputSyncCallbacks input) { - std::u16string converted_resource_name = std::u16string(resource_name.begin(), resource_name.end()); - + std::u16string converted_resource_name(resource_name.begin(), resource_name.end()); napi_value resource_name_value; napi_create_string_utf16(env, converted_resource_name.c_str(), NAPI_AUTO_LENGTH, &resource_name_value); - napi_threadsafe_function notify_rename_threadsafe_callback; napi_value notify_rename_value; napi_status status_ref = napi_get_reference_value(env, input.notify_rename_callback_ref, ¬ify_rename_value); - napi_valuetype valuetype; napi_status type_status = napi_typeof(env, notify_rename_value, &valuetype); - if (type_status != napi_ok || valuetype != napi_function) { fprintf(stderr, "notify_rename_value is not a function.\n"); @@ -128,27 +78,22 @@ void register_threadsafe_notify_rename_callback(const std::string &resource_name napi_status status = napi_create_threadsafe_function( env, notify_rename_value, - NULL, + nullptr, resource_name_value, 0, 1, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, notify_rename_call, - ¬ify_rename_threadsafe_callback); - + &g_notify_rename_tsfn); if (status != napi_ok) { - const napi_extended_error_info *errorInfo = NULL; + const napi_extended_error_info *errorInfo = nullptr; napi_get_last_error_info(env, &errorInfo); fprintf(stderr, "Failed to create threadsafe function: %s\n", errorInfo->error_message); - fprintf(stderr, "N-API Status Code: %d\n", errorInfo->error_code); - fprintf(stderr, "Engine-specific error code: %u\n", errorInfo->engine_error_code); abort(); } - - setup_global_tsfn_rename(notify_rename_threadsafe_callback); } void CALLBACK notify_rename_callback_wrapper( @@ -157,35 +102,25 @@ void CALLBACK notify_rename_callback_wrapper( { LPCVOID fileIdentity = callbackInfo->FileIdentity; DWORD fileIdentityLength = callbackInfo->FileIdentityLength; - const wchar_t *wchar_ptr = static_cast(fileIdentity); std::wstring fileIdentityStr(wchar_ptr, fileIdentityLength / sizeof(wchar_t)); - PCWSTR targetPathArg = callbackParameters->Rename.TargetPath; - NotifyRenameArgs *args = new NotifyRenameArgs(); - args->targetPathArg = std::wstring(targetPathArg); - args->fileIdentityArg = fileIdentityStr; - // wprintf(L"Callback notify_rename_callback_wrapper called\n"); - // wprintf(L"g_notify_rename_threadsafe_callback = %s\n", g_notify_rename_threadsafe_callback); - napi_status status = napi_call_threadsafe_function(g_notify_rename_threadsafe_callback, args, napi_tsfn_blocking); + auto renameCtx = GetOrCreateRenameContext(callbackInfo->ConnectionKey, callbackInfo->TransferKey); + renameCtx->targetPath = std::wstring(targetPathArg); + renameCtx->fileIdentity = fileIdentityStr; + napi_status status = napi_call_threadsafe_function(g_notify_rename_tsfn, renameCtx.get(), napi_tsfn_blocking); if (status != napi_ok) - { wprintf(L"Callback called unsuccessfully.\n"); - }; CF_OPERATION_PARAMETERS opParams = {0}; - { - std::unique_lock lock(mtx); - while (!ready) - { - cv.wait(lock); - } + std::unique_lock lock(renameCtx->mtx); + while (!renameCtx->ready) + renameCtx->cv.wait(lock); } - - opParams.AckRename.CompletionStatus = callbackResult ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; + opParams.AckRename.CompletionStatus = renameCtx->callbackResult ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; opParams.ParamSize = sizeof(CF_OPERATION_PARAMETERS); CF_OPERATION_INFO opInfo = {0}; @@ -194,10 +129,13 @@ void CALLBACK notify_rename_callback_wrapper( opInfo.ConnectionKey = callbackInfo->ConnectionKey; opInfo.TransferKey = callbackInfo->TransferKey; - HRESULT hr = CfExecute( - &opInfo, - &opParams); - + HRESULT hr = CfExecute(&opInfo, &opParams); + if (FAILED(hr)) + wprintf(L"Error in CfExecute() rename action, HRESULT: %lx\n", hr); + { + std::lock_guard lock(renameCtx->mtx); + renameCtx->ready = false; + } printf("Mark item as async: %ls\n", targetPathArg); WCHAR systemPath[MAX_PATH]; if (!GetWindowsDirectoryW(systemPath, sizeof(systemPath) / sizeof(WCHAR))) @@ -205,28 +143,11 @@ void CALLBACK notify_rename_callback_wrapper( wprintf(L"Error al obtener el directorio de Windows: %d\n", GetLastError()); return; } - // Extrae la letra de la unidad del directorio del sistema std::wstring driveLetter(systemPath, 2); - // Combina la letra de unidad con la ruta relativa si la ruta no existe std::wstring absolutePath = targetPathArg; if (PathFileExistsW(absolutePath.c_str()) == FALSE) - { absolutePath = driveLetter + L"\\" + targetPathArg; - } - // Imprime la ruta - // wprintf(L"absolutePath: %ls\n", absolutePath.c_str()); bool isDirectory = std::filesystem::is_directory(absolutePath); - // printf("Is directory: %d\n", isDirectory); - - Placeholders::UpdateSyncStatus(absolutePath, callbackResult, isDirectory); - - if (FAILED(hr)) - { - wprintf(L"Error in CfExecute() rename action, HRESULT: %lx\n", hr); - } - - { - std::lock_guard lock(mtx); - ready = false; // Reset ready - } + + RemoveRenameContext(callbackInfo->TransferKey); } \ No newline at end of file diff --git a/native-src/sync_root_interface/callbacks/NotifyRename/RenameTransferContext.cpp b/native-src/sync_root_interface/callbacks/NotifyRename/RenameTransferContext.cpp new file mode 100644 index 00000000..6e764636 --- /dev/null +++ b/native-src/sync_root_interface/callbacks/NotifyRename/RenameTransferContext.cpp @@ -0,0 +1,31 @@ +#include "RenameTransferContext.h" + +struct CfRenameKeyLess { + bool operator()(const CF_TRANSFER_KEY &a, const CF_TRANSFER_KEY &b) const { + return a.QuadPart < b.QuadPart; + } +}; + +static std::map, CfRenameKeyLess> g_renameContextMap; +static std::mutex g_renameContextMapMutex; + +std::shared_ptr GetOrCreateRenameContext( + CF_CONNECTION_KEY connKey, + CF_TRANSFER_KEY transferKey) +{ + std::lock_guard lock(g_renameContextMapMutex); + auto it = g_renameContextMap.find(transferKey); + if (it != g_renameContextMap.end()) + return it->second; + auto ctx = std::make_shared(); + ctx->connectionKey = connKey; + ctx->transferKey = transferKey; + g_renameContextMap[transferKey] = ctx; + return ctx; +} + +void RemoveRenameContext(CF_TRANSFER_KEY transferKey) +{ + std::lock_guard lock(g_renameContextMapMutex); + g_renameContextMap.erase(transferKey); +} From fc224fe5a2d45c0247c06eeeb92f312066cb694f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonz=C3=A1lez?= <117672238+cg27shokworks@users.noreply.github.com> Date: Thu, 13 Feb 2025 18:38:35 +0100 Subject: [PATCH 2/2] Merge pull request #129 from internxt/fix/revert-shell-forcing fix: revert shell forcing --- native-src/placeholders_interface/Planceholders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-src/placeholders_interface/Planceholders.cpp b/native-src/placeholders_interface/Planceholders.cpp index ae749f53..ee851929 100644 --- a/native-src/placeholders_interface/Planceholders.cpp +++ b/native-src/placeholders_interface/Planceholders.cpp @@ -607,7 +607,7 @@ HRESULT Placeholders::UpdatePinState(const std::wstring &path, const PinState st const auto cfState = pinStateToCfPinState(state); HRESULT result = CfSetPinState(handleForPath(path).get(), cfState, CF_SET_PIN_FLAG_NONE, nullptr); - ForceShellRefresh(path); + // ForceShellRefresh(path); if (result != S_OK) {