Skip to content
13 changes: 12 additions & 1 deletion include/sync_root_interface/SyncRoot.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
#include <cfapi.h>
#include <Callbacks.h>
#include "stdafx.h"
#include <iostream>
#include <vector>

struct SyncRoots
{
std::wstring id;
std::wstring path;
std::wstring displayName;
std::wstring version;
};

struct ItemInfo
{
Expand All @@ -15,6 +25,7 @@ class SyncRoot
{
public:
static HRESULT RegisterSyncRoot(const wchar_t *syncRootPath, const wchar_t *providerName, const wchar_t *providerVersion, const GUID &providerId, const wchar_t *logoPath);
static std::vector<SyncRoots> GetRegisteredSyncRoots();
static HRESULT ConnectSyncRoot(const wchar_t *syncRootPath, InputSyncCallbacks syncCallbacks, napi_env env, CF_CONNECTION_KEY *connectionKey);
static HRESULT DisconnectSyncRoot(const wchar_t *syncRootPath);
static HRESULT UnregisterSyncRoot(const GUID &providerId);
Expand All @@ -25,4 +36,4 @@ class SyncRoot

private:
CF_CONNECTION_KEY connectionKey;
};
};
1 change: 1 addition & 0 deletions include/virtual_drive/Wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
napi_value CreatePlaceholderFile(napi_env env, napi_callback_info args);
napi_value UnregisterSyncRootWrapper(napi_env env, napi_callback_info args);
napi_value RegisterSyncRootWrapper(napi_env env, napi_callback_info args);
napi_value GetRegisteredSyncRootsWrapper(napi_env env, napi_callback_info args);
napi_value ConnectSyncRootWrapper(napi_env env, napi_callback_info args);
napi_value CreateEntryWrapper(napi_env env, napi_callback_info args);
napi_value DisconnectSyncRootWrapper(napi_env env, napi_callback_info args);
Expand Down
18 changes: 18 additions & 0 deletions native-src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ napi_value init(napi_env env, napi_value exports)
return nullptr;
}

// GetRegisteredSyncRootsWrapper
napi_property_descriptor getRegisteredSyncRootsRootDesc = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this write well? SyncRootsRoot?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmm it's true that it looks weird but all wrappers have the RootDesc at the end

"getRegisteredSyncRoots",
nullptr,
GetRegisteredSyncRootsWrapper,
nullptr,
nullptr,
nullptr,
napi_default,
nullptr};

napi_status defineGetRegisteredSyncRootsRootDescStatus = napi_define_properties(env, exports, 1, &getRegisteredSyncRootsRootDesc);
if (defineGetRegisteredSyncRootsRootDescStatus != napi_ok)
{
napi_throw_error(env, nullptr, "Failed to define getRegisteredSyncRoots function");
return nullptr;
}

