Skip to content
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ node_modules
/.clang-tidy
**/.test
/.appanalyzer

.bitfun/
Binary file added AppScope/resources/base/media/tray_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 16 additions & 4 deletions entry/build-profile.json5
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
{
"apiType": "stageMode",
"buildOption": {
"resOptions": {},
"externalNativeOptions": {
"path": "src/main/cpp/CMakeLists.txt",
"cppFlags": "",
"arguments": ""
}
},
"buildOptionSet": [
{
"name": "release",
"nativeLib": {
"debugSymbol": {
"strip": true,
"exclude": []
}
},
"arkOptions": {
"obfuscation": {
"ruleOptions": {
Expand All @@ -15,11 +27,11 @@
}
}
}
},
}
],
"targets": [
{
"name": "default",
},
"name": "default"
}
]
}
}
11 changes: 9 additions & 2 deletions entry/oh-package-lock.json5

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions entry/oh-package.json5
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
"license": "",
"dependencies": {
"nextcloud": "file:../nextcloud",
"libcloudsync.so": "file:./src/main/cpp/types/libcloudsync"
},
}
2 changes: 1 addition & 1 deletion entry/patch.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"app": {
"bundleName": "me.moody.nextcloud",
"patchVersionCode": 2000865,
"patchVersionCode": 2001296,
"versionCode": 1000000
},
"module": {
Expand Down
6 changes: 6 additions & 0 deletions entry/src/main/cpp/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"clangd.arguments": [
"--compile-commands-dir=${workspaceFolder}/../../../.cxx/default/default/debug/arm64-v8a/",
"--query-driver=**"
]
}
27 changes: 27 additions & 0 deletions entry/src/main/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.5.0)
project(Nextcloud)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()

include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)

add_library(cloudsync
SHARED
src/napi_init.cpp
)
target_link_libraries(
cloudsync
PUBLIC
libace_napi.z.so
libohclouddiskmanager.so
libhilog_ndk.z.so
libdeviceinfo_ndk.z.so
)
15 changes: 15 additions & 0 deletions entry/src/main/cpp/include/Logging.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once
#define LOG_DOMAIN 0

#include <hilog/log.h>

#define LogFmt(fmt, ...) "[%{public}s:%{public}d] " fmt, __func__, __LINE__, ##__VA_ARGS__

#define LogE(fmt, ...) OH_LOG_Print(LogType::LOG_APP, LogLevel::LOG_ERROR, LOG_DOMAIN, LOG_TAG, LogFmt(fmt, ##__VA_ARGS__))
#define LogW(fmt, ...) OH_LOG_Print(LogType::LOG_APP, LogLevel::LOG_WARN, LOG_DOMAIN, LOG_TAG, LogFmt(fmt, ##__VA_ARGS__))
#define LogI(fmt, ...) OH_LOG_Print(LogType::LOG_APP, LogLevel::LOG_INFO, LOG_DOMAIN, LOG_TAG, LogFmt(fmt, ##__VA_ARGS__))
#define LogD(fmt, ...) OH_LOG_Print(LogType::LOG_APP, LogLevel::LOG_DEBUG, LOG_DOMAIN, LOG_TAG, LogFmt(fmt, ##__VA_ARGS__))

// clang-format off
#define NAPI_ERR_RET(expr, msg, ...) if ((expr) != napi_ok) { LogI(msg, ##__VA_ARGS__); return; }
// clang-format on
68 changes: 68 additions & 0 deletions entry/src/main/cpp/include/NapiCallback.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <js_native_api.h>
#include <js_native_api_types.h>
#include <node_api.h>
#include <node_api_types.h>
#include <string_view>
#include <type_traits>

struct NapiObject
{
public:
NapiObject() = default;
virtual ~NapiObject() = default;
virtual napi_value ToNapiValue(napi_env env) const = 0;
};

