diff --git a/interfaces/kits/js/clouddiskmanager/BUILD.gn b/interfaces/kits/js/clouddiskmanager/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..2728c697a39404bc7eb491c5efa0e0dc67af86bd --- /dev/null +++ b/interfaces/kits/js/clouddiskmanager/BUILD.gn @@ -0,0 +1,74 @@ +# Copyright (c) 2025 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("//foundation/filemanagement/dfs_service/distributedfile.gni") + +config("optimize-size") { + cflags = [ + "-fdata-sections", + "-ffunction-sections", + "-Oz", + ] + cflags_cc = [ + "-fvisibility-inlines-hidden", + "-Oz", + ] +} + +ohos_shared_library("clouddiskmanager") { + branch_protector_ret = "pac_ret" + configs = [ ":optimize-size" ] + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + + include_dirs = [ + "clouddiskdatamanager", + ] + + sources = [ + "clouddiskdatamanager/cloud_disk_manager_napi_utils.cpp", + "clouddiskdatamanager/sync_folder_handler_callback_napi.cpp", + "clouddiskdatamanager/sync_folder_handler_napi.cpp", + "cloud_disk_manager_module.cpp", + ] + + deps = [ + "${innerkits_native_path}/clouddiskservice_kit_inner:clouddiskservice_kit_inner", + "${utils_path}:libdistributedfileutils", + ] + + external_deps = [ + "c_utils:utils", + "file_api:filemgmt_libhilog", + "file_api:filemgmt_libn", + "hilog:libhilog", + "napi:ace_napi", + ] + + defines = [ + "LOG_DOMAIN=0xD004309", + "LOG_TAG=\"CLOUD_FILE_SYNC\"", + ] + + relative_install_dir = "module/file" + + part_name = "dfs_service" + subsystem_name = "filemanagement" +} diff --git a/interfaces/kits/js/clouddiskmanager/cloud_disk_manager_module.cpp b/interfaces/kits/js/clouddiskmanager/cloud_disk_manager_module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f379fce0040e05d88851122a419974ab60555c8f --- /dev/null +++ b/interfaces/kits/js/clouddiskmanager/cloud_disk_manager_module.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 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. + */ + +#include "sync_folder_handler_napi.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudDiskService { +using namespace FileManagement::LibN; +/*********************************************** + * Module export and register + ***********************************************/ +static napi_value Init(napi_env env, napi_value exports) +{ + LOGI("CloudDiskManager napi init"); + std::vector> products; + products.emplace_back(std::make_unique(env, exports)); + for (auto &&product : products) { + if (!product->Export()) { + LOGE("INNER BUG. Failed to export class %{public}s for module cloudDiskManager", + product->GetClassName().c_str()); + return nullptr; + } else { + LOGI("Class %{public}s for module cloudDiskManager has been exported", product->GetClassName().c_str()); + } + } + + return exports; +} + +static napi_module _module = {.nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "file.cloudDiskManager", + .nm_priv = ((void *)0), + .reserved = {0}}; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&_module); +} +} // namespace OHOS::FileManagement::CloudSync diff --git a/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/cloud_disk_manager_napi_utils.cpp b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/cloud_disk_manager_napi_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d22382ea0274c49894e1d713b86b72a00101961 --- /dev/null +++ b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/cloud_disk_manager_napi_utils.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2025 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. + */ + +#include "cloud_disk_manager_napi_utils.h" + +#include "dfs_error.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudDiskService { +using namespace FileManagement::LibN; +using namespace std; + +NVal ChangeDataToNapi(napi_env env, const ChangeData &record) +{ + NVal obj = NVal::CreateObject(env); + obj.AddProp("updateSequenceNumber", NVal::CreateBigIntUint64(env, record.updateSequenceNumber).val_); + obj.AddProp("fileId", NVal::CreateUTF8String(env, record.fileId).val_); + obj.AddProp("parentFileId", NVal::CreateUTF8String(env, record.parentFileId).val_); + obj.AddProp("relativePath", NVal::CreateUTF8String(env, record.relativePath).val_); + obj.AddProp("operationType", NVal::CreateInt32(env, static_cast(record.operationType)).val_); + obj.AddProp("size", NVal::CreateBigIntUint64(env, record.size).val_); + obj.AddProp("mtime", NVal::CreateBigIntUint64(env, record.mtime).val_); + obj.AddProp("timeStamp", NVal::CreateBigIntUint64(env, record.timeStamp).val_); + return obj; +} + +NVal ChangeDataVectorToNapi(napi_env env, const std::vector &syncRootRecords) +{ + napi_value results = nullptr; + + napi_status status = napi_create_array(env, &results); + if (status != napi_ok) { + LOGE("Failed to create array"); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + + int32_t index = 0; + for (const ChangeData &record : syncRootRecords) { + status = napi_set_element(env, results, index, ChangeDataToNapi(env, record).val_); + if (status != napi_ok) { + LOGE("Failed to set element on data, index: %{public}d", index); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + index++; + } + return {env, results}; +} + +LibN::NVal ChangesResultToNapi(napi_env env, const ChangesResult &changesResult) +{ + NVal obj = NVal::CreateObject(env); + obj.AddProp("nextUsn", NVal::CreateBigIntUint64(env, changesResult.nextUsn).val_); + obj.AddProp("isEof", NVal::CreateBool(env, changesResult.isEof).val_); + obj.AddProp("changesData", ChangeDataVectorToNapi(env, changesResult.changesData).val_); + return obj; +} + +LibN::NVal FileSyncStateToNapi(napi_env env, const FileSyncState &fileSyncStates) +{ + NVal obj = NVal::CreateObject(env); + obj.AddProp("path", NVal::CreateUTF8String(env, fileSyncStates.path).val_); + obj.AddProp("state", NVal::CreateInt32(env, static_cast(fileSyncStates.state)).val_); + return obj; +} + +LibN::NVal FileSyncStateVectorToNapi(napi_env env, const std::vector &fileSyncStates) +{ + napi_value results = nullptr; + + napi_status status = napi_create_array(env, &results); + if (status != napi_ok) { + LOGE("Failed to create array"); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + + int32_t index = 0; + for (const FileSyncState &fileSyncState : fileSyncStates) { + status = napi_set_element(env, results, index, FileSyncStateToNapi(env, fileSyncState).val_); + if (status != napi_ok) { + LOGE("Failed to set element on data, index: %{public}d", index); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + index++; + } + return {env, results}; +} + +LibN::NVal StringVectorToNapi(napi_env env, const std::vector &strs) +{ + napi_value results = nullptr; + + napi_status status = napi_create_array(env, &results); + if (status != napi_ok) { + LOGE("Failed to create array"); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + + int32_t index = 0; + for (const std::string &s : strs) { + status = napi_set_element(env, results, index, NVal::CreateUTF8String(env, s).val_); + if (status != napi_ok) { + LOGE("Failed to set element on data, index: %{public}d", index); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + index++; + } + return {env, results}; +} + +LibN::NVal FailedListToNapi(napi_env env, const FailedList &failed) +{ + NVal obj = NVal::CreateObject(env); + obj.AddProp("path", NVal::CreateUTF8String(env, failed.path).val_); + obj.AddProp("error", NVal::CreateInt32(env, static_cast(failed.error)).val_); + return obj; +} + +LibN::NVal FailedListVectorToNapi(napi_env env, const std::vector &failedList) +{ + napi_value results = nullptr; + + napi_status status = napi_create_array(env, &results); + if (status != napi_ok) { + LOGE("Failed to create array"); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + + int32_t index = 0; + for (const FailedList &failed : failedList) { + status = napi_set_element(env, results, index, FailedListToNapi(env, failed).val_); + if (status != napi_ok) { + LOGE("Failed to set element on data, index: %{public}d", index); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + index++; + } + return {env, results}; +} + +LibN::NVal ResultListToNapi(napi_env env, const ResultList &result) +{ + NVal obj = NVal::CreateObject(env); + obj.AddProp("path", NVal::CreateUTF8String(env, result.path).val_); + obj.AddProp("error", NVal::CreateInt32(env, static_cast(result.error)).val_); + obj.AddProp("isSuccess", NVal::CreateBool(env, result.isSuccess).val_); + obj.AddProp("state", NVal::CreateInt32(env, static_cast(result.state)).val_); + return obj; +} + +LibN::NVal ResultListVectorToNapi(napi_env env, const std::vector &resultList) +{ + napi_value results = nullptr; + + napi_status status = napi_create_array(env, &results); + if (status != napi_ok) { + LOGE("Failed to create array"); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + + int32_t index = 0; + for (const ResultList &ret : resultList) { + status = napi_set_element(env, results, index, ResultListToNapi(env, ret).val_); + if (status != napi_ok) { + LOGE("Failed to set element on data, index: %{public}d", index); + return {env, NError(LibN::STORAGE_SERVICE_SYS_CAP_TAG + LibN::E_IPCSS).GetNapiErr(env)}; + } + index++; + } + return {env, results}; +} + + +bool ParseFileSyncState(LibN::NVal fileSyncStateVal, FileSyncState &fileSyncState) +{ + if (!fileSyncStateVal.TypeIs(napi_object) || !fileSyncStateVal.HasProp("path") || + !fileSyncStateVal.HasProp("state")) { + LOGE("fileSyncStateVal not FileSyncState"); + return false; + } + + bool succ = false; + std::unique_ptr pathVal; + tie(succ, pathVal, std::ignore) = fileSyncStateVal.GetProp("path").ToUTF8String(); + if (!succ) { + LOGE("parse path failed"); + return false; + } + + int32_t state = 0; + tie(succ, state) = fileSyncStateVal.GetProp("state").ToInt32(); + if (!succ) { + LOGE("parse state failed"); + return false; + } + + fileSyncState.path = std::string(pathVal.get()); + fileSyncState.state = static_cast(state); + return true; +} + +bool ParseFileSyncStateArray(LibN::NVal fileSyncStatesVal, std::vector &fileSyncStates) +{ + if (!fileSyncStatesVal.TypeIs(napi_object)) { + LOGE("fileSyncStatesVal not object"); + return false; + } + + bool isArray = false; + napi_is_array(fileSyncStatesVal.env_, fileSyncStatesVal.val_, &isArray); + if (!isArray) { + LOGE("fileSyncStatesVal not array"); + return false; + } + + uint32_t size = 0; + napi_get_array_length(fileSyncStatesVal.env_, fileSyncStatesVal.val_, &size); + napi_value element; + FileSyncState fileSyncState; + for (uint32_t i = 0; i < size; ++i) { + napi_get_element(fileSyncStatesVal.env_, fileSyncStatesVal.val_, i, &element); + NVal fileSyncStateVal = NVal(fileSyncStatesVal.env_, element); + if (!ParseFileSyncState(fileSyncStateVal, fileSyncState)) { + LOGE("ParseFileSyncState %{public}u failed", i); + return false; + } + fileSyncStates.emplace_back(fileSyncState); + } + + return true; +} +} // namespace OHOS::FileManagement::CloudDiskService \ No newline at end of file diff --git a/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/cloud_disk_manager_napi_utils.h b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/cloud_disk_manager_napi_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..053e1276f86c221f94261108537af9a79426e293 --- /dev/null +++ b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/cloud_disk_manager_napi_utils.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 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 OHOS_FILEMGMT_CLOUD_DISK_MANAGER_NAPI_UTILS_H +#define OHOS_FILEMGMT_CLOUD_DISK_MANAGER_NAPI_UTILS_H + +#include + +#include "cloud_disk_common.h" +#include "filemgmt_libn.h" + +namespace OHOS::FileManagement::CloudDiskService { +LibN::NVal ChangeDataToNapi(napi_env env, const ChangeData &record); +LibN::NVal ChangeDataVectorToNapi(napi_env env, const std::vector &syncRootRecords); +LibN::NVal ChangesResultToNapi(napi_env env, const ChangesResult &changesResult); +LibN::NVal FileSyncStateToNapi(napi_env env, const FileSyncState &fileSyncStates); +LibN::NVal FileSyncStateVectorToNapi(napi_env env, const std::vector &fileSyncStates); +LibN::NVal StringVectorToNapi(napi_env env, const std::vector &strs); +LibN::NVal FailedListToNapi(napi_env env, const FailedList &failed); +LibN::NVal FailedListVectorToNapi(napi_env env, const std::vector &failedList); +LibN::NVal ResultListToNapi(napi_env env, const ResultList &result); +LibN::NVal ResultListVectorToNapi(napi_env env, const std::vector &resultList); + +bool ParseFileSyncStateArray(LibN::NVal fileSyncStatesVal, std::vector &fileSyncStates); +bool ParseFileSyncState(LibN::NVal fileSyncStateVal, FileSyncState &fileSyncState); +} // namespace OHOS::FileManagement::CloudDiskService +#endif // OHOS_FILEMGMT_CLOUD_DISK_MANAGER_NAPI_UTILS_H \ No newline at end of file diff --git a/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_callback_napi.cpp b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_callback_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6222379a3263853ca371f5151453e771d4fd6ba1 --- /dev/null +++ b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_callback_napi.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2025 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. + */ + +#include "sync_folder_handler_callback_napi.h" + +#include "cloud_disk_manager_napi_utils.h" +#include "dfs_error.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudDiskService { +SyncFolderHandlerCallbackImpl::SyncFolderHandlerCallbackImpl(napi_env env, napi_value func): env_(env) +{ + napi_status status = napi_create_reference(env_, func, 1, &cbOnRef_); + if (status != napi_ok) { + LOGE("Failed to create napi ref, %{public}d", status); + } +} + +SyncFolderHandlerCallbackImpl::~SyncFolderHandlerCallbackImpl() +{ + if (cbOnRef_ != nullptr) { + napi_status status = napi_delete_reference(env_, cbOnRef_); + if (status != napi_ok) { + LOGE("Failed to delete napi ref, %{public}d", status); + } + cbOnRef_ = nullptr; + } +} + +void SyncFolderHandlerCallbackImpl::OnChangeData(std::vector &changeData) +{ + LOGI("callback OnChangeData"); + std::shared_ptr callbackImpl = shared_from_this(); + napi_status status = napi_send_event( + callbackImpl->env_, + [callbackImpl, changeData]() mutable { + auto env = callbackImpl->env_; + auto ref = callbackImpl->cbOnRef_; + if (env == nullptr || ref == nullptr) { + LOGE("The env context is invalid"); + return; + } + napi_handle_scope scope = nullptr; + napi_status status = napi_open_handle_scope(env, &scope); + if (status != napi_ok) { + LOGE("Failed to open handle scope, status: %{public}d", status); + return; + } + napi_value jsCallback = nullptr; + status = napi_get_reference_value(env, ref, &jsCallback); + if (status != napi_ok) { + LOGE("Create reference failed, status: %{public}d", status); + napi_close_handle_scope(env, scope); + return; + } + napi_value jsProgress = ChangeDataVectorToNapi(env, changeData).val_; + if (jsProgress == nullptr) { + napi_close_handle_scope(env, scope); + return; + } + napi_value jsResult = nullptr; + status = napi_call_function(env, nullptr, jsCallback, 1, &jsProgress, &jsResult); + if (status != napi_ok) { + LOGE("napi call function failed, status: %{public}d", status); + return; + } + napi_close_handle_scope(env, scope); + }, + napi_eprio_immediate); + if (status != napi_ok) { + LOGE("Failed to execute libuv work queue, status: %{public}d", status); + } +} + +void SyncFolderHandlerCallbackImpl::OnReturnSetFailedList(std::vector &failedList) +{ + LOGI("callback OnReturnSetFailedList"); + std::shared_ptr callbackImpl = shared_from_this(); + napi_status status = napi_send_event( + callbackImpl->env_, + [callbackImpl, failedList]() mutable { + auto env = callbackImpl->env_; + auto ref = callbackImpl->cbOnRef_; + if (env == nullptr || ref == nullptr) { + LOGE("The env context is invalid"); + return; + } + napi_handle_scope scope = nullptr; + napi_status status = napi_open_handle_scope(env, &scope); + if (status != napi_ok) { + LOGE("Failed to open handle scope, status: %{public}d", status); + return; + } + napi_value jsCallback = nullptr; + status = napi_get_reference_value(env, ref, &jsCallback); + if (status != napi_ok) { + LOGE("Create reference failed, status: %{public}d", status); + napi_close_handle_scope(env, scope); + return; + } + napi_value jsProgress = FailedListVectorToNapi(env, failedList).val_; + if (jsProgress == nullptr) { + napi_close_handle_scope(env, scope); + return; + } + napi_value jsResult = nullptr; + status = napi_call_function(env, nullptr, jsCallback, 1, &jsProgress, &jsResult); + if (status != napi_ok) { + LOGE("napi call function failed, status: %{public}d", status); + return; + } + napi_close_handle_scope(env, scope); + }, + napi_eprio_immediate); + if (status != napi_ok) { + LOGE("Failed to execute libuv work queue, status: %{public}d", status); + } +} + +void SyncFolderHandlerCallbackImpl::OnReturnGetResult(std::vector &resultList) +{ + LOGI("callback OnReturnGetResult"); + std::shared_ptr callbackImpl = shared_from_this(); + napi_status status = napi_send_event( + callbackImpl->env_, + [callbackImpl, resultList]() mutable { + auto env = callbackImpl->env_; + auto ref = callbackImpl->cbOnRef_; + if (env == nullptr || ref == nullptr) { + LOGE("The env context is invalid"); + return; + } + napi_handle_scope scope = nullptr; + napi_status status = napi_open_handle_scope(env, &scope); + if (status != napi_ok) { + LOGE("Failed to open handle scope, status: %{public}d", status); + return; + } + napi_value jsCallback = nullptr; + status = napi_get_reference_value(env, ref, &jsCallback); + if (status != napi_ok) { + LOGE("Create reference failed, status: %{public}d", status); + napi_close_handle_scope(env, scope); + return; + } + napi_value jsProgress = ResultListVectorToNapi(env, resultList).val_; + if (jsProgress == nullptr) { + napi_close_handle_scope(env, scope); + return; + } + napi_value jsResult = nullptr; + status = napi_call_function(env, nullptr, jsCallback, 1, &jsProgress, &jsResult); + if (status != napi_ok) { + LOGE("napi call function failed, status: %{public}d", status); + return; + } + napi_close_handle_scope(env, scope); + }, + napi_eprio_immediate); + if (status != napi_ok) { + LOGE("Failed to execute libuv work queue, status: %{public}d", status); + } +} + +void SyncFolderHandlerCallbackImpl::OnDeathRecipient() +{} +} // namespace OHOS::FileManagement::CloudDiskService \ No newline at end of file diff --git a/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_callback_napi.h b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_callback_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..c4e4db4ed8aa9755e8f82b68075a3b58b53917ac --- /dev/null +++ b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_callback_napi.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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 OHOS_FILEMGMT_SYNC_FOLDER_HANDLER_CALLBACK_NAPI_H +#define OHOS_FILEMGMT_SYNC_FOLDER_HANDLER_CALLBACK_NAPI_H + +#include +#include + +#include "cloud_disk_service_callback.h" +#include "filemgmt_libn.h" + +namespace OHOS::FileManagement::CloudDiskService { + +class SyncFolderHandlerCallbackImpl : public CloudDiskServiceCallback, + public std::enable_shared_from_this { +public: + SyncFolderHandlerCallbackImpl(napi_env env, napi_value func); + ~SyncFolderHandlerCallbackImpl(); + void OnChangeData(std::vector &changeData) override; + void OnReturnSetFailedList(std::vector &failedList) override; + void OnReturnGetResult(std::vector &resultList) override; + void OnDeathRecipient() override; + +public: + napi_ref cbOnRef_; + napi_env env_; +}; + +struct SyncFolderHandlerEntity { + explicit SyncFolderHandlerEntity(const std::string &folder) : syncFolder(folder) {} + std::string syncFolder; +}; +} // namespace OHOS::FileManagement::CloudDiskService +#endif // OHOS_FILEMGMT_SYNC_FOLDER_HANDLER_CALLBACK_NAPI_H \ No newline at end of file diff --git a/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_napi.cpp b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_napi.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36b45aabc1487e8158b4c355e403893ca16ad55b --- /dev/null +++ b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_napi.cpp @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2025 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. + */ + +#include "sync_folder_handler_napi.h" + +#include + +#include "async_work.h" +#include "cloud_disk_manager_napi_utils.h" +#include "cloud_disk_service_manager.h" +#include "dfs_error.h" +#include "sync_folder_handler_callback_napi.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudDiskService { +using namespace FileManagement::LibN; +using namespace std; + +struct CloudDiskServiceParam { + ChangesResult changesResult; +}; + +std::string SyncFolderHandlerNapi::GetClassName() +{ + return className_; +} + +bool SyncFolderHandlerNapi::Export() +{ + std::vector props = { + NVal::DeclareNapiFunction("registerSyncFolderChanges", SyncFolderHandlerNapi::RegisterSyncFolderChanges), + NVal::DeclareNapiFunction("unregisterSyncFolderChanges", SyncFolderHandlerNapi::UnregisterSyncFolderChanges), + NVal::DeclareNapiFunction("getSyncFolderChanges", SyncFolderHandlerNapi::GetSyncFolderChanges), + NVal::DeclareNapiFunction("getFileSyncStates", SyncFolderHandlerNapi::GetFileSyncStates), + NVal::DeclareNapiFunction("setFileSyncStates", SyncFolderHandlerNapi::SetFileSyncStates), + }; + + return ToExport(props); +} + +bool SyncFolderHandlerNapi::ToExport(std::vector props) +{ + std::string className = GetClassName(); + auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props)); + if (!succ) { + NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(exports_.env_); + LOGE("Failed to define SyncRootManager class"); + return false; + } + + succ = NClass::SaveClass(exports_.env_, className, classValue); + if (!succ) { + NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(exports_.env_); + LOGE("Failed to save SyncRootManager class"); + return false; + } + + return exports_.AddProp(className, classValue); +} + +napi_value SyncFolderHandlerNapi::Constructor(napi_env env, napi_callback_info info) +{ + LOGI("SyncRootManager Constructor"); + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE)) { + LOGE("Start Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + bool succ = false; + std::unique_ptr syncFolderVal; + tie(succ, syncFolderVal, std::ignore) = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); + if (!succ) { + LOGE("get param syncFolder failed"); + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + + std::string syncFolder(syncFolderVal.get()); + LOGI("syncFolder: %{public}s", syncFolder.c_str()); + auto syncRootFolderEntity = make_unique(syncFolder); + if (!NClass::SetEntityFor(env, funcArg.GetThisVar(), move(syncRootFolderEntity))) { + LOGE("Failed to set syncRootFolderEntity"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + return funcArg.GetThisVar(); +} + +napi_value SyncFolderHandlerNapi::RegisterSyncFolderChanges(napi_env env, napi_callback_info info) +{ + LOGI("napi RegisterSyncFolderChanges start"); + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(static_cast(NARG_CNT::ONE))) { + NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + NVal callbackVal = NVal(env, funcArg[NARG_POS::FIRST]); + if (!callbackVal.TypeIs(napi_function)) { + LOGE("callback not function"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + std::shared_ptr callbackImpl = + std::make_shared(env, callbackVal.val_); + + auto syncFolderHandlerEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!syncFolderHandlerEntity) { + LOGE("failed to get syncFolderHandlerEntity"); + NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(env); + return nullptr; + } + std::string syncFolder = syncFolderHandlerEntity->syncFolder; + + LOGI("napi RegisterSyncFolderChanges uri: %{public}s", syncFolder.c_str()); + auto cbExec = [syncFolder, callbackImpl]() -> NError { + int32_t ret = CloudDiskServiceManager::GetInstance().RegisterSyncFolderChanges(syncFolder, callbackImpl); + LOGI("napi RegisterSyncFolderChanges end, ret: %{public}d", ret); + if (ret != E_OK) { + return NError(Convert2JsErrNum(ret)); + } else { + return NError(ERRNO_NOERR); + } + }; + auto cbComplete = [](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } else { + return { NVal::CreateUndefined(env) }; + } + }; + + std::string procedureName = "RegisterSyncFolderChanges"; + auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast(NARG_CNT::TWO)); + return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_; +} + +napi_value SyncFolderHandlerNapi::UnregisterSyncFolderChanges(napi_env env, napi_callback_info info) +{ + LOGI("napi UnregisterSyncFolderChanges start"); + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(static_cast(NARG_CNT::ZERO))) { + NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + auto syncFolderHandlerEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!syncFolderHandlerEntity) { + LOGE("failed to get syncFolderHandlerEntity"); + NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(env); + return nullptr; + } + std::string syncFolder = syncFolderHandlerEntity->syncFolder; + + LOGI("napi UnregisterSyncFolderChanges syncFolder: %{public}s", syncFolder.c_str()); + auto cbExec = [syncFolder]() -> NError { + int32_t ret = CloudDiskServiceManager::GetInstance().UnregisterSyncFolderChanges(syncFolder); + LOGI("napi UnregisterSyncFolderChanges end, ret: %{public}d", ret); + if (ret != E_OK) { + return NError(Convert2JsErrNum(ret)); + } else { + return NError(ERRNO_NOERR); + } + }; + auto cbComplete = [](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } else { + return { NVal::CreateUndefined(env) }; + } + }; + + std::string procedureName = "UnregisterSyncFolderChanges"; + auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast(NARG_CNT::ONE)); + return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_; +} + +napi_value SyncFolderHandlerNapi::GetSyncFolderChanges(napi_env env, napi_callback_info info) +{ + LOGI("napi GetSyncFolderChanges start"); + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(static_cast(NARG_CNT::TWO))) { + NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + bool succ = false; + int64_t count = 0; + tie(succ, count) = NVal(env, funcArg[NARG_POS::FIRST]).ToInt64(); + if (!succ || count < 0) { + LOGE("get param count failed, count: %{public}" PRId64, count); + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + + int64_t startUsn = 0; + tie(succ, startUsn) = NVal(env, funcArg[NARG_POS::SECOND]).ToInt64(); + if (!succ || startUsn < 0) { + LOGE("get param startUSN failed, startUsn: %{public}" PRId64, startUsn); + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + + auto syncFolderHandlerEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!syncFolderHandlerEntity) { + LOGE("failed to get syncFolderHandlerEntity"); + NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(env); + return nullptr; + } + std::string syncFolder = syncFolderHandlerEntity->syncFolder; + + std::shared_ptr param = std::make_shared(); + LOGI("napi GetSyncFolderChanges syncFolder: %{public}s, count: %{public}" PRId64 ", startUSN: %{public}" PRId64, + syncFolder.c_str(), count, startUsn); + auto cbExec = [syncFolder, count, startUsn, param]() -> NError { + int32_t ret = CloudDiskServiceManager::GetInstance().GetSyncFolderChanges(syncFolder, count, startUsn, + param->changesResult); + LOGI("napi GetSyncFolderChanges end, ret: %{public}d, nextUsn: %{public}" PRIu64 ", isEof: %{public}d", + ret, param->changesResult.nextUsn, param->changesResult.isEof); + if (ret != E_OK) { + return NError(Convert2JsErrNum(ret)); + } else { + return NError(ERRNO_NOERR); + } + }; + auto cbComplete = [param](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } else { + return ChangesResultToNapi(env, param->changesResult); + } + }; + + std::string procedureName = "GetSyncFolderChanges"; + auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast(NARG_CNT::THREE)); + return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_; +} + +napi_value SyncFolderHandlerNapi::GetFileSyncStates(napi_env env, napi_callback_info info) +{ + LOGI("napi GetFileSyncStates start"); + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(static_cast(NARG_CNT::TWO))) { + NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + NVal pathArrayVal(env, funcArg[NARG_POS::FIRST]); + if (!pathArrayVal.TypeIs(napi_object)) { + LOGE("Invalid uris argments not is napi_object"); + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + bool succ = false; + std::vector pathArray; + tie(succ, pathArray, ignore) = pathArrayVal.ToStringArray(); + if (!succ) { + LOGE("Invalid pathArray argments"); + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + + NVal callbackVal = NVal(env, funcArg[NARG_POS::SECOND]); + if (!callbackVal.TypeIs(napi_function)) { + LOGE("callback not function"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + std::shared_ptr callbackImpl = + std::make_shared(env, callbackVal.val_); + + auto syncFolderHandlerEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!syncFolderHandlerEntity) { + LOGE("failed to get syncFolderHandlerEntity"); + NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(env); + return nullptr; + } + std::string syncFolder = syncFolderHandlerEntity->syncFolder; + + LOGI("napi GetFileSyncStates syncFolder: %{public}s, pathArray.size: %{public}d", + syncFolder.c_str(), static_cast(pathArray.size())); + for (const auto &s : pathArray) { + LOGI("path: %{public}s", s.c_str()); + } + auto cbExec = [syncFolder, pathArray, callbackImpl]() -> NError { + int32_t ret = CloudDiskServiceManager::GetInstance().GetFileSyncStates(syncFolder, pathArray, callbackImpl); + LOGI("napi GetFileSyncStates end, ret: %{public}d", ret); + if (ret != E_OK) { + return NError(Convert2JsErrNum(ret)); + } else { + return NError(ERRNO_NOERR); + } + }; + auto cbComplete = [](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } else { + return { NVal::CreateUndefined(env) }; + } + }; + + std::string procedureName = "GetFileSyncStates"; + auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast(NARG_CNT::THREE)); + return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_; +} + +napi_value SyncFolderHandlerNapi::SetFileSyncStates(napi_env env, napi_callback_info info) +{ + LOGI("napi SetFileSyncStates start"); + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(static_cast(NARG_CNT::TWO))) { + NError(E_PARAMS).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + NVal fileSyncStatesVal = NVal(env, funcArg[NARG_POS::FIRST]); + std::vector fileSyncStates; + if (!ParseFileSyncStateArray(fileSyncStatesVal, fileSyncStates)) { + LOGE("get param fileSyncStates failed"); + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + + NVal callbackVal = NVal(env, funcArg[NARG_POS::SECOND]); + if (!callbackVal.TypeIs(napi_function)) { + LOGE("callback not function"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + std::shared_ptr callbackImpl = + std::make_shared(env, callbackVal.val_); + + auto syncFolderHandlerEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!syncFolderHandlerEntity) { + LOGE("failed to get syncFolderHandlerEntity"); + NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(env); + return nullptr; + } + std::string syncFolder = syncFolderHandlerEntity->syncFolder; + + LOGI("napi SetFileSyncStates syncFolder: %{public}s, fileSyncStates.size: %{public}d", + syncFolder.c_str(), static_cast(fileSyncStates.size())); + for (const auto &state : fileSyncStates) { + LOGI("napi path: %{public}s, state: %{public}d", state.path.c_str(), static_cast(state.state)); + } + auto cbExec = [syncFolder, fileSyncStates, callbackImpl]() -> NError { + int32_t ret = CloudDiskServiceManager::GetInstance().SetFileSyncStates(syncFolder, fileSyncStates, + callbackImpl); + LOGI("napi SetFileSyncStates end, ret: %{public}d", ret); + if (ret != E_OK) { + return NError(Convert2JsErrNum(ret)); + } else { + return NError(ERRNO_NOERR); + } + }; + auto cbComplete = [](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } else { + return { NVal::CreateUndefined(env) }; + } + }; + + std::string procedureName = "SetFileSyncStates"; + auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast(NARG_CNT::THREE)); + return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbComplete).val_; +} +} // namespace OHOS::FileManagement::CloudDiskService \ No newline at end of file diff --git a/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_napi.h b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..1ece409f84fb5f04dc4db8ac71f6587a6c2315b5 --- /dev/null +++ b/interfaces/kits/js/clouddiskmanager/clouddiskdatamanager/sync_folder_handler_napi.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 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 OHOS_FILEMGMT_SYNC_FOLDER_HANDLER_NAPI_H +#define OHOS_FILEMGMT_SYNC_FOLDER_HANDLER_NAPI_H + +#include +#include + +#include "filemgmt_libn.h" + +namespace OHOS::FileManagement::CloudDiskService { +class SyncFolderHandlerNapi final : public LibN::NExporter { +public: + SyncFolderHandlerNapi(napi_env env, napi_value exports) : NExporter(env, exports) {} + ~SyncFolderHandlerNapi() = default; + + bool Export() override; + bool ToExport(std::vector props); + std::string GetClassName() override; + static napi_value Constructor(napi_env env, napi_callback_info info); + static napi_value RegisterSyncFolderChanges(napi_env env, napi_callback_info info); + static napi_value UnregisterSyncFolderChanges(napi_env env, napi_callback_info info); + static napi_value GetSyncFolderChanges(napi_env env, napi_callback_info info); + static napi_value GetFileSyncStates(napi_env env, napi_callback_info info); + static napi_value SetFileSyncStates(napi_env env, napi_callback_info info); + +private: + inline static std::string className_ = "SyncFolderHandler"; +}; +} // namespace OHOS::FileManagement::CloudDiskService +#endif // OHOS_FILEMGMT_SYNC_FOLDER_HANDLER_NAPI_H \ No newline at end of file