Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
2 changes: 1 addition & 1 deletion include/logger/Logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
25 changes: 25 additions & 0 deletions include/sync_root_interface/RenameTransferContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once
#include <map>
#include <memory>
#include <mutex>
#include <condition_variable>
#include <string>
#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<RenameContext> GetOrCreateRenameContext(
CF_CONNECTION_KEY connKey,
CF_TRANSFER_KEY transferKey);

void RemoveRenameContext(CF_TRANSFER_KEY transferKey);
18 changes: 16 additions & 2 deletions native-src/logger/Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::mutex> guard(log_mutex);

auto now = std::chrono::system_clock::now();
Expand All @@ -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) {
Expand All @@ -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;
}
}
1 change: 0 additions & 1 deletion native-src/placeholders_interface/Planceholders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,118 +7,68 @@
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <filesystem>

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<std::mutex> 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<RenameContext*>(data);
{
Logger::getInstance().log("response_callback_fn: Setting callback result.", LogLevel::DEBUG, FOREGROUND_BLUE);
std::lock_guard<std::mutex> 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<NotifyRenameArgs *>(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<RenameContext*>(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<std::mutex> 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, &notify_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");
Expand All @@ -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,
&notify_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(
Expand All @@ -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<const wchar_t *>(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<std::mutex> lock(mtx);
while (!ready)
{
cv.wait(lock);
}
std::unique_lock<std::mutex> 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};
Expand All @@ -194,39 +129,25 @@ 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<std::mutex> 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)))
{
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<std::mutex> lock(mtx);
ready = false; // Reset ready
}

RemoveRenameContext(callbackInfo->TransferKey);
}
Original file line number Diff line number Diff line change
@@ -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<CF_TRANSFER_KEY, std::shared_ptr<RenameContext>, CfRenameKeyLess> g_renameContextMap;
static std::mutex g_renameContextMapMutex;

std::shared_ptr<RenameContext> GetOrCreateRenameContext(
CF_CONNECTION_KEY connKey,
CF_TRANSFER_KEY transferKey)
{
std::lock_guard<std::mutex> lock(g_renameContextMapMutex);
auto it = g_renameContextMap.find(transferKey);
if (it != g_renameContextMap.end())
return it->second;
auto ctx = std::make_shared<RenameContext>();
ctx->connectionKey = connKey;
ctx->transferKey = transferKey;
g_renameContextMap[transferKey] = ctx;
return ctx;
}

void RemoveRenameContext(CF_TRANSFER_KEY transferKey)
{
std::lock_guard<std::mutex> lock(g_renameContextMapMutex);
g_renameContextMap.erase(transferKey);
}