// ConnectSyncRootWrapper
napi_property_descriptor connectSyncRootDesc = {
"connectSyncRoot",
Expand Down
51 changes: 48 additions & 3 deletions native-src/sync_root_interface/SyncRoot.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include "Callbacks.h"
#include "SyncRoot.h"
#include "stdafx.h"
#include <iostream>
#include <iostream>
#include <filesystem>
#include "Logger.h"
#include <iostream>
#include <vector>

namespace fs = std::filesystem;
// variable to disconect
Expand Down Expand Up @@ -146,7 +146,7 @@ HRESULT SyncRoot::RegisterSyncRoot(const wchar_t *syncRootPath, const wchar_t *p

// Context
std::wstring syncRootIdentity(syncRootPath);
syncRootIdentity.append(L"->");
syncRootIdentity.append(L"#intx#");
syncRootIdentity.append(providerName);

winrt::IBuffer contextBuffer = winrt::CryptographicBuffer::ConvertStringToBinary(syncRootIdentity.data(), winrt::BinaryStringEncoding::Utf8);
Expand All @@ -170,6 +170,51 @@ HRESULT SyncRoot::RegisterSyncRoot(const wchar_t *syncRootPath, const wchar_t *p
}
}

std::vector<SyncRoots> SyncRoot::GetRegisteredSyncRoots()
{
std::vector<SyncRoots> syncRootList;
try
{
auto syncRoots = winrt::StorageProviderSyncRootManager::GetCurrentSyncRoots();

printf("Sync roots count: %d\n", syncRoots.Size());

for (auto const &info : syncRoots)
{
auto contextBuffer = info.Context();
std::wstring contextString;
if (contextBuffer)
{
contextString = winrt::CryptographicBuffer::ConvertBinaryToString(
winrt::BinaryStringEncoding::Utf8,
contextBuffer)
.c_str();
}

/**
* v2.5.1 Jonathan Arce
* Sync root register are now filtered using the characters '->' and '#inxt#' to identify our register.
* Currently, we only use '#inxt#' in the register, but to support previous versions, we are still
* including '->' in the filter. In future versions, the filtering by '->' should be removed.
*/
if (contextString.find(L"#inxt#") != std::wstring::npos || contextString.find(L"->") != std::wstring::npos)
{
SyncRoots sr;
sr.id = info.Id();
sr.path = info.Path().Path();
sr.displayName = info.DisplayNameResource();
sr.version = info.Version();
syncRootList.push_back(sr);
}
}
}
catch (...)
{
Logger::getInstance().log("ERROR: getting sync root", LogLevel::INFO);
}
return syncRootList;
}

HRESULT SyncRoot::UnregisterSyncRoot(const GUID &providerId)
{
try
Expand Down
74 changes: 74 additions & 0 deletions native-src/virtual_drive/Wrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@
#include "LoggerPath.h"
#include <Logger.h>
#include <SyncRoot.h>
#include <codecvt>
#include <locale>
#include <vector>

std::string WStringToUTF8(const std::wstring &wstr)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
return conv.to_bytes(wstr);
}

napi_value CreatePlaceholderFile(napi_env env, napi_callback_info args)
{
Expand Down Expand Up @@ -202,6 +211,71 @@ napi_value RegisterSyncRootWrapper(napi_env env, napi_callback_info args)
return napiResult;
}

napi_value GetRegisteredSyncRootsWrapper(napi_env env, napi_callback_info args)
{
try
{
std::vector<SyncRoots> roots = SyncRoot::GetRegisteredSyncRoots();

napi_value jsArray;
napi_status status = napi_create_array_with_length(env, roots.size(), &jsArray);
if (status != napi_ok)
throw std::runtime_error("Error creating the array");

for (size_t i = 0; i < roots.size(); i++)
{
napi_value jsObj;
status = napi_create_object(env, &jsObj);
if (status != napi_ok)
throw std::runtime_error("Error creating the object");

Copy link
Contributor

@dajimenezriv-internxt dajimenezriv-internxt Mar 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here I assume it should be // Property "id"

std::string id = WStringToUTF8(roots[i].id);
napi_value napiId;
status = napi_create_string_utf8(env, id.c_str(), id.size(), &napiId);
if (status != napi_ok)
throw std::runtime_error("Error creating the string id");
napi_set_named_property(env, jsObj, "id", napiId);

std::string path = WStringToUTF8(roots[i].path);
napi_value napiPath;
status = napi_create_string_utf8(env, path.c_str(), path.size(), &napiPath);
if (status != napi_ok)
throw std::runtime_error("Error creating the string path");
napi_set_named_property(env, jsObj, "path", napiPath);

std::string displayName = WStringToUTF8(roots[i].displayName);
napi_value napiDisplayName;
status = napi_create_string_utf8(env, displayName.c_str(), displayName.size(), &napiDisplayName);
if (status != napi_ok)
throw std::runtime_error("Error creating the string displayName");
napi_set_named_property(env, jsObj, "displayName", napiDisplayName);

std::string version = WStringToUTF8(roots[i].version);
napi_value napiVersion;
status = napi_create_string_utf8(env, version.c_str(), version.size(), &napiVersion);
if (status != napi_ok)
throw std::runtime_error("Error creating the string version");
napi_set_named_property(env, jsObj, "version", napiVersion);

status = napi_set_element(env, jsArray, i, jsObj);
if (status != napi_ok)
throw std::runtime_error("Error setting the element in the array");
}

return jsArray;
}
catch (const std::exception &ex)
{
napi_throw_error(env, nullptr, ex.what());
return nullptr;
}
catch (...)
{
napi_throw_error(env, nullptr, "An unknown error occurred in GetRegisteredSyncRootsWrapper");
return nullptr;
}
}

napi_value ConnectSyncRootWrapper(napi_env env, napi_callback_info args)
{
try
Expand Down
5 changes: 5 additions & 0 deletions src/addon-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ export class Addon {
return this.parseAddonZod("registerSyncRoot", result);
}

getRegisteredSyncRoots() {
const result = addon.getRegisteredSyncRoots();
return this.parseAddonZod("getRegisteredSyncRoots", result);
}

connectSyncRoot({ callbacks }: { callbacks: Callbacks }) {
const result = addon.connectSyncRoot(this.syncRootPath, callbacks);
return this.parseAddonZod("connectSyncRoot", result);
Expand Down
1 change: 1 addition & 0 deletions src/addon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ export type TAddon = {
* TODO: Returns a type in c++ that is not initialized
*/
updateFileIdentity(itemPath: string, id: string, isDirectory: boolean): any;
getRegisteredSyncRoots(): z.infer<typeof addonZod.getRegisteredSyncRoots>;
};
8 changes: 8 additions & 0 deletions src/addon/addon-zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,12 @@ export const addonZod = {
registerSyncRoot: z.literal(0),
updateSyncStatus: z.boolean(),
unregisterSyncRoot: z.number(),
getRegisteredSyncRoots: z.array(
z.object({
id: z.string(),
path: z.string(),
displayName: z.string(),
version: z.string(),
}),
),
};
4 changes: 4 additions & 0 deletions src/virtual-drive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ class VirtualDrive {
});
}

static getRegisteredSyncRoots() {
return DependencyInjectionAddonProvider.get().getRegisteredSyncRoots();
}

unregisterSyncRoot() {
return this.addon.unregisterSyncRoot({ providerId: this.providerId });
}
Expand Down