• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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 "cloud_file_napi.h"
17 
18 #include <memory>
19 #include <mutex>
20 #include <sys/types.h>
21 
22 #include "async_work.h"
23 #include "cloud_sync_manager.h"
24 #include "dfs_error.h"
25 #include "dfsu_access_token_helper.h"
26 #include "filemgmt_libn.h"
27 #include "n_napi.h"
28 #include "utils_log.h"
29 
30 namespace OHOS::FileManagement::CloudSync {
31 using namespace FileManagement::LibN;
32 using namespace std;
StartDownloadInner(const std::string & uri)33 int32_t CloudDownloadCallbackImplNapi::StartDownloadInner(const std::string &uri)
34 {
35     int64_t downloadId = 0;
36     std::lock_guard<std::mutex> lock(downloadInfoMtx_);
37     int32_t ret = CloudSyncManager::GetInstance().StartDownloadFile(uri, shared_from_this(), downloadId);
38     if (ret != E_OK) {
39         LOGE("Start batch download failed! ret = %{public}d", ret);
40         return ret;
41     }
42 
43     downloadInfos_[downloadId] = std::make_shared<SingleProgressNapi>(downloadId);
44     return ret;
45 }
46 
StopDownloadInner(const std::string & uri)47 int32_t CloudDownloadCallbackImplNapi::StopDownloadInner(const std::string &uri)
48 {
49     auto downloadIdList = GetDownloadIdsByUri(uri);
50     int32_t ret = E_OK;
51     int32_t resErr = E_OK;
52     LOGI("Stop Download downloadId list size: %{public}zu", downloadIdList.size());
53     for (auto taskId : downloadIdList) {
54         resErr = CloudSyncManager::GetInstance().StopDownloadFile(taskId, true);
55         if (resErr != E_OK) {
56             ret = resErr;
57             continue;
58         }
59     }
60     if (ret != E_OK) {
61         LOGE("Stop Download failed! ret = %{public}d", ret);
62     }
63     return ret;
64 }
65 
Constructor(napi_env env,napi_callback_info info)66 napi_value CloudFileDownloadNapi::Constructor(napi_env env, napi_callback_info info)
67 {
68     LOGI("CloudFileDownloadNapi::Constructor begin");
69     NFuncArg funcArg(env, info);
70     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
71         LOGE("Start Number of arguments unmatched");
72         NError(JsErrCode::E_IPCSS).ThrowErr(env);
73         return nullptr;
74     }
75     auto downloadEntity = make_unique<DownloadEntity>();
76     if (!NClass::SetEntityFor<DownloadEntity>(env, funcArg.GetThisVar(), move(downloadEntity))) {
77         LOGE("Failed to set download entity.");
78         NError(JsErrCode::E_IPCSS).ThrowErr(env);
79         return nullptr;
80     }
81     LOGI("CloudFileDownloadNapi::Constructor end");
82     return funcArg.GetThisVar();
83 }
84 
GetCallbackImpl(napi_env env,NFuncArg & funcArg,bool isInit)85 static std::shared_ptr<CloudDownloadCallbackImplNapi> GetCallbackImpl(napi_env env, NFuncArg &funcArg, bool isInit)
86 {
87     auto downloadEntity = NClass::GetEntityOf<DownloadEntity>(env, funcArg.GetThisVar());
88     if (!downloadEntity) {
89         LOGE("Failed to get file cache entity.");
90         return nullptr;
91     }
92 
93     if (downloadEntity->callbackImpl == nullptr && isInit) {
94         downloadEntity->callbackImpl = std::make_shared<CloudDownloadCallbackImplNapi>(env);
95     }
96     return downloadEntity->callbackImpl;
97 }
98 
Start(napi_env env,napi_callback_info info)99 napi_value CloudFileDownloadNapi::Start(napi_env env, napi_callback_info info)
100 {
101     LOGI("Start begin");
102     NFuncArg funcArg(env, info);
103     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
104         LOGE("Start Number of arguments unmatched");
105         NError(E_PARAMS).ThrowErr(env);
106         return nullptr;
107     }
108     auto [succUri, uri, size] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
109     if (!succUri || size == 0) {
110         LOGE("Start get uri parameter failed!");
111         NError(E_PARAMS).ThrowErr(env);
112         return nullptr;
113     }
114 
115     auto callbackImpl = GetCallbackImpl(env, funcArg, true);
116     auto cbExec = [uri{string(uri.get())}, callbackImpl{callbackImpl}]() -> NError {
117         if (callbackImpl == nullptr) {
118             LOGE("Failed to get download callback");
119             return NError(E_PARAMS);
120         }
121         int32_t ret = callbackImpl->StartDownloadInner(uri);
122         if (ret != E_OK) {
123             LOGE("Start Download failed! ret = %{public}d", ret);
124             return NError(Convert2JsErrNum(ret));
125         }
126         LOGI("Start Download Success!");
127         return NError(ERRNO_NOERR);
128     };
129 
130     auto cbCompl = [](napi_env env, NError err) -> NVal {
131         if (err) {
132             return {env, err.GetNapiErr(env)};
133         }
134         return NVal::CreateUndefined(env);
135     };
136 
137     string procedureName = "cloudFileDownload";
138     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
139     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_;
140 }
141 
CheckPermissions(const string & permission,bool isSystemApp)142 static int32_t CheckPermissions(const string &permission, bool isSystemApp)
143 {
144     if (!permission.empty() && !DfsuAccessTokenHelper::CheckCallerPermission(permission)) {
145         LOGE("permission denied");
146         return JsErrCode::E_PERMISSION;
147     }
148     if (isSystemApp && !DfsuAccessTokenHelper::IsSystemApp()) {
149         LOGE("caller hap is not system hap");
150         return JsErrCode::E_PERMISSION_SYS;
151     }
152     return E_OK;
153 }
154 
On(napi_env env,napi_callback_info info)155 napi_value CloudFileDownloadNapi::On(napi_env env, napi_callback_info info)
156 {
157     LOGI("On begin");
158     NFuncArg funcArg(env, info);
159     if (!funcArg.InitArgs(NARG_CNT::TWO)) {
160         LOGE("On Number of arguments unmatched");
161         NError(E_PARAMS).ThrowErr(env);
162         return nullptr;
163     }
164     int32_t ret = CheckPermissions(PERM_CLOUD_SYNC, true);
165     if (ret != E_OK) {
166         LOGE("On get progress failed!");
167         NError(ret).ThrowErr(env);
168         return nullptr;
169     }
170     auto [succProgress, progress, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
171     if (!succProgress || std::string(progress.get()) != "progress") {
172         LOGE("On get progress failed!");
173         NError(E_PARAMS).ThrowErr(env);
174         return nullptr;
175     }
176 
177     if (!NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function)) {
178         LOGE("Argument type mismatch");
179         NError(E_PARAMS).ThrowErr(env);
180         return nullptr;
181     }
182     auto callbackImpl = GetCallbackImpl(env, funcArg, true);
183     if (callbackImpl == nullptr) {
184         NError(E_PARAMS).ThrowErr(env);
185         return nullptr;
186     }
187     ret = callbackImpl->RegisterCallback(funcArg[NARG_POS::SECOND]);
188     if (ret != napi_ok) {
189         LOGE("On register callback fail, ret: %{public}d", ret);
190         NError(JsErrCode::E_IPCSS).ThrowErr(env);
191         return nullptr;
192     }
193 
194     return NVal::CreateUndefined(env).val_;
195 }
196 
Off(napi_env env,napi_callback_info info)197 napi_value CloudFileDownloadNapi::Off(napi_env env, napi_callback_info info)
198 {
199     LOGI("Off begin");
200     NFuncArg funcArg(env, info);
201     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
202         LOGE("Off Number of arguments unmatched");
203         NError(E_PARAMS).ThrowErr(env);
204         return nullptr;
205     }
206     int32_t ret = CheckPermissions(PERM_CLOUD_SYNC, true);
207     if (ret != E_OK) {
208         LOGE("Off get progress failed!");
209         NError(ret).ThrowErr(env);
210         return nullptr;
211     }
212     auto [succProgress, progress, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
213     if (!succProgress || std::string(progress.get()) != "progress") {
214         LOGE("Off get progress failed!");
215         NError(E_PARAMS).ThrowErr(env);
216         return nullptr;
217     }
218 
219     napi_value callbackVel = nullptr;
220     if (funcArg.GetArgc() == (uint)NARG_CNT::TWO) {
221         if (!NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function)) {
222             LOGE("Off argument type mismatch");
223             NError(E_PARAMS).ThrowErr(env);
224             return nullptr;
225         }
226         callbackVel = funcArg[NARG_POS::SECOND];
227     }
228 
229     auto callbackImpl = GetCallbackImpl(env, funcArg, false);
230     if (callbackImpl == nullptr || callbackImpl->UnregisterCallback(callbackVel) != napi_ok) {
231         LOGE("Off no callback is registered for this event type");
232         NError(JsErrCode::E_IPCSS).ThrowErr(env);
233         return nullptr;
234     }
235     return NVal::CreateUndefined(env).val_;
236 }
237 
Stop(napi_env env,napi_callback_info info)238 napi_value CloudFileDownloadNapi::Stop(napi_env env, napi_callback_info info)
239 {
240     LOGI("Stop begin");
241     NFuncArg funcArg(env, info);
242     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
243         LOGE("Stop Number of arguments unmatched");
244         NError(E_PARAMS).ThrowErr(env);
245         return nullptr;
246     }
247 
248     auto [succUri, uri, size] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
249     if (!succUri || size == 0) {
250         LOGE("Stop get uri parameter failed!");
251         NError(E_PARAMS).ThrowErr(env);
252         return nullptr;
253     }
254 
255     auto callbackImpl = GetCallbackImpl(env, funcArg, false);
256     auto cbExec = [uri{string(uri.get())}, callbackImpl{callbackImpl}]() -> NError {
257         if (callbackImpl == nullptr) {
258             LOGE("Failed to get download callback");
259             return NError(E_PARAMS);
260         }
261         int32_t ret = callbackImpl->StopDownloadInner(uri);
262         if (ret != E_OK) {
263             LOGE("Stop Download failed! ret = %{public}d", ret);
264             return NError(Convert2JsErrNum(ret));
265         }
266         return NError(ERRNO_NOERR);
267     };
268 
269     auto cbCompl = [](napi_env env, NError err) -> NVal {
270         if (err) {
271             return {env, err.GetNapiErr(env)};
272         }
273         return NVal::CreateUndefined(env);
274     };
275 
276     string procedureName = "cloudFileDownload";
277     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
278     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_;
279 }
280 
ToExport(std::vector<napi_property_descriptor> props)281 bool CloudFileDownloadNapi::ToExport(std::vector<napi_property_descriptor> props)
282 {
283     std::string className = GetClassName();
284     auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props));
285     if (!succ) {
286         NError(JsErrCode::E_IPCSS).ThrowErr(exports_.env_);
287         LOGE("Failed to define GallerySync class");
288         return false;
289     }
290 
291     succ = NClass::SaveClass(exports_.env_, className, classValue);
292     if (!succ) {
293         NError(JsErrCode::E_IPCSS).ThrowErr(exports_.env_);
294         LOGE("Failed to save GallerySync class");
295         return false;
296     }
297 
298     return exports_.AddProp(className, classValue);
299 }
300 
Export()301 bool CloudFileDownloadNapi::Export()
302 {
303     vector<napi_property_descriptor> props = {
304         NVal::DeclareNapiFunction("start", CloudFileDownloadNapi::Start),
305         NVal::DeclareNapiFunction("on", CloudFileDownloadNapi::On),
306         NVal::DeclareNapiFunction("off", CloudFileDownloadNapi::Off),
307         NVal::DeclareNapiFunction("stop", CloudFileDownloadNapi::Stop),
308     };
309     return ToExport(props);
310 }
311 
SetClassName(std::string classname)312 void CloudFileDownloadNapi::SetClassName(std::string classname)
313 {
314     className_ = classname;
315 }
316 
GetClassName()317 string CloudFileDownloadNapi::GetClassName()
318 {
319     return className_;
320 }
321 } // namespace OHOS::FileManagement::CloudSync