diff --git a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp index 2ccf869e5aabae40423eec2672653278ebe36783..bdf8b5fbe732893a5161b0db368f8fad50df9773 100644 --- a/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp +++ b/datamgr_service/services/distributeddataservice/service/cloud/cloud_service_stub.cpp @@ -15,6 +15,8 @@ #define LOG_TAG "CloudServiceStub" #include "cloud_service_stub.h" +#include + #include "ipc_skeleton.h" #include "itypes_util.h" #include "log_print.h" @@ -53,6 +55,12 @@ int CloudServiceStub::OnRemoteRequest(uint32_t code, OHOS::MessageParcel &data, int32_t CloudServiceStub::OnEnableCloud(const std::string &id, MessageParcel &data, MessageParcel &reply) { + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } std::map switches; if (!ITypesUtil::Unmarshal(data, switches)) { ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); @@ -64,12 +72,24 @@ int32_t CloudServiceStub::OnEnableCloud(const std::string &id, MessageParcel &da int32_t CloudServiceStub::OnDisableCloud(const std::string &id, MessageParcel &data, MessageParcel &reply) { + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } auto result = DisableCloud(id); return ITypesUtil::Marshal(reply, result) ? ERR_NONE : IPC_STUB_WRITE_PARCEL_ERR; } int32_t CloudServiceStub::OnChangeAppSwitch(const std::string &id, MessageParcel &data, MessageParcel &reply) { + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } std::string bundleName; int32_t appSwitch = SWITCH_OFF; if (!ITypesUtil::Unmarshal(data, bundleName, appSwitch)) { @@ -82,6 +102,12 @@ int32_t CloudServiceStub::OnChangeAppSwitch(const std::string &id, MessageParcel int32_t CloudServiceStub::OnClean(const std::string &id, MessageParcel &data, MessageParcel &reply) { + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } std::map actions; if (!ITypesUtil::Unmarshal(data, actions)) { ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); @@ -93,6 +119,12 @@ int32_t CloudServiceStub::OnClean(const std::string &id, MessageParcel &data, Me int32_t CloudServiceStub::OnNotifyDataChange(const std::string &id, MessageParcel &data, MessageParcel &reply) { + auto tokenId = IPCSkeleton::GetCallingTokenID(); + if (OHOS::Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId) == + OHOS::Security::AccessToken::TOKEN_HAP) { + ZLOGE("permission denied!"); + return -1; + } std::string bundleName; if (!ITypesUtil::Unmarshal(data, bundleName)) { ZLOGE("Unmarshal id:%{public}s", Anonymous::Change(id).c_str()); diff --git a/relational_store/frameworks/js/napi/cloud_data/BUILD.gn b/relational_store/frameworks/js/napi/cloud_data/BUILD.gn index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fdd30566cee10fe872125c436425065d3282118d 100644 --- a/relational_store/frameworks/js/napi/cloud_data/BUILD.gn +++ b/relational_store/frameworks/js/napi/cloud_data/BUILD.gn @@ -0,0 +1,56 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") +import("//foundation/distributeddatamgr/relational_store/relational_store.gni") + +ohos_copy("relational_store_declaration") { + sources = [ "./api" ] + outputs = [ target_out_dir + "/$target_name/" ] + module_source_dir = target_out_dir + "/$target_name" + module_install_name = "" +} + +ohos_shared_library("clouddata") { + sources = [ + "src/entry_point.cpp", + "src/js_config.cpp", + "src/js_const_properties.cpp", + "src/js_error_utils.cpp", + "src/js_util.cpp", + "src/napi_queue.cpp", + ] + include_dirs = [ + "include", + "${relational_store_js_common_path}/include", + "${relational_store_napi_path}/cloud_data/include", + "${relational_store_innerapi_path}/cloud_data/include", + "//foundation/distributeddatamgr/kv_store/frameworks/common", + ] + defines = [ "SQLITE_DISTRIBUTE_RELATIONAL" ] + + external_deps = [ + "ability_runtime:abilitykit_native", + "ability_runtime:napi_base_context", + "c_utils:utils", + "hitrace_native:hitrace_meter", + "hiviewdfx_hilog_native:libhilog", + "napi:ace_napi", + "relational_store:native_appdatafwk", + "relational_store:native_rdb", + ] + + subsystem_name = "distributeddatamgr" + part_name = "relational_store" + relative_install_dir = "module/data" +} diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_config.h b/relational_store/frameworks/js/napi/cloud_data/include/js_config.h new file mode 100644 index 0000000000000000000000000000000000000000..80b212fcfe83f2e0513dfdedda2dcd8237abff9d --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_config.h @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef LDBPROJ_JS_CONFIG_H +#define LDBPROJ_JS_CONFIG_H +#include "js_const_properties.h" +#include "js_util.h" +#include "log_print.h" + +namespace OHOS::CloudData { +class JsConfig { +public: + JsConfig(); + ~JsConfig(); + + static napi_value EnableCloud(napi_env env, napi_callback_info info); + static napi_value DisableCloud(napi_env env, napi_callback_info info); + static napi_value ChangeAppCloudSwitch(napi_env env, napi_callback_info info); + static napi_value Clean(napi_env env, napi_callback_info info); + static napi_value NotifyDataChange(napi_env env, napi_callback_info info); +}; + +} // namespace OHOS::CloudData + +#endif //LDBPROJ_JS_CONFIG_H diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_const_properties.h b/relational_store/frameworks/js/napi/cloud_data/include/js_const_properties.h new file mode 100644 index 0000000000000000000000000000000000000000..6245a158699a31639fa32b27ee61834b5fd2b393 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_const_properties.h @@ -0,0 +1,25 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef LDBPROJ_JS_CONST_PROPERTIES_H +#define LDBPROJ_JS_CONST_PROPERTIES_H +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::CloudData { +napi_status InitConstProperties(napi_env env, napi_value exports); +} // namespace OHOS::CloudData +#endif //LDBPROJ_JS_CONST_PROPERTIES_H diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h b/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..fbbbc6b79ad486b6299b9da569dd5ec3f898a921 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_error_utils.h @@ -0,0 +1,69 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef LDBPROJ_JS_ERROR_UTILS_H +#define LDBPROJ_JS_ERROR_UTILS_H +#include +#include + +#include "cloud_service.h" +#include "js_native_api.h" +#include "log_print.h" +#include "napi/native_common.h" + +namespace OHOS { +namespace CloudData { +using Status = OHOS::CloudData::CloudService::Status; + +struct JsErrorCode { + int32_t status; + int32_t jsCode; + const char *message; +}; + +const std::optional GetJsErrorCode(int32_t errorCode); +Status GenerateNapiError(Status status, int32_t &errCode, std::string &errMessage); +void ThrowNapiError(napi_env env, int32_t errCode, std::string errMessage, bool isParamsCheck = true); +napi_value GenerateErrorMsg(napi_env env, JsErrorCode jsInfo); + +#define ASSERT_ERR(env, assertion, errorCode, message) \ + do { \ + if (!(assertion)) { \ + ThrowNapiError(env, errorCode, message); \ + return nullptr; \ + } \ + } while (0) + +#define ASSERT_BUSINESS_ERR(ctxt, assertion, errorCode, message) \ + do { \ + if (!(assertion)) { \ + (ctxt)->isThrowError = true; \ + ThrowNapiError((ctxt)->env, errorCode, message); \ + return; \ + } \ + } while (0) + +#define ASSERT_PERMISSION_ERR(ctxt, assertion, errorCode, message) \ + do { \ + if (!(assertion)) { \ + (ctxt)->isThrowError = true; \ + ThrowNapiError((ctxt)->env, errorCode, message, false); \ + return; \ + } \ + } while (0) + +} // namespace CloudData +} // namespace OHOS +#endif //LDBPROJ_JS_ERROR_UTILS_H diff --git a/relational_store/frameworks/js/napi/cloud_data/include/js_util.h b/relational_store/frameworks/js/napi/cloud_data/include/js_util.h new file mode 100644 index 0000000000000000000000000000000000000000..cc26fb01ee951e697b9240ec0d438b50f955f6e6 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/js_util.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef LDBPROJ_JS_UTIL_H +#define LDBPROJ_JS_UTIL_H +#include +#include + +#include "js_error_utils.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::CloudData { +class JSUtil final { +public: + enum { + /* exported js Action is (CloudData::Action-1) */ + CLEAR_CLOUD_INFO = 0, + CLEAR_CLOUD_DATA_AND_INFO = 1, + }; + + struct StatusMsg { + napi_status status = napi_ok; + StatusMsg(napi_status status) : status(status) {} + operator napi_status() + { + return status; + } + }; + + using Status = OHOS::CloudData::CloudService::Status; + + static StatusMsg GetValue(napi_env env, napi_value in, napi_value &out); + static StatusMsg SetValue(napi_env env, napi_value in, napi_value &out); + /* napi_value <-> bool */ + static StatusMsg GetValue(napi_env env, napi_value in, bool &out); + static StatusMsg SetValue(napi_env env, const bool &in, napi_value &out); + /* napi_value <-> std::string */ + static StatusMsg GetValue(napi_env env, napi_value in, std::string &out); + static StatusMsg SetValue(napi_env env, const std::string &in, napi_value &out); + /* napi_value <-> int32_t */ + static napi_status GetValue(napi_env env, napi_value in, int32_t &out); + static napi_status SetValue(napi_env env, const int32_t &in, napi_value &out); + /* napi_value <-> std::map */ + static StatusMsg GetValue(napi_env env, napi_value in, std::map &out); + static StatusMsg SetValue(napi_env env, const std::map &in, napi_value &out); + /* napi_value <-> std::map */ + static StatusMsg GetValue(napi_env env, napi_value in, std::map &out); + + /* napi_get_named_property wrapper */ + template + static inline napi_status GetNamedProperty(napi_env env, napi_value in, const std::string &prop, T &value) + { + bool hasProp = false; + napi_status status = napi_has_named_property(env, in, prop.c_str(), &hasProp); + if (!hasProp) { + return napi_generic_failure; + } + if ((status == napi_ok) && hasProp) { + napi_value inner = nullptr; + status = napi_get_named_property(env, in, prop.c_str(), &inner); + if ((status == napi_ok) && (inner != nullptr)) { + return GetValue(env, inner, value); + } + } + return napi_invalid_arg; + }; + + static bool ValidSubscribeType(int32_t type) + { + return (CLEAR_CLOUD_INFO <= type) && (type <= CLEAR_CLOUD_DATA_AND_INFO); + } + +private: + enum { + /* std::map to js::tuple */ + TUPLE_KEY = 0, + TUPLE_VALUE, + TUPLE_SIZE + }; +}; +} // namespace OHOS::CloudData +#endif //LDBPROJ_JS_UTIL_H diff --git a/relational_store/frameworks/js/napi/cloud_data/include/napi_queue.h b/relational_store/frameworks/js/napi/cloud_data/include/napi_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..3e92eed53b2a9800774b7c54a08278c0832a3954 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/include/napi_queue.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef LDBPROJ_NAPI_QUEUE_H +#define LDBPROJ_NAPI_QUEUE_H +#include +#include +#include + +#include "log_print.h" +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS::CloudData { +constexpr size_t ARGC_MAX = 6; +using NapiCbInfoParser = std::function; +using NapiAsyncExecute = std::function; +using NapiAsyncComplete = std::function; + +struct ContextBase { + virtual ~ContextBase(); + void GetCbInfo(napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser(), + bool sync = false); + + inline void GetCbInfoSync(napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser()) + { + /* sync = true, means no callback, not AsyncWork. */ + GetCbInfo(env, info, parse, true); + } + + napi_env env = nullptr; + napi_value output = nullptr; + napi_status status = napi_invalid_arg; + std::string error; + int32_t jsCode = 0; + bool isThrowError = false; + + napi_value self = nullptr; + void *native = nullptr; + +private: + napi_ref callbackRef = nullptr; + napi_ref selfRef = nullptr; + friend class NapiQueue; +}; + +/* check condition related to argc/argv, return and logging. */ +#define ASSERT_ARGS(ctxt, condition, message) \ + do { \ + if (!(condition)) { \ + (ctxt)->status = napi_invalid_arg; \ + (ctxt)->error = std::string(message); \ + ZLOGE("test (" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +#define ASSERT_STATUS(ctxt, message) \ + do { \ + if ((ctxt)->status != napi_ok) { \ + (ctxt)->error = std::string(message); \ + ZLOGE("test (ctxt->status == napi_ok) failed: " message); \ + return; \ + } \ + } while (0) + +/* check condition, return and logging if condition not true. */ +#define ASSERT(condition, message, retVal) \ + do { \ + if (!(condition)) { \ + ZLOGE("test (" #condition ") failed: " message); \ + return retVal; \ + } \ + } while (0) + +#define ASSERT_VOID(condition, message) \ + do { \ + if (!(condition)) { \ + ZLOGE("test (" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +#define ASSERT_NULL(condition, message) ASSERT(condition, message, nullptr) + +#define ASSERT_CALL(env, theCall, object) \ + do { \ + if ((theCall) != napi_ok) { \ + delete (object); \ + GET_AND_THROW_LAST_ERROR((env)); \ + return nullptr; \ + } \ + } while (0) + +class NapiQueue { +public: + static napi_value AsyncWork(napi_env env, std::shared_ptr ctxt, const std::string &name, + NapiAsyncExecute execute = NapiAsyncExecute(), NapiAsyncComplete complete = NapiAsyncComplete()); + +private: + enum { + /* AsyncCallback / Promise output result index */ + RESULT_ERROR = 0, + RESULT_DATA = 1, + RESULT_ALL = 2 + }; + + struct AsyncContext { + napi_env env = nullptr; + std::shared_ptr ctx; + NapiAsyncExecute execute = nullptr; + NapiAsyncComplete complete = nullptr; + napi_deferred deferred = nullptr; + napi_async_work work = nullptr; + ~AsyncContext() + { + execute = nullptr; + complete = nullptr; + ctx = nullptr; + if (env != nullptr) { + if (work != nullptr) { + napi_delete_async_work(env, work); + } + } + } + }; + static void GenerateOutput(AsyncContext &ctx, napi_value output); +}; +} // namespace OHOS::CloudData +#endif //LDBPROJ_NAPI_QUEUE_H diff --git a/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp b/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp new file mode 100644 index 0000000000000000000000000000000000000000..12eb000aec88642c3038f4ec074f41dc16f24c2b --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/entry_point.cpp @@ -0,0 +1,50 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#define LOG_TAG "EntryPoint" +#include "js_config.h" +#include "js_const_properties.h" +#include "log_print.h" + +using namespace OHOS::CloudData; + +static napi_value Init(napi_env env, napi_value exports) +{ + const napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("enableCloud", JsConfig::EnableCloud), + DECLARE_NAPI_FUNCTION("disableCloud", JsConfig::DisableCloud), + DECLARE_NAPI_FUNCTION("changeAppCloudSwitch", JsConfig::ChangeAppCloudSwitch), + DECLARE_NAPI_FUNCTION("clean", JsConfig::Clean), + DECLARE_NAPI_FUNCTION("notifyDataChange", JsConfig::NotifyDataChange), + + }; + napi_status status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + ZLOGI("init cloudData config %{public}d", status); + status = InitConstProperties(env, exports); + ZLOGI("init Enumerate Constants %{public}d", status); + return exports; +} + +static __attribute__((constructor)) void RegisterModule() +{ + static napi_module module = { .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "data.cloudData", + .nm_priv = ((void *)0), + .reserved = { 0 } }; + napi_module_register(&module); + ZLOGI("module register data.cloudData"); +} diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d2abf659e67f4369ad06a4744457751bfd1ec12 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_config.cpp @@ -0,0 +1,221 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#define LOG_TAG "JsConfig" +#include "js_config.h" + +#include "cloud_manager.h" +#include "js_error_utils.h" +#include "js_util.h" +#include "log_print.h" +#include "napi_queue.h" + +using namespace OHOS::CloudData; + +JsConfig::JsConfig() {} + +JsConfig::~JsConfig() {} + +/* + * [JS API Prototype] + * [AsyncCallback] + * enableCloud(accountId: string, switches: {[bundleName: string]: boolean}, callback: AsyncCallback): void; + * [Promise] + * enableCloud(accountId: string, switches: {[bundleName: string]: boolean}): Promise; + */ +napi_value JsConfig::EnableCloud(napi_env env, napi_callback_info info) +{ + struct EnableCloudContext : public ContextBase { + std::string accountId; + std::map switches1; + std::map switches2; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 2 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, "The type of key must be string."); + ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->switches1); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of key must be {[bundleName: string]: boolean}."); + for (auto item : ctxt->switches1) { + ctxt->switches2.insert(std::pair(item.first, static_cast(item.second))); + } + }); + + ASSERT_NULL(!ctxt->isThrowError, "EnableCloud exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->EnableCloud(ctxt->accountId, ctxt->switches2); + ZLOGD("EnableCloud return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCallback] + * disableCloud(accountId: string, callback: AsyncCallback): void; + * [Promise] + * disableCloud(accountId: string): Promise; + */ +napi_value JsConfig::DisableCloud(napi_env env, napi_callback_info info) +{ + struct DisableCloudContext : public ContextBase { + std::string accountId; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 2 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of accountId must be string."); + }); + + ASSERT_NULL(!ctxt->isThrowError, "DisableCloud exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->DisableCloud(ctxt->accountId); + ZLOGD("DisableCloud return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCallback] + * changeAppCloudSwitch(accountId: string, bundleName: string, status :boolean, callback: AsyncCallback): void; + * [Promise] + * changeAppCloudSwitch(accountId: string, bundleName: string, status :boolean): Promise; + */ +napi_value JsConfig::ChangeAppCloudSwitch(napi_env env, napi_callback_info info) +{ + struct ChangeAppSwitchContext : public ContextBase { + std::string accountId; + std::string bundleName; + bool status; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 3 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 3, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of accountId must be string."); + ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->bundleName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of bundleName must be string."); + ctxt->status = JSUtil::GetValue(env, argv[2], ctxt->status); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of bundleName must be boolean."); + }); + + ASSERT_NULL(!ctxt->isThrowError, "ChangeAppCloudSwitch exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->ChangeAppSwitch(ctxt->accountId, ctxt->bundleName, ctxt->status); + ZLOGD("kvStore->Put return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCallback] + * clean(accountId: string, appActions: {[bundleName: string]: Action}, callback: AsyncCallback): void; + * [Promise] + * clean(accountId: string, appActions: {[bundleName: string]: Action}): Promise; + */ +napi_value JsConfig::Clean(napi_env env, napi_callback_info info) +{ + struct CleanContext : public ContextBase { + std::string accountId; + std::map actions; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 2 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of accountId must be string."); + ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->actions); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of actions must be {[bundleName: string]: int32_t}."); + }); + + ASSERT_NULL(!ctxt->isThrowError, "Clean exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->Clean(ctxt->accountId, ctxt->actions); + ZLOGD("Clean return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} + +/* + * [JS API Prototype] + * [AsyncCallback] + * notifyDataChange(accountId: string, bundleName: string, callback: AsyncCallback): void; + * [Promise] + * notifyDataChange(accountId: string, bundleName: string): Promise; + */ +napi_value JsConfig::NotifyDataChange(napi_env env, napi_callback_info info) +{ + struct ChangeAppSwitchContext : public ContextBase { + std::string accountId; + std::string bundleName; + }; + auto ctxt = std::make_shared(); + ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) { + // required 2 arguments :: + ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect."); + ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->accountId); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of accountId must be string."); + ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->bundleName); + ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::INVALID_ARGUMENT, + "The type of bundleName must be string."); + }); + + ASSERT_NULL(!ctxt->isThrowError, "NotifyDataChange exit"); + + auto execute = [ctxt]() { + auto proxy = CloudManager::GetInstance().GetCloudService(); + int32_t status = proxy->NotifyDataChange(ctxt->accountId, ctxt->bundleName); + ZLOGD("NotifyDataChange return %{public}d", status); + ctxt->status = (GenerateNapiError(static_cast(status), ctxt->jsCode, ctxt->error) == Status::SUCCESS) + ? napi_ok + : napi_generic_failure; + }; + return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute); +} \ No newline at end of file diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_const_properties.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_const_properties.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60f4df42ae7d5cbbc1c5bc00684c756f1de5bba4 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_const_properties.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#define LOG_TAG "Const_Properties" +#include "js_const_properties.h" + +#include "cloud_service.h" +#include "log_print.h" +#include "napi_queue.h" + +using Action = OHOS::CloudData::CloudService::Action; +namespace OHOS::CloudData { +static napi_status SetNamedProperty(napi_env env, napi_value &obj, const std::string &name, int32_t value) +{ + napi_value property = nullptr; + napi_status status = napi_create_int32(env, value, &property); + ASSERT(status == napi_ok, "int32_t to napi_value failed!", status); + status = napi_set_named_property(env, obj, name.c_str(), property); + ASSERT(status == napi_ok, "napi_set_named_property failed!", status); + return status; +} + +static napi_value ExportAction(napi_env env) +{ + napi_value action = nullptr; + napi_create_object(env, &action); + SetNamedProperty(env, action, "CLEAR_CLOUD_INFO", (int32_t)Action::CLEAR_CLOUD_INFO); + SetNamedProperty(env, action, "CLEAR_CLOUD_DATA_AND_INFO", (int32_t)Action::CLEAR_CLOUD_DATA_AND_INFO); + napi_object_freeze(env, action); + return action; +} + +napi_status InitConstProperties(napi_env env, napi_value exports) +{ + const napi_property_descriptor properties[] = { + DECLARE_NAPI_PROPERTY("Action", ExportAction(env)), + }; + size_t count = sizeof(properties) / sizeof(properties[0]); + + return napi_define_properties(env, exports, count, properties); +} +} // namespace OHOS::CloudData diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_error_utils.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_error_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..300c99ee1db7ac1f8c83ed42505b091f0305ee34 --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_error_utils.cpp @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#define LOG_TAG "JS_ERROR_UTILS" + +#include "js_error_utils.h" + +#include + +namespace OHOS::CloudData { +using JsErrorCode = OHOS::CloudData::JsErrorCode; + +static constexpr JsErrorCode JS_ERROR_CODE_MSGS[] = { + { Status::INVALID_ARGUMENT, 401, "Parameter error." }, +}; + +const std::optional GetJsErrorCode(int32_t errorCode) +{ + auto jsErrorCode = JsErrorCode{ errorCode, -1, "" }; + auto iter = std::lower_bound(JS_ERROR_CODE_MSGS, + JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]), jsErrorCode, + [](const JsErrorCode &jsErrorCode1, const JsErrorCode &jsErrorCode2) { + return jsErrorCode1.status < jsErrorCode2.status; + }); + if (iter < JS_ERROR_CODE_MSGS + sizeof(JS_ERROR_CODE_MSGS) / sizeof(JS_ERROR_CODE_MSGS[0]) && + iter->status == errorCode) { + return *iter; + } + return std::nullopt; +} + +Status GenerateNapiError(Status status, int32_t &errCode, std::string &errMessage) +{ + auto errorMsg = GetJsErrorCode(status); + if (errorMsg.has_value()) { + auto napiError = errorMsg.value(); + errCode = napiError.jsCode; + errMessage = napiError.message; + } else { + // unmatched status return unified error code + errCode = -1; + errMessage = ""; + } + ZLOGD("GenerateNapiError errCode is %{public}d", errCode); + if (errCode == 0) { + return Status::SUCCESS; + } + return status; +} + +void ThrowNapiError(napi_env env, int32_t status, std::string errMessage, bool isParamsCheck) +{ + ZLOGD("ThrowNapiError message: %{public}s", errMessage.c_str()); + if (status == Status::SUCCESS) { + return; + } + auto errorMsg = GetJsErrorCode(status); + JsErrorCode napiError; + if (errorMsg.has_value()) { + napiError = errorMsg.value(); + } else { + napiError.jsCode = -1; + napiError.message = ""; + } + + std::string message(napiError.message); + if (isParamsCheck) { + napiError.jsCode = 401; + message += errMessage; + } + + std::string jsCode; + if (napiError.jsCode == -1) { + jsCode = ""; + } else { + jsCode = std::to_string(napiError.jsCode); + } + napi_throw_error(env, jsCode.c_str(), message.c_str()); +} +} // namespace OHOS::CloudData diff --git a/relational_store/frameworks/js/napi/cloud_data/src/js_util.cpp b/relational_store/frameworks/js/napi/cloud_data/src/js_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..554e7ee24e0b925711a4137c22c2a8e32bf54d4a --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/js_util.cpp @@ -0,0 +1,166 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#define LOG_TAG "JSUtil" +#include "js_util.h" + +#include "log_print.h" +#include "napi_base_context.h" +#include "napi_queue.h" + +namespace OHOS::CloudData { +constexpr int32_t STR_MAX_LENGTH = 4096; +constexpr size_t STR_TAIL_LENGTH = 1; + +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, napi_value &out) +{ + out = in; + return napi_ok; +} + +JSUtil::StatusMsg JSUtil::SetValue(napi_env env, napi_value in, napi_value &out) +{ + out = in; + return napi_ok; +} + +/* napi_value <-> bool */ +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, bool &out) +{ + return napi_get_value_bool(env, in, &out); +} + +JSUtil::StatusMsg JSUtil::SetValue(napi_env env, const bool &in, napi_value &out) +{ + return napi_get_boolean(env, in, &out); +} + +/* napi_value <-> int32_t */ +napi_status JSUtil::GetValue(napi_env env, napi_value in, int32_t &out) +{ + return napi_get_value_int32(env, in, &out); +} + +napi_status JSUtil::SetValue(napi_env env, const int32_t &in, napi_value &out) +{ + return napi_create_int32(env, in, &out); +} + +/* napi_value <-> std::string */ +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, std::string &out) +{ + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, in, &type); + ASSERT((status == napi_ok) && (type == napi_string), "invalid type", napi_invalid_arg); + + size_t maxLen = STR_MAX_LENGTH; + status = napi_get_value_string_utf8(env, in, NULL, 0, &maxLen); + if (maxLen <= 0) { + return status; + } + ZLOGD("napi_value -> std::string get length %{public}d", (int)maxLen); + char *buf = new (std::nothrow) char[maxLen + STR_TAIL_LENGTH]; + if (buf != nullptr) { + size_t len = 0; + status = napi_get_value_string_utf8(env, in, buf, maxLen + STR_TAIL_LENGTH, &len); + if (status == napi_ok) { + buf[len] = 0; + out = std::string(buf); + } + delete[] buf; + } else { + status = napi_generic_failure; + } + return status; +} + +JSUtil::StatusMsg JSUtil::SetValue(napi_env env, const std::string &in, napi_value &out) +{ + return napi_create_string_utf8(env, in.c_str(), in.size(), &out); +} + +/* napi_value <-> std::map */ +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, std::map &out) +{ + ZLOGD("napi_value -> std::map "); + out.clear(); + uint32_t length = 0; + napi_status status = napi_get_array_length(env, in, &length); + ASSERT((status == napi_ok) && (length > 0), "get_map failed!", napi_invalid_arg); + for (uint32_t i = 0; i < length; ++i) { + napi_value item = nullptr; + status = napi_get_element(env, in, i, &item); + ASSERT((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg); + int index = 0; + napi_value item1 = nullptr; + status = napi_get_element(env, item, index++, &item1); + std::string key; + status = GetValue(env, item1, key); + napi_value item2 = nullptr; + status = napi_get_element(env, item, index, &item2); + bool value; + status = GetValue(env, item2, value); + out.insert(std::pair(key, status)); + } + return status; +} + +/* napi_value <-> std::map */ +JSUtil::StatusMsg JSUtil::GetValue(napi_env env, napi_value in, std::map &out) +{ + ZLOGD("napi_value -> std::map "); + out.clear(); + uint32_t length = 0; + napi_status status = napi_get_array_length(env, in, &length); + ASSERT((status == napi_ok) && (length > 0), "get_map failed!", napi_invalid_arg); + for (uint32_t i = 0; i < length; ++i) { + napi_value item = nullptr; + status = napi_get_element(env, in, i, &item); + ASSERT((item != nullptr) && (status == napi_ok), "no element", napi_invalid_arg); + int index = 0; + napi_value item1 = nullptr; + status = napi_get_element(env, item, index++, &item1); + std::string key; + status = GetValue(env, item1, key); + napi_value item2 = nullptr; + status = napi_get_element(env, item, index, &item2); + int32_t actionType; + status = GetValue(env, item2, actionType); + ASSERT(ValidSubscribeType(actionType) == true, "not action", napi_invalid_arg); + out.insert(std::pair(key, actionType)); + } + return status; +} + +JSUtil::StatusMsg JSUtil::SetValue(napi_env env, const std::map &in, napi_value &out) +{ + ZLOGD("napi_value <- std::map "); + napi_status status = napi_create_array_with_length(env, in.size(), &out); + ASSERT((status == napi_ok), "invalid object", status); + int index = 0; + for (const auto &[key, value] : in) { + napi_value element = nullptr; + napi_create_array_with_length(env, TUPLE_SIZE, &element); + napi_value jsKey = nullptr; + napi_create_string_utf8(env, key.c_str(), key.size(), &jsKey); + napi_set_element(env, element, TUPLE_KEY, jsKey); + napi_value jsValue = nullptr; + napi_create_int32(env, static_cast(value), &jsValue); + napi_set_element(env, element, TUPLE_VALUE, jsValue); + napi_set_element(env, out, index++, element); + } + return status; +} + +} // namespace OHOS::CloudData diff --git a/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp b/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4db2a0ba68532d148413f4b52c6a83b473db660d --- /dev/null +++ b/relational_store/frameworks/js/napi/cloud_data/src/napi_queue.cpp @@ -0,0 +1,163 @@ +/* +* Copyright (c) 2023 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#define LOG_TAG "NapiQueue" +#include "napi_queue.h" + +namespace OHOS::CloudData { +ContextBase::~ContextBase() +{ + ZLOGD("no memory leak after callback or promise[resolved/rejected]"); + if (env != nullptr) { + if (callbackRef != nullptr) { + auto status = napi_delete_reference(env, callbackRef); + ZLOGD("status:%{public}d", status); + } + if (selfRef != nullptr) { + auto status = napi_delete_reference(env, selfRef); + ZLOGD("status:%{public}d", status); + } + env = nullptr; + } +} + +void ContextBase::GetCbInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parse, bool sync) +{ + env = envi; + size_t argc = ARGC_MAX; + napi_value argv[ARGC_MAX] = { nullptr }; + status = napi_get_cb_info(env, info, &argc, argv, &self, nullptr); + ASSERT_STATUS(this, "napi_get_cb_info failed!"); + ASSERT_ARGS(this, argc <= ARGC_MAX, "too many arguments!"); + ASSERT_ARGS(this, self != nullptr, "no JavaScript this argument!"); + if (!sync) { + napi_create_reference(env, self, 1, &selfRef); + } + status = napi_unwrap(env, self, &native); + ASSERT_STATUS(this, "self unwrap failed!"); + + if (!sync && (argc > 0)) { + // get the last arguments :: + size_t index = argc - 1; + napi_valuetype type = napi_undefined; + napi_status tyst = napi_typeof(env, argv[index], &type); + if ((tyst == napi_ok) && (type == napi_function)) { + status = napi_create_reference(env, argv[index], 1, &callbackRef); + ASSERT_STATUS(this, "ref callback failed!"); + argc = index; + ZLOGD("async callback, no promise"); + } else { + ZLOGD("no callback, async pormose"); + } + } + + if (parse) { + parse(argc, argv); + } else { + ASSERT_ARGS(this, argc == 0, "required no arguments!"); + } +} + +napi_value NapiQueue::AsyncWork(napi_env env, std::shared_ptr ctxt, const std::string &name, + NapiAsyncExecute execute, NapiAsyncComplete complete) +{ + ZLOGD("name=%{public}s", name.c_str()); + AsyncContext *aCtx = new AsyncContext; + aCtx->env = env; + aCtx->ctx = std::move(ctxt); + aCtx->execute = std::move(execute); + aCtx->complete = std::move(complete); + napi_value promise = nullptr; + if (aCtx->ctx->callbackRef == nullptr) { + napi_create_promise(env, &aCtx->deferred, &promise); + ZLOGD("create deferred promise"); + } else { + napi_get_undefined(env, &promise); + } + + napi_value resource = nullptr; + napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &resource); + napi_create_async_work( + env, nullptr, resource, + [](napi_env env, void *data) { + ASSERT_VOID(data != nullptr, "napi_async_execute_callback nullptr"); + auto actx = reinterpret_cast(data); + ZLOGD("napi_async_execute_callback ctxt->status=%{public}d", actx->ctx->status); + if (actx->execute && actx->ctx->status == napi_ok) { + actx->execute(); + } + }, + [](napi_env env, napi_status status, void *data) { + ASSERT_VOID(data != nullptr, "napi_async_complete_callback nullptr"); + auto actx = reinterpret_cast(data); + ZLOGD("napi_async_complete_callback status=%{public}d, ctxt->status=%{public}d", status, actx->ctx->status); + if ((status != napi_ok) && (actx->ctx->status == napi_ok)) { + actx->ctx->status = status; + } + napi_value output = nullptr; + if ((actx->complete) && (status == napi_ok) && (actx->ctx->status == napi_ok)) { + actx->complete(output); + } + GenerateOutput(*actx, output); + delete actx; + }, + reinterpret_cast(aCtx), &aCtx->work); + auto status = napi_queue_async_work(env, aCtx->work); + if (status != napi_ok) { + napi_get_undefined(env, &promise); + delete aCtx; + } + return promise; +} + +void NapiQueue::GenerateOutput(AsyncContext &ctx, napi_value output) +{ + napi_value result[RESULT_ALL] = { nullptr }; + if (ctx.ctx->status == napi_ok) { + napi_get_undefined(ctx.env, &result[RESULT_ERROR]); + if (output == nullptr) { + napi_get_undefined(ctx.env, &output); + } + result[RESULT_DATA] = output; + } else { + napi_value message = nullptr; + napi_value errorCode = nullptr; + if (ctx.ctx->jsCode != 0 && ctx.ctx->jsCode != -1) { + napi_create_string_utf8(ctx.env, std::to_string(ctx.ctx->jsCode).c_str(), NAPI_AUTO_LENGTH, &errorCode); + } + if (ctx.ctx->jsCode == -1) { + std::string jscode = ""; + napi_create_string_utf8(ctx.env, jscode.c_str(), NAPI_AUTO_LENGTH, &errorCode); + } + napi_create_string_utf8(ctx.env, ctx.ctx->error.c_str(), NAPI_AUTO_LENGTH, &message); + napi_create_error(ctx.env, errorCode, message, &result[RESULT_ERROR]); + napi_get_undefined(ctx.env, &result[RESULT_DATA]); + } + if (ctx.deferred != nullptr) { + if (ctx.ctx->status == napi_ok) { + ZLOGD("deferred promise resolved"); + napi_resolve_deferred(ctx.env, ctx.deferred, result[RESULT_DATA]); + } else { + ZLOGD("deferred promise rejected"); + napi_reject_deferred(ctx.env, ctx.deferred, result[RESULT_ERROR]); + } + } else { + napi_value callback = nullptr; + napi_get_reference_value(ctx.env, ctx.ctx->callbackRef, &callback); + napi_value callbackResult = nullptr; + ZLOGD("call callback function"); + napi_call_function(ctx.env, nullptr, callback, RESULT_ALL, result, &callbackResult); + } +} +} // namespace OHOS::CloudData