From 79fbeef6402e11c909c00c33da632b18307da6bf Mon Sep 17 00:00:00 2001 From: fengjq Date: Mon, 16 Jun 2025 16:30:33 +0800 Subject: [PATCH] BugFix for download file Signed-off-by: fengjq --- .../src/data_sync_manager.cpp | 24 +- .../include/cloud_sync_manager_impl.h | 18 +- .../src/cloud_sync_manager_impl.cpp | 171 +------- .../src/cloud_sync_service_proxy_lite.cpp | 31 +- .../cloud_file_kit_inner/data_sync_manager.h | 16 +- .../cloudsync_kit_inner/cloud_sync_common.h | 8 +- .../cloudsync_kit_inner/cloud_sync_manager.h | 16 +- .../js/ani/ani_helper/include/ani_utils.h | 7 +- .../kits/js/ani/ani_helper/src/ani_utils.cpp | 72 ++- .../kits/js/ani/file_cloud_sync/BUILD.gn | 7 +- .../ets/@ohos.file.cloudSync.ets | 90 +++- .../include/cloud_file_cache_ani.h | 5 + ...ack_ani.h => download_callback_impl_ani.h} | 33 +- .../include/download_callback_middle_ani.h | 47 ++ .../include/download_progress_ani.h | 116 +++++ ...middle.h => multi_download_progress_ani.h} | 23 +- .../include/register_callback_manager_ani.h} | 31 +- .../src/bind_function_class.cpp | 98 ++++- .../src/cloud_download_ani.cpp | 125 +++--- .../src/cloud_download_callback_ani.cpp | 138 ------ .../src/cloud_file_cache_ani.cpp | 145 +++--- .../src/download_callback_impl_ani.cpp | 109 +++++ .../src/download_callback_middle_ani.cpp | 92 ++++ .../src/download_progress_ani.cpp | 119 +++++ .../src/multi_download_progress_ani.cpp | 331 ++++++++++++++ .../src/register_callback_manager_ani.cpp | 161 +++++++ interfaces/kits/js/cloudfilesync/BUILD.gn | 6 +- .../cloudfilesync/cloud_file_cache_core.cpp | 151 +++---- .../js/cloudfilesync/cloud_file_cache_core.h | 60 +-- .../cloudfilesync/cloud_file_cache_napi.cpp | 414 +++++++++++------- .../js/cloudfilesync/cloud_file_cache_napi.h | 41 +- .../kits/js/cloudfilesync/cloud_file_core.cpp | 64 +-- .../kits/js/cloudfilesync/cloud_file_core.h | 11 +- .../cloud_file_download_napi.cpp | 39 -- .../kits/js/cloudfilesync/cloud_file_napi.cpp | 298 ++++++------- .../kits/js/cloudfilesync/cloud_file_napi.h | 52 +-- .../cloudfilesync/cloud_sync_n_exporter.cpp | 18 +- .../js/cloudfilesync/cloud_sync_n_exporter.h | 1 + .../download_callback_middle_napi.cpp | 89 ++++ .../download_callback_middle_napi.h | 50 +++ .../cloudfilesync/download_progress_napi.cpp | 82 ++++ .../js/cloudfilesync/download_progress_napi.h | 116 +++++ .../multi_download_progress_core.cpp | 163 +++++++ .../multi_download_progress_core.h | 53 +++ .../multi_download_progress_napi.cpp | 279 ++++++++++++ .../multi_download_progress_napi.h | 51 +++ ...cpp => register_callback_manager_napi.cpp} | 12 +- ...ger.h => register_callback_manager_napi.h} | 11 +- .../cloudsyncservice/ICloudSyncService.idl | 10 +- .../include/ipc/cloud_sync_service.h | 11 +- .../src/ipc/cloud_sync_service.cpp | 84 +--- 51 files changed, 2935 insertions(+), 1264 deletions(-) rename interfaces/kits/js/ani/file_cloud_sync/include/{cloud_download_callback_ani.h => download_callback_impl_ani.h} (44%) create mode 100644 interfaces/kits/js/ani/file_cloud_sync/include/download_callback_middle_ani.h create mode 100644 interfaces/kits/js/ani/file_cloud_sync/include/download_progress_ani.h rename interfaces/kits/js/ani/file_cloud_sync/include/{cloud_download_callback_middle.h => multi_download_progress_ani.h} (48%) rename interfaces/kits/js/{cloudfilesync/cloud_file_download_napi.h => ani/file_cloud_sync/include/register_callback_manager_ani.h} (45%) delete mode 100644 interfaces/kits/js/ani/file_cloud_sync/src/cloud_download_callback_ani.cpp create mode 100644 interfaces/kits/js/ani/file_cloud_sync/src/download_callback_impl_ani.cpp create mode 100644 interfaces/kits/js/ani/file_cloud_sync/src/download_callback_middle_ani.cpp create mode 100644 interfaces/kits/js/ani/file_cloud_sync/src/download_progress_ani.cpp create mode 100644 interfaces/kits/js/ani/file_cloud_sync/src/multi_download_progress_ani.cpp create mode 100644 interfaces/kits/js/ani/file_cloud_sync/src/register_callback_manager_ani.cpp delete mode 100644 interfaces/kits/js/cloudfilesync/cloud_file_download_napi.cpp create mode 100644 interfaces/kits/js/cloudfilesync/download_callback_middle_napi.cpp create mode 100644 interfaces/kits/js/cloudfilesync/download_callback_middle_napi.h create mode 100644 interfaces/kits/js/cloudfilesync/download_progress_napi.cpp create mode 100644 interfaces/kits/js/cloudfilesync/download_progress_napi.h create mode 100644 interfaces/kits/js/cloudfilesync/multi_download_progress_core.cpp create mode 100644 interfaces/kits/js/cloudfilesync/multi_download_progress_core.h create mode 100644 interfaces/kits/js/cloudfilesync/multi_download_progress_napi.cpp create mode 100644 interfaces/kits/js/cloudfilesync/multi_download_progress_napi.h rename interfaces/kits/js/cloudfilesync/{register_callback_manager.cpp => register_callback_manager_napi.cpp} (90%) rename interfaces/kits/js/cloudfilesync/{register_callback_manager.h => register_callback_manager_napi.h} (79%) diff --git a/frameworks/native/cloud_file_kit_inner/src/data_sync_manager.cpp b/frameworks/native/cloud_file_kit_inner/src/data_sync_manager.cpp index e9fe89a6c..9b998bf01 100644 --- a/frameworks/native/cloud_file_kit_inner/src/data_sync_manager.cpp +++ b/frameworks/native/cloud_file_kit_inner/src/data_sync_manager.cpp @@ -93,27 +93,9 @@ int32_t DataSyncManager::StartDownloadFile(const BundleNameUserInfo &bundleNameU } int32_t DataSyncManager::StopDownloadFile(const BundleNameUserInfo &bundleNameUserInfo, - const std::string &path, - bool needClean) -{ - return E_OK; -} - -int32_t DataSyncManager::StopFileCache(const BundleNameUserInfo &bundleNameUserInfo, - int64_t downloadId, - bool needClean, - int32_t timeout) -{ - return E_OK; -} - -int32_t DataSyncManager::RegisterDownloadFileCallback(const BundleNameUserInfo &bundleNameUserInfo, - const sptr &downloadCallback) -{ - return E_OK; -} - -int32_t DataSyncManager::UnregisterDownloadFileCallback(const BundleNameUserInfo &bundleNameUserInfo) + int64_t downloadId, + bool needClean, + int32_t timeout) { return E_OK; } diff --git a/frameworks/native/cloudsync_kit_inner/include/cloud_sync_manager_impl.h b/frameworks/native/cloudsync_kit_inner/include/cloud_sync_manager_impl.h index 6afddaace..de592796b 100644 --- a/frameworks/native/cloudsync_kit_inner/include/cloud_sync_manager_impl.h +++ b/frameworks/native/cloudsync_kit_inner/include/cloud_sync_manager_impl.h @@ -54,19 +54,17 @@ public: int32_t NotifyEventChange(int32_t userId, const std::string &eventId, const std::string &extraData) override; int32_t EnableCloud(const std::string &accoutId, const SwitchDataObj &switchData) override; int32_t DisableCloud(const std::string &accoutId) override; - int32_t StartDownloadFile(const std::string &uri) override; - int32_t StartFileCache(const std::string &uri) override; - int32_t StartFileCache(const std::vector &uriVec, int64_t &downloadId, - int32_t fieldkey = FIELDKEY_CONTENT, + int32_t StartDownloadFile(const std::string &uri, + const std::shared_ptr downloadCallback, + int64_t &downloadId) override; + int32_t StartFileCache(const std::vector &uriVec, + int64_t &downloadId, + int32_t fieldkey = FieldKey::FIELDKEY_CONTENT, const std::shared_ptr downloadCallback = nullptr, int32_t timeout = -1) override; - int32_t StopDownloadFile(const std::string &uri, bool needClean = false) override; + int32_t StopDownloadFile(int64_t downloadId, bool needClean = false) override; int32_t StopFileCache(int64_t downloadId, bool needClean = false, int32_t timeout = -1) override; int32_t DownloadThumb() override; - int32_t RegisterDownloadFileCallback(const std::shared_ptr downloadCallback) override; - int32_t RegisterFileCacheCallback(const std::shared_ptr downloadCallback) override; - int32_t UnregisterDownloadFileCallback() override; - int32_t UnregisterFileCacheCallback() override; int32_t GetSyncTime(int64_t &syncTime, const std::string &bundleName = "") override; int32_t CleanCache(const std::string &uri) override; int32_t CleanFileCache(const std::string &uri) override; @@ -105,10 +103,8 @@ private: std::atomic_flag isFirstCall_{false}; sptr deathRecipient_; std::shared_ptr callback_; - std::shared_ptr downloadCallback_; sptr listener_; std::mutex subscribeMutex_; - std::mutex downloadMutex_; std::mutex callbackMutex_; void SubscribeListener(std::string bundleName = ""); }; diff --git a/frameworks/native/cloudsync_kit_inner/src/cloud_sync_manager_impl.cpp b/frameworks/native/cloudsync_kit_inner/src/cloud_sync_manager_impl.cpp index c67cd8bcc..486708a6c 100644 --- a/frameworks/native/cloudsync_kit_inner/src/cloud_sync_manager_impl.cpp +++ b/frameworks/native/cloudsync_kit_inner/src/cloud_sync_manager_impl.cpp @@ -320,7 +320,9 @@ int32_t CloudSyncManagerImpl::NotifyEventChange( return ret; } -int32_t CloudSyncManagerImpl::StartDownloadFile(const std::string &uri) +int32_t CloudSyncManagerImpl::StartDownloadFile(const std::string &uri, + const std::shared_ptr downloadCallback, + int64_t &downloadId) { LOGI("StartDownloadFile start"); auto CloudSyncServiceProxy = ServiceProxy::GetInstance(); @@ -328,8 +330,12 @@ int32_t CloudSyncManagerImpl::StartDownloadFile(const std::string &uri) LOGE("proxy is null"); return E_SA_LOAD_FAILED; } + if (downloadCallback == nullptr) { + LOGW("The callback is null, download progress may not be received"); + } SetDeathRecipient(CloudSyncServiceProxy->AsObject()); - int32_t ret = CloudSyncServiceProxy->StartDownloadFile(uri); + auto dlCallback = sptr(new (std::nothrow) CloudDownloadCallbackClient(downloadCallback)); + int32_t ret = CloudSyncServiceProxy->StartDownloadFile(uri, dlCallback, downloadId); LOGI("StartDownloadFile ret %{public}d", ret); return ret; } @@ -357,40 +363,19 @@ int32_t CloudSyncManagerImpl::BatchCleanFile(const std::vector &f return CloudSyncServiceProxy->BatchCleanFile(fileInfoObj, failCloudId); } -int32_t CloudSyncManagerImpl::StartFileCache(const std::string &uri) -{ - LOGI("StartFileCache start"); - int64_t downloadId = 0; - auto CloudSyncServiceProxy = ServiceProxy::GetInstance(); - if (!CloudSyncServiceProxy) { - LOGE("proxy is null"); - return E_SA_LOAD_FAILED; - } - SetDeathRecipient(CloudSyncServiceProxy->AsObject()); - std::vector uriVec; - uriVec.push_back(uri); - bool isCallbackValid = false; - int32_t timeout = -1; - sptr dlCallback = sptr(new (std::nothrow) CloudDownloadCallbackClient(nullptr)); - int32_t ret = CloudSyncServiceProxy->StartFileCache(uriVec, downloadId, FIELDKEY_CONTENT, isCallbackValid, - dlCallback, timeout); - LOGI("StartFileCache ret %{public}d", ret); - return ret; -} - int32_t CloudSyncManagerImpl::StartFileCache(const std::vector &uriVec, - int64_t &downloadId, int32_t fieldkey, + int64_t &downloadId, + int32_t fieldkey, const std::shared_ptr downloadCallback, int32_t timeout) { - LOGI("StartFileCache batch start, uriVec size: %{public}zu, fieldKey: %{public}d, Callback is null: %{public}d", - uriVec.size(), fieldkey, (downloadCallback == nullptr)); + LOGI("Start, uriVec size: %{public}zu, fieldKey: %{public}d", uriVec.size(), fieldkey); if (uriVec.empty()) { - LOGE("StartFileCache, uri list is empty"); + LOGE("The uri list is empty"); return E_INVAL_ARG; } if (uriVec.size() > MAX_FILE_CACHE_NUM) { - LOGE("StartFileCache, the size of uri list exceeded the maximum limit, size: %{public}zu", uriVec.size()); + LOGE("The size of uri list exceeded the maximum limit, size: %{public}zu", uriVec.size()); return E_EXCEED_MAX_SIZE; } auto CloudSyncServiceProxy = ServiceProxy::GetInstance(); @@ -400,24 +385,14 @@ int32_t CloudSyncManagerImpl::StartFileCache(const std::vector &uri } SetDeathRecipient(CloudSyncServiceProxy->AsObject()); - bool isCallbackValid = false; - sptr dlCallback = sptr(new (std::nothrow) CloudDownloadCallbackClient(nullptr)); - if (downloadCallback != nullptr) { - dlCallback = sptr(new (std::nothrow) CloudDownloadCallbackClient(downloadCallback)); - isCallbackValid = true; - if (dlCallback == nullptr) { - LOGE("register download callback failed"); - isCallbackValid = false; - } + if (downloadCallback == nullptr) { + LOGW("The callback is null, download progress may not be received"); } - - int32_t ret = CloudSyncServiceProxy->StartFileCache(uriVec, downloadId, fieldkey, - isCallbackValid, dlCallback, timeout); - LOGI("StartFileCache batch ret %{public}d", ret); - return ret; + auto dlCallback = sptr(new (std::nothrow) CloudDownloadCallbackClient(downloadCallback)); + return CloudSyncServiceProxy->StartFileCache(uriVec, downloadId, fieldkey, dlCallback, timeout); } -int32_t CloudSyncManagerImpl::StopDownloadFile(const std::string &uri, bool needClean) +int32_t CloudSyncManagerImpl::StopDownloadFile(int64_t downloadId, bool needClean) { LOGI("StopDownloadFile start"); auto CloudSyncServiceProxy = ServiceProxy::GetInstance(); @@ -426,7 +401,7 @@ int32_t CloudSyncManagerImpl::StopDownloadFile(const std::string &uri, bool need return E_SA_LOAD_FAILED; } SetDeathRecipient(CloudSyncServiceProxy->AsObject()); - int32_t ret = CloudSyncServiceProxy->StopDownloadFile(uri, needClean); + int32_t ret = CloudSyncServiceProxy->StopDownloadFile(downloadId, needClean); LOGI("StopDownloadFile ret %{public}d", ret); return ret; } @@ -630,98 +605,6 @@ int32_t CloudSyncManagerImpl::DownloadThumb() return ret; } -int32_t CloudSyncManagerImpl::RegisterDownloadFileCallback( - const std::shared_ptr downloadCallback) -{ - LOGI("RegisterDownloadFileCallback start"); - auto CloudSyncServiceProxy = ServiceProxy::GetInstance(); - if (!CloudSyncServiceProxy) { - LOGE("proxy is null"); - return E_SA_LOAD_FAILED; - } - { - unique_lock lock(downloadMutex_); - auto dlCallback = sptr(new (std::nothrow) CloudDownloadCallbackClient(downloadCallback)); - if (dlCallback == nullptr || - CloudSyncServiceProxy->RegisterDownloadFileCallback(dlCallback) != E_OK) { - LOGE("register download callback failed"); - } else { - downloadCallback_ = downloadCallback; - } - } - SubscribeListener(); - SetDeathRecipient(CloudSyncServiceProxy->AsObject()); - return E_OK; -} - -int32_t CloudSyncManagerImpl::RegisterFileCacheCallback( - const std::shared_ptr downloadCallback) -{ - LOGI("RegisterFileCacheCallback start"); - auto CloudSyncServiceProxy = ServiceProxy::GetInstance(); - if (!CloudSyncServiceProxy) { - LOGE("proxy is null"); - return E_SA_LOAD_FAILED; - } - { - unique_lock lock(downloadMutex_); - auto dlCallback = sptr(new (std::nothrow) CloudDownloadCallbackClient(downloadCallback)); - if (dlCallback == nullptr || - CloudSyncServiceProxy->RegisterFileCacheCallback(dlCallback) != E_OK) { - LOGE("register download callback failed"); - } else { - downloadCallback_ = downloadCallback; - } - } - SubscribeListener(); - SetDeathRecipient(CloudSyncServiceProxy->AsObject()); - return E_OK; -} - -int32_t CloudSyncManagerImpl::UnregisterDownloadFileCallback() -{ - LOGI("UnregisterDownloadFileCallback start"); - auto CloudSyncServiceProxy = ServiceProxy::GetInstance(); - if (!CloudSyncServiceProxy) { - LOGE("proxy is null"); - return E_SA_LOAD_FAILED; - } - int32_t ret = E_OK; - { - unique_lock lock(downloadMutex_); - ret = CloudSyncServiceProxy->UnregisterDownloadFileCallback(); - LOGI("UnregisterDownloadFileCallback ret %{public}d", ret); - if (ret == E_OK) { - downloadCallback_ = nullptr; - } - } - SubscribeListener(); - SetDeathRecipient(CloudSyncServiceProxy->AsObject()); - return ret; -} - -int32_t CloudSyncManagerImpl::UnregisterFileCacheCallback() -{ - LOGI("UnregisterFileCacheCallback start"); - auto CloudSyncServiceProxy = ServiceProxy::GetInstance(); - if (!CloudSyncServiceProxy) { - LOGE("proxy is null"); - return E_SA_LOAD_FAILED; - } - int32_t ret = E_OK; - { - unique_lock lock(downloadMutex_); - ret = CloudSyncServiceProxy->UnregisterFileCacheCallback(); - LOGI("UnregisterFileCacheCallback ret %{public}d", ret); - if (ret == E_OK) { - downloadCallback_ = nullptr; - } - } - SubscribeListener(); - SetDeathRecipient(CloudSyncServiceProxy->AsObject()); - return ret; -} - void CloudSyncManagerImpl::SetDeathRecipient(const sptr &remoteObject) { if (!isFirstCall_.test_and_set()) { @@ -839,7 +722,7 @@ void CloudSyncManagerImpl::SubscribeListener(std::string bundleName) auto ret = samgr->UnSubscribeSystemAbility(FILEMANAGEMENT_CLOUD_SYNC_SERVICE_SA_ID, listener_); LOGI("unsubscribed to systemAbility ret %{public}d", ret); } - if (callback_ != nullptr || downloadCallback_ != nullptr) { + if (callback_ != nullptr) { listener_ = new SystemAbilityStatusChange(bundleName); auto ret = samgr->SubscribeSystemAbility(FILEMANAGEMENT_CLOUD_SYNC_SERVICE_SA_ID, listener_); LOGI("subscribed to systemAbility ret %{public}d", ret); @@ -856,18 +739,6 @@ bool CloudSyncManagerImpl::ResetProxyCallback(uint32_t retryCount, const string return false; } bool hasCallback = false; - { - unique_lock downloadLock(downloadMutex_); - if (downloadCallback_ != nullptr) { - auto dlCallback = sptr(new (std::nothrow) CloudDownloadCallbackClient(downloadCallback_)); - if (dlCallback == nullptr || - cloudSyncServiceProxy->RegisterDownloadFileCallback(dlCallback) != E_OK) { - LOGW("register download callback failed, try time is %{public}d", retryCount); - } else { - hasCallback = true; - } - } - } if (callback_ != nullptr) { auto callback = sptr(new (std::nothrow) CloudSyncCallbackClient(callback_)); if (callback == nullptr || @@ -877,7 +748,7 @@ bool CloudSyncManagerImpl::ResetProxyCallback(uint32_t retryCount, const string hasCallback = true; } } - if (hasCallback) { + if (retryCount == 0 && hasCallback) { CloudSyncManagerImpl::GetInstance().SetDeathRecipient(cloudSyncServiceProxy->AsObject()); } return true; diff --git a/frameworks/native/cloudsync_kit_inner_lite/src/cloud_sync_service_proxy_lite.cpp b/frameworks/native/cloudsync_kit_inner_lite/src/cloud_sync_service_proxy_lite.cpp index 134d9bf27..4337b08fe 100644 --- a/frameworks/native/cloudsync_kit_inner_lite/src/cloud_sync_service_proxy_lite.cpp +++ b/frameworks/native/cloudsync_kit_inner_lite/src/cloud_sync_service_proxy_lite.cpp @@ -243,7 +243,9 @@ int32_t CloudSyncServiceProxy::NotifyEventChange( return E_OK; } -int32_t CloudSyncServiceProxy::StartDownloadFile(const std::string &uri) +int32_t CloudSyncServiceProxy::StartDownloadFile(const std::string &uri, + const std::shared_ptr downloadCallback, + int64_t &downloadId) { return E_OK; } @@ -251,7 +253,6 @@ int32_t CloudSyncServiceProxy::StartDownloadFile(const std::string &uri) int32_t CloudSyncServiceProxy::StartFileCacheWriteParcel(MessageParcel &data, const std::vector &pathVec, int32_t &fieldkey, - bool isCallbackValid, const sptr &downloadCallback, int32_t timeout) { @@ -259,15 +260,15 @@ int32_t CloudSyncServiceProxy::StartFileCacheWriteParcel(MessageParcel &data, } int32_t CloudSyncServiceProxy::StartFileCache(const std::vector &uriVec, - int64_t &downloadId, int32_t fieldkey, - bool isCallbackValid, + int64_t &downloadId, + int32_t fieldkey, const sptr &downloadCallback, int32_t timeout) { return E_OK; } -int32_t CloudSyncServiceProxy::StopDownloadFile(const std::string &uri, bool needClean) +int32_t CloudSyncServiceProxy::StopDownloadFile(int64_t downloadId, bool needClean) { return E_OK; } @@ -282,26 +283,6 @@ int32_t CloudSyncServiceProxy::DownloadThumb() return E_OK; } -int32_t CloudSyncServiceProxy::RegisterDownloadFileCallback(const sptr &downloadCallback) -{ - return E_OK; -} - -int32_t CloudSyncServiceProxy::RegisterFileCacheCallback(const sptr &downloadCallback) -{ - return E_OK; -} - -int32_t CloudSyncServiceProxy::UnregisterDownloadFileCallback() -{ - return E_OK; -} - -int32_t CloudSyncServiceProxy::UnregisterFileCacheCallback() -{ - return E_OK; -} - int32_t CloudSyncServiceProxy::UploadAsset(const int32_t userId, const std::string &request, std::string &result) { return E_OK; diff --git a/interfaces/inner_api/native/cloud_file_kit_inner/data_sync_manager.h b/interfaces/inner_api/native/cloud_file_kit_inner/data_sync_manager.h index 1a4bf8690..aef152d43 100644 --- a/interfaces/inner_api/native/cloud_file_kit_inner/data_sync_manager.h +++ b/interfaces/inner_api/native/cloud_file_kit_inner/data_sync_manager.h @@ -51,21 +51,15 @@ public: virtual void UnRegisterCloudSyncCallback(const std::string &bundleName, const std::string &callerBundleName); virtual int32_t IsSkipSync(const std::string &bundleName, const int32_t userId, bool forceFlag); virtual int32_t StartDownloadFile(const BundleNameUserInfo &bundleNameUserInfo, - const std::vector &pathVec, + const std::vector &uriVec, int64_t &downloadId, int32_t fieldkey, const sptr &downloadCallback, int32_t timeout = -1); virtual int32_t StopDownloadFile(const BundleNameUserInfo &bundleNameUserInfo, - const std::string &path, - bool needClean = false); - virtual int32_t StopFileCache(const BundleNameUserInfo &bundleNameUserInfo, - int64_t downloadId, - bool needClean, - int32_t timeout = -1); - virtual int32_t RegisterDownloadFileCallback(const BundleNameUserInfo &bundleNameUserInfo, - const sptr &downloadCallback); - virtual int32_t UnregisterDownloadFileCallback(const BundleNameUserInfo &bundleNameUserInfo); + int64_t downloadId, + bool needClean, + int32_t timeout = -1); virtual int32_t CleanCloudFile(const int32_t userId, const std::string &bundleName, const int action); virtual int32_t CleanRemainFile(const std::string &bundleName, const int32_t userId); virtual int32_t OptimizeStorage(const std::string &bundleName, const int32_t userId, const int32_t agingDays); @@ -106,6 +100,6 @@ public: bool &isConflict); virtual int32_t ClearFileConflict(const BundleNameUserInfo &bundleNameUserInfo, const std::string &uri); }; -} // namespace OHOS::FileManagement::CloudSync +} // namespace OHOS::FileManagement::CloudFile #endif // OHOS_CLOUD_FILE_DATA_SYNC_MANAGER_H \ No newline at end of file diff --git a/interfaces/inner_api/native/cloudsync_kit_inner/cloud_sync_common.h b/interfaces/inner_api/native/cloudsync_kit_inner/cloud_sync_common.h index 4c8ab81da..c8a9d2fd5 100644 --- a/interfaces/inner_api/native/cloudsync_kit_inner/cloud_sync_common.h +++ b/interfaces/inner_api/native/cloudsync_kit_inner/cloud_sync_common.h @@ -25,10 +25,10 @@ namespace OHOS::FileManagement::CloudSync { #define FIELD_KEY_MAX_SIZE 4 constexpr int32_t CLEAN_FILE_MAX_SIZE = 200; -enum FieldKey { - FIELDKEY_CONTENT = 1 << 0, - FIELDKEY_THUMB = 1 << 1, - FIELDKEY_LCD = 1 << 2, +enum FieldKey : int32_t { + FIELDKEY_CONTENT = 0, + FIELDKEY_THUMB, + FIELDKEY_LCD, }; struct DownloadProgressObj : public Parcelable { diff --git a/interfaces/inner_api/native/cloudsync_kit_inner/cloud_sync_manager.h b/interfaces/inner_api/native/cloudsync_kit_inner/cloud_sync_manager.h index 2d540d36e..c221ba977 100644 --- a/interfaces/inner_api/native/cloudsync_kit_inner/cloud_sync_manager.h +++ b/interfaces/inner_api/native/cloudsync_kit_inner/cloud_sync_manager.h @@ -113,19 +113,17 @@ public: virtual int32_t OptimizeStorage(const OptimizeSpaceOptions &optimizeOptions, const std::shared_ptr optimizeCallback = nullptr) = 0; virtual int32_t StopOptimizeStorage() = 0; - virtual int32_t StartDownloadFile(const std::string &path) = 0; - virtual int32_t StartFileCache(const std::string &path) = 0; - virtual int32_t StartFileCache(const std::vector &pathVec, int64_t &downloadId, - int32_t fieldkey = FIELDKEY_CONTENT, + virtual int32_t StartDownloadFile(const std::string &uri, + const std::shared_ptr downloadCallback, + int64_t &downloadId) = 0; + virtual int32_t StartFileCache(const std::vector &uriVec, + int64_t &downloadId, + int32_t fieldkey = FieldKey::FIELDKEY_CONTENT, const std::shared_ptr downloadCallback = nullptr, int32_t timeout = -1) = 0; - virtual int32_t StopDownloadFile(const std::string &path, bool needClean = false) = 0; + virtual int32_t StopDownloadFile(int64_t downloadId, bool needClean = false) = 0; virtual int32_t StopFileCache(int64_t downloadId, bool needClean = false, int32_t timeout = -1) = 0; virtual int32_t DownloadThumb() = 0; - virtual int32_t RegisterDownloadFileCallback(const std::shared_ptr downloadCallback) = 0; - virtual int32_t RegisterFileCacheCallback(const std::shared_ptr downloadCallback) = 0; - virtual int32_t UnregisterDownloadFileCallback() = 0; - virtual int32_t UnregisterFileCacheCallback() = 0; virtual int32_t GetSyncTime(int64_t &syncTime, const std::string &bundleName = "") = 0; virtual int32_t CleanCache(const std::string &uri) = 0; virtual int32_t CleanFileCache(const std::string &uri) = 0; diff --git a/interfaces/kits/js/ani/ani_helper/include/ani_utils.h b/interfaces/kits/js/ani/ani_helper/include/ani_utils.h index 805d2901c..73feec1b4 100644 --- a/interfaces/kits/js/ani/ani_helper/include/ani_utils.h +++ b/interfaces/kits/js/ani/ani_helper/include/ani_utils.h @@ -29,11 +29,16 @@ static thread_local std::shared_ptr mainHandler; class ANIUtils { public: static ani_status AniString2String(ani_env *env, ani_string str, std::string &res); + static std::tuple EnumToInt32(ani_env *env, ani_enum_item enumItem); + static std::tuple> AniToStringArray(ani_env *env, ani_array_ref strArray); + + static std::tuple ToAniString(ani_env *env, const std::string &str); + static std::tuple ToAniStringArray(ani_env *env, const std::vector &strList); static bool SendEventToMainThread(const std::function func); private: ANIUtils() = default; ~ANIUtils() = default; }; -} // OHOS::FileManagement::CloudSync +} // namespace OHOS::FileManagement::CloudSync #endif // OHOS_FILEMGMT_ANI_UTILS_H \ No newline at end of file diff --git a/interfaces/kits/js/ani/ani_helper/src/ani_utils.cpp b/interfaces/kits/js/ani/ani_helper/src/ani_utils.cpp index b3ed7e3c6..186290b3a 100644 --- a/interfaces/kits/js/ani/ani_helper/src/ani_utils.cpp +++ b/interfaces/kits/js/ani/ani_helper/src/ani_utils.cpp @@ -17,9 +17,11 @@ #include "fs_error.h" #include "utils_log.h" +#include +#include namespace OHOS::FileManagement::CloudSync { - +using namespace arkts::ani_signature; ani_status ANIUtils::AniString2String(ani_env *env, ani_string str, std::string &res) { ani_size strSize; @@ -41,6 +43,72 @@ ani_status ANIUtils::AniString2String(ani_env *env, ani_string str, std::string return ANI_OK; } +std::tuple ANIUtils::ToAniString(ani_env *env, const std::string &str) +{ + ani_string result; + bool succ = (ANI_OK == env->String_NewUTF8(str.c_str(), str.size(), &result)); + return {succ, std::move(result)}; +} + +std::tuple ANIUtils::EnumToInt32(ani_env *env, ani_enum_item enumItem) +{ + ani_int result; + bool succ = (ANI_OK == env->EnumItem_GetValue_Int(enumItem, &result)); + return {succ, result}; +} + +std::tuple> ANIUtils::AniToStringArray(ani_env *env, ani_array_ref strArray) +{ + ani_size arraySize; + ani_status ret; + if ((ret = env->Array_GetLength(strArray, &arraySize)) != ANI_OK) { + LOGE("Failed to get array size, %{public}d", ret); + return {false, {}}; + } + std::vector res; + for (ani_size i = 0; i < arraySize; ++i) { + ani_ref strRef; + if ((ret = env->Array_Get_Ref(strArray, i, &strRef)) != ANI_OK) { + LOGE("Failed to get string item, %{public}d", ret); + return {false, {}}; + } + std::string strItem; + if ((ret = ANIUtils::AniString2String(env, static_cast(strRef), strItem)) != ANI_OK) { + LOGE("Failed to get string item, %{public}d", ret); + return {false, {}}; + } + res.emplace_back(strItem); + } + return {true, res}; +} + +std::tuple ANIUtils::ToAniStringArray(ani_env *env, const std::vector &strList) +{ + size_t length = strList.size(); + const std::string *strArray = strList.data(); + std::string classDesc = Builder::BuildClass("std.core.String").Descriptor(); + ani_class cls = nullptr; + if (env->FindClass(classDesc.c_str(), &cls) != ANI_OK) { + return {false, nullptr}; + } + ani_array_ref result = nullptr; + if (env->Array_New_Ref(cls, length, nullptr, &result) != ANI_OK) { + return {false, nullptr}; + } + for (size_t i = 0; i < length; ++i) { + auto [succ, item] = ANIUtils::ToAniString(env, strArray[i]); + if (!succ) { + LOGE("Failed to conver to ani string"); + return {false, nullptr}; + } + if (env->Array_Set_Ref(result, i, item) != ANI_OK) { + LOGE("Failed to set element for array"); + return {false, nullptr}; + } + } + return {true, result}; +} + bool ANIUtils::SendEventToMainThread(const std::function func) { if (func == nullptr) { @@ -59,4 +127,4 @@ bool ANIUtils::SendEventToMainThread(const std::function func) mainHandler->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::HIGH, {}); return true; } -} \ No newline at end of file +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/BUILD.gn b/interfaces/kits/js/ani/file_cloud_sync/BUILD.gn index a0b529aed..06058a143 100644 --- a/interfaces/kits/js/ani/file_cloud_sync/BUILD.gn +++ b/interfaces/kits/js/ani/file_cloud_sync/BUILD.gn @@ -32,13 +32,18 @@ ohos_shared_library("cloud_sync_ani") { "${interfaces_js_path}/cloudfilesync/cloud_file_core.cpp", "${interfaces_js_path}/cloudfilesync/cloud_sync_core.cpp", "${interfaces_js_path}/cloudfilesync/file_sync_core.cpp", + "${interfaces_js_path}/cloudfilesync/multi_download_progress_core.cpp", "src/bind_function_class.cpp", "src/cloud_download_ani.cpp", - "src/cloud_download_callback_ani.cpp", "src/cloud_file_cache_ani.cpp", "src/cloud_sync_ani.cpp", "src/cloud_sync_callback_ani.cpp", + "src/download_callback_impl_ani.cpp", + "src/download_callback_middle_ani.cpp", + "src/download_progress_ani.cpp", "src/file_sync_ani.cpp", + "src/multi_download_progress_ani.cpp", + "src/register_callback_manager_ani.cpp", ] sanitize = { integer_overflow = true diff --git a/interfaces/kits/js/ani/file_cloud_sync/ets/@ohos.file.cloudSync.ets b/interfaces/kits/js/ani/file_cloud_sync/ets/@ohos.file.cloudSync.ets index 871c4561d..7e7359221 100644 --- a/interfaces/kits/js/ani/file_cloud_sync/ets/@ohos.file.cloudSync.ets +++ b/interfaces/kits/js/ani/file_cloud_sync/ets/@ohos.file.cloudSync.ets @@ -183,6 +183,30 @@ export default namespace cloudSync { error: DownloadErrorType; }; + export class MultiDownloadProgress { + static { + loadLibrary("cloud_sync_ani"); + } + state: State; + taskId: number; + successfulCount: number; + failedCount: number; + totalCount: number; + downloadedSize: number; + totalSize: number; + errType: DownloadErrorType; + + private nativePtr: long = 0; + + constructor(ptr: long) { + if (this.nativePtr === 0) { + this.nativePtr = ptr; + } + } + native getFailedFiles(): Array; + native getSuccessfulFiles(): Array; + }; + export type DownloadcCallback = (pg: DownloadProgress) => void; export class Download { @@ -286,6 +310,29 @@ export default namespace cloudSync { UPLOAD_FAILURE = 6, } + export enum DownloadFileType { + CONTENT = 0, + THUMBNAIL = 1, + LCD = 2 + } + + export interface FailedFileInfo { + uri: string; + error: DownloadErrorType; + } + + export class FailedFileInfoInner implements FailedFileInfo { + constructor( + uri: string, + error: DownloadErrorType + ) { + this.uri = uri; + this.error = error; + } + uri: string; + error: DownloadErrorType; + }; + export class ChangeDataInner implements ChangeData { constructor( type: NotifyType, @@ -301,7 +348,7 @@ export default namespace cloudSync { uris: Array; }; - export class FileSync{ + export class FileSync { static { loadLibrary("cloud_sync_ani"); } @@ -447,6 +494,23 @@ export default namespace cloudSync { }); } + startBatch(uris: Array, fileType?: DownloadFileType): Promise { + let fieldKey: DownloadFileType = DownloadFileType.CONTENT; + if (fileType !== undefined) { + fieldKey = fileType; + } + return new Promise((resolve: (result: number) => void, + reject: (e: BusinessError) => void): number => { + let promise = taskpool.execute((uris: Array, fieldKey: DownloadFileType): number => + this.CloudFileCacheStartBatch(uris, fieldKey), uris, fieldKey); + promise.then((ret: number): void => { + resolve(ret); + }, (e: BusinessError): void => { + reject(e); + }); + }); + } + stop(uri: string, needClean?: boolean): Promise { let clean: boolean = false; if (needClean !== undefined) { @@ -479,8 +543,28 @@ export default namespace cloudSync { }); } + stopBatch(downloadId: number, needClean?: boolean): Promise { + let clean: boolean = false; + if (needClean !== undefined) { + clean = needClean; + } + return new Promise((resolve: (result: undefined) => void, + reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((downloadId: number, clean: boolean): number => { + return this.StopBatchInner(downloadId, clean); + }, downloadId, clean); + promise.then((): void => { + resolve(undefined); + }, (e: BusinessError): void => { + reject(e); + }); + }); + } + native CloudFileCacheStart(uri: string): void; native CloudFileCacheStop(uri: string, clean: boolean): void; + native CloudFileCacheStartBatch(uris: Array, fieldKey: DownloadFileType): number; + native CloudFileCacheStopBatch(downloadId: number, clean: boolean): void; native cleanCache(uri: string): void; StartInner(uri: string): int { @@ -491,6 +575,10 @@ export default namespace cloudSync { this.CloudFileCacheStop(uri, clean); return 0; } + StopBatchInner(downloadId: number, clean: boolean): int { + this.CloudFileCacheStopBatch(downloadId, clean); + return 0; + } }; export enum OptimizeState { diff --git a/interfaces/kits/js/ani/file_cloud_sync/include/cloud_file_cache_ani.h b/interfaces/kits/js/ani/file_cloud_sync/include/cloud_file_cache_ani.h index 181c6d8fb..fc138b4a4 100644 --- a/interfaces/kits/js/ani/file_cloud_sync/include/cloud_file_cache_ani.h +++ b/interfaces/kits/js/ani/file_cloud_sync/include/cloud_file_cache_ani.h @@ -27,7 +27,12 @@ public: static void CloudFileCacheOff0(ani_env *env, ani_object object, ani_string evt, ani_object fun); static void CloudFileCacheOff1(ani_env *env, ani_object object, ani_string evt); static void CloudFileCacheStart(ani_env *env, ani_object object, ani_string uri); + static ani_double CloudFileCacheStartBatch(ani_env *env, + ani_object object, + ani_array_ref uriList, + ani_enum_item fileType); static void CloudFileCacheStop(ani_env *env, ani_object object, ani_string uri, ani_boolean needClean); + static void CloudFileCacheStopBatch(ani_env *env, ani_object object, ani_double taskId, ani_boolean needClean); static void CloudFileCacheCleanCache(ani_env *env, ani_object object, ani_string uri); }; } // namespace OHOS::FileManagement::CloudSync diff --git a/interfaces/kits/js/ani/file_cloud_sync/include/cloud_download_callback_ani.h b/interfaces/kits/js/ani/file_cloud_sync/include/download_callback_impl_ani.h similarity index 44% rename from interfaces/kits/js/ani/file_cloud_sync/include/cloud_download_callback_ani.h rename to interfaces/kits/js/ani/file_cloud_sync/include/download_callback_impl_ani.h index 5bebbca86..a0d6089ac 100644 --- a/interfaces/kits/js/ani/file_cloud_sync/include/cloud_download_callback_ani.h +++ b/interfaces/kits/js/ani/file_cloud_sync/include/download_callback_impl_ani.h @@ -13,29 +13,24 @@ * limitations under the License. */ -#ifndef OHOS_FILEMGMT_CLOUD_DOWNLOAD_CALLBACK_ANI_H -#define OHOS_FILEMGMT_CLOUD_DOWNLOAD_CALLBACK_ANI_H +#ifndef OHOS_FILEMGMT_DOWNLOAD_CALLBACK_IMPL_ANI_H +#define OHOS_FILEMGMT_DOWNLOAD_CALLBACK_IMPL_ANI_H -#include -#include - -#include "cloud_download_callback_middle.h" +#include "download_callback_middle_ani.h" namespace OHOS::FileManagement::CloudSync { - -class CloudDownloadCallbackAniImpl : public CloudDownloadCallbackMiddle, - public std::enable_shared_from_this { +class CloudDownloadCallbackImplAni : public CloudDlCallbackMiddleAni { public: - CloudDownloadCallbackAniImpl(ani_env *env, ani_ref fun, bool isBatch = false); - ~CloudDownloadCallbackAniImpl() override = default; - void OnDownloadProcess(const DownloadProgressObj &progress) override; - void DeleteReference() override; + int32_t StartDownloadInner(const std::string &uri); + int32_t StopDownloadInner(const std::string &uri); +}; -private: - void GetDownloadProgress(const DownloadProgressObj &progress, const ani_class &cls, ani_object &pg); - ani_env *env_; - ani_ref cbOnRef_ = nullptr; - bool isBatch_; +class CloudFileCacheCallbackImplAni : public CloudDlCallbackMiddleAni { +public: + int32_t StartDownloadInner(const std::string &uri, int32_t fieldKey); + int32_t StartDownloadInner(const std::vector &uriList, int64_t &downloadId, int32_t fieldKey); + int32_t StopDownloadInner(const std::string &uri, bool needClean); + int32_t StopDownloadInner(int64_t downloadId, bool needClean); }; } // namespace OHOS::FileManagement::CloudSync -#endif // OHOS_FILEMGMT_CLOUD_DOWNLOAD_CALLBACK_ANI_H +#endif // OHOS_FILEMGMT_DOWNLOAD_CALLBACK_IMPL_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/include/download_callback_middle_ani.h b/interfaces/kits/js/ani/file_cloud_sync/include/download_callback_middle_ani.h new file mode 100644 index 000000000..f1e23eeb8 --- /dev/null +++ b/interfaces/kits/js/ani/file_cloud_sync/include/download_callback_middle_ani.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_DOWNLOAD_CALLBACK_MIDDLE_ANI_H +#define OHOS_FILEMGMT_DOWNLOAD_CALLBACK_MIDDLE_ANI_H + +#include +#include +#include +#include +#include + +#include "cloud_download_callback.h" +#include "download_progress_ani.h" +#include "register_callback_manager_ani.h" + +namespace OHOS::FileManagement::CloudSync { +class CloudDlCallbackMiddleAni : public CloudDownloadCallback, + public RegisterCallbackManagerAni, + public std::enable_shared_from_this { +public: + virtual ~CloudDlCallbackMiddleAni() = default; + void OnDownloadProcess(const DownloadProgressObj &progress) override; + void RemoveDownloadInfo(int64_t downloadId); + +protected: + std::vector GetDownloadIdsByUri(const std::string &uri); + std::shared_ptr GetDownloadInfo(int64_t downloadId); + +protected: + std::mutex downloadInfoMtx_; + std::unordered_map> downloadInfos_; +}; +} // namespace OHOS::FileManagement::CloudSync +#endif // OHOS_FILEMGMT_DOWNLOAD_CALLBACK_MIDDLE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/include/download_progress_ani.h b/interfaces/kits/js/ani/file_cloud_sync/include/download_progress_ani.h new file mode 100644 index 000000000..678e3cdef --- /dev/null +++ b/interfaces/kits/js/ani/file_cloud_sync/include/download_progress_ani.h @@ -0,0 +1,116 @@ +/* + * 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_DOWNLOAD_PROGRESS_ANI_H +#define OHOS_FILEMGMT_DOWNLOAD_PROGRESS_ANI_H + +#include +#include +#include + +#include "ani_utils.h" +#include "cloud_sync_common.h" + +namespace OHOS::FileManagement::CloudSync { +class DlProgressAni { +public: + explicit DlProgressAni(int64_t downloadId) : taskId_(downloadId) {} + virtual ~DlProgressAni() = default; + virtual void Update(const DownloadProgressObj &progress) = 0; + virtual ani_object ConvertToObject(ani_env *env) = 0; + + // Use default inline + int64_t GetTaskId() const + { + return taskId_; + } + int64_t GetTotalSize() const + { + return totalSize_; + } + int64_t GetDownloadedSize() const + { + return downloadedSize_; + } + int32_t GetState() const + { + return state_; + } + int32_t GetErrorType() const + { + return errorType_; + } + bool IsNeedClean() const + { + return needClean_; + } + std::string GetUri() const + { + return uri_; + } + +protected: + std::string uri_; + // taskId_ is used to identify the download task, it is unique for each download + int64_t taskId_{0}; + int64_t totalSize_{0}; + int64_t downloadedSize_{0}; + int32_t state_{0}; + int32_t errorType_{0}; + bool needClean_{false}; +}; + +class SingleProgressAni : public DlProgressAni { +public: + explicit SingleProgressAni(int64_t downloadId) : DlProgressAni(downloadId) {} + void Update(const DownloadProgressObj &progress) override; + ani_object ConvertToObject(ani_env *env) override; +}; + +class BatchProgressAni : public DlProgressAni, public std::enable_shared_from_this { +public: + explicit BatchProgressAni(int64_t downloadId) : DlProgressAni(downloadId) {} + void Update(const DownloadProgressObj &progress) override; + ani_object ConvertToObject(ani_env *env) override; + + // Getters for batch download progress + int64_t GetTotalNum() const + { + return totalNum_; + } + std::size_t GetSuccNum() const + { + return downloadedFiles_.size(); + } + std::size_t GetFailedNum() const + { + return failedFiles_.size(); + } + std::unordered_set GetDownloadedFiles() const + { + return downloadedFiles_; + } + std::unordered_map GetFailedFiles() const + { + return failedFiles_; + } + +private: + int64_t totalNum_{0}; + std::unordered_set downloadedFiles_; + std::unordered_map failedFiles_; +}; +} // namespace OHOS::FileManagement::CloudSync +#endif // OHOS_FILEMGMT_DOWNLOAD_PROGRESS_ANI_H diff --git a/interfaces/kits/js/ani/file_cloud_sync/include/cloud_download_callback_middle.h b/interfaces/kits/js/ani/file_cloud_sync/include/multi_download_progress_ani.h similarity index 48% rename from interfaces/kits/js/ani/file_cloud_sync/include/cloud_download_callback_middle.h rename to interfaces/kits/js/ani/file_cloud_sync/include/multi_download_progress_ani.h index 53d7b9a05..e0500a2c3 100644 --- a/interfaces/kits/js/ani/file_cloud_sync/include/cloud_download_callback_middle.h +++ b/interfaces/kits/js/ani/file_cloud_sync/include/multi_download_progress_ani.h @@ -4,7 +4,7 @@ * 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 + * 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, @@ -13,18 +13,23 @@ * limitations under the License. */ -#ifndef OHOS_FILEMGMT_CLOUD_DOWNLOAD_CALLBACK_MIDDLE_H -#define OHOS_FILEMGMT_CLOUD_DOWNLOAD_CALLBACK_MIDDLE_H +#ifndef OHOS_FILEMGMT_MULTI_DOWNLOAD_PROGRESS_ANI_H +#define OHOS_FILEMGMT_MULTI_DOWNLOAD_PROGRESS_ANI_H -#include "cloud_download_callback.h" +#include "multi_download_progress_core.h" namespace OHOS::FileManagement::CloudSync { +class MultiDlProgressAni final { +public: + static void Constructor(ani_env *env, ani_object object); + static ani_array_ref GetFailedFileList(ani_env *env, ani_object object); + static ani_array_ref GetDownloadedFileList(ani_env *env, ani_object object); +}; -class CloudDownloadCallbackMiddle : public CloudDownloadCallback { +class MultiDlProgressWrapper final { public: - virtual ~CloudDownloadCallbackMiddle() = default; - virtual void OnDownloadProcess(const DownloadProgressObj &progress) = 0; - virtual void DeleteReference() {}; + static ani_object Wrap(ani_env *env, MultiDlProgressCore *multiDlProgress); + static MultiDlProgressCore *Unwrap(ani_env *env, ani_object object); }; } // namespace OHOS::FileManagement::CloudSync -#endif // OHOS_FILEMGMT_CLOUD_DOWNLOAD_CALLBACK_MIDDLE_H +#endif // OHOS_FILEMGMT_MULTI_DOWNLOAD_PROGRESS_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_download_napi.h b/interfaces/kits/js/ani/file_cloud_sync/include/register_callback_manager_ani.h similarity index 45% rename from interfaces/kits/js/cloudfilesync/cloud_file_download_napi.h rename to interfaces/kits/js/ani/file_cloud_sync/include/register_callback_manager_ani.h index ea22a0070..a8949d8d9 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_download_napi.h +++ b/interfaces/kits/js/ani/file_cloud_sync/include/register_callback_manager_ani.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 @@ -13,18 +13,31 @@ * limitations under the License. */ -#ifndef OHOS_FILEMGMT_CLOUD_FILE_DOWNLOAD_NAPI_H -#define OHOS_FILEMGMT_CLOUD_FILE_DOWNLOAD_NAPI_H +#ifndef OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_ANI_H +#define OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_ANI_H -#include "cloud_file_napi.h" +#include +#include + +#include "ani_utils.h" namespace OHOS::FileManagement::CloudSync { -class CloudFileDownloadNapi final : public CloudFileNapi { +class RegisterCallbackManagerAni { public: - CloudFileDownloadNapi(napi_env env, napi_value exports) : CloudFileNapi(env, exports) {} - ~CloudFileDownloadNapi() = default; + void SetVm(ani_env *env); + bool IsExisted(ani_env *env, ani_ref ref); + ani_status RegisterCallback(ani_env *env, ani_object callback); + ani_status UnregisterCallback(ani_env *env, ani_object callback); + + void OnJsCallback(ani_env *env, ani_object value, uint32_t argc); + ani_env *GetEnv(); + void DetachEnv(); - bool Export() override; +protected: + ani_vm *vm_{nullptr}; + std::recursive_mutex callbackMtx_; + std::atomic validRefNum_{0}; + std::list> callbackList_; }; } // namespace OHOS::FileManagement::CloudSync -#endif // OHOS_FILEMGMT_CLOUD_FILE_DOWNLOAD_NAPI_H \ No newline at end of file +#endif // OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/bind_function_class.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/bind_function_class.cpp index 810383dfc..7295a98a7 100644 --- a/interfaces/kits/js/ani/file_cloud_sync/src/bind_function_class.cpp +++ b/interfaces/kits/js/ani/file_cloud_sync/src/bind_function_class.cpp @@ -20,6 +20,7 @@ #include "cloud_file_cache_ani.h" #include "cloud_sync_ani.h" #include "file_sync_ani.h" +#include "multi_download_progress_ani.h" #include "utils_log.h" using namespace OHOS; @@ -67,9 +68,9 @@ static ani_status BindContextOnGallery(ani_env *env) return ANI_OK; } -static ani_status BindContextOnCloudFileCache(ani_env *env) +static ani_status BindContextOnMultiDlProgress(ani_env *env) { - ani_namespace ns {}; + ani_namespace ns{}; Namespace nsSign = Builder::BuildNamespace("@ohos.file.cloudSync.cloudSync"); ani_status ret = env->FindNamespace(nsSign.Descriptor().c_str(), &ns); if (ret != ANI_OK) { @@ -77,32 +78,86 @@ static ani_status BindContextOnCloudFileCache(ani_env *env) return ret; } - Type clsName = Builder::BuildClass("CloudFileCache"); + Type clsName = Builder::BuildClass("MultiDownloadProgress"); ani_class cls; ret = env->Namespace_FindClass(ns, clsName.Descriptor().c_str(), &cls); if (ret != ANI_OK) { LOGE("find class failed. ret = %{public}d", ret); return ret; } + std::string ct = Builder::BuildConstructorName(); + std::string succSign = Builder::BuildSignatureDescriptor({}, Builder::BuildClass("escompat.Array")); + std::string failSign = Builder::BuildSignatureDescriptor({}, Builder::BuildClass("escompat.Array")); + std::array methods = { + ani_native_function{"getFailedFiles", succSign.c_str(), + reinterpret_cast(MultiDlProgressAni::GetFailedFileList)}, + ani_native_function{"getSuccessfulFiles", failSign.c_str(), + reinterpret_cast(MultiDlProgressAni::GetDownloadedFileList)}, + }; + + ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size()); + if (ret != ANI_OK) { + LOGE("bind native method failed. ret = %{public}d", ret); + return ret; + }; + + return ANI_OK; +} + +static ani_status GetClassName(ani_env *env, ani_class *cls, const char *typeDesc) +{ + ani_namespace ns{}; + Namespace nsSign = Builder::BuildNamespace("@ohos.file.cloudSync.cloudSync"); + ani_status ret = env->FindNamespace(nsSign.Descriptor().c_str(), &ns); + if (ret != ANI_OK) { + LOGE("find namespace failed. ret = %{public}d", ret); + return ret; + } + + Type clsName = Builder::BuildClass(typeDesc); + ret = env->Namespace_FindClass(ns, clsName.Descriptor().c_str(), cls); + if (ret != ANI_OK) { + LOGE("find class failed. ret = %{public}d", ret); + return ret; + } + return ret; +} + +static ani_status BindContextOnCloudFileCache(ani_env *env) +{ + ani_class cls; + ani_status ret = GetClassName(env, &cls, "CloudFileCache"); + if (ret != ANI_OK) { + return ret; + } + std::string ct = Builder::BuildConstructorName(); std::string vSign = Builder::BuildSignatureDescriptor({}); std::string onOffSign = Builder::BuildSignatureDescriptor( {Builder::BuildClass("std.core.String"), Builder::BuildFunctionalObject(1, false)}); std::string sSign = Builder::BuildSignatureDescriptor({Builder::BuildClass("std.core.String")}); - std::string sbSign = Builder::BuildSignatureDescriptor( - {Builder::BuildClass("std.core.String"), Builder::BuildBoolean()}); + std::string startBatchSign = Builder::BuildSignatureDescriptor( + {Builder::BuildClass("escompat.Array"), Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadFileType")}, + {Builder::BuildDouble()}); + std::string sbSign = + Builder::BuildSignatureDescriptor({Builder::BuildClass("std.core.String"), Builder::BuildBoolean()}); + std::string stopBatchSign = Builder::BuildSignatureDescriptor({Builder::BuildDouble(), Builder::BuildBoolean()}); std::array methods = { ani_native_function{ct.c_str(), vSign.c_str(), - reinterpret_cast(CloudFileCacheAni::CloudFileCacheConstructor)}, + reinterpret_cast(CloudFileCacheAni::CloudFileCacheConstructor)}, ani_native_function{"on", onOffSign.c_str(), reinterpret_cast(CloudFileCacheAni::CloudFileCacheOn)}, ani_native_function{"off", onOffSign.c_str(), reinterpret_cast(CloudFileCacheAni::CloudFileCacheOff0)}, ani_native_function{"off", sSign.c_str(), reinterpret_cast(CloudFileCacheAni::CloudFileCacheOff1)}, ani_native_function{"CloudFileCacheStart", sSign.c_str(), - reinterpret_cast(CloudFileCacheAni::CloudFileCacheStart)}, + reinterpret_cast(CloudFileCacheAni::CloudFileCacheStart)}, + ani_native_function{"CloudFileCacheStartBatch", startBatchSign.c_str(), + reinterpret_cast(CloudFileCacheAni::CloudFileCacheStartBatch)}, ani_native_function{"CloudFileCacheStop", sbSign.c_str(), - reinterpret_cast(CloudFileCacheAni::CloudFileCacheStop)}, + reinterpret_cast(CloudFileCacheAni::CloudFileCacheStop)}, + ani_native_function{"CloudFileCacheStopBatch", stopBatchSign.c_str(), + reinterpret_cast(CloudFileCacheAni::CloudFileCacheStopBatch)}, ani_native_function{"cleanCache", sSign.c_str(), - reinterpret_cast(CloudFileCacheAni::CloudFileCacheCleanCache)}, + reinterpret_cast(CloudFileCacheAni::CloudFileCacheCleanCache)}, }; ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size()); @@ -181,22 +236,22 @@ static ani_status BindContextOnStaticFunction(ani_env *env) {Builder::BuildClass("std.core.String"), Builder::BuildBoolean(), Builder::BuildFunctionalObject(1, false)}); std::string sSign = Builder::BuildSignatureDescriptor({Builder::BuildClass("std.core.String")}); std::string vSign = Builder::BuildSignatureDescriptor({}); - std::string optfSign = Builder::BuildSignatureDescriptor({ - Builder::BuildClass("@ohos.file.cloudSync.cloudSync.OptimizeSpaceParam"), - Builder::BuildFunctionalObject(1, false)}); + std::string optfSign = + Builder::BuildSignatureDescriptor({Builder::BuildClass("@ohos.file.cloudSync.cloudSync.OptimizeSpaceParam"), + Builder::BuildFunctionalObject(1, false)}); std::array methods = { ani_native_function{"getFileSyncStateInner", siSign.c_str(), - reinterpret_cast(CloudSyncAni::GetFileSyncState)}, + reinterpret_cast(CloudSyncAni::GetFileSyncState)}, ani_native_function{"registerChangeInner", sbfSign.c_str(), - reinterpret_cast(CloudSyncAni::RegisterChange)}, + reinterpret_cast(CloudSyncAni::RegisterChange)}, ani_native_function{"unregisterChangeInner", sSign.c_str(), - reinterpret_cast(CloudSyncAni::UnRegisterChange)}, + reinterpret_cast(CloudSyncAni::UnRegisterChange)}, ani_native_function{"optimizeStorageInner", vSign.c_str(), - reinterpret_cast(CloudSyncAni::OptimizeStorage)}, + reinterpret_cast(CloudSyncAni::OptimizeStorage)}, ani_native_function{"startOptimizeSpaceInner", optfSign.c_str(), - reinterpret_cast(CloudSyncAni::StartOptimizeStorage)}, + reinterpret_cast(CloudSyncAni::StartOptimizeStorage)}, ani_native_function{"stopOptimizeSpaceInner", vSign.c_str(), - reinterpret_cast(CloudSyncAni::StopOptimizeStorage)}, + reinterpret_cast(CloudSyncAni::StopOptimizeStorage)}, }; ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size()); @@ -231,8 +286,7 @@ static ani_status BindContextOnDownload(ani_env *env) {Builder::BuildClass("std.core.String"), Builder::BuildFunctionalObject(1, false)}); std::string sSign = Builder::BuildSignatureDescriptor({Builder::BuildClass("std.core.String")}); std::array methods = { - ani_native_function{ct.c_str(), vSign.c_str(), - reinterpret_cast(CloudDownloadAni::DownloadConstructor)}, + ani_native_function{ct.c_str(), vSign.c_str(), reinterpret_cast(CloudDownloadAni::DownloadConstructor)}, ani_native_function{"on", onOffSign.c_str(), reinterpret_cast(CloudDownloadAni::DownloadOn)}, ani_native_function{"off", onOffSign.c_str(), reinterpret_cast(CloudDownloadAni::DownloadOff0)}, ani_native_function{"off", sSign.c_str(), reinterpret_cast(CloudDownloadAni::DownloadOff1)}, @@ -261,6 +315,10 @@ ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) if (status != ANI_OK) { return status; } + status = BindContextOnMultiDlProgress(env); + if (status != ANI_OK) { + return status; + } status = BindContextOnCloudFileCache(env); if (status != ANI_OK) { return status; diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/cloud_download_ani.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/cloud_download_ani.cpp index 9f293bb58..97f921d65 100644 --- a/interfaces/kits/js/ani/file_cloud_sync/src/cloud_download_ani.cpp +++ b/interfaces/kits/js/ani/file_cloud_sync/src/cloud_download_ani.cpp @@ -16,15 +16,14 @@ #include "cloud_download_ani.h" #include "ani_utils.h" +#include "dfsu_access_token_helper.h" +#include "dfs_error.h" #include "error_handler.h" #include "utils_log.h" namespace OHOS::FileManagement::CloudSync { - using namespace arkts::ani_signature; -const int32_t E_IPCSS = 13600001; - static CloudFileCore *CloudDownloadUnwrap(ani_env *env, ani_object object) { ani_long nativePtr; @@ -38,6 +37,19 @@ static CloudFileCore *CloudDownloadUnwrap(ani_env *env, ani_object object) return cloudDownload; } +static int32_t CheckPermissions(const string &permission, bool isSystemApp) +{ + if (!permission.empty() && !DfsuAccessTokenHelper::CheckCallerPermission(permission)) { + LOGE("permission denied"); + return JsErrCode::E_PERMISSION; + } + if (isSystemApp && !DfsuAccessTokenHelper::IsSystemApp()) { + LOGE("caller hap is not system hap"); + return JsErrCode::E_PERMISSION_SYS; + } + return E_OK; +} + void CloudDownloadAni::DownloadConstructor(ani_env *env, ani_object object) { ani_namespace ns {}; @@ -85,87 +97,81 @@ void CloudDownloadAni::DownloadConstructor(ani_env *env, ani_object object) void CloudDownloadAni::DownloadOn(ani_env *env, ani_object object, ani_string evt, ani_object fun) { - ani_ref cbOnRef; - ani_status ret = env->GlobalReference_Create(reinterpret_cast(fun), &cbOnRef); + std::string event; + ani_status ret = ANIUtils::AniString2String(env, evt, event); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; + } + if (event != "progress") { + LOGE("Invalid argument for event type."); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - auto callback = std::make_shared(env, cbOnRef); - std::string event; - ret = ANIUtils::AniString2String(env, evt, event); - if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + int32_t res = CheckPermissions(PERM_CLOUD_SYNC, true); + if (res != E_OK) { + LOGE("On get progress failed!"); + ErrorHandler::Throw(env, res); return; } auto cloudDownload = CloudDownloadUnwrap(env, object); if (cloudDownload == nullptr) { LOGE("Cannot wrap cloudDownload."); - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - auto data = cloudDownload->DoOn(event, callback); - if (!data.IsSuccess()) { - const auto &err = data.GetError(); - LOGE("cloud download do on failed, ret = %{public}d", err.GetErrNo()); - ErrorHandler::Throw(env, err); + + std::shared_ptr callbackImpl = cloudDownload->GetCallbackImpl(true); + callbackImpl->SetVm(env); + auto status = callbackImpl->RegisterCallback(env, fun); + if (status != ANI_OK) { + LOGE("Failed to register callback, status: %{public}d.", status); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; } } void CloudDownloadAni::DownloadOff0(ani_env *env, ani_object object, ani_string evt, ani_object fun) { - ani_ref cbOnRef; - ani_status ret = env->GlobalReference_Create(reinterpret_cast(fun), &cbOnRef); + std::string event; + ani_status ret = ANIUtils::AniString2String(env, evt, event); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; + } + if (event != "progress") { + LOGE("Invalid argument for event type."); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - auto callback = std::make_shared(env, cbOnRef); - std::string event; - ret = ANIUtils::AniString2String(env, evt, event); - if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + int32_t res = CheckPermissions(PERM_CLOUD_SYNC, true); + if (res != E_OK) { + LOGE("On get progress failed!"); + ErrorHandler::Throw(env, res); return; } auto cloudDownload = CloudDownloadUnwrap(env, object); if (cloudDownload == nullptr) { LOGE("Cannot wrap cloudDownload."); - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - auto data = cloudDownload->DoOff(event, callback); - if (!data.IsSuccess()) { - const auto &err = data.GetError(); - LOGE("cloud download do off failed, ret = %{public}d", err.GetErrNo()); - ErrorHandler::Throw(env, err); + + std::shared_ptr callbackImpl = cloudDownload->GetCallbackImpl(false); + if (callbackImpl == nullptr || callbackImpl->UnregisterCallback(env, fun) != ANI_OK) { + LOGE("Failed to unregister callback"); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; } } void CloudDownloadAni::DownloadOff1(ani_env *env, ani_object object, ani_string evt) { - std::string event; - ani_status ret = ANIUtils::AniString2String(env, evt, event); - if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); - return; - } - - auto cloudDownload = CloudDownloadUnwrap(env, object); - if (cloudDownload == nullptr) { - LOGE("Cannot wrap cloudDownload."); - ErrorHandler::Throw(env, E_IPCSS); - return; - } - auto data = cloudDownload->DoOff(event); - if (!data.IsSuccess()) { - const auto &err = data.GetError(); - LOGE("cloud download do off failed, ret = %{public}d", err.GetErrNo()); - ErrorHandler::Throw(env, err); - } + DownloadOff0(env, object, evt, nullptr); } void CloudDownloadAni::DownloadStart(ani_env *env, ani_object object, ani_string uri) @@ -173,16 +179,18 @@ void CloudDownloadAni::DownloadStart(ani_env *env, ani_object object, ani_string std::string uriInput; ani_status ret = ANIUtils::AniString2String(env, uri, uriInput); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_PERMISSION); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } auto cloudDownload = CloudDownloadUnwrap(env, object); if (cloudDownload == nullptr) { LOGE("Cannot wrap cloudDownload."); - ErrorHandler::Throw(env, E_PERMISSION); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } + std::shared_ptr callbackImpl = cloudDownload->GetCallbackImpl(true); + callbackImpl->SetVm(env); auto data = cloudDownload->DoStart(uriInput); if (!data.IsSuccess()) { const auto &err = data.GetError(); @@ -196,16 +204,23 @@ void CloudDownloadAni::DownloadStop(ani_env *env, ani_object object, ani_string std::string uriInput; ani_status ret = ANIUtils::AniString2String(env, uri, uriInput); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_PERMISSION); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } auto cloudDownload = CloudDownloadUnwrap(env, object); if (cloudDownload == nullptr) { LOGE("Cannot wrap cloudDownload."); - ErrorHandler::Throw(env, E_PERMISSION); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } + std::shared_ptr callbackImpl = cloudDownload->GetCallbackImpl(false); + if (callbackImpl == nullptr) { + LOGE("Cannot get callbackImpl before stop."); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; + } + auto data = cloudDownload->DoStop(uriInput); if (!data.IsSuccess()) { const auto &err = data.GetError(); @@ -213,4 +228,4 @@ void CloudDownloadAni::DownloadStop(ani_env *env, ani_object object, ani_string ErrorHandler::Throw(env, err); } } -} \ No newline at end of file +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/cloud_download_callback_ani.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/cloud_download_callback_ani.cpp deleted file mode 100644 index 3e727b17d..000000000 --- a/interfaces/kits/js/ani/file_cloud_sync/src/cloud_download_callback_ani.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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_download_callback_ani.h" - -#include "ani_utils.h" -#include "utils_log.h" - -namespace OHOS::FileManagement::CloudSync { - -using namespace arkts::ani_signature; -constexpr int32_t ANI_SCOPE_SIZE = 16; - -CloudDownloadCallbackAniImpl::CloudDownloadCallbackAniImpl(ani_env *env, ani_ref fun, bool isBatch) -{ - env_ = env; - if (fun != nullptr) { - cbOnRef_ = fun; - } - isBatch_ = isBatch; -} - -void CloudDownloadCallbackAniImpl::GetDownloadProgress( - const DownloadProgressObj &progress, const ani_class &cls, ani_object &pg) -{ - ani_method ctor; - std::string ct = Builder::BuildConstructorName(); - std::string argSign = Builder::BuildSignatureDescriptor({ - Builder::BuildDouble(), Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.State"), - Builder::BuildDouble(), Builder::BuildDouble(), Builder::BuildClass("std.core.String"), - Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadErrorType") - }); - ani_status ret = env_->Class_FindMethod(cls, ct.c_str(), argSign.c_str(), &ctor); - if (ret != ANI_OK) { - LOGE("find ctor method failed. ret = %{public}d", ret); - return; - } - ani_string uri = nullptr; - ret = env_->String_NewUTF8(progress.path.c_str(), progress.path.size(), &uri); - if (ret != ANI_OK) { - LOGE("get uri failed. ret = %{public}d", ret); - return; - } - - ani_enum stateEnum; - Type stateSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.State"); - env_->FindEnum(stateSign.Descriptor().c_str(), &stateEnum); - ani_enum downloadErrorEnum; - Type errorSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadErrorType"); - env_->FindEnum(errorSign.Descriptor().c_str(), &downloadErrorEnum); - - ani_enum_item stateEnumItem; - ani_enum_item downloadErrorEnumItem; - env_->Enum_GetEnumItemByIndex(downloadErrorEnum, progress.downloadErrorType, &downloadErrorEnumItem); - - if (!isBatch_) { - env_->Enum_GetEnumItemByIndex(stateEnum, progress.state, &stateEnumItem); - ret = env_->Object_New(cls, ctor, &pg, static_cast(progress.downloadId), stateEnumItem, - static_cast(progress.downloadedSize), static_cast(progress.totalSize), uri, - downloadErrorEnumItem); - } else { - env_->Enum_GetEnumItemByIndex(stateEnum, progress.batchState, &stateEnumItem); - ret = env_->Object_New(cls, ctor, &pg, static_cast(progress.downloadId), stateEnumItem, - static_cast(progress.batchDownloadSize), static_cast(progress.batchTotalSize), - static_cast(progress.batchSuccNum), static_cast(progress.batchFailNum), - static_cast(progress.batchTotalNum), downloadErrorEnumItem); - } - - if (ret != ANI_OK) { - LOGE("create new object failed. ret = %{public}d", ret); - } -} - -void CloudDownloadCallbackAniImpl::OnDownloadProcess(const DownloadProgressObj &progress) -{ - auto task = [this, progress]() { - LOGI("CloudDownloadCallbackAniImpl OnDownloadProcess"); - ani_env *tmpEnv = env_; - ani_size nr_refs = ANI_SCOPE_SIZE; - ani_status ret = tmpEnv->CreateLocalScope(nr_refs); - if (ret != ANI_OK) { - LOGE("crete local scope failed. ret = %{public}d", ret); - return; - } - ani_namespace ns {}; - Namespace nsSign = Builder::BuildNamespace("@ohos.file.cloudSync.cloudSync"); - ret = tmpEnv->FindNamespace(nsSign.Descriptor().c_str(), &ns); - if (ret != ANI_OK) { - LOGE("find namespace failed. ret = %{public}d", ret); - return; - } - Type clsName = Builder::BuildClass("DownloadProgressInner"); - ani_class cls; - ret = tmpEnv->Namespace_FindClass(ns, clsName.Descriptor().c_str(), &cls); - if (ret != ANI_OK) { - LOGE("find class failed. ret = %{public}d", ret); - return; - } - ani_object pg; - GetDownloadProgress(progress, cls, pg); - ani_ref ref_; - ani_fn_object etsCb = reinterpret_cast(cbOnRef_); - std::vector vec = { pg }; - ret = tmpEnv->FunctionalObject_Call(etsCb, 1, vec.data(), &ref_); - if (ret != ANI_OK) { - LOGE("ani call function failed. ret = %{public}d", ret); - return; - } - ret = tmpEnv->DestroyLocalScope(); - if (ret != ANI_OK) { - LOGE("failed to DestroyLocalScope. ret = %{public}d", ret); - } - }; - if (!ANIUtils::SendEventToMainThread(task)) { - LOGE("failed to send event"); - } -} - -void CloudDownloadCallbackAniImpl::DeleteReference() -{ - if (cbOnRef_ != nullptr) { - env_->GlobalReference_Delete(cbOnRef_); - cbOnRef_ = nullptr; - } -} -} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/cloud_file_cache_ani.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/cloud_file_cache_ani.cpp index a3f654561..aaae6131c 100644 --- a/interfaces/kits/js/ani/file_cloud_sync/src/cloud_file_cache_ani.cpp +++ b/interfaces/kits/js/ani/file_cloud_sync/src/cloud_file_cache_ani.cpp @@ -16,6 +16,7 @@ #include "cloud_file_cache_ani.h" #include "ani_utils.h" +#include "dfs_error.h" #include "error_handler.h" #include "utils_log.h" @@ -23,8 +24,6 @@ namespace OHOS::FileManagement::CloudSync { using namespace arkts::ani_signature; -const int32_t E_IPCSS = 13600001; - static CloudFileCacheCore *CloudFileCacheUnwrap(ani_env *env, ani_object object) { ani_long nativePtr; @@ -88,112 +87,132 @@ void CloudFileCacheAni::CloudFileCacheOn(ani_env *env, ani_object object, ani_st std::string event; ani_status ret = ANIUtils::AniString2String(env, evt, event); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - ani_ref cbOnRef; - ret = env->GlobalReference_Create(reinterpret_cast(fun), &cbOnRef); - if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); - return; + if (event == "multiProgress") { + event = MULTI_PROGRESS; } - std::shared_ptr callback = nullptr; - if (event == "progress") { - callback = std::make_shared(env, cbOnRef); - } else if (event == "multiProgress") { - callback = std::make_shared(env, cbOnRef, true); + if (event != PROGRESS && event != MULTI_PROGRESS) { + LOGE("Invalid argument for event type."); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; } auto cloudFileCache = CloudFileCacheUnwrap(env, object); if (cloudFileCache == nullptr) { LOGE("Cannot wrap cloudFileCache."); - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - auto data = cloudFileCache->DoOn(event, callback); - if (!data.IsSuccess()) { - const auto &err = data.GetError(); - LOGE("cloudFileCache do on failed, ret = %{public}d", err.GetErrNo()); - ErrorHandler::Throw(env, err); + + std::shared_ptr callbackImpl = cloudFileCache->GetCallbackImpl(event, true); + callbackImpl->SetVm(env); + auto status = callbackImpl->RegisterCallback(env, fun); + if (status != ANI_OK) { + LOGE("Failed to register callback, status: %{public}d.", status); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; } } void CloudFileCacheAni::CloudFileCacheOff0(ani_env *env, ani_object object, ani_string evt, ani_object fun) { - ani_ref cbOnRef; - ani_status ret = env->GlobalReference_Create(reinterpret_cast(fun), &cbOnRef); + std::string event; + ani_status ret = ANIUtils::AniString2String(env, evt, event); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - auto callback = std::make_shared(env, cbOnRef); - std::string event; - ret = ANIUtils::AniString2String(env, evt, event); - if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + if (event == "multiProgress") { + event = MULTI_PROGRESS; + } + if (event != PROGRESS && event == MULTI_PROGRESS) { + LOGE("Invalid argument for event type."); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } auto cloudFileCache = CloudFileCacheUnwrap(env, object); if (cloudFileCache == nullptr) { LOGE("Cannot wrap cloudFileCache."); - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - auto data = cloudFileCache->DoOff(event, callback); - if (!data.IsSuccess()) { - const auto &err = data.GetError(); - LOGE("cloudFileCache do off failed, ret = %{public}d", err.GetErrNo()); - ErrorHandler::Throw(env, err); + + std::shared_ptr callbackImpl = cloudFileCache->GetCallbackImpl(event, false); + if (callbackImpl == nullptr || callbackImpl->UnregisterCallback(env, fun) != ANI_OK) { + LOGE("Failed to unregister callback."); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; } } void CloudFileCacheAni::CloudFileCacheOff1(ani_env *env, ani_object object, ani_string evt) { - std::string event; - ani_status ret = ANIUtils::AniString2String(env, evt, event); + CloudFileCacheOff0(env, object, evt, nullptr); +} + +void CloudFileCacheAni::CloudFileCacheStart(ani_env *env, ani_object object, ani_string uri) +{ + std::string uriInput; + ani_status ret = ANIUtils::AniString2String(env, uri, uriInput); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } auto cloudFileCache = CloudFileCacheUnwrap(env, object); if (cloudFileCache == nullptr) { LOGE("Cannot wrap cloudFileCache."); - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } - auto data = cloudFileCache->DoOff(event); + auto data = cloudFileCache->DoStart(uriInput); if (!data.IsSuccess()) { const auto &err = data.GetError(); - LOGE("cloudFileCache do off failed, ret = %{public}d", err.GetErrNo()); + LOGE("cloudFileCache do start failed, ret = %{public}d", err.GetErrNo()); ErrorHandler::Throw(env, err); } } -void CloudFileCacheAni::CloudFileCacheStart(ani_env *env, ani_object object, ani_string uri) +ani_double CloudFileCacheAni::CloudFileCacheStartBatch(ani_env *env, + ani_object object, + ani_array_ref uriList, + ani_enum_item fileType) { - std::string uriInput; - ani_status ret = ANIUtils::AniString2String(env, uri, uriInput); - if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); - return; + ani_double errResult = 0; + auto [ret, urisInput] = ANIUtils::AniToStringArray(env, uriList); + if (!ret) { + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return errResult; + } + + int32_t fieldKey = static_cast(FieldKey::FIELDKEY_CONTENT); + tie(ret, fieldKey) = ANIUtils::EnumToInt32(env, fileType); + if (!ret) { + LOGE("cloudFileCache get fileType failed"); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return errResult; } auto cloudFileCache = CloudFileCacheUnwrap(env, object); if (cloudFileCache == nullptr) { LOGE("Cannot wrap cloudFileCache."); - ErrorHandler::Throw(env, E_IPCSS); - return; + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return errResult; } - auto data = cloudFileCache->DoStart(uriInput); + auto data = cloudFileCache->DoStart(urisInput, fieldKey); if (!data.IsSuccess()) { const auto &err = data.GetError(); LOGE("cloudFileCache do start failed, ret = %{public}d", err.GetErrNo()); ErrorHandler::Throw(env, err); + return errResult; } + + return static_cast(data.GetData().value()); } void CloudFileCacheAni::CloudFileCacheStop(ani_env *env, ani_object object, ani_string uri, ani_boolean needClean) @@ -201,14 +220,14 @@ void CloudFileCacheAni::CloudFileCacheStop(ani_env *env, ani_object object, ani_ std::string uriInput; ani_status ret = ANIUtils::AniString2String(env, uri, uriInput); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } auto cloudFileCache = CloudFileCacheUnwrap(env, object); if (cloudFileCache == nullptr) { LOGE("Cannot wrap cloudFileCache."); - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } @@ -222,19 +241,41 @@ void CloudFileCacheAni::CloudFileCacheStop(ani_env *env, ani_object object, ani_ } } +void CloudFileCacheAni::CloudFileCacheStopBatch(ani_env *env, + ani_object object, + ani_double taskId, + ani_boolean needClean) +{ + auto cloudFileCache = CloudFileCacheUnwrap(env, object); + if (cloudFileCache == nullptr) { + LOGE("Cannot wrap cloudFileCache."); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); + return; + } + + bool needCleanInput = needClean; + + auto data = cloudFileCache->DoStop(static_cast(taskId), needCleanInput); + if (!data.IsSuccess()) { + const auto &err = data.GetError(); + LOGE("cloudFileCache do stop failed, ret = %{public}d", err.GetErrNo()); + ErrorHandler::Throw(env, err); + } +} + void CloudFileCacheAni::CloudFileCacheCleanCache(ani_env *env, ani_object object, ani_string uri) { std::string uriInput; ani_status ret = ANIUtils::AniString2String(env, uri, uriInput); if (ret != ANI_OK) { - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } auto cloudFileCache = CloudFileCacheUnwrap(env, object); if (cloudFileCache == nullptr) { LOGE("Cannot wrap cloudFileCache."); - ErrorHandler::Throw(env, E_IPCSS); + ErrorHandler::Throw(env, JsErrCode::E_IPCSS); return; } auto data = cloudFileCache->CleanCache(uriInput); diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/download_callback_impl_ani.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/download_callback_impl_ani.cpp new file mode 100644 index 000000000..2137fc343 --- /dev/null +++ b/interfaces/kits/js/ani/file_cloud_sync/src/download_callback_impl_ani.cpp @@ -0,0 +1,109 @@ +/* + * 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 "download_callback_impl_ani.h" +#include "cloud_sync_manager.h" +#include "dfs_error.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudSync { +int32_t CloudDownloadCallbackImplAni::StartDownloadInner(const std::string &uri) +{ + int64_t downloadId = 0; + std::lock_guard lock(downloadInfoMtx_); + int32_t ret = CloudSyncManager::GetInstance().StartDownloadFile(uri, shared_from_this(), downloadId); + if (ret != E_OK) { + LOGE("Start batch download failed! ret = %{public}d", ret); + return ret; + } + + downloadInfos_.insert(std::make_pair(downloadId, std::make_shared(downloadId))); + return ret; +} + +int32_t CloudDownloadCallbackImplAni::StopDownloadInner(const std::string &uri) +{ + auto downloadIdList = GetDownloadIdsByUri(uri); + int32_t ret = E_OK; + int32_t resErr = E_OK; + LOGI("Stop Download downloadId list size: %{public}zu", downloadIdList.size()); + for (auto taskId : downloadIdList) { + resErr = CloudSyncManager::GetInstance().StopDownloadFile(taskId, true); + if (resErr != E_OK) { + ret = resErr; + continue; + } + } + if (ret != E_OK) { + LOGE("Stop Download failed! ret = %{public}d", ret); + } + return ret; +} + +int32_t CloudFileCacheCallbackImplAni::StartDownloadInner(const std::string &uri, int32_t fieldKey) +{ + int64_t downloadId = 0; + std::lock_guard lock(downloadInfoMtx_); + int32_t ret = CloudSyncManager::GetInstance().StartFileCache({uri}, downloadId, fieldKey, shared_from_this()); + if (ret != E_OK) { + LOGE("Start single download failed! ret = %{public}d", ret); + return ret; + } + downloadInfos_.insert(std::make_pair(downloadId, std::make_shared(downloadId))); + return ret; +} + +int32_t CloudFileCacheCallbackImplAni::StopDownloadInner(const std::string &uri, bool needClean) +{ + auto downloadIdList = GetDownloadIdsByUri(uri); + int32_t ret = E_OK; + int32_t resErr = E_OK; + LOGI("Stop Download downloadId list size: %{public}zu", downloadIdList.size()); + for (auto taskId : downloadIdList) { + resErr = CloudSyncManager::GetInstance().StopFileCache(taskId, needClean); + if (resErr != E_OK) { + ret = resErr; + continue; + } + } + if (ret != E_OK) { + LOGE("Stop Download failed! ret = %{public}d", ret); + } + return ret; +} + +int32_t CloudFileCacheCallbackImplAni::StartDownloadInner(const std::vector &uriVec, + int64_t &downloadId, + int32_t fieldKey) +{ + std::unique_lock lock(downloadInfoMtx_); + int32_t ret = CloudSyncManager::GetInstance().StartFileCache(uriVec, downloadId, fieldKey, shared_from_this()); + if (ret != E_OK) { + LOGE("Start batch download failed! ret = %{public}d", ret); + return ret; + } + downloadInfos_.insert(std::make_pair(downloadId, std::make_shared(downloadId))); + return ret; +} + +int32_t CloudFileCacheCallbackImplAni::StopDownloadInner(int64_t downloadId, bool needClean) +{ + int32_t ret = CloudSyncManager::GetInstance().StopFileCache(downloadId, needClean); + if (ret != E_OK) { + LOGE("Batch stop file cache failed! ret = %{public}d", ret); + } + return ret; +} +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/download_callback_middle_ani.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/download_callback_middle_ani.cpp new file mode 100644 index 000000000..9b405475d --- /dev/null +++ b/interfaces/kits/js/ani/file_cloud_sync/src/download_callback_middle_ani.cpp @@ -0,0 +1,92 @@ +/* + * 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 "download_callback_middle_ani.h" +#include "dfs_error.h" +#include "multi_download_progress_ani.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudSync { +constexpr int32_t ANI_SCOPE_SIZE = 16; +void CloudDlCallbackMiddleAni::RemoveDownloadInfo(int64_t downloadId) +{ + std::lock_guard lock(downloadInfoMtx_); + downloadInfos_.erase(downloadId); +} + +std::shared_ptr CloudDlCallbackMiddleAni::GetDownloadInfo(int64_t downloadId) +{ + std::lock_guard lock(downloadInfoMtx_); + auto it = downloadInfos_.find(downloadId); + if (it != downloadInfos_.end()) { + return it->second; + } + return nullptr; +} + +std::vector CloudDlCallbackMiddleAni::GetDownloadIdsByUri(const std::string &uri) +{ + std::vector ids; + std::lock_guard lock(downloadInfoMtx_); + for (const auto &[id, progress] : downloadInfos_) { + if (progress->GetUri() == uri) { + ids.push_back(id); + } + } + return ids; +} + +void CloudDlCallbackMiddleAni::OnDownloadProcess(const DownloadProgressObj &progress) +{ + auto fileCacheInfo = GetDownloadInfo(progress.downloadId); + if (fileCacheInfo == nullptr) { + LOGE("Failed to callback, no such taskId: %{public}lld", static_cast(progress.downloadId)); + return; + } + fileCacheInfo->Update(progress); + std::shared_ptr callbackImpl = shared_from_this(); + auto task = [fileCacheInfo, callbackImpl]() mutable { + if (fileCacheInfo == nullptr || callbackImpl == nullptr) { + LOGE("Failed to callback, is callbackImpl null: %{public}d", (callbackImpl == nullptr)); + return; + } + LOGI("CloudDownloadCallbackAniImpl OnDownloadProcess"); + ani_env *tmpEnv = callbackImpl->GetEnv(); + if (tmpEnv == nullptr) { + LOGE("Failed to get env from vm"); + return; + } + ani_size nr_refs = ANI_SCOPE_SIZE; + ani_status ret = tmpEnv->CreateLocalScope(nr_refs); + if (ret != ANI_OK) { + LOGE("crete local scope failed. ret = %{public}d", ret); + return; + } + ani_object pg = fileCacheInfo->ConvertToObject(tmpEnv); + callbackImpl->OnJsCallback(tmpEnv, pg, 1); + ret = tmpEnv->DestroyLocalScope(); + if (ret != ANI_OK) { + LOGE("failed to DestroyLocalScope. ret = %{public}d", ret); + } + if (fileCacheInfo->IsNeedClean()) { + callbackImpl->RemoveDownloadInfo(fileCacheInfo->GetTaskId()); + } + callbackImpl->DetachEnv(); + }; + if (!ANIUtils::SendEventToMainThread(task)) { + LOGE("failed to send event"); + } +} +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/download_progress_ani.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/download_progress_ani.cpp new file mode 100644 index 000000000..88c6511f5 --- /dev/null +++ b/interfaces/kits/js/ani/file_cloud_sync/src/download_progress_ani.cpp @@ -0,0 +1,119 @@ +/* + * 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 "download_progress_ani.h" +#include "error_handler.h" +#include "multi_download_progress_ani.h" + +namespace OHOS::FileManagement::CloudSync { +using namespace arkts::ani_signature; +void SingleProgressAni::Update(const DownloadProgressObj &progress) +{ + if (taskId_ != progress.downloadId) { + return; + } + uri_ = progress.path; + totalSize_ = progress.totalSize; + downloadedSize_ = progress.downloadedSize; + state_ = progress.state; + errorType_ = progress.downloadErrorType; + needClean_ = (progress.state != DownloadProgressObj::RUNNING); +} + +ani_object SingleProgressAni::ConvertToObject(ani_env *env) +{ + ani_class cls; + ani_status ret; + std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.DownloadProgressInner").Descriptor(); + if ((ret = env->FindClass(classDesc.c_str(), &cls)) != ANI_OK) { + LOGE("Cannot find class %{private}s, err: %{public}d", classDesc.c_str(), ret); + return nullptr; + } + + ani_method ctor; + std::string ct = Builder::BuildConstructorName(); + std::string argSign = Builder::BuildSignatureDescriptor( + {Builder::BuildDouble(), Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.State"), Builder::BuildDouble(), + Builder::BuildDouble(), Builder::BuildClass("std.core.String"), + Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadErrorType")}); + ret = env->Class_FindMethod(cls, ct.c_str(), argSign.c_str(), &ctor); + if (ret != ANI_OK) { + LOGE("find ctor method failed. ret = %{public}d", ret); + return nullptr; + } + ani_string uri = nullptr; + ret = env->String_NewUTF8(uri_.c_str(), uri_.size(), &uri); + if (ret != ANI_OK) { + LOGE("get uri failed. ret = %{public}d", ret); + return nullptr; + } + + ani_enum stateEnum; + Type stateSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.State"); + env->FindEnum(stateSign.Descriptor().c_str(), &stateEnum); + ani_enum downloadErrorEnum; + Type errorSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadErrorType"); + env->FindEnum(errorSign.Descriptor().c_str(), &downloadErrorEnum); + + ani_enum_item stateEnumItem; + ani_enum_item downloadErrorEnumItem; + env->Enum_GetEnumItemByIndex(downloadErrorEnum, errorType_, &downloadErrorEnumItem); + env->Enum_GetEnumItemByIndex(stateEnum, state_, &stateEnumItem); + ani_object pg; + ret = env->Object_New(cls, ctor, &pg, static_cast(taskId_), stateEnumItem, + static_cast(downloadedSize_), static_cast(totalSize_), uri, + downloadErrorEnumItem); + if (ret != ANI_OK) { + LOGE("create new object failed. ret = %{public}d", ret); + } + return pg; +} + +void BatchProgressAni::Update(const DownloadProgressObj &progress) +{ + if (taskId_ != progress.downloadId) { + return; + } + state_ = static_cast(progress.batchState); + taskId_ = progress.downloadId; + downloadedSize_ = progress.batchDownloadSize; + totalSize_ = progress.batchTotalSize; + totalNum_ = progress.batchTotalNum; + errorType_ = static_cast(progress.downloadErrorType); + if (progress.state == DownloadProgressObj::COMPLETED) { + downloadedFiles_.insert(progress.path); + } else if (progress.state != DownloadProgressObj::RUNNING) { + failedFiles_.insert(std::make_pair(progress.path, static_cast(progress.downloadErrorType))); + } + needClean_ = ((progress.batchTotalNum == progress.batchFailNum + progress.batchSuccNum) && + progress.batchState != DownloadProgressObj::RUNNING); +} + +ani_object BatchProgressAni::ConvertToObject(ani_env *env) +{ + ModuleFileIO::FsResult data = MultiDlProgressCore::Constructor(); + if (!data.IsSuccess()) { + return nullptr; + } + MultiDlProgressCore *multiProgress = data.GetData().value(); + multiProgress->SetProgress(shared_from_this()); + + ani_object pg = MultiDlProgressWrapper::Wrap(env, multiProgress); + if (pg == nullptr) { + delete multiProgress; + } + return pg; +} +} // namespace OHOS::FileManagement::CloudSync diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/multi_download_progress_ani.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/multi_download_progress_ani.cpp new file mode 100644 index 000000000..2252f6bef --- /dev/null +++ b/interfaces/kits/js/ani/file_cloud_sync/src/multi_download_progress_ani.cpp @@ -0,0 +1,331 @@ +/* + * 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 "multi_download_progress_ani.h" + +#include "ani_utils.h" +#include "dfs_error.h" +#include "error_handler.h" +#include "multi_download_progress_core.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudSync { +using namespace arkts::ani_signature; +using namespace std; +const static string STATE_SETTER = Builder::BuildSetterName("state"); +const static string TAKSKID_SETTER = Builder::BuildSetterName("taskId"); +const static string SUCC_COUNT_SETTER = Builder::BuildSetterName("successfulCount"); +const static string FAILED_COUNT_SETTER = Builder::BuildSetterName("failedCount"); +const static string TOTAL_COUNT_SETTER = Builder::BuildSetterName("totalCount"); +const static string DOWNLOAD_SIZE_SETTER = Builder::BuildSetterName("downloadedSize"); +const static string TOTAL_SIZE_SETTER = Builder::BuildSetterName("totalSize"); +const static string ERROR_SETTER = Builder::BuildSetterName("errType"); + +static ani_status SetEnumState(ani_env *env, const ani_class &cls, ani_object &object, const char *name, int32_t value) +{ + ani_method setter; + ani_status ret; + if ((ret = env->Class_FindMethod(cls, name, nullptr, &setter)) != ANI_OK) { + LOGE("Class_FindMethod Fail %{public}s, err: %{public}d", name, ret); + return ret; + } + ani_enum stateEnum; + std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.State").Descriptor(); + ret = env->FindEnum(classDesc.c_str(), &stateEnum); + if (ret != ANI_OK) { + LOGE("FindEnum %{public}s failed, err: %{public}d", classDesc.c_str(), ret); + return ret; + } + + ani_enum_item enumItem; + ret = env->Enum_GetEnumItemByIndex(stateEnum, value, &enumItem); + if (ret != ANI_OK) { + LOGE("Enum_GetEnumItemByIndex failed, err: %{public}d", ret); + return ret; + } + + return env->Object_CallMethod_Void(object, setter, enumItem); +} + +static ani_status + SetEnumErrType(ani_env *env, const ani_class &cls, ani_object &object, const char *name, int32_t value) +{ + ani_method setter; + ani_status ret; + if ((ret = env->Class_FindMethod(cls, name, nullptr, &setter)) != ANI_OK) { + LOGE("Class_FindMethod Fail %{public}s, err: %{public}d", name, ret); + return ret; + } + ani_enum stateEnum; + std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.DownloadErrorType").Descriptor(); + ret = env->FindEnum(classDesc.c_str(), &stateEnum); + if (ret != ANI_OK) { + LOGE("FindEnum %{public}s failed, err: %{public}d", classDesc.c_str(), ret); + return ret; + } + + ani_enum_item enumItem; + ret = env->Enum_GetEnumItemByIndex(stateEnum, value, &enumItem); + if (ret != ANI_OK) { + LOGE("Enum_GetEnumItemByIndex failed, err: %{public}d", ret); + return ret; + } + + return env->Object_CallMethod_Void(object, setter, enumItem); +} + +static ani_status SetProperties(ani_env *env, const ani_class &cls, ani_object &pg, MultiDlProgressCore *progressCore) +{ + vector> numProperties = { + {TAKSKID_SETTER, ani_double(static_cast(progressCore->GetTaskId()))}, + {SUCC_COUNT_SETTER, ani_double(static_cast(progressCore->GetDownloadedNum()))}, + {FAILED_COUNT_SETTER, ani_double(static_cast(progressCore->GetFailedNum()))}, + {TOTAL_COUNT_SETTER, ani_double(static_cast(progressCore->GetTotalNum()))}, + {DOWNLOAD_SIZE_SETTER, ani_double(static_cast(progressCore->GetDownloadedSize()))}, + {TOTAL_SIZE_SETTER, ani_double(static_cast(progressCore->GetTotalSize()))}, + }; + ani_status ret; + for (auto iter : numProperties) { + auto key = iter.first.data(); + ani_method setter; + if ((ret = env->Class_FindMethod(cls, key, nullptr, &setter)) != ANI_OK) { + LOGE("Class_FindMethod Fail %{public}s, err: %{public}d", key, ret); + return ret; + } + if ((ret = env->Object_CallMethod_Void(pg, setter, iter.second)) != ANI_OK) { + LOGE("Class_FindMethod Fail %{public}s, err: %{public}d", key, ret); + return ret; + } + } + + if ((ret = SetEnumState(env, cls, pg, STATE_SETTER.data(), progressCore->GetStatus())) != ANI_OK) { + LOGE("Failed to get state enum, err: %{public}d", ret); + return ret; + } + if ((ret = SetEnumErrType(env, cls, pg, ERROR_SETTER.data(), progressCore->GetErrorType())) != ANI_OK) { + LOGE("Failed to get errType enum, err: %{public}d", ret); + return ret; + } + return ANI_OK; +} + +MultiDlProgressCore *MultiDlProgressWrapper::Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + LOGE("Unwrap MultiDlProgressCore err: %{public}d", static_cast(ret)); + return nullptr; + } + std::uintptr_t ptrValue = static_cast(nativePtr); + MultiDlProgressCore *multiDlProgress = reinterpret_cast(ptrValue); + return multiDlProgress; +} + +ani_object MultiDlProgressWrapper::Wrap(ani_env *env, MultiDlProgressCore *multiDlProgress) +{ + if (multiDlProgress == nullptr) { + LOGE("MultiDlProgressCore pointer is null!"); + return nullptr; + } + + ani_status ret; + ani_class cls; + std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.MultiDownloadProgress").Descriptor(); + if ((ret = env->FindClass(classDesc.c_str(), &cls)) != ANI_OK) { + LOGE("Cannot find class %{public}s, err: %{public}d", classDesc.c_str(), ret); + return nullptr; + } + + ani_method ctor; + auto ctorDesc = Builder::BuildConstructorName(); + auto ctorSig = Builder::BuildSignatureDescriptor({Builder::BuildLong()}); + if ((ret = env->Class_FindMethod(cls, ctorDesc.c_str(), ctorSig.c_str(), &ctor)) != ANI_OK) { + LOGE("Cannot find class %{public}s constructor method, err: %{public}d", classDesc.c_str(), ret); + return nullptr; + } + + ani_object progressObject; + if ((ret = env->Object_New(cls, ctor, &progressObject, reinterpret_cast(multiDlProgress))) != ANI_OK) { + LOGE("New StatInner Fail, err: %{public}d", ret); + return nullptr; + } + + if ((ret = SetProperties(env, cls, progressObject, multiDlProgress)) != ANI_OK) { + LOGE("SetProperties Fail, err: %{public}d", ret); + return nullptr; + } + + return progressObject; +} + +void MultiDlProgressAni::Constructor(ani_env *env, ani_object object) +{ + ani_status ret; + ani_class cls; + std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.MultiDownloadProgress").Descriptor(); + if ((ret = env->FindClass(classDesc.c_str(), &cls)) != ANI_OK) { + LOGE("Cannot find class %{public}s, err: %{public}d", classDesc.c_str(), ret); + ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED); + return; + } + + ani_method ctor; + auto ctorDesc = Builder::BuildConstructorName(); + std::string bindSign = Builder::BuildSignatureDescriptor({Builder::BuildLong()}); + ret = env->Class_FindMethod(cls, ctorDesc.c_str(), bindSign.c_str(), &ctor); + if (ret != ANI_OK) { + LOGE("find class ctor. ret = %{public}d", static_cast(ret)); + ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED); + return; + } + + FsResult data = MultiDlProgressCore::Constructor(); + if (!data.IsSuccess()) { + LOGE("MultiDlProgress constructor failed."); + const auto &err = data.GetError(); + ErrorHandler::Throw(env, err); + return; + } + + const MultiDlProgressCore *multiDlProgress = data.GetData().value(); + ret = env->Object_CallMethod_Void(object, ctor, reinterpret_cast(multiDlProgress)); + if (ret != ANI_OK) { + LOGE("bindNativePtr failed."); + delete multiDlProgress; + ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED); + } +} + +static tuple + ToFailedFileInfo(ani_env *env, ani_class cls, ani_method ctor, const FailedFileInfo &files) +{ + auto [succ, fileUri] = ANIUtils::ToAniString(env, files.uri); + if (!succ) { + LOGE("Convert FailedFileInfo uri to ani string failed!"); + return {false, nullptr}; + } + + ani_status ret; + ani_enum downloadErrorEnum; + Type errorSign = Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadErrorType"); + if ((ret = env->FindEnum(errorSign.Descriptor().c_str(), &downloadErrorEnum)) != ANI_OK) { + LOGE("Find DownloadErrorType enum failed!, err: %{public}d", ret); + return {false, nullptr}; + } + ani_enum_item downloadErrorEnumItem; + if ((ret = env->Enum_GetEnumItemByIndex(downloadErrorEnum, files.error, &downloadErrorEnumItem)) != ANI_OK) { + LOGE("Find DownloadErrorType enum failed!, err: %{public}d", ret); + return {false, nullptr}; + } + + ani_object obj; + if ((ret = env->Object_New(cls, ctor, &obj, fileUri, downloadErrorEnumItem)) != ANI_OK) { + LOGE("Create FailedFileInfo object failed!, err: %{public}d", ret); + return {false, nullptr}; + } + + return {true, obj}; +} + +static std::tuple ToAniObjectArray(ani_env *env, const std::vector &objList) +{ + ani_status ret; + ani_class cls; + std::string classDesc = Builder::BuildClass("@ohos.file.cloudSync.cloudSync.FailedFileInfoInner").Descriptor(); + if ((ret = env->FindClass(classDesc.c_str(), &cls)) != ANI_OK) { + LOGE("Cannot find class %{public}s, err: %{public}d", classDesc.c_str(), ret); + return {false, nullptr}; + } + + ani_method ctor; + auto ctorDesc = Builder::BuildConstructorName(); + auto ctorSig = + Builder::BuildSignatureDescriptor({Builder::BuildClass("std.core.String"), + Builder::BuildEnum("@ohos.file.cloudSync.cloudSync.DownloadErrorType")}); + if ((ret = env->Class_FindMethod(cls, ctorDesc.c_str(), ctorSig.c_str(), &ctor)) != ANI_OK) { + LOGE("Cannot find class %{public}s constructor method, err: %{public}d", classDesc.c_str(), ret); + return {false, nullptr}; + } + + size_t length = objList.size(); + const FailedFileInfo *objArray = objList.data(); + ani_array_ref result = nullptr; + if (env->Array_New_Ref(cls, length, nullptr, &result) != ANI_OK) { + LOGE("Failed to new array"); + return {false, nullptr}; + } + for (size_t i = 0; i < length; i++) { + auto [succ, item] = ToFailedFileInfo(env, cls, ctor, objArray[i]); + if (!succ) { + LOGE("Failed to get element for array"); + return {false, nullptr}; + } + if (env->Array_Set_Ref(result, i, item) != ANI_OK) { + LOGE("Failed to set element for array"); + return {false, nullptr}; + } + } + return {true, result}; +} + +ani_array_ref MultiDlProgressAni::GetFailedFileList(ani_env *env, ani_object object) +{ + auto multiDlProgress = MultiDlProgressWrapper::Unwrap(env, object); + if (multiDlProgress == nullptr) { + LOGE("Cannot wrap multiDlProgress."); + ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED); + return nullptr; + } + auto data = multiDlProgress->GetFailedFileList(); + if (!data.IsSuccess()) { + const auto &err = data.GetError(); + LOGE("multiDlProgress get failed list failed, ret = %{public}d", err.GetErrNo()); + ErrorHandler::Throw(env, err); + return nullptr; + } + + auto [succ, res] = ToAniObjectArray(env, data.GetData().value()); + if (!succ) { + ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED); + return nullptr; + } + return res; +} + +ani_array_ref MultiDlProgressAni::GetDownloadedFileList(ani_env *env, ani_object object) +{ + auto multiDlProgress = MultiDlProgressWrapper::Unwrap(env, object); + if (multiDlProgress == nullptr) { + LOGE("Cannot wrap multiDlProgress."); + ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED); + return nullptr; + } + auto data = multiDlProgress->GetDownloadedFileList(); + if (!data.IsSuccess()) { + const auto &err = data.GetError(); + LOGE("multiDlProgress get downloaded list failed, ret = %{public}d", err.GetErrNo()); + ErrorHandler::Throw(env, err); + return nullptr; + } + + auto [succ, res] = ANIUtils::ToAniStringArray(env, data.GetData().value()); + if (!succ) { + ErrorHandler::Throw(env, JsErrCode::E_INNER_FAILED); + return nullptr; + } + return res; +} +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/ani/file_cloud_sync/src/register_callback_manager_ani.cpp b/interfaces/kits/js/ani/file_cloud_sync/src/register_callback_manager_ani.cpp new file mode 100644 index 000000000..165fc1454 --- /dev/null +++ b/interfaces/kits/js/ani/file_cloud_sync/src/register_callback_manager_ani.cpp @@ -0,0 +1,161 @@ +/* + * 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 "register_callback_manager_ani.h" + +#include + +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudSync { +using namespace std; +// JS thread invokes native function +void RegisterCallbackManagerAni::SetVm(ani_env *env) +{ + if (vm_ == nullptr) { + env->GetVM(&vm_); + } +} + +ani_status RegisterCallbackManagerAni::RegisterCallback(ani_env *env, ani_object callback) +{ + if (callback == nullptr) { + return ANI_INVALID_ARGS; + } + ani_ref ref; + ani_status ret = env->GlobalReference_Create(reinterpret_cast(callback), &ref); + if (ret != ANI_OK) { + LOGE("Failed to create reference: %{public}d", ret); + return ret; + } + std::lock_guard lock(callbackMtx_); + if (IsExisted(env, ref)) { + return ANI_OK; + } + + callbackList_.push_back(std::make_pair(true, ref)); + validRefNum_++; + return ANI_OK; +} + +ani_status RegisterCallbackManagerAni::UnregisterCallback(ani_env *env, ani_object callback) +{ + if (validRefNum_ == 0) { + return ANI_OK; + } + std::lock_guard lock(callbackMtx_); + if (callback == nullptr) { + for (auto &iter : callbackList_) { + iter.first = false; + } + validRefNum_ = 0; + return ANI_OK; + } + ani_ref ref; + ani_status ret = env->GlobalReference_Create(reinterpret_cast(callback), &ref); + if (ret != ANI_OK) { + LOGE("Failed to create reference: %{public}d", ret); + return ret; + } + ani_boolean isSame = false; + for (auto &iter : callbackList_) { + ret = env->Reference_StrictEquals(iter.second, ref, &isSame); + if (ret != ANI_OK) { + LOGE("Failed to strict compare: %{public}d", ret); + continue; + } + if (isSame) { + if (iter.first) { + iter.first = false; + validRefNum_--; + } + break; + } + } + + return ANI_OK; +} + +// No need to lock +bool RegisterCallbackManagerAni::IsExisted(ani_env *env, ani_ref ref) +{ + ani_boolean isSame = false; + for (auto &iter : callbackList_) { + ani_status ret = env->Reference_StrictEquals(iter.second, ref, &isSame); + if (ret != ANI_OK) { + LOGE("Failed to strict compare: %{public}d", ret); + continue; + } + if (isSame) { + return iter.first; + } + } + + return false; +} + +// Running in JS thread +void RegisterCallbackManagerAni::OnJsCallback(ani_env *env, ani_object value, uint32_t argc) +{ + std::lock_guard lock(callbackMtx_); + for (auto iter = callbackList_.begin(); iter != callbackList_.end();) { + if (!iter->first) { + env->GlobalReference_Delete(iter->second); + iter = callbackList_.erase(iter); + continue; + } + ani_ref ref; + ani_fn_object etsCb = reinterpret_cast(iter->second); + std::vector vec = {value}; + ani_status ret = env->FunctionalObject_Call(etsCb, argc, vec.data(), &ref); + if (ret != ANI_OK) { + LOGE("ani call function failed. ret = %{public}d", ret); + return; + } + iter++; + } +} + +ani_env *RegisterCallbackManagerAni::GetEnv() +{ + if (vm_ == nullptr) { + return nullptr; + } + + ani_env *env{nullptr}; + ani_options aniArgs{0, nullptr}; + ani_status ret = vm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); + if (ret != ANI_OK) { + ret = vm_->GetEnv(ANI_VERSION_1, &env); + if (ret != ANI_OK) { + LOGE("vm GetEnv, err: %{private}d", ret); + return nullptr; + } + } + return env; +} + +void RegisterCallbackManagerAni::DetachEnv() +{ + if (vm_ == nullptr) { + return; + } + + ani_status ret; + if ((ret = vm_->DetachCurrentThread()) != ANI_OK) { + LOGE("detach current env failed, err: %{private}d", ret); + } +} +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/BUILD.gn b/interfaces/kits/js/cloudfilesync/BUILD.gn index fac14ae41..1028950c0 100644 --- a/interfaces/kits/js/cloudfilesync/BUILD.gn +++ b/interfaces/kits/js/cloudfilesync/BUILD.gn @@ -39,14 +39,16 @@ ohos_shared_library("cloudsync") { } sources = [ "cloud_file_cache_napi.cpp", - "cloud_file_download_napi.cpp", "cloud_file_napi.cpp", "cloud_file_version_napi.cpp", "cloud_sync_n_exporter.cpp", "cloud_sync_napi.cpp", + "download_callback_middle_napi.cpp", + "download_progress_napi.cpp", "file_sync_napi.cpp", "gallery_sync_napi.cpp", - "register_callback_manager.cpp", + "multi_download_progress_napi.cpp", + "register_callback_manager_napi.cpp", ] deps = [ "${innerkits_native_path}/cloudsync_kit_inner:cloudsync_kit_inner", diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_cache_core.cpp b/interfaces/kits/js/cloudfilesync/cloud_file_cache_core.cpp index e982b80fb..b57676346 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_cache_core.cpp +++ b/interfaces/kits/js/cloudfilesync/cloud_file_cache_core.cpp @@ -19,146 +19,97 @@ #include "utils_log.h" namespace OHOS::FileManagement::CloudSync { -const int32_t E_PARAMS = 401; - -bool RegisterManager::HasEvent(const string &eventType) -{ - unique_lock registerMutex_; - bool hasEvent = false; - for (auto &iter : registerInfo_) { - if (iter->eventType == eventType) { - hasEvent = true; - break; - } - } - return hasEvent; -} - -bool RegisterManager::AddRegisterInfo(shared_ptr info) -{ - if (HasEvent(info->eventType)) { - return false; - } - { - unique_lock registerMutex_; - registerInfo_.insert(info); - } - return true; -} - -bool RegisterManager::RemoveRegisterInfo(const string &eventType) -{ - unique_lock registerMutex_; - bool isFound = false; - for (auto iter = registerInfo_.begin(); iter != registerInfo_.end();) { - if ((*iter)->eventType == eventType) { - isFound = true; - iter = registerInfo_.erase(iter); - } else { - iter++; - } - } - return isFound; -} - +using namespace ModuleFileIO; FsResult CloudFileCacheCore::Constructor() { CloudFileCacheCore *cloudFileCachePtr = new CloudFileCacheCore(); if (cloudFileCachePtr == nullptr) { LOGE("Failed to create CloudFileCacheCore object on heap."); - return FsResult::Error(ENOMEM); + return FsResult::Error(Convert2ErrNum(E_SERVICE_INNER_ERROR)); } return FsResult::Success(move(cloudFileCachePtr)); } -CloudFileCacheCore::CloudFileCacheCore() +FsResult CloudFileCacheCore::DoOn(const string &event, const shared_ptr callback) { - LOGI("Create fileCacheEntity"); - fileCacheEntity = make_unique(); + return FsResult::Success(); } -FsResult CloudFileCacheCore::DoOn(const string &event, const shared_ptr callback) +FsResult CloudFileCacheCore::DoOff(const string &event, + const optional> &callback) { - LOGI("On begin"); - if (event != PROGRESS && event != MULTI_PROGRESS) { - LOGE("On get progress failed!"); - return FsResult::Error(E_PARAMS); - } - - if (!fileCacheEntity) { - LOGE("Failed to get file cache entity."); - return FsResult::Error(E_PARAMS); - } + return FsResult::Success(); +} - auto arg = make_shared(); - arg->eventType = event; - arg->callback = callback; - if (!fileCacheEntity->registerMgr.AddRegisterInfo(arg)) { - LOGE("Batch-On register callback fail, callback already exist"); - return FsResult::Error(E_PARAMS); +std::shared_ptr CloudFileCacheCore::GetCallbackImpl(const std::string &eventType, + bool isInit) +{ + std::shared_ptr callbackImpl = nullptr; + std::lock_guard lock(registerMutex_); + auto iter = registerMap_.find(eventType); + if (iter == registerMap_.end() || iter->second == nullptr) { + if (isInit) { + callbackImpl = std::make_shared(); + registerMap_.insert(make_pair(eventType, callbackImpl)); + } + } else { + callbackImpl = iter->second; } + return callbackImpl; +} - int32_t ret = CloudSyncManager::GetInstance().RegisterFileCacheCallback(arg->callback); +FsResult CloudFileCacheCore::DoStart(const string &uri) +{ + auto callbackImpl = GetCallbackImpl(PROGRESS, true); + int32_t ret = callbackImpl->StartDownloadInner(uri, FieldKey::FIELDKEY_CONTENT); if (ret != E_OK) { - LOGE("RegisterDownloadFileCallback error, ret: %{public}d", ret); - (void)fileCacheEntity->registerMgr.RemoveRegisterInfo(event); + LOGE("Stop Download failed! ret = %{public}d", ret); return FsResult::Error(Convert2ErrNum(ret)); } return FsResult::Success(); } -FsResult CloudFileCacheCore::DoOff( - const string &event, const optional> &callback) +FsResult CloudFileCacheCore::DoStart(const std::vector &uriList, int32_t fieldKey) { - LOGI("Off begin"); - if (event != PROGRESS && event != MULTI_PROGRESS) { - LOGE("Off get progress failed!"); - return FsResult::Error(E_PARAMS); - } - - if (!fileCacheEntity) { - LOGE("Failed to get file cache entity."); - return FsResult::Error(E_PARAMS); - } - - if (!fileCacheEntity->registerMgr.HasEvent(event)) { - LOGE("Batch-Off no callback is registered for this event type: %{public}s.", event.c_str()); - return FsResult::Error(E_PARAMS); - } - - int32_t ret = CloudSyncManager::GetInstance().UnregisterFileCacheCallback(); + auto callbackImpl = GetCallbackImpl(MULTI_PROGRESS, true); + int64_t downloadId = 0; + int32_t ret = callbackImpl->StartDownloadInner(uriList, downloadId, fieldKey); if (ret != E_OK) { - LOGE("Failed to unregister callback, error: %{public}d", ret); - return FsResult::Error(Convert2ErrNum(ret)); - } - - if (!fileCacheEntity->registerMgr.RemoveRegisterInfo(event)) { - LOGE("Batch-Off remove callback is failed, event type: %{public}s.", event.c_str()); - return FsResult::Error(E_PARAMS); + LOGE("Stop Download failed! ret = %{public}d", ret); + return FsResult::Error(Convert2ErrNum(ret)); } - return FsResult::Success(); + return FsResult::Success(downloadId); } -FsResult CloudFileCacheCore::DoStart(const string &uri) +FsResult CloudFileCacheCore::DoStop(const string &uri, bool needClean) { - int32_t ret = CloudSyncManager::GetInstance().StartFileCache(uri); + auto callbackImpl = GetCallbackImpl(PROGRESS, false); + if (callbackImpl == nullptr) { + LOGE("Failed to stop download, callback is null!"); + return FsResult::Error(E_INVAL_ARG); + } + int32_t ret = callbackImpl->StopDownloadInner(uri, needClean); if (ret != E_OK) { - LOGE("Start Download failed with errormessage: ret = %{public}d", ret); + LOGE("Stop Download failed! ret = %{public}d", ret); return FsResult::Error(Convert2ErrNum(ret)); } - LOGI("Start Download successfully!"); return FsResult::Success(); } -FsResult CloudFileCacheCore::DoStop(const string &uri, const bool needClean) +FsResult CloudFileCacheCore::DoStop(int64_t downloadId, bool needClean) { - int32_t ret = CloudSyncManager::GetInstance().StopDownloadFile(uri, needClean); + auto callbackImpl = GetCallbackImpl(MULTI_PROGRESS, false); + if (callbackImpl == nullptr) { + LOGE("Failed to stop batch download, callback is null!"); + return FsResult::Error(EINVAL); + } + int32_t ret = callbackImpl->StopDownloadInner(downloadId, needClean); if (ret != E_OK) { - LOGE("Stop Download failed! ret = %{public}d", ret); + LOGE("Stop batch download failed! ret = %{public}d", ret); return FsResult::Error(Convert2ErrNum(ret)); } diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_cache_core.h b/interfaces/kits/js/cloudfilesync/cloud_file_cache_core.h index 151f3b962..6bcee4394 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_cache_core.h +++ b/interfaces/kits/js/cloudfilesync/cloud_file_cache_core.h @@ -20,59 +20,33 @@ #include #include -#include "cloud_download_callback_ani.h" +#include "download_callback_impl_ani.h" #include "filemgmt_libfs.h" namespace OHOS::FileManagement::CloudSync { -using namespace ModuleFileIO; -using namespace std; const std::string PROGRESS = "progress"; -const std::string MULTI_PROGRESS = "multiProgress"; - -struct RegisterInfoArg { - std::string eventType; - std::shared_ptr callback; - ~RegisterInfoArg() - { - if (callback != nullptr) { - callback->DeleteReference(); - callback = nullptr; - } - } -}; - -class RegisterManager { -public: - RegisterManager() = default; - ~RegisterManager() = default; - bool AddRegisterInfo(std::shared_ptr info); - bool RemoveRegisterInfo(const std::string &eventType); - bool HasEvent(const std::string &eventType); - -private: - std::mutex registerMutex_; - std::unordered_set> registerInfo_; -}; - -struct FileCacheEntity { - RegisterManager registerMgr; -}; - +const std::string MULTI_PROGRESS = "batchDownload"; class CloudFileCacheCore { public: - CloudFileCacheCore(); + CloudFileCacheCore() = default; ~CloudFileCacheCore() = default; - static FsResult Constructor(); - FsResult DoOn(const std::string &event, const std::shared_ptr callback); - FsResult DoOff(const string &event, - const std::optional> &callback = std::nullopt); - FsResult DoStart(const string &uri); - FsResult DoStop(const string &uri, bool needClean = false); - FsResult CleanCache(const string &uri); + static ModuleFileIO::FsResult Constructor(); + ModuleFileIO::FsResult DoOn(const std::string &event, + const std::shared_ptr callback); + ModuleFileIO::FsResult + DoOff(const std::string &event, + const std::optional> &callback = std::nullopt); + ModuleFileIO::FsResult DoStart(const std::string &uri); + ModuleFileIO::FsResult DoStart(const std::vector &uriList, int32_t fieldKey); + ModuleFileIO::FsResult DoStop(const std::string &uri, bool needClean = false); + ModuleFileIO::FsResult DoStop(int64_t downloadId, bool needClean = false); + ModuleFileIO::FsResult CleanCache(const std::string &uri); + std::shared_ptr GetCallbackImpl(const std::string &eventType, bool isInit); private: - std::unique_ptr fileCacheEntity; + std::mutex registerMutex_; + std::unordered_map> registerMap_; }; } // namespace OHOS::FileManagement::CloudSync diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_cache_napi.cpp b/interfaces/kits/js/cloudfilesync/cloud_file_cache_napi.cpp index c522b993c..fac76ca5c 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_cache_napi.cpp +++ b/interfaces/kits/js/cloudfilesync/cloud_file_cache_napi.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-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 @@ -17,13 +17,16 @@ #include #include +#include +#include #include #include "async_work.h" #include "cloud_sync_manager.h" #include "dfs_error.h" +#include "multi_download_progress_napi.h" +#include "register_callback_manager_napi.h" #include "utils_log.h" -#include "uv.h" namespace OHOS::FileManagement::CloudSync { using namespace FileManagement::LibN; @@ -31,44 +34,59 @@ using namespace std; static const std::set errForSingleFileSync = { ENOENT, EACCES, EAGAIN, EINTR, ENOSYS, E_ILLEGAL_URI }; -bool RegisterManager::HasEvent(const string &eventType) +int32_t CloudFileCacheCallbackImplNapi::StartDownloadInner(const std::string &uri, int32_t fieldKey) { - unique_lock registerMutex_; - bool hasEvent = false; - for (auto &iter : registerInfo_) { - if (iter->eventType == eventType) { - hasEvent = true; - break; - } + int64_t downloadId = 0; + std::lock_guard lock(downloadInfoMtx_); + int32_t ret = CloudSyncManager::GetInstance().StartFileCache({uri}, downloadId, fieldKey, shared_from_this()); + if (ret != E_OK) { + LOGE("Start single download failed! ret = %{public}d", ret); + return ret; } - return hasEvent; + downloadInfos_.insert(std::make_pair(downloadId, std::make_shared(downloadId))); + return ret; } -bool RegisterManager::AddRegisterInfo(shared_ptr info) +int32_t CloudFileCacheCallbackImplNapi::StopDownloadInner(const std::string &uri, bool needClean) { - if (HasEvent(info->eventType)) { - return false; + auto downloadIdList = GetDownloadIdsByUri(uri); + int32_t ret = E_OK; + int32_t resErr = E_OK; + LOGI("Stop Download downloadId list size: %{public}zu", downloadIdList.size()); + for (auto taskId : downloadIdList) { + resErr = CloudSyncManager::GetInstance().StopFileCache(taskId, needClean); + if (resErr != E_OK) { + ret = resErr; + continue; + } } - { - unique_lock registerMutex_; - registerInfo_.insert(info); + if (ret != E_OK) { + LOGE("Stop Download failed! ret = %{public}d", ret); } - return true; + return ret; } -bool RegisterManager::RemoveRegisterInfo(const string &eventType) +int32_t CloudFileCacheCallbackImplNapi::StartDownloadInner(const std::vector &uriVec, + int64_t &downloadId, + int32_t fieldKey) { - unique_lock registerMutex_; - bool isFound = false; - for (auto iter = registerInfo_.begin(); iter != registerInfo_.end();) { - if ((*iter)->eventType == eventType) { - isFound = true; - iter = registerInfo_.erase(iter); - } else { - iter++; - } + std::unique_lock lock(downloadInfoMtx_); + int32_t ret = CloudSyncManager::GetInstance().StartFileCache(uriVec, downloadId, fieldKey, shared_from_this()); + if (ret != E_OK) { + LOGE("Start batch download failed! ret = %{public}d", ret); + return ret; } - return isFound; + downloadInfos_.insert(std::make_pair(downloadId, std::make_shared(downloadId))); + return ret; +} + +int32_t CloudFileCacheCallbackImplNapi::StopDownloadInner(int64_t downloadId, bool needClean) +{ + int32_t ret = CloudSyncManager::GetInstance().StopFileCache(downloadId, needClean); + if (ret != E_OK) { + LOGE("Batch stop file cache failed! ret = %{public}d", ret); + } + return ret; } napi_value CloudFileCacheNapi::Constructor(napi_env env, napi_callback_info info) @@ -76,14 +94,14 @@ napi_value CloudFileCacheNapi::Constructor(napi_env env, napi_callback_info info NFuncArg funcArg(env, info); if (!funcArg.InitArgs(NARG_CNT::ZERO)) { LOGE("Start Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); return nullptr; } auto fileCacheEntity = make_unique(); if (!NClass::SetEntityFor(env, funcArg.GetThisVar(), move(fileCacheEntity))) { LOGE("Failed to set file cache entity."); - NError(E_UNKNOWN_ERR).ThrowErr(env); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); return nullptr; } return funcArg.GetThisVar(); @@ -94,14 +112,14 @@ bool CloudFileCacheNapi::ToExport(std::vector props) std::string className = GetClassName(); auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props)); if (!succ) { - NError(E_UNKNOWN_ERR).ThrowErr(exports_.env_); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(exports_.env_); LOGE("Failed to define GallerySync class"); return false; } succ = NClass::SaveClass(exports_.env_, className, classValue); if (!succ) { - NError(E_UNKNOWN_ERR).ThrowErr(exports_.env_); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(exports_.env_); LOGE("Failed to save GallerySync class"); return false; } @@ -147,7 +165,7 @@ napi_value CloudFileCacheNapi::CleanFileCache(napi_env env, napi_callback_info i { LOGI("CleanCache start"); NFuncArg funcArg(env, info); - + if (!funcArg.InitArgs(NARG_CNT::ONE)) { NError(EINVAL).ThrowErr(env); LOGE("Number of arguments unmatched"); @@ -187,31 +205,63 @@ bool CloudFileCacheNapi::Export() return ToExport(props); } +static std::shared_ptr + GetCallbackImpl(napi_env env, NFuncArg &funcArg, const std::string &eventType, bool isInit) +{ + auto fileCacheEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!fileCacheEntity) { + LOGE("Failed to get file cache entity."); + return nullptr; + } + + std::shared_ptr callbackImpl = nullptr; + auto iter = fileCacheEntity->registerMap.find(eventType); + if (iter == fileCacheEntity->registerMap.end() || iter->second == nullptr) { + if (isInit) { + callbackImpl = std::make_shared(env); + fileCacheEntity->registerMap.insert(make_pair(eventType, callbackImpl)); + } + } else { + callbackImpl = iter->second; + } + return callbackImpl; +} + +static std::tuple ParseUriFromParam(napi_env env, NFuncArg &funcArg) +{ + auto [succ, uri, size] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); + if (!succ || size == 0) { + LOGE("Off get progress failed!"); + return {EINVAL, ""}; + } + return {E_OK, string(uri.get())}; +} + napi_value CloudFileCacheNapi::StartFileCache(napi_env env, napi_callback_info info) { NFuncArg funcArg(env, info); if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { LOGE("Start Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); + NError(EINVAL).ThrowErr(env); return nullptr; } - auto [succUri, uri, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); - if (!succUri) { - LOGE("Start get uri parameter failed!"); - NError(E_PARAMS).ThrowErr(env); + + auto [ret, uri] = ParseUriFromParam(env, funcArg); + if (ret != E_OK) { + NError(ret).ThrowErr(env); return nullptr; } - - auto cbExec = [uri = string(uri.get())]() -> NError { - int32_t ret = CloudSyncManager::GetInstance().StartFileCache(uri); + auto callbackImpl = GetCallbackImpl(env, funcArg, PROGRESS, true); + auto cbExec = [uri{uri}, callbackImpl{callbackImpl}]() -> NError { + if (callbackImpl == nullptr) { + LOGE("Failed to get download callback"); + return NError(EINVAL); + } + int32_t ret = callbackImpl->StartDownloadInner(uri, FieldKey::FIELDKEY_CONTENT); if (ret != E_OK) { - LOGE("Start Download failed! ret = %{public}d", ret); - if (ret != E_INVAL_ARG) { - ret = E_BROKEN_IPC; - } + ret = (ret == E_CLOUD_SDK) ? E_SERVICE_INNER_ERROR : ret; return NError(Convert2JsErrNum(ret)); } - LOGI("Start Download Success!"); return NError(ERRNO_NOERR); }; @@ -227,20 +277,9 @@ napi_value CloudFileCacheNapi::StartFileCache(napi_env env, napi_callback_info i return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_; } -napi_value CloudFileCacheNapi::StopFileCache(napi_env env, napi_callback_info info) +static tuple GetCleanFlagForStop(napi_env env, NFuncArg &funcArg) { - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { - LOGE("Stop Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; - } - auto [succ, uri, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); - if (!succ) { - LOGE("Stop get uri parameter failed!"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; - } + bool succ = false; bool needClean = false; size_t maxArgSize = static_cast(NARG_CNT::TWO); if (funcArg.GetArgc() >= NARG_CNT::TWO) { @@ -249,19 +288,42 @@ napi_value CloudFileCacheNapi::StopFileCache(napi_env env, napi_callback_info in tie(succ, needClean) = option.ToBool(); if (!succ) { LOGE("Failed to get clean flag!"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; + return {EINVAL, false, false}; } maxArgSize = static_cast(NARG_CNT::THREE); } } - auto cbExec = [uri = string(uri.get()), env = env, needClean]() -> NError { - int32_t ret = CloudSyncManager::GetInstance().StopDownloadFile(uri, needClean); + return {E_OK, needClean, maxArgSize}; +} + +napi_value CloudFileCacheNapi::StopFileCache(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { + LOGE("Stop Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [res, uri] = ParseUriFromParam(env, funcArg); + if (res != E_OK) { + NError(res).ThrowErr(env); + return nullptr; + } + + auto [ret, needClean, maxArgSize] = GetCleanFlagForStop(env, funcArg); + if (ret != E_OK) { + NError(ret).ThrowErr(env); + return nullptr; + } + auto callbackImpl = GetCallbackImpl(env, funcArg, PROGRESS, false); + auto cbExec = [uri{uri}, needClean{needClean}, callbackImpl{callbackImpl}]() -> NError { + if (callbackImpl == nullptr) { + LOGE("Failed to get download callback"); + return NError(JsErrCode::E_INNER_FAILED); + } + int32_t ret = callbackImpl->StopDownloadInner(uri, needClean); if (ret != E_OK) { - LOGE("Stop Download failed! ret = %{public}d", ret); - if (ret != E_INVAL_ARG) { - ret = E_BROKEN_IPC; - } + ret = (ret == E_CLOUD_SDK) ? E_SERVICE_INNER_ERROR : ret; return NError(Convert2JsErrNum(ret)); } return NError(ERRNO_NOERR); @@ -280,47 +342,80 @@ napi_value CloudFileCacheNapi::StopFileCache(napi_env env, napi_callback_info in } struct FileCacheArg { - vector uriList; - int64_t downloadId; + std::vector uriList; + int64_t downloadId = 0; + std::shared_ptr callbackImpl = nullptr; + int32_t fieldKey = FieldKey::FIELDKEY_CONTENT; }; +static std::tuple, int32_t> FillParamForBatchStart(napi_env env, + NFuncArg &funcArg) +{ + size_t maxArgSize = static_cast(NARG_CNT::TWO); + auto [succ, uriArray, size] = NVal(env, funcArg[NARG_POS::FIRST]).ToStringArray(); + if (!succ || size == 0) { + LOGE("Start get uri array parameter failed!"); + return {EINVAL, nullptr, maxArgSize}; + } + + int32_t fieldKey = 0; + if (funcArg.GetArgc() >= NARG_CNT::TWO) { + NVal option(env, funcArg[NARG_POS::SECOND]); + if (!option.TypeIs(napi_function)) { + tie(succ, fieldKey) = option.ToInt32(); + if (!succ) { + LOGE("Failed to get fileType!"); + return {EINVAL, nullptr, maxArgSize}; + } + maxArgSize = static_cast(NARG_CNT::THREE); + } + } + + auto fileCache = std::make_shared(); + fileCache->uriList.swap(uriArray); + fileCache->fieldKey = fieldKey; + fileCache->callbackImpl = GetCallbackImpl(env, funcArg, MULTI_PROGRESS, true); + return {E_OK, fileCache, maxArgSize}; +} + napi_value CloudFileCacheNapi::StartBatchFileCache(napi_env env, napi_callback_info info) { NFuncArg funcArg(env, info); if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { LOGE("Start Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); + NError(EINVAL).ThrowErr(env); return nullptr; } - auto fileUris = std::make_shared(); - auto [resGetUris, uriArray, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToStringArray(); - if (!resGetUris) { - LOGE("Start get uri array parameter failed!"); - NError(E_PARAMS).ThrowErr(env); + auto [ret, fileCache, maxArgSize] = FillParamForBatchStart(env, funcArg); + if (ret != E_OK) { + NError(ret).ThrowErr(env); return nullptr; } - fileUris->uriList = uriArray; - auto cbExec = [fileUris]() -> NError { - int32_t ret = CloudSyncManager::GetInstance().StartFileCache(fileUris->uriList, fileUris->downloadId); + auto cbExec = [fileCache{fileCache}]() -> NError { + if (fileCache == nullptr || fileCache->callbackImpl == nullptr) { + LOGE("Failed to get download callback"); + return NError(JsErrCode::E_INNER_FAILED); + } + int32_t ret = + fileCache->callbackImpl->StartDownloadInner(fileCache->uriList, fileCache->downloadId, fileCache->fieldKey); if (ret != E_OK) { - LOGE("Batch start file cache failed! ret = %{public}d", ret); - ret = (ret == E_CLOUD_SDK) ? E_UNKNOWN_ERR : ret; + ret = (ret == E_CLOUD_SDK) ? E_SERVICE_INNER_ERROR : ret; return NError(Convert2JsErrNum(ret)); } return NError(ERRNO_NOERR); }; - auto cbCompl = [fileUris](napi_env env, NError err) -> NVal { + auto cbCompl = [fileCache{fileCache}](napi_env env, NError err) -> NVal { if (err) { return {env, err.GetNapiErr(env)}; } - return NVal::CreateInt64(env, fileUris->downloadId); + return NVal::CreateInt64(env, fileCache->downloadId); }; string procedureName = "cloudFileCache"; - auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast(NARG_CNT::TWO)); + auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, maxArgSize); return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_; } @@ -329,37 +424,31 @@ napi_value CloudFileCacheNapi::StopBatchFileCache(napi_env env, napi_callback_in NFuncArg funcArg(env, info); if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { LOGE("Start Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); + NError(EINVAL).ThrowErr(env); return nullptr; } auto [succ, downloadId] = NVal(env, funcArg[NARG_POS::FIRST]).ToInt64(); if (!succ || downloadId <= 0) { - LOGE("Start get download ID parameter failed!"); - NError(E_PARAMS).ThrowErr(env); + LOGE("Start get taskId parameter failed!"); + NError(EINVAL).ThrowErr(env); return nullptr; } - bool needClean = false; - size_t maxArgSize = static_cast(NARG_CNT::TWO); - if (funcArg.GetArgc() >= NARG_CNT::TWO) { - NVal option(env, funcArg[NARG_POS::SECOND]); - if (!option.TypeIs(napi_function)) { - tie(succ, needClean) = option.ToBool(); - if (!succ) { - LOGE("Failed to get clean flag!"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; - } - maxArgSize = static_cast(NARG_CNT::THREE); - } + auto [ret, needClean, maxArgSize] = GetCleanFlagForStop(env, funcArg); + if (ret != E_OK) { + NError(ret).ThrowErr(env); + return nullptr; } - - auto cbExec = [downloadId = downloadId, needClean]() -> NError { - int32_t ret = CloudSyncManager::GetInstance().StopFileCache(downloadId, needClean); + auto callbackImpl = GetCallbackImpl(env, funcArg, MULTI_PROGRESS, false); + auto cbExec = [downloadId{downloadId}, needClean{needClean}, callbackImpl{callbackImpl}]() -> NError { + if (callbackImpl == nullptr) { + LOGE("Failed to get download callback"); + return NError(JsErrCode::E_INNER_FAILED); + } + int32_t ret = callbackImpl->StopDownloadInner(downloadId, needClean); if (ret != E_OK) { - LOGE("Batch stop file cache failed! ret = %{public}d", ret); - ret = (ret == E_CLOUD_SDK) ? E_UNKNOWN_ERR : ret; + ret = (ret == E_CLOUD_SDK) ? E_SERVICE_INNER_ERROR : ret; return NError(Convert2JsErrNum(ret)); } return NError(ERRNO_NOERR); @@ -377,55 +466,56 @@ napi_value CloudFileCacheNapi::StopBatchFileCache(napi_env env, napi_callback_in return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_; } +static std::tuple ParseEventFromParam(napi_env env, NFuncArg &funcArg) +{ + auto [succProgress, progress, size] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); + if (!succProgress || size == 0) { + LOGE("Off get progress failed!"); + NError(EINVAL).ThrowErr(env); + return {EINVAL, ""}; + } + string eventType(progress.get()); + if (eventType == "multiProgress") { + eventType = MULTI_PROGRESS; + } + if ((eventType != PROGRESS && eventType != MULTI_PROGRESS)) { + LOGE("Off get progress failed!"); + return {EINVAL, ""}; + } + return {E_OK, eventType}; +} + napi_value CloudFileCacheNapi::On(napi_env env, napi_callback_info info) { NFuncArg funcArg(env, info); if (!funcArg.InitArgs(NARG_CNT::TWO)) { LOGE("Batch-On Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); + NError(EINVAL).ThrowErr(env); return nullptr; } - auto [succProgress, progress, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); - string eventType(progress.get()); - if (!succProgress || (eventType != PROGRESS && eventType != MULTI_PROGRESS)) { - LOGE("Batch-On get progress failed!"); - NError(E_PARAMS).ThrowErr(env); + auto [ret, eventType] = ParseEventFromParam(env, funcArg); + if (ret != E_OK) { + LOGE("On get event type failed!"); + NError(ret).ThrowErr(env); return nullptr; } if (!NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function)) { LOGE("Batch-On argument type mismatch"); - NError(E_PARAMS).ThrowErr(env); + NError(EINVAL).ThrowErr(env); return nullptr; } - auto fileCacheEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); - if (!fileCacheEntity) { - LOGE("Failed to get file cache entity."); - NError(E_PARAMS).ThrowErr(env); + auto callbackImpl = GetCallbackImpl(env, funcArg, eventType, true); + if (callbackImpl == nullptr) { + LOGE("Failed to init callback"); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); return nullptr; } - - auto arg = make_shared(); - arg->eventType = eventType; - if (eventType == PROGRESS) { - arg->callback = make_shared(env, NVal(env, funcArg[(int)NARG_POS::SECOND]).val_); - } else { - arg->callback = - make_shared(env, NVal(env, funcArg[(int)NARG_POS::SECOND]).val_, true); - } - - if (!fileCacheEntity->registerMgr.AddRegisterInfo(arg)) { - LOGE("Batch-On register callback fail, callback already exist"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; - } - - int32_t ret = CloudSyncManager::GetInstance().RegisterFileCacheCallback(arg->callback); - if (ret != E_OK) { - LOGE("Failed to register callback, error: %{public}d", ret); - (void)fileCacheEntity->registerMgr.RemoveRegisterInfo(eventType); - NError(Convert2JsErrNum(ret)).ThrowErr(env); + auto status = callbackImpl->RegisterCallback(funcArg[NARG_POS::SECOND]); + if (status != napi_ok) { + LOGE("Failed to register callback, status: %{public}d", status); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); return nullptr; } @@ -437,46 +527,30 @@ napi_value CloudFileCacheNapi::Off(napi_env env, napi_callback_info info) NFuncArg funcArg(env, info); if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { LOGE("Off Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; - } - auto [succProgress, progress, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); - string eventType(progress.get()); - if (!succProgress || (eventType != PROGRESS && eventType != MULTI_PROGRESS)) { - LOGE("Batch-Off get progress failed!"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; - } - - if (funcArg.GetArgc() == (uint)NARG_CNT::TWO && !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function)) { - LOGE("Batch-Off argument type mismatch"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; - } - - auto fileCacheEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); - if (!fileCacheEntity) { - LOGE("Failed to get file cache entity."); - NError(E_PARAMS).ThrowErr(env); + NError(EINVAL).ThrowErr(env); return nullptr; } - - if (!fileCacheEntity->registerMgr.HasEvent(eventType)) { - LOGE("Batch-Off no callback is registered for this event type: %{public}s.", eventType.c_str()); - NError(E_PARAMS).ThrowErr(env); + auto [ret, eventType] = ParseEventFromParam(env, funcArg); + if (ret != E_OK) { + LOGE("Off get event type failed!"); + NError(ret).ThrowErr(env); return nullptr; } - int32_t ret = CloudSyncManager::GetInstance().UnregisterFileCacheCallback(); - if (ret != E_OK) { - LOGE("Failed to unregister callback, error: %{public}d", ret); - NError(Convert2JsErrNum(ret)).ThrowErr(env); - return nullptr; + napi_value callbackVel = nullptr; + if (funcArg.GetArgc() == (uint)NARG_CNT::TWO) { + if (!NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function)) { + LOGE("Off argument type mismatch"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + callbackVel = funcArg[NARG_POS::SECOND]; } - if (!fileCacheEntity->registerMgr.RemoveRegisterInfo(eventType)) { - LOGE("Batch-Off no callback is registered for this event type: %{public}s.", eventType.c_str()); - NError(E_PARAMS).ThrowErr(env); + auto callbackImpl = GetCallbackImpl(env, funcArg, eventType, false); + if (callbackImpl == nullptr || callbackImpl->UnregisterCallback(callbackVel) != napi_ok) { + LOGE("Failed to unregister callback, for eventType: %{public}s.", eventType.c_str()); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); return nullptr; } diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_cache_napi.h b/interfaces/kits/js/cloudfilesync/cloud_file_cache_napi.h index 87194a418..983cd1442 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_cache_napi.h +++ b/interfaces/kits/js/cloudfilesync/cloud_file_cache_napi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-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 @@ -17,12 +17,16 @@ #define OHOS_FILEMGMT_CLOUD_FILE_CACHE_NAPI_H #include -#include -#include "cloud_file_napi.h" +#include +#include + +#include "download_callback_middle_napi.h" +#include "download_progress_napi.h" +#include "filemgmt_libn.h" namespace OHOS::FileManagement::CloudSync { const std::string PROGRESS = "progress"; -const std::string MULTI_PROGRESS = "multiProgress"; +const std::string MULTI_PROGRESS = "batchDownload"; class CloudFileCacheNapi final : public LibN::NExporter { public: CloudFileCacheNapi(napi_env env, napi_value exports) : NExporter(env, exports) {} @@ -44,33 +48,18 @@ public: private: inline static std::string className_ = "CloudFileCache"; }; -struct RegisterInfoArg { - std::string eventType; - std::shared_ptr callback; - ~RegisterInfoArg() - { - if (callback != nullptr) { - callback->DeleteReference(); - callback = nullptr; - } - } -}; -class RegisterManager { +class CloudFileCacheCallbackImplNapi : public CloudDlCallbackMiddleNapi { public: - RegisterManager() = default; - ~RegisterManager() = default; - bool AddRegisterInfo(std::shared_ptr info); - bool RemoveRegisterInfo(const std::string &eventType); - bool HasEvent(const std::string &eventType); - -private: - std::mutex registerMutex_; - std::unordered_set> registerInfo_; + explicit CloudFileCacheCallbackImplNapi(napi_env env) : CloudDlCallbackMiddleNapi(env) {} + int32_t StartDownloadInner(const std::string &uri, int32_t fieldKey); + int32_t StartDownloadInner(const std::vector &uriList, int64_t &downloadId, int32_t fieldKey); + int32_t StopDownloadInner(const std::string &uri, bool needClean); + int32_t StopDownloadInner(int64_t downloadId, bool needClean); }; struct FileCacheEntity { - RegisterManager registerMgr; + std::unordered_map> registerMap; }; } // namespace OHOS::FileManagement::CloudSync #endif // OHOS_FILEMGMT_CLOUD_FILE_DOWNLOAD_NAPI_H \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_core.cpp b/interfaces/kits/js/cloudfilesync/cloud_file_core.cpp index ff5e92b66..46c24df08 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_core.cpp +++ b/interfaces/kits/js/cloudfilesync/cloud_file_core.cpp @@ -23,7 +23,6 @@ namespace OHOS::FileManagement::CloudSync { using namespace std; -const int32_t E_PARAMS = 401; FsResult CloudFileCore::Constructor() { @@ -36,14 +35,21 @@ FsResult CloudFileCore::Constructor() return FsResult::Success(move(cloudfile)); } -CloudFileCore::CloudFileCore() {} +std::shared_ptr CloudFileCore::GetCallbackImpl(bool isInit) +{ + if (callback_ == nullptr && isInit) { + callback_ = std::make_shared(); + } + return callback_; +} FsResult CloudFileCore::DoStart(const string &uri) { LOGI("Start begin"); - int32_t ret = CloudSyncManager::GetInstance().StartDownloadFile(uri); + auto callbackImpl = GetCallbackImpl(true); + int32_t ret = callbackImpl->StartDownloadInner(uri); if (ret != E_OK) { - LOGE("Start Download failed! ret = %{public}d", ret); + LOGE("Stop Download failed! ret = %{public}d", ret); return FsResult::Error(Convert2ErrNum(ret)); } @@ -51,58 +57,26 @@ FsResult CloudFileCore::DoStart(const string &uri) return FsResult::Success(); } -FsResult CloudFileCore::DoOn(const string &event, const shared_ptr callback) +FsResult CloudFileCore::DoOn(const string &event, const shared_ptr callback) { - LOGI("On begin"); - if (event != "progress") { - LOGE("On get progress failed!"); - return FsResult::Error(E_PARAMS); - } - - if (callback_ != nullptr) { - LOGI("callback already exist"); - return FsResult::Success(); - } - - callback_ = callback; - int32_t ret = CloudSyncManager::GetInstance().RegisterDownloadFileCallback(callback_); - if (ret != E_OK) { - LOGE("RegisterDownloadFileCallback error, ret: %{public}d", ret); - return FsResult::Error(Convert2ErrNum(ret)); - } - return FsResult::Success(); } -FsResult CloudFileCore::DoOff( - const string &event, const optional> &callback) +FsResult CloudFileCore::DoOff(const string &event, + const optional> &callback) { - LOGI("Off begin"); - if (event != "progress") { - LOGE("Off get progress failed!"); - return FsResult::Error(E_PARAMS); - } - - /* callback_ may be nullptr */ - int32_t ret = CloudSyncManager::GetInstance().UnregisterDownloadFileCallback(); - if (ret != E_OK) { - LOGE("UnregisterDownloadFileCallback error, ret: %{public}d", ret); - return FsResult::Error(Convert2ErrNum(ret)); - } - - if (callback_ != nullptr) { - /* delete callback */ - callback_->DeleteReference(); - callback_ = nullptr; - } - return FsResult::Success(); } FsResult CloudFileCore::DoStop(const string &uri, bool needClean) { LOGI("Stop begin"); - int32_t ret = CloudSyncManager::GetInstance().StopDownloadFile(uri, needClean); + auto callbackImpl = GetCallbackImpl(false); + if (callbackImpl == nullptr) { + LOGE("Failed to stop download, callback is null!"); + return FsResult::Error(E_INVAL_ARG); + } + int32_t ret = callbackImpl->StopDownloadInner(uri); if (ret != E_OK) { LOGE("Stop Download failed! ret = %{public}d", ret); return FsResult::Error(Convert2ErrNum(ret)); diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_core.h b/interfaces/kits/js/cloudfilesync/cloud_file_core.h index 5e87dc83b..771de3217 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_core.h +++ b/interfaces/kits/js/cloudfilesync/cloud_file_core.h @@ -18,7 +18,7 @@ #include -#include "cloud_download_callback_ani.h" +#include "download_callback_impl_ani.h" #include "filemgmt_libfs.h" namespace OHOS::FileManagement::CloudSync { @@ -26,18 +26,19 @@ using namespace ModuleFileIO; class CloudFileCore { public: - CloudFileCore(); + CloudFileCore() = default; ~CloudFileCore() = default; static FsResult Constructor(); FsResult DoStart(const std::string &uri); - FsResult DoOn(const std::string &event, const std::shared_ptr callback); + FsResult DoOn(const std::string &event, const std::shared_ptr callback); FsResult DoOff(const std::string &event, - const std::optional> &callback = std::nullopt); + const std::optional> &callback = std::nullopt); FsResult DoStop(const std::string &uri, bool needClean = false); + std::shared_ptr GetCallbackImpl(bool isInit); private: - std::shared_ptr callback_; + std::shared_ptr callback_; }; } // namespace OHOS::FileManagement::CloudSync #endif // OHOS_FILEMGMT_CLOUD_FILE_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_download_napi.cpp b/interfaces/kits/js/cloudfilesync/cloud_file_download_napi.cpp deleted file mode 100644 index be31b237b..000000000 --- a/interfaces/kits/js/cloudfilesync/cloud_file_download_napi.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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. - */ - -#include "cloud_file_download_napi.h" - -#include - -#include "cloud_sync_manager.h" -#include "dfs_error.h" -#include "utils_log.h" -#include "async_work.h" -#include "uv.h" - -namespace OHOS::FileManagement::CloudSync { -using namespace FileManagement::LibN; -using namespace std; - -bool CloudFileDownloadNapi::Export() -{ - SetClassName("Download"); - bool success = CloudFileNapi::Export(); - if (!success) { - return false; - } - return true; -} -} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_napi.cpp b/interfaces/kits/js/cloudfilesync/cloud_file_napi.cpp index fd6988281..be9ad9c58 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_napi.cpp +++ b/interfaces/kits/js/cloudfilesync/cloud_file_napi.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-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 @@ -13,37 +13,90 @@ * limitations under the License. */ -#include "cloud_file_download_napi.h" +#include "cloud_file_napi.h" +#include +#include #include #include "async_work.h" -#include "cloud_file_napi.h" #include "cloud_sync_manager.h" #include "dfs_error.h" +#include "dfsu_access_token_helper.h" +#include "filemgmt_libn.h" +#include "n_napi.h" #include "utils_log.h" -#include "uv.h" namespace OHOS::FileManagement::CloudSync { using namespace FileManagement::LibN; using namespace std; -const int32_t ARGS_ONE = 1; +int32_t CloudDownloadCallbackImplNapi::StartDownloadInner(const std::string &uri) +{ + int64_t downloadId = 0; + std::lock_guard lock(downloadInfoMtx_); + int32_t ret = CloudSyncManager::GetInstance().StartDownloadFile(uri, shared_from_this(), downloadId); + if (ret != E_OK) { + LOGE("Start batch download failed! ret = %{public}d", ret); + return ret; + } + + downloadInfos_.insert(std::make_pair(downloadId, std::make_shared(downloadId))); + return ret; +} + +int32_t CloudDownloadCallbackImplNapi::StopDownloadInner(const std::string &uri) +{ + auto downloadIdList = GetDownloadIdsByUri(uri); + int32_t ret = E_OK; + int32_t resErr = E_OK; + LOGI("Stop Download downloadId list size: %{public}zu", downloadIdList.size()); + for (auto taskId : downloadIdList) { + resErr = CloudSyncManager::GetInstance().StopDownloadFile(taskId, true); + if (resErr != E_OK) { + ret = resErr; + continue; + } + } + if (ret != E_OK) { + LOGE("Stop Download failed! ret = %{public}d", ret); + } + return ret; +} -napi_value CloudFileNapi::Constructor(napi_env env, napi_callback_info info) +napi_value CloudFileDownloadNapi::Constructor(napi_env env, napi_callback_info info) { - LOGI("CloudFileNapi::Constructor begin"); + LOGI("CloudFileDownloadNapi::Constructor begin"); NFuncArg funcArg(env, info); if (!funcArg.InitArgs(NARG_CNT::ZERO)) { LOGE("Start Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); + NError(JsErrCode::E_IPCSS).ThrowErr(env); + return nullptr; + } + auto downloadEntity = make_unique(); + if (!NClass::SetEntityFor(env, funcArg.GetThisVar(), move(downloadEntity))) { + LOGE("Failed to set download entity."); + NError(JsErrCode::E_IPCSS).ThrowErr(env); return nullptr; } - isDownloadCallbackRegistered_ = false; - LOGI("CloudFileNapi::Constructor end"); + LOGI("CloudFileDownloadNapi::Constructor end"); return funcArg.GetThisVar(); } -napi_value CloudFileNapi::Start(napi_env env, napi_callback_info info) +static std::shared_ptr GetCallbackImpl(napi_env env, NFuncArg &funcArg, bool isInit) +{ + auto downloadEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!downloadEntity) { + LOGE("Failed to get file cache entity."); + return nullptr; + } + + if (downloadEntity->callbackImpl == nullptr && isInit) { + downloadEntity->callbackImpl = std::make_shared(env); + } + return downloadEntity->callbackImpl; +} + +napi_value CloudFileDownloadNapi::Start(napi_env env, napi_callback_info info) { LOGI("Start begin"); NFuncArg funcArg(env, info); @@ -52,25 +105,20 @@ napi_value CloudFileNapi::Start(napi_env env, napi_callback_info info) NError(E_PARAMS).ThrowErr(env); return nullptr; } - auto [succUri, uri, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); - if (!succUri) { + auto [succUri, uri, size] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); + if (!succUri || size == 0) { LOGE("Start get uri parameter failed!"); NError(E_PARAMS).ThrowErr(env); return nullptr; } - auto cbExec = [uri = string(uri.get()), env = env]() -> NError { - lock_guard lock(mtx_); - if (callback_ != nullptr && !isDownloadCallbackRegistered_) { - int32_t ret = CloudSyncManager::GetInstance().RegisterDownloadFileCallback(callback_); - if (ret != E_OK) { - LOGE("RegisterDownloadFileCallback error, ret: %{public}d", ret); - return NError(Convert2JsErrNum(ret)); - } - isDownloadCallbackRegistered_ = true; + auto callbackImpl = GetCallbackImpl(env, funcArg, true); + auto cbExec = [uri{string(uri.get())}, callbackImpl{callbackImpl}]() -> NError { + if (callbackImpl == nullptr) { + LOGE("Failed to get download callback"); + return NError(E_PARAMS); } - - int32_t ret = CloudSyncManager::GetInstance().StartDownloadFile(uri); + int32_t ret = callbackImpl->StartDownloadInner(uri); if (ret != E_OK) { LOGE("Start Download failed! ret = %{public}d", ret); return NError(Convert2JsErrNum(ret)); @@ -91,96 +139,20 @@ napi_value CloudFileNapi::Start(napi_env env, napi_callback_info info) return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_; } -CloudDownloadCallbackImpl::CloudDownloadCallbackImpl(napi_env env, napi_value fun, bool isBatch) : env_(env) -{ - if (fun != nullptr) { - napi_create_reference(env_, fun, 1, &cbOnRef_); - } - isBatch_ = isBatch; -} - -void CloudDownloadCallbackImpl::OnComplete(UvChangeMsg *msg) -{ - auto downloadcCallback = msg->CloudDownloadCallback_.lock(); - if (downloadcCallback == nullptr || downloadcCallback->cbOnRef_ == nullptr) { - LOGE("downloadcCallback->cbOnRef_ is nullptr"); - return; - } - auto env = downloadcCallback->env_; - auto ref = downloadcCallback->cbOnRef_; - napi_handle_scope scope = nullptr; - napi_open_handle_scope(env, &scope); - napi_value jsCallback = nullptr; - napi_status 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; - } - NVal obj = NVal::CreateObject(env); - if (!msg->isBatch_) { - obj.AddProp("state", NVal::CreateInt32(env, (int32_t)msg->downloadProgress_.state).val_); - obj.AddProp("processed", NVal::CreateInt64(env, msg->downloadProgress_.downloadedSize).val_); - obj.AddProp("size", NVal::CreateInt64(env, msg->downloadProgress_.totalSize).val_); - obj.AddProp("uri", NVal::CreateUTF8String(env, msg->downloadProgress_.path).val_); - } else { - LOGI("Batch download callback items"); - obj.AddProp("state", NVal::CreateInt32(env, (int32_t)msg->downloadProgress_.batchState).val_); - obj.AddProp("downloadedSize", NVal::CreateInt64(env, msg->downloadProgress_.batchDownloadSize).val_); - obj.AddProp("totalSize", NVal::CreateInt64(env, msg->downloadProgress_.batchTotalSize).val_); - obj.AddProp("successfulNum", NVal::CreateInt64(env, msg->downloadProgress_.batchSuccNum).val_); - obj.AddProp("failedNum", NVal::CreateInt64(env, msg->downloadProgress_.batchFailNum).val_); - obj.AddProp("totalNum", NVal::CreateInt64(env, msg->downloadProgress_.batchTotalNum).val_); - } - obj.AddProp("taskId", NVal::CreateInt64(env, msg->downloadProgress_.downloadId).val_); - obj.AddProp("error", NVal::CreateInt32(env, (int32_t)msg->downloadProgress_.downloadErrorType).val_); - - LOGI("OnComplete callback start for taskId: %{public}lld", - static_cast(msg->downloadProgress_.downloadId)); - napi_value retVal = nullptr; - napi_value global = nullptr; - napi_get_global(env, &global); - status = napi_call_function(env, global, jsCallback, ARGS_ONE, &(obj.val_), &retVal); - if (status != napi_ok) { - LOGE("napi call function failed, status: %{public}d", status); - } - napi_close_handle_scope(env, scope); -} - -void CloudDownloadCallbackImpl::OnDownloadProcess(const DownloadProgressObj &progress) +static int32_t CheckPermissions(const string &permission, bool isSystemApp) { - UvChangeMsg *msg = new (std::nothrow) UvChangeMsg(shared_from_this(), progress, isBatch_); - if (msg == nullptr) { - LOGE("Failed to create uv message object"); - return; + if (!permission.empty() && !DfsuAccessTokenHelper::CheckCallerPermission(permission)) { + LOGE("permission denied"); + return JsErrCode::E_PERMISSION; } - auto task = [msg]() { - if (msg->CloudDownloadCallback_.expired()) { - LOGE("CloudDownloadCallback_ is expired"); - delete msg; - return; - } - msg->CloudDownloadCallback_.lock()->OnComplete(msg); - delete msg; - }; - napi_status ret = napi_send_event(env_, task, napi_event_priority::napi_eprio_immediate); - if (ret != napi_ok) { - LOGE("Failed to execute libuv work queue, ret: %{public}d", ret); - delete msg; - return; - } -} - -void CloudDownloadCallbackImpl::DeleteReference() -{ - if (cbOnRef_ != nullptr) { - napi_delete_reference(env_, cbOnRef_); - cbOnRef_ = nullptr; - return; + if (isSystemApp && !DfsuAccessTokenHelper::IsSystemApp()) { + LOGE("caller hap is not system hap"); + return JsErrCode::E_PERMISSION_SYS; } + return E_OK; } -napi_value CloudFileNapi::On(napi_env env, napi_callback_info info) +napi_value CloudFileDownloadNapi::On(napi_env env, napi_callback_info info) { LOGI("On begin"); NFuncArg funcArg(env, info); @@ -189,6 +161,12 @@ napi_value CloudFileNapi::On(napi_env env, napi_callback_info info) NError(E_PARAMS).ThrowErr(env); return nullptr; } + int32_t ret = CheckPermissions(PERM_CLOUD_SYNC, true); + if (ret != E_OK) { + LOGE("On get progress failed!"); + NError(ret).ThrowErr(env); + return nullptr; + } auto [succProgress, progress, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); if (!succProgress || std::string(progress.get()) != "progress") { LOGE("On get progress failed!"); @@ -201,18 +179,18 @@ napi_value CloudFileNapi::On(napi_env env, napi_callback_info info) NError(E_PARAMS).ThrowErr(env); return nullptr; } - - if (callback_ != nullptr) { - LOGI("callback already exist"); - return NVal::CreateUndefined(env).val_; + auto callbackImpl = GetCallbackImpl(env, funcArg, true); + ret = callbackImpl->RegisterCallback(funcArg[NARG_POS::SECOND]); + if (ret != napi_ok) { + LOGE("On register callback fail, ret: %{public}d", ret); + NError(E_PARAMS).ThrowErr(env); + return nullptr; } - callback_ = make_shared(env, NVal(env, funcArg[(int)NARG_POS::SECOND]).val_); - return NVal::CreateUndefined(env).val_; } -napi_value CloudFileNapi::Off(napi_env env, napi_callback_info info) +napi_value CloudFileDownloadNapi::Off(napi_env env, napi_callback_info info) { LOGI("Off begin"); NFuncArg funcArg(env, info); @@ -221,6 +199,12 @@ napi_value CloudFileNapi::Off(napi_env env, napi_callback_info info) NError(E_PARAMS).ThrowErr(env); return nullptr; } + int32_t ret = CheckPermissions(PERM_CLOUD_SYNC, true); + if (ret != E_OK) { + LOGE("On get progress failed!"); + NError(ret).ThrowErr(env); + return nullptr; + } auto [succProgress, progress, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); if (!succProgress || std::string(progress.get()) != "progress") { LOGE("Off get progress failed!"); @@ -228,62 +212,53 @@ napi_value CloudFileNapi::Off(napi_env env, napi_callback_info info) return nullptr; } - if (funcArg.GetArgc() == (uint)NARG_CNT::TWO && !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function)) { - LOGE("Argument type mismatch"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; + napi_value callbackVel = nullptr; + if (funcArg.GetArgc() == (uint)NARG_CNT::TWO) { + if (!NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function)) { + LOGE("Off argument type mismatch"); + NError(E_PARAMS).ThrowErr(env); + return nullptr; + } + callbackVel = funcArg[NARG_POS::SECOND]; } - /* callback_ may be nullptr */ - int32_t ret = CloudSyncManager::GetInstance().UnregisterDownloadFileCallback(); - if (ret != E_OK) { - LOGE("UnregisterDownloadFileCallback error, ret: %{public}d", ret); - NError(Convert2JsErrNum(ret)).ThrowErr(env); + auto callbackImpl = GetCallbackImpl(env, funcArg, true); + if (callbackImpl == nullptr || callbackImpl->UnregisterCallback(callbackVel) != napi_ok) { + LOGE("Off no callback is registered for this event type"); + NError(E_PARAMS).ThrowErr(env); return nullptr; } - if (callback_ != nullptr) { - /* napi delete reference */ - callback_->DeleteReference(); - callback_ = nullptr; - } return NVal::CreateUndefined(env).val_; } -napi_value CloudFileNapi::Stop(napi_env env, napi_callback_info info) +napi_value CloudFileDownloadNapi::Stop(napi_env env, napi_callback_info info) { LOGI("Stop begin"); NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { LOGE("Stop Number of arguments unmatched"); NError(E_PARAMS).ThrowErr(env); return nullptr; } - auto [succUri, uri, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); - if (!succUri) { + + auto [succUri, uri, size] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); + if (!succUri || size == 0) { LOGE("Stop get uri parameter failed!"); NError(E_PARAMS).ThrowErr(env); return nullptr; } - bool needClean = false; - size_t maxArgSize = static_cast(NARG_CNT::TWO); - if (funcArg.GetArgc() >= NARG_CNT::TWO) { - NVal ui(env, NVal(env, funcArg[(int)NARG_POS::SECOND]).val_); - if (ui.TypeIs(napi_boolean)) { - bool needCleanIgnore; - std::tie(needCleanIgnore, needClean) = NVal(env, funcArg[NARG_POS::SECOND]).ToBool(); - maxArgSize = static_cast(NARG_CNT::THREE); + + auto callbackImpl = GetCallbackImpl(env, funcArg, true); + auto cbExec = [uri{string(uri.get())}, callbackImpl{callbackImpl}]() -> NError { + if (callbackImpl == nullptr) { + LOGE("Failed to get download callback"); + return NError(E_PARAMS); } - } - if (funcArg.GetArgc() == NARG_CNT::THREE) { - maxArgSize = static_cast(NARG_CNT::THREE); - } - auto cbExec = [uri = string(uri.get()), env = env, needClean]() -> NError { - int32_t ret = CloudSyncManager::GetInstance().StopDownloadFile(uri, needClean); + int32_t ret = callbackImpl->StopDownloadInner(uri); if (ret != E_OK) { LOGE("Stop Download failed! ret = %{public}d", ret); return NError(Convert2JsErrNum(ret)); } - LOGI("Stop Download Success!"); return NError(ERRNO_NOERR); }; @@ -295,24 +270,23 @@ napi_value CloudFileNapi::Stop(napi_env env, napi_callback_info info) }; string procedureName = "cloudFileDownload"; - auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, maxArgSize); + auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast(NARG_CNT::TWO)); return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_; } -bool CloudFileNapi::ToExport(std::vector props) +bool CloudFileDownloadNapi::ToExport(std::vector props) { std::string className = GetClassName(); - auto [succ, classValue] = - NClass::DefineClass(exports_.env_, className, Constructor, std::move(props)); + auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props)); if (!succ) { - NError(E_GETRESULT).ThrowErr(exports_.env_); + NError(JsErrCode::E_IPCSS).ThrowErr(exports_.env_); LOGE("Failed to define GallerySync class"); return false; } succ = NClass::SaveClass(exports_.env_, className, classValue); if (!succ) { - NError(E_GETRESULT).ThrowErr(exports_.env_); + NError(JsErrCode::E_IPCSS).ThrowErr(exports_.env_); LOGE("Failed to save GallerySync class"); return false; } @@ -320,23 +294,23 @@ bool CloudFileNapi::ToExport(std::vector props) return exports_.AddProp(className, classValue); } -bool CloudFileNapi::Export() +bool CloudFileDownloadNapi::Export() { vector props = { - NVal::DeclareNapiFunction("start", CloudFileNapi::Start), - NVal::DeclareNapiFunction("on", CloudFileNapi::On), - NVal::DeclareNapiFunction("off", CloudFileNapi::Off), - NVal::DeclareNapiFunction("stop", CloudFileNapi::Stop), + NVal::DeclareNapiFunction("start", CloudFileDownloadNapi::Start), + NVal::DeclareNapiFunction("on", CloudFileDownloadNapi::On), + NVal::DeclareNapiFunction("off", CloudFileDownloadNapi::Off), + NVal::DeclareNapiFunction("stop", CloudFileDownloadNapi::Stop), }; return ToExport(props); } -void CloudFileNapi::SetClassName(std::string classname) +void CloudFileDownloadNapi::SetClassName(std::string classname) { className_ = classname; } -string CloudFileNapi::GetClassName() +string CloudFileDownloadNapi::GetClassName() { return className_; } diff --git a/interfaces/kits/js/cloudfilesync/cloud_file_napi.h b/interfaces/kits/js/cloudfilesync/cloud_file_napi.h index 3eb1e22c3..8a7b5a954 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_file_napi.h +++ b/interfaces/kits/js/cloudfilesync/cloud_file_napi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2023-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 @@ -16,15 +16,17 @@ #ifndef OHOS_FILEMGMT_CLOUD_FILE_NAPI_H #define OHOS_FILEMGMT_CLOUD_FILE_NAPI_H -#include "cloud_download_callback.h" +#include + +#include "download_callback_middle_napi.h" +#include "download_progress_napi.h" #include "filemgmt_libn.h" namespace OHOS::FileManagement::CloudSync { -class CloudDownloadCallbackImpl; -class CloudFileNapi : public LibN::NExporter { +class CloudFileDownloadNapi : public LibN::NExporter { public: - CloudFileNapi(napi_env env, napi_value exports) : NExporter(env, exports) {} - ~CloudFileNapi() = default; + CloudFileDownloadNapi(napi_env env, napi_value exports) : NExporter(env, exports) {} + ~CloudFileDownloadNapi() = default; bool Export() override; bool ToExport(std::vector props); @@ -37,39 +39,19 @@ public: static napi_value Stop(napi_env env, napi_callback_info info); private: - inline static std::mutex mtx_; - inline static bool isDownloadCallbackRegistered_; - static inline std::shared_ptr callback_; - inline static std::string className_ = "CloudFileNapi"; + inline static std::string className_ = "Download"; }; -class CloudDownloadCallbackImpl : public CloudDownloadCallback, - public std::enable_shared_from_this { +class CloudDownloadCallbackImplNapi : public CloudDlCallbackMiddleNapi { public: - CloudDownloadCallbackImpl(napi_env env, napi_value fun, bool isBatch = false); - ~CloudDownloadCallbackImpl() = default; - void OnDownloadProcess(const DownloadProgressObj &progress) override; - void DeleteReference(); - - class UvChangeMsg { - public: - UvChangeMsg(std::shared_ptr CloudDownloadCallbackIn, - DownloadProgressObj downloadProgress, - bool isBatch) - : CloudDownloadCallback_(CloudDownloadCallbackIn), downloadProgress_(downloadProgress), isBatch_(isBatch) - { - } - ~UvChangeMsg() {} - std::weak_ptr CloudDownloadCallback_; - DownloadProgressObj downloadProgress_; - bool isBatch_; - }; + explicit CloudDownloadCallbackImplNapi(napi_env env) : CloudDlCallbackMiddleNapi(env) {} + int32_t StartDownloadInner(const std::string &uri); + int32_t StopDownloadInner(const std::string &uri); +}; -private: - static void OnComplete(UvChangeMsg *msg); - napi_env env_; - napi_ref cbOnRef_ = nullptr; - bool isBatch_; +struct DownloadEntity { + std::shared_ptr callbackImpl{nullptr}; }; + } // namespace OHOS::FileManagement::CloudSync #endif // OHOS_FILEMGMT_CLOUD_FILE_NAPI_H \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/cloud_sync_n_exporter.cpp b/interfaces/kits/js/cloudfilesync/cloud_sync_n_exporter.cpp index 4ac005cee..0850082a0 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_sync_n_exporter.cpp +++ b/interfaces/kits/js/cloudfilesync/cloud_sync_n_exporter.cpp @@ -15,12 +15,12 @@ #include "cloud_sync_n_exporter.h" #include "cloud_file_cache_napi.h" -#include "cloud_file_download_napi.h" #include "cloud_file_napi.h" #include "cloud_file_version_napi.h" #include "cloud_sync_napi.h" #include "file_sync_napi.h" #include "gallery_sync_napi.h" +#include "multi_download_progress_napi.h" #include "utils_log.h" namespace OHOS::FileManagement::CloudSync { @@ -61,6 +61,7 @@ napi_value CloudSyncExport(napi_env env, napi_value exports) InitNotifyType(env, exports); InitCloudSyncFuncs(env, exports); InitOptimizeState(env, exports); + InitDownloadFileType(env, exports); std::vector> products; products.emplace_back(std::make_unique(env, exports)); @@ -68,6 +69,7 @@ napi_value CloudSyncExport(napi_env env, napi_value exports) products.emplace_back(std::make_unique(env, exports)); products.emplace_back(std::make_unique(env, exports)); products.emplace_back(std::make_unique(env, exports)); + 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 cloudSyncDownload ", @@ -226,6 +228,20 @@ void InitCloudSyncFuncs(napi_env env, napi_value exports) napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); } +void InitDownloadFileType(napi_env env, napi_value exports) +{ + char propertyName[] = "DownloadFileType"; + napi_property_descriptor desc[] = { + DECLARE_NAPI_STATIC_PROPERTY("CONTENT", NVal::CreateInt32(env, FieldKey::FIELDKEY_CONTENT).val_), + DECLARE_NAPI_STATIC_PROPERTY("THUMBNAIL", NVal::CreateInt32(env, FieldKey::FIELDKEY_THUMB).val_), + DECLARE_NAPI_STATIC_PROPERTY("LCD", NVal::CreateInt32(env, FieldKey::FIELDKEY_LCD).val_), + }; + napi_value obj = nullptr; + napi_create_object(env, &obj); + napi_define_properties(env, obj, sizeof(desc) / sizeof(desc[0]), desc); + napi_set_named_property(env, exports, propertyName, obj); +} + static napi_module _module = { .nm_version = 1, .nm_flags = 0, diff --git a/interfaces/kits/js/cloudfilesync/cloud_sync_n_exporter.h b/interfaces/kits/js/cloudfilesync/cloud_sync_n_exporter.h index 597ddd59b..3b3131e25 100644 --- a/interfaces/kits/js/cloudfilesync/cloud_sync_n_exporter.h +++ b/interfaces/kits/js/cloudfilesync/cloud_sync_n_exporter.h @@ -28,5 +28,6 @@ void InitDownloadErrorType(napi_env env, napi_value exports); void InitNotifyType(napi_env env, napi_value exports); void InitCloudSyncFuncs(napi_env env, napi_value exports); void InitOptimizeState(napi_env env, napi_value exports); +void InitDownloadFileType(napi_env env, napi_value exports); } // namespace OHOS::FileManagement::CloudSync #endif // OHOS_FILEMGMT_CLOUD_SYNC_N_EXPORTER_H \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/download_callback_middle_napi.cpp b/interfaces/kits/js/cloudfilesync/download_callback_middle_napi.cpp new file mode 100644 index 000000000..bd0ba7c62 --- /dev/null +++ b/interfaces/kits/js/cloudfilesync/download_callback_middle_napi.cpp @@ -0,0 +1,89 @@ +/* + * 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 "download_callback_middle_napi.h" +#include "dfs_error.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudSync { +void CloudDlCallbackMiddleNapi::RemoveDownloadInfo(int64_t downloadId) +{ + std::lock_guard lock(downloadInfoMtx_); + downloadInfos_.erase(downloadId); +} + +std::shared_ptr CloudDlCallbackMiddleNapi::GetDownloadInfo(int64_t downloadId) +{ + std::lock_guard lock(downloadInfoMtx_); + auto it = downloadInfos_.find(downloadId); + if (it != downloadInfos_.end()) { + return it->second; + } + return nullptr; +} + +std::vector CloudDlCallbackMiddleNapi::GetDownloadIdsByUri(const std::string &uri) +{ + std::vector ids; + std::lock_guard lock(downloadInfoMtx_); + for (const auto &[id, progress] : downloadInfos_) { + if (progress->GetUri() == uri) { + ids.push_back(id); + } + } + return ids; +} + +void CloudDlCallbackMiddleNapi::OnDownloadProcess(const DownloadProgressObj &progress) +{ + auto fileCacheInfo = GetDownloadInfo(progress.downloadId); + if (fileCacheInfo == nullptr) { + LOGE("Failed to callback, no such taskId: %{public}lld", static_cast(progress.downloadId)); + return; + } + fileCacheInfo->Update(progress); + std::shared_ptr callbackImpl = shared_from_this(); + napi_status status = napi_send_event( + callbackImpl->env_, + [fileCacheInfo, callbackImpl]() mutable { + if (fileCacheInfo == nullptr || callbackImpl == nullptr) { + LOGE("Failed to callback, is callbackImpl null: %{public}d", (callbackImpl == nullptr)); + return; + } + napi_env tmpEnv = callbackImpl->env_; + napi_handle_scope scope = nullptr; + napi_status status = napi_open_handle_scope(tmpEnv, &scope); + if (status != napi_ok) { + LOGE("Failed to open handle scope, status: %{public}d", status); + napi_close_handle_scope(tmpEnv, scope); + return; + } + napi_value jsProgress = fileCacheInfo->ConvertToValue(tmpEnv); + if (jsProgress == nullptr) { + napi_close_handle_scope(tmpEnv, scope); + return; + } + callbackImpl->OnJsCallback(&jsProgress, 1); + napi_close_handle_scope(tmpEnv, scope); + if (fileCacheInfo->IsNeedClean()) { + callbackImpl->RemoveDownloadInfo(fileCacheInfo->GetTaskId()); + } + }, + napi_eprio_immediate); + if (status != napi_ok) { + LOGE("Failed to execute libuv work queue, status: %{public}d", status); + } +} +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/download_callback_middle_napi.h b/interfaces/kits/js/cloudfilesync/download_callback_middle_napi.h new file mode 100644 index 000000000..da7229004 --- /dev/null +++ b/interfaces/kits/js/cloudfilesync/download_callback_middle_napi.h @@ -0,0 +1,50 @@ +/* + * 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_DOWNLOAD_CALLBACK_MIDDLE_NAPI_H +#define OHOS_FILEMGMT_DOWNLOAD_CALLBACK_MIDDLE_NAPI_H + +#include +#include +#include +#include +#include + +#include "cloud_download_callback.h" +#include "download_progress_napi.h" +#include "register_callback_manager_napi.h" + +namespace OHOS::FileManagement::CloudSync { +class CloudDlCallbackMiddleNapi : public CloudDownloadCallback, + public RegisterCallbackManagerNapi, + public std::enable_shared_from_this { +public: + explicit CloudDlCallbackMiddleNapi(napi_env env) : RegisterCallbackManagerNapi(env) {} + virtual ~CloudDlCallbackMiddleNapi() = default; + void OnDownloadProcess(const DownloadProgressObj &progress) override; + void RemoveDownloadInfo(int64_t downloadId); + +protected: + virtual void DownloadProgressInner(std::shared_ptr progress){}; + std::vector GetDownloadIdsByUri(const std::string &uri); + std::shared_ptr GetDownloadInfo(int64_t downloadId); + +protected: + std::mutex downloadInfoMtx_; + std::unordered_map> downloadInfos_; +}; + +} // namespace OHOS::FileManagement::CloudSync +#endif // OHOS_FILEMGMT_DOWNLOAD_CALLBACK_MIDDLE_NAPI_H \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/download_progress_napi.cpp b/interfaces/kits/js/cloudfilesync/download_progress_napi.cpp new file mode 100644 index 000000000..c8090b7f1 --- /dev/null +++ b/interfaces/kits/js/cloudfilesync/download_progress_napi.cpp @@ -0,0 +1,82 @@ +/* + * 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 "download_progress_napi.h" +#include "dfs_error.h" +#include "multi_download_progress_napi.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudSync { +using namespace FileManagement::LibN; +void SingleProgressNapi::Update(const DownloadProgressObj &progress) +{ + if (taskId_ != progress.downloadId) { + return; + } + uri_ = progress.path; + totalSize_ = progress.totalSize; + downloadedSize_ = progress.downloadedSize; + state_ = progress.state; + errorType_ = progress.downloadErrorType; + needClean_ = (progress.state != DownloadProgressObj::RUNNING); +} + +napi_value SingleProgressNapi::ConvertToValue(napi_env env) +{ + NVal obj = NVal::CreateObject(env); + obj.AddProp("state", NVal::CreateInt32(env, state_).val_); + obj.AddProp("processed", NVal::CreateInt64(env, downloadedSize_).val_); + obj.AddProp("size", NVal::CreateInt64(env, totalSize_).val_); + obj.AddProp("uri", NVal::CreateUTF8String(env, uri_).val_); + obj.AddProp("error", NVal::CreateInt32(env, errorType_).val_); + return obj.val_; +} + +void BatchProgressNapi::Update(const DownloadProgressObj &progress) +{ + if (taskId_ != progress.downloadId) { + return; + } + state_ = static_cast(progress.batchState); + taskId_ = progress.downloadId; + downloadedSize_ = progress.batchDownloadSize; + totalSize_ = progress.batchTotalSize; + totalNum_ = progress.batchTotalNum; + errorType_ = static_cast(progress.downloadErrorType); + if (progress.state == DownloadProgressObj::COMPLETED) { + downloadedFiles_.insert(progress.path); + } else if (progress.state != DownloadProgressObj::RUNNING) { + failedFiles_.insert(std::make_pair(progress.path, static_cast(progress.downloadErrorType))); + } + needClean_ = ((progress.batchTotalNum == progress.batchFailNum + progress.batchSuccNum) && + progress.batchState != DownloadProgressObj::RUNNING); +} + +napi_value BatchProgressNapi::ConvertToValue(napi_env env) +{ + napi_value progressVal = NClass::InstantiateClass(env, MultiDlProgressNapi::className_, {}); + if (progressVal == nullptr) { + LOGE("Failed to instantiate class"); + return nullptr; + } + auto progressEntity = NClass::GetEntityOf(env, progressVal); + if (progressEntity == nullptr) { + LOGE("Failed to get progressEntity."); + return nullptr; + } + progressEntity->downloadProgress = std::make_unique(*this); + return progressVal; +} +} // namespace OHOS::FileManagement::CloudSync diff --git a/interfaces/kits/js/cloudfilesync/download_progress_napi.h b/interfaces/kits/js/cloudfilesync/download_progress_napi.h new file mode 100644 index 000000000..514fe7699 --- /dev/null +++ b/interfaces/kits/js/cloudfilesync/download_progress_napi.h @@ -0,0 +1,116 @@ +/* + * 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_DOWNLOAD_PROGRESS_NAPI_H +#define OHOS_FILEMGMT_DOWNLOAD_PROGRESS_NAPI_H + +#include +#include +#include + +#include "cloud_sync_common.h" +#include "n_napi.h" + +namespace OHOS::FileManagement::CloudSync { +class DlProgressNapi { +public: + explicit DlProgressNapi(int64_t downloadId) : taskId_(downloadId) {} + virtual ~DlProgressNapi() = default; + virtual void Update(const DownloadProgressObj &progress) = 0; + virtual napi_value ConvertToValue(napi_env env) = 0; + + // Use default inline + int64_t GetTaskId() const + { + return taskId_; + } + int64_t GetTotalSize() const + { + return totalSize_; + } + int64_t GetDownloadedSize() const + { + return downloadedSize_; + } + int32_t GetState() const + { + return state_; + } + int32_t GetErrorType() const + { + return errorType_; + } + bool IsNeedClean() const + { + return needClean_; + } + std::string GetUri() const + { + return uri_; + } + +protected: + std::string uri_; + // taskId_ is used to identify the download task, it is unique for each download task. + int64_t taskId_{0}; + int64_t totalSize_{0}; + int64_t downloadedSize_{0}; + int32_t state_{0}; + int32_t errorType_{0}; + bool needClean_{false}; +}; + +class SingleProgressNapi : public DlProgressNapi { +public: + explicit SingleProgressNapi(int64_t downloadId) : DlProgressNapi(downloadId) {} + void Update(const DownloadProgressObj &progress) override; + napi_value ConvertToValue(napi_env env) override; +}; + +class BatchProgressNapi : public DlProgressNapi { +public: + explicit BatchProgressNapi(int64_t downloadId) : DlProgressNapi(downloadId) {} + void Update(const DownloadProgressObj &progress) override; + napi_value ConvertToValue(napi_env env) override; + + // Getters for batch download progress + int64_t GetTotalNum() const + { + return totalNum_; + } + std::size_t GetSuccNum() const + { + return downloadedFiles_.size(); + } + std::size_t GetFailedNum() const + { + return failedFiles_.size(); + } + std::unordered_set GetDownloadedFiles() const + { + return downloadedFiles_; + } + std::unordered_map GetFailedFiles() const + { + return failedFiles_; + } + +private: + int64_t totalNum_{0}; + std::unordered_set downloadedFiles_; + std::unordered_map failedFiles_; +}; +} // namespace OHOS::FileManagement::CloudSync +#endif // OHOS_FILEMGMT_DOWNLOAD_PROGRESS_NAPI_H diff --git a/interfaces/kits/js/cloudfilesync/multi_download_progress_core.cpp b/interfaces/kits/js/cloudfilesync/multi_download_progress_core.cpp new file mode 100644 index 000000000..2f045c174 --- /dev/null +++ b/interfaces/kits/js/cloudfilesync/multi_download_progress_core.cpp @@ -0,0 +1,163 @@ +/* + * 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 "multi_download_progress_core.h" + +#include "cloud_sync_common.h" +#include "dfs_error.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudSync { +using namespace ModuleFileIO; +using namespace std; +FsResult MultiDlProgressCore::Constructor() +{ + MultiDlProgressCore *dlProgress = new MultiDlProgressCore(); + if (dlProgress == nullptr) { + LOGE("Failed to create MultiDlProgressCore object on heap."); + return FsResult::Error(Convert2ErrNum(E_SERVICE_INNER_ERROR)); + } + + return FsResult::Success(move(dlProgress)); +} + +int32_t MultiDlProgressCore::GetStatus() +{ + int32_t state = static_cast(DownloadProgressObj::Status::FAILED); + if (downloadProgress == nullptr) { + LOGE("Failed to get multiDlProgress."); + } else { + state = downloadProgress->GetState(); + } + + return state; +} + +int64_t MultiDlProgressCore::GetTaskId() +{ + int64_t taskId = 0; + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + taskId = downloadProgress->GetTaskId(); + } + + return taskId; +} + +int64_t MultiDlProgressCore::GetDownloadedNum() +{ + int64_t succNum = -1; + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + succNum = downloadProgress->GetSuccNum(); + } + + return succNum; +} + +int64_t MultiDlProgressCore::GetFailedNum() +{ + int64_t failedNum = -1; + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + failedNum = downloadProgress->GetFailedNum(); + } + + return failedNum; +} + +int64_t MultiDlProgressCore::GetTotalNum() +{ + int64_t totalNum = -1; + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + totalNum = downloadProgress->GetTotalNum(); + } + + return totalNum; +} + +int64_t MultiDlProgressCore::GetDownloadedSize() +{ + int64_t downloadSize = INT64_MAX; + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + downloadSize = downloadProgress->GetDownloadedSize(); + } + + return downloadSize; +} + +int64_t MultiDlProgressCore::GetTotalSize() +{ + int64_t totalSize = INT64_MAX; + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + totalSize = downloadProgress->GetTotalSize(); + } + + return totalSize; +} + +int32_t MultiDlProgressCore::GetErrorType() +{ + int32_t errorType = static_cast(DownloadProgressObj::DownloadErrorType::UNKNOWN_ERROR); + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + errorType = downloadProgress->GetErrorType(); + } + + return errorType; +} + +FsResult> MultiDlProgressCore::GetFailedFileList() +{ + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + return FsResult>::Error(Convert2ErrNum(E_SERVICE_INNER_ERROR)); + } + auto failedFiles = downloadProgress->GetFailedFiles(); + std::vector res; + for (auto &iter : failedFiles) { + res.emplace_back(iter.first, iter.second); + } + + return FsResult>::Success(res); +} + +FsResult> MultiDlProgressCore::GetDownloadedFileList() +{ + if (downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + return FsResult>::Error(Convert2ErrNum(E_SERVICE_INNER_ERROR)); + } + + auto downloadedFiles = downloadProgress->GetDownloadedFiles(); + std::vector res(downloadedFiles.begin(), downloadedFiles.end()); + return FsResult>::Success(res); +} + +void MultiDlProgressCore::SetProgress(std::shared_ptr progress) +{ + downloadProgress = progress; +} +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/multi_download_progress_core.h b/interfaces/kits/js/cloudfilesync/multi_download_progress_core.h new file mode 100644 index 000000000..3c6942389 --- /dev/null +++ b/interfaces/kits/js/cloudfilesync/multi_download_progress_core.h @@ -0,0 +1,53 @@ +/* + * 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_MULTI_DOWNLOAD_PROGRESS_CORE_H +#define OHOS_FILEMGMT_MULTI_DOWNLOAD_PROGRESS_CORE_H + +#include + +#include "download_progress_ani.h" +#include "filemgmt_libfs.h" + +namespace OHOS::FileManagement::CloudSync { +struct FailedFileInfo { + FailedFileInfo(const std::string &file, int32_t err) : uri(file), error(err) {} + std::string uri; + int32_t error{0}; +}; + +class MultiDlProgressCore { +public: + MultiDlProgressCore() = default; + ~MultiDlProgressCore() = default; + + static ModuleFileIO::FsResult Constructor(); + int32_t GetStatus(); + int64_t GetTaskId(); + int64_t GetDownloadedNum(); + int64_t GetFailedNum(); + int64_t GetTotalNum(); + int64_t GetDownloadedSize(); + int64_t GetTotalSize(); + int32_t GetErrorType(); + ModuleFileIO::FsResult> GetFailedFileList(); + ModuleFileIO::FsResult> GetDownloadedFileList(); + void SetProgress(std::shared_ptr progress); + +private: + std::shared_ptr downloadProgress{nullptr}; +}; +} // namespace OHOS::FileManagement::CloudSync +#endif // OHOS_FILEMGMT_MULTI_DOWNLOAD_PROGRESS_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/multi_download_progress_napi.cpp b/interfaces/kits/js/cloudfilesync/multi_download_progress_napi.cpp new file mode 100644 index 000000000..426f035f2 --- /dev/null +++ b/interfaces/kits/js/cloudfilesync/multi_download_progress_napi.cpp @@ -0,0 +1,279 @@ +/* + * 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 "multi_download_progress_napi.h" + +#include "cloud_sync_common.h" +#include "dfs_error.h" +#include "download_progress_napi.h" +#include "utils_log.h" + +namespace OHOS::FileManagement::CloudSync { +using namespace FileManagement::LibN; +using namespace std; +napi_value MultiDlProgressNapi::Constructor(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + auto progressEntity = make_unique(); + if (progressEntity == nullptr) { + LOGE("Failed to request heap memory."); + return nullptr; + } + if (!NClass::SetEntityFor(env, funcArg.GetThisVar(), move(progressEntity))) { + LOGE("Failed to set progressEntity."); + return nullptr; + } + return funcArg.GetThisVar(); +} + +napi_value MultiDlProgressNapi::GetStatus(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + int32_t state = static_cast(DownloadProgressObj::Status::FAILED); + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + state = progressEntity->downloadProgress->GetState(); + } + + return NVal::CreateInt32(env, state).val_; +} + +napi_value MultiDlProgressNapi::GetTaskId(napi_env env, napi_callback_info info) +{ + int64_t taskId = 0; + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + taskId = progressEntity->downloadProgress->GetTaskId(); + } + + return NVal::CreateInt64(env, taskId).val_; +} + +napi_value MultiDlProgressNapi::GetDownloadedNum(napi_env env, napi_callback_info info) +{ + int64_t succNum = -1; + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + succNum = static_cast(progressEntity->downloadProgress->GetSuccNum()); + } + + return NVal::CreateInt64(env, succNum).val_; +} + +napi_value MultiDlProgressNapi::GetFailedNum(napi_env env, napi_callback_info info) +{ + int64_t failedNum = -1; + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + failedNum = static_cast(progressEntity->downloadProgress->GetFailedNum()); + } + + return NVal::CreateInt64(env, failedNum).val_; +} + +napi_value MultiDlProgressNapi::GetTotalNum(napi_env env, napi_callback_info info) +{ + int64_t totalNum = -1; + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + totalNum = progressEntity->downloadProgress->GetTotalNum(); + } + + return NVal::CreateInt64(env, totalNum).val_; +} + +napi_value MultiDlProgressNapi::GetDownloadedSize(napi_env env, napi_callback_info info) +{ + int64_t downloadSize = INT64_MAX; + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + downloadSize = progressEntity->downloadProgress->GetDownloadedSize(); + } + + return NVal::CreateInt64(env, downloadSize).val_; +} + +napi_value MultiDlProgressNapi::GetTotalSize(napi_env env, napi_callback_info info) +{ + int64_t totalSize = INT64_MAX; + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + totalSize = progressEntity->downloadProgress->GetTotalSize(); + } + + return NVal::CreateInt64(env, totalSize).val_; +} + +napi_value MultiDlProgressNapi::GetErrorType(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + funcArg.InitArgs(NARG_CNT::ZERO); + int32_t errorType = static_cast(DownloadProgressObj::DownloadErrorType::UNKNOWN_ERROR); + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + } else { + errorType = progressEntity->downloadProgress->GetErrorType(); + } + + return NVal::CreateInt32(env, errorType).val_; +} + +napi_value MultiDlProgressNapi::GetFailedFileList(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + LOGE("Failed to get param."); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); + return nullptr; + } + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); + return nullptr; + } + napi_value res = nullptr; + napi_status status = napi_create_array(env, &res); + if (status != napi_ok) { + HILOGE("Failed to creat array"); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); + return nullptr; + } + + size_t index = 0; + auto failedFiles = progressEntity->downloadProgress->GetFailedFiles(); + for (const auto &iter : failedFiles) { + NVal obj = NVal::CreateObject(env); + obj.AddProp("uri", NVal::CreateUTF8String(env, iter.first).val_); + obj.AddProp("error", NVal::CreateInt32(env, iter.second).val_); + status = napi_set_element(env, res, index, obj.val_); + if (status != napi_ok) { + HILOGE("Failed to set element on data, %{public}s", GetAnonyString(iter.first).c_str()); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); + return nullptr; + } + index++; + } + + return res; +} + +napi_value MultiDlProgressNapi::GetDownloadedFileList(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + LOGE("Failed to get param."); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); + return nullptr; + } + auto progressEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (progressEntity == nullptr || progressEntity->downloadProgress == nullptr) { + LOGE("Failed to get MultiDlProgressEntity."); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); + return nullptr; + } + napi_value res = nullptr; + napi_status status = napi_create_array(env, &res); + if (status != napi_ok) { + HILOGE("Failed to creat array"); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); + return nullptr; + } + + size_t index = 0; + auto downloadedFiles = progressEntity->downloadProgress->GetDownloadedFiles(); + for (const auto &item : downloadedFiles) { + status = napi_set_element(env, res, index, NVal::CreateUTF8String(env, item).val_); + if (status != napi_ok) { + HILOGE("Failed to set element on data, %{public}s", GetAnonyString(item).c_str()); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(env); + return nullptr; + } + index++; + } + + return res; +} + +std::string MultiDlProgressNapi::GetClassName() +{ + return className_; +} + +bool MultiDlProgressNapi::Export() +{ + vector props = { + NVal::DeclareNapiGetter("state", GetStatus), + NVal::DeclareNapiGetter("taskId", GetTaskId), + NVal::DeclareNapiGetter("successfulCount", GetDownloadedNum), + NVal::DeclareNapiGetter("failedCount", GetFailedNum), + NVal::DeclareNapiGetter("totalCount", GetTotalNum), + NVal::DeclareNapiGetter("downloadedSize", GetDownloadedSize), + NVal::DeclareNapiGetter("totalSize", GetTotalSize), + NVal::DeclareNapiGetter("errType", GetErrorType), + NVal::DeclareNapiFunction("getFailedFiles", GetFailedFileList), + NVal::DeclareNapiFunction("getSuccessfulFiles", GetDownloadedFileList), + }; + + string className = GetClassName(); + bool succ = false; + napi_value classValue = nullptr; + tie(succ, classValue) = + NClass::DefineClass(exports_.env_, className, MultiDlProgressNapi::Constructor, move(props)); + if (!succ) { + LOGE("Define class exceptions"); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(exports_.env_); + return false; + } + succ = NClass::SaveClass(exports_.env_, className, classValue); + if (!succ) { + LOGE("Save class exceptions"); + NError(JsErrCode::E_INNER_FAILED).ThrowErr(exports_.env_); + return false; + } + + return exports_.AddProp(className, classValue); +} + +} // namespace OHOS::FileManagement::CloudSync \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/multi_download_progress_napi.h b/interfaces/kits/js/cloudfilesync/multi_download_progress_napi.h new file mode 100644 index 000000000..e5ebaeecf --- /dev/null +++ b/interfaces/kits/js/cloudfilesync/multi_download_progress_napi.h @@ -0,0 +1,51 @@ +/* + * 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_MULTI_DOWNLOAD_PROGRESS_NAPI_H +#define OHOS_FILEMGMT_MULTI_DOWNLOAD_PROGRESS_NAPI_H + +#include + +#include "filemgmt_libn.h" + +namespace OHOS::FileManagement::CloudSync { +class BatchProgressNapi; +class MultiDlProgressNapi final : public LibN::NExporter { +public: + MultiDlProgressNapi(napi_env env, napi_value exports) : NExporter(env, exports) {} + ~MultiDlProgressNapi() = default; + + bool Export() override; + std::string GetClassName() override; + static napi_value Constructor(napi_env env, napi_callback_info info); + static napi_value GetStatus(napi_env env, napi_callback_info info); + static napi_value GetTaskId(napi_env env, napi_callback_info info); + static napi_value GetDownloadedNum(napi_env env, napi_callback_info info); + static napi_value GetFailedNum(napi_env env, napi_callback_info info); + static napi_value GetTotalNum(napi_env env, napi_callback_info info); + static napi_value GetDownloadedSize(napi_env env, napi_callback_info info); + static napi_value GetTotalSize(napi_env env, napi_callback_info info); + static napi_value GetErrorType(napi_env env, napi_callback_info info); + static napi_value GetFailedFileList(napi_env env, napi_callback_info info); + static napi_value GetDownloadedFileList(napi_env env, napi_callback_info info); + + inline static const std::string className_ = "MultiDownloadProgress"; +}; + +struct MultiDlProgressEntity { + std::unique_ptr downloadProgress{nullptr}; +}; +} // namespace OHOS::FileManagement::CloudSync +#endif // OHOS_FILEMGMT_MULTI_DOWNLOAD_PROGRESS_NAPI_H \ No newline at end of file diff --git a/interfaces/kits/js/cloudfilesync/register_callback_manager.cpp b/interfaces/kits/js/cloudfilesync/register_callback_manager_napi.cpp similarity index 90% rename from interfaces/kits/js/cloudfilesync/register_callback_manager.cpp rename to interfaces/kits/js/cloudfilesync/register_callback_manager_napi.cpp index 3d3cbb623..67a2d6e1d 100644 --- a/interfaces/kits/js/cloudfilesync/register_callback_manager.cpp +++ b/interfaces/kits/js/cloudfilesync/register_callback_manager_napi.cpp @@ -13,12 +13,14 @@ * limitations under the License. */ -#include "register_callback_manager.h" +#include "register_callback_manager_napi.h" + #include "utils_log.h" namespace OHOS::FileManagement::CloudSync { +using namespace FileManagement::LibN; using namespace std; -napi_status RegisterCallbackManager::RegisterCallback(napi_value callback) +napi_status RegisterCallbackManagerNapi::RegisterCallback(napi_value callback) { if (callback == nullptr) { return napi_invalid_arg; @@ -39,7 +41,7 @@ napi_status RegisterCallbackManager::RegisterCallback(napi_value callback) return napi_ok; } -napi_status RegisterCallbackManager::UnregisterCallback(napi_value callback) +napi_status RegisterCallbackManagerNapi::UnregisterCallback(napi_value callback) { if (validRefNum_ == 0) { return napi_ok; @@ -78,7 +80,7 @@ napi_status RegisterCallbackManager::UnregisterCallback(napi_value callback) } // No need to lock -bool RegisterCallbackManager::IsExisted(napi_value callback) +bool RegisterCallbackManagerNapi::IsExisted(napi_value callback) { bool isExisted = false; napi_value val = nullptr; @@ -102,7 +104,7 @@ bool RegisterCallbackManager::IsExisted(napi_value callback) } // Running in JS thread -void RegisterCallbackManager::OnJsCallback(napi_value *value, uint32_t argc) +void RegisterCallbackManagerNapi::OnJsCallback(napi_value *value, uint32_t argc) { std::lock_guard lock(callbackMtx_); for (auto iter = callbackList_.begin(); iter != callbackList_.end();) { diff --git a/interfaces/kits/js/cloudfilesync/register_callback_manager.h b/interfaces/kits/js/cloudfilesync/register_callback_manager_napi.h similarity index 79% rename from interfaces/kits/js/cloudfilesync/register_callback_manager.h rename to interfaces/kits/js/cloudfilesync/register_callback_manager_napi.h index 51aa3a8af..1c1df12e0 100644 --- a/interfaces/kits/js/cloudfilesync/register_callback_manager.h +++ b/interfaces/kits/js/cloudfilesync/register_callback_manager_napi.h @@ -13,18 +13,19 @@ * limitations under the License. */ -#ifndef OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_H -#define OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_H +#ifndef OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_NAPI_H +#define OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_NAPI_H #include #include +#include "filemgmt_libn.h" #include "n_napi.h" namespace OHOS::FileManagement::CloudSync { -class RegisterCallbackManager { +class RegisterCallbackManagerNapi { public: - explicit RegisterCallbackManager(napi_env env) : env_(env) {} + explicit RegisterCallbackManagerNapi(napi_env env) : env_(env) {} bool IsExisted(napi_value callback); napi_status RegisterCallback(napi_value callback); napi_status UnregisterCallback(napi_value callback); @@ -37,4 +38,4 @@ protected: std::list> callbackList_; }; } // namespace OHOS::FileManagement::CloudSync -#endif // OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_H \ No newline at end of file +#endif // OHOS_FILEMGMT_REGISTER_CALLBACK_MANAGER_NAPI_H \ No newline at end of file diff --git a/services/cloudsyncservice/ICloudSyncService.idl b/services/cloudsyncservice/ICloudSyncService.idl index a29a38546..1ffd78972 100644 --- a/services/cloudsyncservice/ICloudSyncService.idl +++ b/services/cloudsyncservice/ICloudSyncService.idl @@ -45,16 +45,12 @@ interface OHOS.FileManagement.CloudSync.ICloudSyncService void NotifyEventChange([in] int userId, [in] String eventId, [in] String extraData); void EnableCloud([in] String accoutId, [in] SwitchDataObj switchData); void DisableCloud([in] String accoutId); - void StartDownloadFile([in] String path); - void StartFileCache([in] String[] pathVec, [out] long downloadId, [in] int fieldkey, [in] boolean isCallbackValid, + void StartDownloadFile([in] String uri, [in] IRemoteObject downloadCallback, [out] long downloadId); + void StartFileCache([in] String[] uriVec, [out] long downloadId, [in] int fieldkey, [in] IRemoteObject downloadCallback, [in] int timeout); - void StopDownloadFile([in] String path, [in] boolean needClean); + void StopDownloadFile([in] long downloadId, [in] boolean needClean); void StopFileCache([in] long downloadId, [in] boolean needClean, [in] int timeout); void DownloadThumb(); - void RegisterDownloadFileCallback([in] IRemoteObject downloadCallback); - void RegisterFileCacheCallback([in] IRemoteObject downloadCallback); - void UnregisterDownloadFileCallback(); - void UnregisterFileCacheCallback(); void UploadAsset([in] int userId, [in] String request, [out] String resultStr); void DownloadFile([in] int userId, [in] String bundleName, [in] AssetInfoObj assetInfoObj); void DownloadFiles([in] int userId, [in] String bundleName, [in] AssetInfoObj[] assetInfoObj, diff --git a/services/cloudsyncservice/include/ipc/cloud_sync_service.h b/services/cloudsyncservice/include/ipc/cloud_sync_service.h index 6642870c6..901236844 100644 --- a/services/cloudsyncservice/include/ipc/cloud_sync_service.h +++ b/services/cloudsyncservice/include/ipc/cloud_sync_service.h @@ -63,20 +63,17 @@ public: ErrCode NotifyEventChange(int32_t userId, const std::string &eventId, const std::string &extraData) override; ErrCode EnableCloud(const std::string &accoutId, const SwitchDataObj &switchData) override; ErrCode DisableCloud(const std::string &accoutId) override; - ErrCode StartDownloadFile(const std::string &path) override; + ErrCode StartDownloadFile(const std::string &uri, + const sptr &downloadCallback, + int64_t &downloadId) override; ErrCode StartFileCache(const std::vector &uriVec, int64_t &downloadId, int32_t fieldkey, - bool isCallbackValid, const sptr &downloadCallback, int32_t timeout = -1) override; - ErrCode StopDownloadFile(const std::string &path, bool needClean = false) override; + ErrCode StopDownloadFile(int64_t downloadId, bool needClean = false) override; ErrCode StopFileCache(int64_t downloadId, bool needClean = false, int32_t timeout = -1) override; ErrCode DownloadThumb() override; - ErrCode RegisterDownloadFileCallback(const sptr &downloadCallback) override; - ErrCode RegisterFileCacheCallback(const sptr &downloadCallback) override; - ErrCode UnregisterDownloadFileCallback() override; - ErrCode UnregisterFileCacheCallback() override; ErrCode UploadAsset(const int32_t userId, const std::string &request, std::string &result) override; ErrCode DownloadFile(const int32_t userId, const std::string &bundleName, const AssetInfoObj &assetInfoObj) override; diff --git a/services/cloudsyncservice/src/ipc/cloud_sync_service.cpp b/services/cloudsyncservice/src/ipc/cloud_sync_service.cpp index c853cec7f..fb377b113 100644 --- a/services/cloudsyncservice/src/ipc/cloud_sync_service.cpp +++ b/services/cloudsyncservice/src/ipc/cloud_sync_service.cpp @@ -800,7 +800,6 @@ int32_t CloudSyncService::Clean(const std::string &accountId, const CleanOptions int32_t CloudSyncService::StartFileCache(const std::vector &uriVec, int64_t &downloadId, int32_t fieldkey, - bool isCallbackValid, const sptr &downloadCallback, int32_t timeout) { @@ -820,16 +819,15 @@ int32_t CloudSyncService::StartFileCache(const std::vector &uriVec, return ret; } - sptr downloadCb = nullptr; - if (isCallbackValid) { - downloadCb = iface_cast(downloadCallback); - } + sptr downloadCb = iface_cast(downloadCallback); ret = dataSyncManager_->StartDownloadFile(bundleNameUserInfo, uriVec, downloadId, fieldkey, downloadCb, timeout); LOGI("End StartFileCache, ret: %{public}d", ret); return ret; } -int32_t CloudSyncService::StartDownloadFile(const std::string &path) +int32_t CloudSyncService::StartDownloadFile(const std::string &uri, + const sptr &downloadCallback, + int64_t &downloadId) { LOGI("Begin StartDownloadFile"); RETURN_ON_ERR(CheckPermissions(PERM_CLOUD_SYNC, true)); @@ -839,16 +837,14 @@ int32_t CloudSyncService::StartDownloadFile(const std::string &path) if (ret != E_OK) { return ret; } - std::vector pathVec; - pathVec.push_back(path); - int64_t downloadId = 0; - ret = dataSyncManager_->StartDownloadFile(bundleNameUserInfo, pathVec, downloadId, CloudSync::FIELDKEY_CONTENT, - nullptr); + sptr downloadCb = iface_cast(downloadCallback); + ret = dataSyncManager_->StartDownloadFile(bundleNameUserInfo, {uri}, downloadId, FieldKey::FIELDKEY_CONTENT, + downloadCb); LOGI("End StartDownloadFile"); return ret; } -int32_t CloudSyncService::StopDownloadFile(const std::string &path, bool needClean) +int32_t CloudSyncService::StopDownloadFile(int64_t downloadId, bool needClean) { LOGI("Begin StopDownloadFile"); RETURN_ON_ERR(CheckPermissions(PERM_CLOUD_SYNC, true)); @@ -859,7 +855,7 @@ int32_t CloudSyncService::StopDownloadFile(const std::string &path, bool needCle return ret; } - ret = dataSyncManager_->StopDownloadFile(bundleNameUserInfo, path, needClean); + ret = dataSyncManager_->StopDownloadFile(bundleNameUserInfo, downloadId, needClean); LOGI("End StopDownloadFile"); return ret; } @@ -875,7 +871,7 @@ int32_t CloudSyncService::StopFileCache(int64_t downloadId, bool needClean, int3 return ret; } - ret = dataSyncManager_->StopFileCache(bundleNameUserInfo, downloadId, needClean, timeout); + ret = dataSyncManager_->StopDownloadFile(bundleNameUserInfo, downloadId, needClean, timeout); LOGI("End StopFileCache, ret: %{public}d", ret); return ret; } @@ -890,66 +886,6 @@ int32_t CloudSyncService::DownloadThumb() return ret; } -int32_t CloudSyncService::RegisterDownloadFileCallback(const sptr &downloadCallback) -{ - LOGI("Begin RegisterDownloadFileCallback"); - RETURN_ON_ERR(CheckPermissions(PERM_CLOUD_SYNC, true)); - - BundleNameUserInfo bundleNameUserInfo; - int ret = GetBundleNameUserInfo(bundleNameUserInfo); - if (ret != E_OK) { - return ret; - } - auto downloadCb = iface_cast(downloadCallback); - ret = dataSyncManager_->RegisterDownloadFileCallback(bundleNameUserInfo, downloadCb); - LOGI("End RegisterDownloadFileCallback"); - return ret; -} - -int32_t CloudSyncService::RegisterFileCacheCallback(const sptr &downloadCallback) -{ - LOGI("Begin RegisterDownloadFileCallback"); - BundleNameUserInfo bundleNameUserInfo; - int ret = GetBundleNameUserInfo(bundleNameUserInfo); - if (ret != E_OK) { - return ret; - } - auto downloadCb = iface_cast(downloadCallback); - ret = dataSyncManager_->RegisterDownloadFileCallback(bundleNameUserInfo, downloadCb); - LOGI("End RegisterDownloadFileCallback"); - return ret; -} - -int32_t CloudSyncService::UnregisterDownloadFileCallback() -{ - LOGI("Begin UnregisterDownloadFileCallback"); - RETURN_ON_ERR(CheckPermissions(PERM_CLOUD_SYNC, true)); - - BundleNameUserInfo bundleNameUserInfo; - int ret = GetBundleNameUserInfo(bundleNameUserInfo); - if (ret != E_OK) { - return ret; - } - - ret = dataSyncManager_->UnregisterDownloadFileCallback(bundleNameUserInfo); - LOGI("End UnregisterDownloadFileCallback"); - return ret; -} - -int32_t CloudSyncService::UnregisterFileCacheCallback() -{ - LOGI("Begin UnregisterFileCacheCallback"); - BundleNameUserInfo bundleNameUserInfo; - int ret = GetBundleNameUserInfo(bundleNameUserInfo); - if (ret != E_OK) { - return ret; - } - - ret = dataSyncManager_->UnregisterDownloadFileCallback(bundleNameUserInfo); - LOGI("End UnregisterFileCacheCallback"); - return ret; -} - int32_t CloudSyncService::UploadAsset(const int32_t userId, const std::string &request, std::string &result) { LOGI("Begin UploadAsset"); -- Gitee