• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <thread>
17 
18 #include "utils_log.h"
19 #include "ipc/cloud_download_callback_manager.h"
20 #include "data_sync/task_state_manager.h"
21 
22 namespace OHOS::FileManagement::CloudSync {
23 using namespace std;
24 using namespace DriveKit;
25 
CloudDownloadCallbackManager()26 CloudDownloadCallbackManager::CloudDownloadCallbackManager()
27 {
28     callback_ = nullptr;
29 }
30 
FindDownload(const std::string path)31 bool CloudDownloadCallbackManager::FindDownload(const std::string path)
32 {
33     bool ret = false;
34     lock_guard<mutex> lock(downloadsMtx_);
35     if (downloads_.find(path) != downloads_.end() &&
36         downloads_[path].state == DownloadProgressObj::Status::RUNNING) {
37         ret = true;
38     }
39     return ret;
40 }
41 
StartDonwload(const std::string path,const int32_t userId,const int64_t downloadId)42 void CloudDownloadCallbackManager::StartDonwload(const std::string path,
43                                                  const int32_t userId,
44                                                  const int64_t downloadId)
45 {
46     lock_guard<mutex> lock(downloadsMtx_);
47     TaskStateManager::GetInstance().StartTask(bundleName_, TaskType::DOWNLOAD_TASK);
48     if (downloads_.find(path) == downloads_.end()) {
49         downloads_[path].refCount = 1;
50     } else {
51         downloads_[path].refCount++;
52     }
53     downloads_[path].state = DownloadProgressObj::Status::RUNNING;
54     downloads_[path].path = path;
55     downloads_[path].downloadId = downloadId;
56     LOGI("download_file : %{public}d start download %{public}s callback success.", userId, path.c_str());
57 }
58 
StopDonwload(const std::string path,const int32_t userId,DownloadProgressObj & download)59 bool CloudDownloadCallbackManager::StopDonwload(const std::string path, const int32_t userId,
60     DownloadProgressObj &download)
61 {
62     bool ret = false;
63     lock_guard<mutex> lock(downloadsMtx_);
64 
65     auto res = downloads_.find(path);
66     bool isDownloading = (res != downloads_.end());
67     if (isDownloading) {
68         download = res->second;
69         LOGI("download_file : %{public}d stop download %{public}s callback success.", userId, path.c_str());
70         downloads_.erase(res);
71         ret = true;
72     } else {
73         LOGI("download_file : %{public}d stop download %{public}s callback fail, task not exist.",
74             userId, path.c_str());
75         ret = false;
76     }
77     CheckTaskState();
78     return ret;
79 }
80 
StopAllDownloads(const int32_t userId)81 std::vector<int64_t> CloudDownloadCallbackManager::StopAllDownloads(const int32_t userId)
82 {
83     std::vector<int64_t> ret;
84     lock_guard<mutex> lock(downloadsMtx_);
85     for (auto &pair : downloads_) {
86         pair.second.state = DownloadProgressObj::Status::FAILED;
87         ret.push_back(pair.second.downloadId);
88         if (callback_ != nullptr) {
89             callback_->OnDownloadProcess(pair.second);
90             LOGI("download_file : %{public}d stop download %{public}s callback success.", userId, pair.first.c_str());
91         }
92     }
93     downloads_.clear();
94     CheckTaskState();
95     return ret;
96 }
97 
RegisterCallback(const int32_t userId,const sptr<ICloudDownloadCallback> downloadCallback)98 void CloudDownloadCallbackManager::RegisterCallback(const int32_t userId,
99                                                     const sptr<ICloudDownloadCallback> downloadCallback)
100 {
101     LOGI("download_file : %{public}d register download callback : %{public}d", userId,
102         downloadCallback != nullptr);
103     unique_lock<mutex> lock(callbackMutex_);
104     callback_ = downloadCallback;
105 }
106 
UnregisterCallback(const int32_t userId)107 void CloudDownloadCallbackManager::UnregisterCallback(const int32_t userId)
108 {
109     LOGI("download_file : %{public}d unregister download callback", userId);
110     unique_lock<mutex> lock(callbackMutex_);
111     callback_ = nullptr;
112 }
113 
OnDownloadFailed(int32_t & downloadErrorType,const DKError & dkError)114 static void OnDownloadFailed(int32_t &downloadErrorType, const DKError &dkError)
115 {
116     downloadErrorType = DownloadProgressObj::UNKNOWN_ERROR;
117     if (static_cast<DKServerErrorCode>(dkError.serverErrorCode) == DKServerErrorCode::NETWORK_ERROR) {
118         downloadErrorType = DownloadProgressObj::NETWORK_UNAVAILABLE;
119     }
120     if (dkError.errorDetails.size() != 0) {
121         auto errorDetailCode = static_cast<DKDetailErrorCode>(dkError.errorDetails[0].detailCode);
122         if (errorDetailCode == DKDetailErrorCode::SPACE_FULL) {
123             downloadErrorType = DownloadProgressObj::LOCAL_STORAGE_FULL;
124         } else if (errorDetailCode == DKDetailErrorCode::THUMBNAIL_NOT_FOUND ||
125                    errorDetailCode == DKDetailErrorCode::ORIGINAL_NOT_EXSIT) {
126             downloadErrorType = DownloadProgressObj::CONTENT_NOT_FOUND;
127         } else if (errorDetailCode == DKDetailErrorCode::USER_REQUEST_TOO_MANY ||
128                    errorDetailCode == DKDetailErrorCode::APP_REQUEST_TOO_MANY ||
129                    errorDetailCode == DKDetailErrorCode::FLOW_CONTROL) {
130             downloadErrorType = DownloadProgressObj::FREQUENT_USER_REQUESTS;
131         }
132     }
133     LOGE("download fail, downloadErrorType %{public}d", downloadErrorType);
134 }
135 
OnDownloadedResult(const std::string path,std::vector<DriveKit::DKDownloadAsset> assetsToDownload,std::shared_ptr<DataHandler> handler,std::shared_ptr<DriveKit::DKContext> context,std::shared_ptr<const DriveKit::DKDatabase> database,const std::map<DriveKit::DKDownloadAsset,DriveKit::DKDownloadResult> & results,const DriveKit::DKError & err)136 void CloudDownloadCallbackManager::OnDownloadedResult(
137     const std::string path,
138     std::vector<DriveKit::DKDownloadAsset> assetsToDownload,
139     std::shared_ptr<DataHandler> handler,
140     std::shared_ptr<DriveKit::DKContext> context,
141     std::shared_ptr<const DriveKit::DKDatabase> database,
142     const std::map<DriveKit::DKDownloadAsset, DriveKit::DKDownloadResult> &results,
143     const DriveKit::DKError &err)
144 {
145     unique_lock<mutex> lock(downloadsMtx_);
146     auto res = downloads_.find(path);
147     bool isDownloading = (res != downloads_.end());
148 
149     LOGI("download_file : [callback downloaded] %{public}s is downloading : %{public}d .",
150          path.c_str(), isDownloading);
151     if (!isDownloading) {
152         lock.unlock();
153         return;
154     }
155 
156     auto download = res->second;
157     download.refCount--;
158     if (download.refCount == 0) {
159         downloads_.erase(res);
160         CheckTaskState();
161     } else {
162         lock.unlock();
163         return;
164     }
165     lock.unlock();
166 
167     LOGI("download_file : [callback downloaded] %{public}s state is %{public}s, localErr is %{public}d.",
168          path.c_str(), download.to_string().c_str(), static_cast<int>(err.dkErrorCode));
169 
170     if (callback_ != nullptr && download.state == DownloadProgressObj::STOPPED) {
171         LOGI("stop state");
172         callback_->OnDownloadProcess(download);
173         return;
174     }
175 
176     auto downloadedState = err.HasError() ? DownloadProgressObj::FAILED : DownloadProgressObj::COMPLETED;
177     /**
178      * Avoiding the issue of cloud service not returning a total error code.
179      * Currently, only single asset download is supported.
180      */
181     for (const auto &it : results) {
182         if (!it.second.IsSuccess()) {
183             LOGE("download file failed, localErr: %{public}d", it.second.GetDKError().dkErrorCode);
184             downloadedState = DownloadProgressObj::FAILED;
185             OnDownloadFailed(download.downloadErrorType, it.second.GetDKError());
186             break;
187         }
188     }
189 
190     if (download.state == DownloadProgressObj::RUNNING) {
191         download.state = downloadedState;
192         if ((assetsToDownload.size() == 1) && (download.state == DownloadProgressObj::COMPLETED)) {
193             (void)handler->OnDownloadSuccess(assetsToDownload[0]);
194         }
195         std::thread([=]() {
196                 this_thread::sleep_for(chrono::seconds(1));
197                 if (callback_ != nullptr) {
198                 callback_->OnDownloadProcess(download);
199                 } else { LOGE("async download callback is nullptr"); }
200                 }).detach();
201     }
202 }
203 
OnDownloadProcess(const std::string path,std::shared_ptr<DriveKit::DKContext> context,DriveKit::DKDownloadAsset asset,DriveKit::TotalSize totalSize,DriveKit::DownloadSize downloadSize)204 void CloudDownloadCallbackManager::OnDownloadProcess(const std::string path,
205                                                      std::shared_ptr<DriveKit::DKContext> context,
206                                                      DriveKit::DKDownloadAsset asset,
207                                                      DriveKit::TotalSize totalSize,
208                                                      DriveKit::DownloadSize downloadSize)
209 {
210     unique_lock<mutex> lock(downloadsMtx_);
211     auto res = downloads_.find(path);
212     bool isDownloading = (res != downloads_.end());
213 
214     LOGI("download_file : [callback downloading] %{public}s is downloading : %{public}d .",
215         path.c_str(), isDownloading);
216     if (!isDownloading) {
217         lock.unlock();
218         return;
219     }
220 
221     auto download = res->second;
222     lock.unlock();
223 
224     download.downloadedSize = downloadSize;
225     download.totalSize = totalSize;
226     LOGI("download_file : [callback downloading] %{public}s state is %{public}s.", path.c_str(),
227          download.to_string().c_str());
228     if (callback_ != nullptr && download.state == DownloadProgressObj::RUNNING) {
229         callback_->OnDownloadProcess(download);
230     }
231 }
232 
SetBundleName(const std::string & bundleName)233 void CloudDownloadCallbackManager::SetBundleName(const std::string &bundleName)
234 {
235     bundleName_ = bundleName;
236 }
237 
CheckTaskState()238 void CloudDownloadCallbackManager::CheckTaskState()
239 {
240     if (downloads_.empty()) {
241         TaskStateManager::GetInstance().CompleteTask(bundleName_, TaskType::DOWNLOAD_TASK);
242     }
243 }
244 
NotifyProcessStop(DownloadProgressObj & download)245 void CloudDownloadCallbackManager::NotifyProcessStop(DownloadProgressObj &download)
246 {
247     download.state = DownloadProgressObj::Status::STOPPED;
248     if (callback_ != nullptr) {
249         callback_->OnDownloadProcess(download);
250     }
251 }
252 } // namespace OHOS::FileManagement::CloudSync
253