template<typename TArg>
requires(std::is_base_of_v<NapiObject, TArg>) class NapiCallback
{
public:
explicit NapiCallback(napi_env e, std::string_view name, napi_value jsCallback) : env(e)
{
napi_value workName;
napi_create_string_utf8(env, name.data(), NAPI_AUTO_LENGTH, &workName);
napi_create_threadsafe_function(env, nullptr, nullptr, workName, 0, 1, nullptr, nullptr, nullptr, JsInvoker, &tsFn);
napi_create_reference(env, jsCallback, 1, &callbackRef);
}

~NapiCallback()
{
napi_delete_reference(env, callbackRef);
}

void Invoke(const TArg *arg) const
{
const auto argContext = new CallbackArg();
argContext->callbackRef = callbackRef;
argContext->arg = arg;
napi_acquire_threadsafe_function(tsFn);
napi_call_threadsafe_function(tsFn, argContext, napi_tsfn_nonblocking);
napi_release_threadsafe_function(tsFn, napi_tsfn_release);
}

private:
struct CallbackArg
{
napi_ref callbackRef = nullptr;
const TArg *arg = nullptr;
};

static void JsInvoker(napi_env env, napi_value js_callBack, void *context, void *data)
{
(void) context;
auto *const argContext = reinterpret_cast<CallbackArg *>(data);
napi_get_reference_value(env, argContext->callbackRef, &js_callBack);
const auto arg = argContext->arg->ToNapiValue(env);
napi_call_function(env, nullptr, js_callBack, 1, &arg, nullptr);
delete argContext;
}

private:
napi_env env = nullptr;
napi_ref callbackRef = nullptr;
napi_threadsafe_function tsFn = nullptr;
};
35 changes: 35 additions & 0 deletions entry/src/main/cpp/include/NapiCallbackStorage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include "Logging.hpp"
#include "NapiCallback.hpp"

#include <js_native_api_types.h>
#include <list>
#include <string_view>

template<typename TArg>
struct NapiCallbackStorage
{
public:
explicit NapiCallbackStorage() = default;

void AddCallback(napi_env env, std::string_view name, napi_value jsCallback)
{
LogD("enter");
const auto callback = std::make_shared<NapiCallback<TArg>>(env, name, jsCallback);
callbacks.push_back(callback);
}

void InvokeAll(const TArg *arg)
{
for (const auto &callback : callbacks)
{
callback->Invoke(arg);
}
}

private:
std::list<std::shared_ptr<NapiCallback<TArg>>> callbacks;
};
91 changes: 91 additions & 0 deletions entry/src/main/cpp/include/NapiUtils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#pragma once

#include <array>
#include <node_api.h>
#include <optional>
#include <string>
#include <utility>

template<napi_valuetype t>
struct NapiValueConverter
{
static constexpr napi_valuetype type = napi_undefined;
void Get(napi_env, napi_value){};
};

#define DeclareNapiValueConverter(_type, _type_t, _convert_func) \
template<> \
struct NapiValueConverter<_type> \
{ \
using type_t = _type_t; \
using optional_t = std::optional<type_t>; \
static constexpr napi_valuetype type = _type; \
static optional_t Get(napi_env env, napi_value value) \
{ \
type_t ret; \
napi_valuetype arg_type = napi_undefined; \
napi_typeof(env, value, &arg_type); \
if (arg_type != _type) \
return std::nullopt; \
_convert_func(env, value, &ret); \
return ret; \
} \
}

DeclareNapiValueConverter(napi_function, napi_value, [](napi_env, napi_value value, napi_value *ret) { *ret = value; });
DeclareNapiValueConverter(napi_object, napi_value, [](napi_env, napi_value value, napi_value *ret) { *ret = value; });
DeclareNapiValueConverter(napi_number, long, napi_get_value_int64);
DeclareNapiValueConverter(napi_boolean, bool, napi_get_value_bool);
DeclareNapiValueConverter(napi_string, std::string,
[](napi_env env, napi_value value, std::string *ret)
{
size_t len = 0;
napi_get_value_string_utf8(env, value, nullptr, 0, &len);
ret->resize(len, '\0');
napi_get_value_string_utf8(env, value, ret->data(), len + 1, &len);
});

template<napi_valuetype... types>
struct NapiArgs
{
static constexpr auto NTypes = sizeof...(types);
using Result = std::tuple<typename NapiValueConverter<types>::type_t...>;
using OptionalResult = std::tuple<typename NapiValueConverter<types>::optional_t...>;
using NapiValueArray = std::array<napi_value, NTypes>;

template<class S = std::make_index_sequence<NTypes>>
struct DoConvert; // doesn't need to be defined

template<size_t... Is>
struct DoConvert<std::index_sequence<Is...>>
{
static OptionalResult impl(napi_env env, NapiValueArray args)
{
return std::make_tuple(NapiValueConverter<types>::Get(env, args[Is])...);
}
};

static std::optional<Result> Get(napi_env env, napi_callback_info info)
{
NapiValueArray args;
size_t argc = NTypes;
napi_get_cb_info(env, info, &argc, args.data(), nullptr, nullptr);

if (argc != NTypes)
{
napi_throw_type_error(env, nullptr, "Wrong number of arguments");
return {};
}

const auto optional_result = DoConvert<>::impl(env, args);
const bool is_all_valid = std::apply([](const auto &...args) { return (... && args.has_value()); }, optional_result);
if (!is_all_valid)
{
napi_throw_type_error(env, nullptr, "Wrong arguments");
return {};
}

const auto result = std::apply([](const auto &...args) { return std::make_tuple(args.value()...); }, optional_result);
return std::make_optional(result);
}
};
Loading