• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "upload_task_napi.h"
17 #include <uv.h>
18 #include "async_call.h"
19 #include "js_util.h"
20 #include "upload_task.h"
21 #include "napi_base_context.h"
22 #include "napi_data_ability_operation.h"
23 #include "upload_task_napiV5.h"
24 
25 using namespace OHOS::AppExecFwk;
26 using namespace OHOS::Request::Upload;
27 namespace OHOS::Request::UploadNapi {
28 std::map<std::string, UploadTaskNapi::Exec> UploadTaskNapi::onTypeHandlers_ = {
29     {"progress", UploadTaskNapi::OnProgress},
30     {"headerReceive", UploadTaskNapi::OnHeaderReceive},
31     {"fail", UploadTaskNapi::OnFail},
32     {"complete", UploadTaskNapi::OnComplete},
33 };
34 std::map<std::string, UploadTaskNapi::Exec> UploadTaskNapi::offTypeHandlers_ = {
35     {"progress", UploadTaskNapi::OffProgress},
36     {"headerReceive", UploadTaskNapi::OffHeaderReceive},
37     {"fail", UploadTaskNapi::OffFail},
38     {"complete", UploadTaskNapi::OffComplete},
39 };
40 
JsUpload(napi_env env,napi_callback_info info)41 napi_value UploadTaskNapi::JsUpload(napi_env env, napi_callback_info info)
42 {
43     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter JsUpload.");
44 
45     std::shared_ptr<UploadTaskNapiV5> proxy = std::make_shared<UploadTaskNapiV5>(env);
46     if (proxy->ParseCallback(env, info)) {
47         return proxy->JsUpload(env, info);
48     }
49     proxy->SetEnv(nullptr);
50     struct ContextInfo {
51         napi_ref ref = nullptr;
52     };
53     auto ctxInfo = std::make_shared<ContextInfo>();
54     auto input = [ctxInfo](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
55         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Upload parser to native params %{public}d!", static_cast<int>(argc));
56         NAPI_ASSERT_BASE(env, (argc > 0) && (argc <= 2), " need 1 or 2 parameters!", napi_invalid_arg);
57         napi_value uploadProxy = nullptr;
58         napi_status status = napi_new_instance(env, GetCtor(env), argc, argv, &uploadProxy);
59         if ((uploadProxy == nullptr) || (status != napi_ok)) {
60             return napi_generic_failure;
61         }
62         napi_create_reference(env, uploadProxy, 1, &(ctxInfo->ref));
63         return napi_ok;
64     };
65     auto output = [ctxInfo](napi_env env, napi_value *result) -> napi_status {
66         napi_status status = napi_get_reference_value(env, ctxInfo->ref, result);
67         napi_delete_reference(env, ctxInfo->ref);
68         return status;
69     };
70     auto context = std::make_shared<AsyncCall::Context>(input, output);
71     AsyncCall asyncCall(env, info, context);
72     return asyncCall.Call(env);
73 }
74 
ParseParam(napi_env env,napi_callback_info info,bool IsRequiredParam,JsParam & jsParam)75 napi_status UploadTaskNapi::ParseParam(napi_env env, napi_callback_info info, bool IsRequiredParam,
76     JsParam &jsParam)
77 {
78     size_t argc = JSUtil::MAX_ARGC;
79     napi_value argv[JSUtil::MAX_ARGC] = {nullptr};
80     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsParam.self, nullptr);
81     if (status != napi_ok) {
82         return napi_invalid_arg;
83     }
84     if (jsParam.self == nullptr) {
85         return napi_invalid_arg;
86     }
87 
88     if (!JSUtil::CheckParamNumber(argc, IsRequiredParam)) {
89         return napi_invalid_arg;
90     }
91     if (!JSUtil::CheckParamType(env, argv[0], napi_string)) {
92         return napi_invalid_arg;
93     }
94     jsParam.type = JSUtil::Convert2String(env, argv[0]);
95     if (onTypeHandlers_.find(jsParam.type) == onTypeHandlers_.end()) {
96         return napi_invalid_arg;
97     }
98     if (argc == TWO_ARG) {
99         if (!JSUtil::CheckParamType(env, argv[1], napi_function)) {
100             return napi_invalid_arg;
101         }
102         jsParam.callback = argv[1];
103     }
104     return napi_ok;
105 }
106 
JsOn(napi_env env,napi_callback_info info)107 napi_value UploadTaskNapi::JsOn(napi_env env, napi_callback_info info)
108 {
109     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter JsOn.");
110     bool IsRequiredParam = true;
111     JsParam jsParam;
112     napi_status status = ParseParam(env, info, IsRequiredParam, jsParam);
113     NAPI_ASSERT(env, status == napi_ok, "ParseParam fail");
114     auto handle = onTypeHandlers_.find(jsParam.type);
115     handle->second(env, jsParam.callback, jsParam.self);
116     return nullptr;
117 }
118 
JsOff(napi_env env,napi_callback_info info)119 napi_value UploadTaskNapi::JsOff(napi_env env, napi_callback_info info)
120 {
121     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter JsOff.");
122     bool IsRequiredParam = false;
123     JsParam jsParam;
124     napi_status status = ParseParam(env, info, IsRequiredParam, jsParam);
125     NAPI_ASSERT(env, status == napi_ok, "ParseParam fail");
126     auto handle = offTypeHandlers_.find(jsParam.type);
127     handle->second(env, jsParam.callback, jsParam.self);
128     return nullptr;
129 }
130 
JsRemove(napi_env env,napi_callback_info info)131 napi_value UploadTaskNapi::JsRemove(napi_env env, napi_callback_info info)
132 {
133     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter JsRemove.");
134     auto context = std::make_shared<RemoveContextInfo>();
135     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
136         NAPI_ASSERT_BASE(env, argc == 0, " should 0 parameter!", napi_invalid_arg);
137         return napi_ok;
138     };
139     auto output = [context](napi_env env, napi_value *result) -> napi_status {
140         napi_status status = napi_get_boolean(env, context->removeStatus, result);
141         return status;
142     };
143     auto exec = [context](AsyncCall::Context *ctx) {
144         context->removeStatus = context->proxy->napiUploadTask_->Remove();
145         if (context->removeStatus == true) {
146             context->status = napi_ok;
147         }
148     };
149     context->SetAction(std::move(input), std::move(output));
150     AsyncCall asyncCall(env, info, std::dynamic_pointer_cast<AsyncCall::Context>(context));
151     return asyncCall.Call(env, exec);
152 }
153 
OnProgress(napi_env env,napi_value callback,napi_value self)154 napi_status UploadTaskNapi::OnProgress(napi_env env, napi_value callback, napi_value self)
155 {
156     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter OnProgress.");
157     UploadTaskNapi *proxy = nullptr;
158     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&proxy)), napi_invalid_arg);
159     NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native upload task", napi_invalid_arg);
160 
161     std::shared_ptr<IProgressCallback> progressCallback = std::make_shared<ProgressCallback>(env, callback);
162     if (JSUtil::Equals(env, callback, progressCallback->GetCallback()) && proxy->onProgress_ != nullptr) {
163         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "OnProgress callback already register!");
164         return napi_generic_failure;
165     }
166 
167     proxy->napiUploadTask_->On(TYPE_PROGRESS_CALLBACK, (void *)(progressCallback.get()));
168     proxy->onProgress_ = std::move(progressCallback);
169     return napi_ok;
170 }
171 
OnHeaderReceive(napi_env env,napi_value callback,napi_value self)172 napi_status UploadTaskNapi::OnHeaderReceive(napi_env env, napi_value callback, napi_value self)
173 {
174     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter OnHeaderReceive.");
175     UploadTaskNapi *proxy = nullptr;
176     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&proxy)), napi_invalid_arg);
177     NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native upload task", napi_invalid_arg);
178 
179     std::shared_ptr<IHeaderReceiveCallback> headerReceiveCallback =
180                                             std::make_shared<HeaderReceiveCallback>(env, callback);
181     if (JSUtil::Equals(env, callback, headerReceiveCallback->GetCallback()) && proxy->onHeaderReceive_ != nullptr) {
182         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "OnHeaderReceive callback already register!");
183         return napi_generic_failure;
184     }
185 
186     proxy->napiUploadTask_->On(TYPE_HEADER_RECEIVE_CALLBACK, (void *)(headerReceiveCallback.get()));
187     proxy->onHeaderReceive_ = std::move(headerReceiveCallback);
188     return napi_ok;
189 }
190 
OnFail(napi_env env,napi_value callback,napi_value self)191 napi_status UploadTaskNapi::OnFail(napi_env env, napi_value callback, napi_value self)
192 {
193     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter OnFail.");
194     UploadTaskNapi *proxy = nullptr;
195     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&proxy)), napi_invalid_arg);
196     NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native upload task", napi_invalid_arg);
197 
198     std::shared_ptr<INotifyCallback> failCallback = std::make_shared<NotifyCallback>(env, callback);
199     if (JSUtil::Equals(env, callback, failCallback->GetCallback()) && proxy->onFail_ != nullptr) {
200         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "OnFail callback already register!");
201         return napi_generic_failure;
202     }
203 
204     proxy->napiUploadTask_->On(TYPE_FAIL_CALLBACK, (void *)(failCallback.get()));
205     proxy->onFail_ = std::move(failCallback);
206     return napi_ok;
207 }
208 
OnComplete(napi_env env,napi_value callback,napi_value self)209 napi_status UploadTaskNapi::OnComplete(napi_env env, napi_value callback, napi_value self)
210 {
211     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter OnComplete.");
212     UploadTaskNapi *proxy = nullptr;
213     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&proxy)), napi_invalid_arg);
214     NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native upload task", napi_invalid_arg);
215 
216     std::shared_ptr<INotifyCallback> completeCallback = std::make_shared<NotifyCallback>(env, callback);
217     if (JSUtil::Equals(env, callback, completeCallback->GetCallback()) && proxy->onComplete_ != nullptr) {
218         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "OnComplete callback already register!");
219         return napi_generic_failure;
220     }
221 
222     proxy->napiUploadTask_->On(TYPE_COMPLETE_CALLBACK, (void *)(completeCallback.get()));
223     proxy->onComplete_ = std::move(completeCallback);
224     return napi_ok;
225 }
226 
OffProgress(napi_env env,napi_value callback,napi_value self)227 napi_status UploadTaskNapi::OffProgress(napi_env env, napi_value callback, napi_value self)
228 {
229     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter OffProgress.");
230     UploadTaskNapi *proxy = nullptr;
231     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&proxy)), napi_invalid_arg);
232     NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native upload task", napi_invalid_arg);
233 
234     if (proxy->onProgress_ == nullptr) {
235         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Progress. proxy->onProgress_ == nullptr.");
236         return napi_generic_failure;
237     } else {
238         std::shared_ptr<IProgressCallback> progressCallback = std::make_shared<ProgressCallback>(env, callback);
239         proxy->napiUploadTask_->Off(TYPE_PROGRESS_CALLBACK, (void *)(progressCallback.get()));
240         proxy->onProgress_ = nullptr;
241     }
242     return napi_ok;
243 }
244 
OffHeaderReceive(napi_env env,napi_value callback,napi_value self)245 napi_status UploadTaskNapi::OffHeaderReceive(napi_env env, napi_value callback, napi_value self)
246 {
247     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter OffHeaderReceive.");
248     UploadTaskNapi *proxy = nullptr;
249     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&proxy)), napi_invalid_arg);
250     NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native upload task", napi_invalid_arg);
251 
252     if (proxy->onHeaderReceive_ == nullptr) {
253         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "HeaderReceive. proxy->onHeaderReceive_ == nullptr.");
254         return napi_generic_failure;
255     } else {
256         std::shared_ptr<IHeaderReceiveCallback> headerReceiveCallback =
257                                                 std::make_shared<HeaderReceiveCallback>(env, callback);
258         proxy->napiUploadTask_->Off(TYPE_HEADER_RECEIVE_CALLBACK, (void *)(headerReceiveCallback.get()));
259         proxy->onHeaderReceive_ = nullptr;
260     }
261     return napi_ok;
262 }
263 
264 
OffFail(napi_env env,napi_value callback,napi_value self)265 napi_status UploadTaskNapi::OffFail(napi_env env, napi_value callback, napi_value self)
266 {
267     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter OffFail.");
268     UploadTaskNapi *proxy = nullptr;
269     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&proxy)), napi_invalid_arg);
270     NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native upload task", napi_invalid_arg);
271 
272     if (proxy->onFail_ == nullptr) {
273         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Fail. proxy->onFail_ == nullptr.");
274         return napi_generic_failure;
275     } else {
276         std::shared_ptr<INotifyCallback> failCallback = std::make_shared<NotifyCallback>(env, callback);
277         proxy->napiUploadTask_->Off(TYPE_FAIL_CALLBACK, failCallback.get());
278         proxy->onFail_ = nullptr;
279     }
280     return napi_ok;
281 }
282 
283 
OffComplete(napi_env env,napi_value callback,napi_value self)284 napi_status UploadTaskNapi::OffComplete(napi_env env, napi_value callback, napi_value self)
285 {
286     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Enter OffComplete.");
287     UploadTaskNapi *proxy = nullptr;
288     NAPI_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&proxy)), napi_invalid_arg);
289     NAPI_ASSERT_BASE(env, proxy != nullptr, "there is no native upload task", napi_invalid_arg);
290     if (proxy->onComplete_ == nullptr) {
291         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "CompleteCallback. proxy->OffComplete_ == nullptr.");
292         return napi_generic_failure;
293     } else {
294         std::shared_ptr<INotifyCallback> completeCallback = std::make_shared<NotifyCallback>(env, callback);
295         proxy->napiUploadTask_->Off(TYPE_COMPLETE_CALLBACK, completeCallback.get());
296         proxy->onComplete_ = nullptr;
297     }
298     return napi_ok;
299 }
300 
operator =(std::shared_ptr<Upload::UploadTask> && uploadTask)301 UploadTaskNapi &UploadTaskNapi::operator=(std::shared_ptr<Upload::UploadTask> &&uploadTask)
302 {
303     if (napiUploadTask_ == uploadTask) {
304         return *this;
305     }
306     napiUploadTask_ = std::move(uploadTask);
307     return *this;
308 }
309 
operator ==(const std::shared_ptr<Upload::UploadTask> & uploadTask)310 bool UploadTaskNapi::operator==(const std::shared_ptr<Upload::UploadTask> &uploadTask)
311 {
312     return napiUploadTask_ == uploadTask;
313 }
314 
GetCtor(napi_env env)315 napi_value UploadTaskNapi::GetCtor(napi_env env)
316 {
317     napi_value cons = nullptr;
318     napi_property_descriptor clzDes[] = {
319         DECLARE_NAPI_METHOD("on", JsOn),
320         DECLARE_NAPI_METHOD("off", JsOff),
321         DECLARE_NAPI_METHOD("remove", JsRemove),
322     };
323     NAPI_CALL(env, napi_define_class(env, "UploadTaskNapi", NAPI_AUTO_LENGTH, Initialize, nullptr,
324                                      sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons));
325     return cons;
326 }
327 
Initialize(napi_env env,napi_callback_info info)328 napi_value UploadTaskNapi::Initialize(napi_env env, napi_callback_info info)
329 {
330     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "constructor upload task!");
331     napi_value self = nullptr;
332     size_t argc = JSUtil::MAX_ARGC;
333     napi_value argv[JSUtil::MAX_ARGC] = {nullptr};
334     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
335     auto *proxy = new (std::nothrow) UploadTaskNapi();
336     if (proxy == nullptr) {
337         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "Failed to create UploadTaskNapi");
338         NAPI_ASSERT(env, false, "Failed to create UploadTaskNapi");
339         return nullptr;
340     }
341     std::shared_ptr<OHOS::AbilityRuntime::Context> context = nullptr;
342     int paramPosition = 0;
343     napi_status getStatus = GetContext(env, &argv[0], paramPosition, context);
344     if (getStatus != napi_ok) {
345         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "Initialize. GetContext fail.");
346         delete proxy;
347         NAPI_ASSERT(env, false, "Initialize. GetContext fail");
348         return nullptr;
349     }
350 
351     proxy->napiUploadConfig_ = JSUtil::ParseUploadConfig(env, argv[paramPosition], "");
352     if (proxy->napiUploadConfig_ == nullptr) {
353         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "Initialize. ParseUploadConfig fail.");
354         delete proxy;
355         NAPI_ASSERT(env, false, "Initialize. ParseUploadConfig fail");
356         return nullptr;
357     }
358 
359     proxy->napiUploadTask_ = std::make_shared<Upload::UploadTask>(proxy->napiUploadConfig_);
360     proxy->napiUploadTask_->SetContext(context);
361     proxy->napiUploadTask_->ExecuteTask();
362     UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "Initialize. GetAndSetContext[%{public}d]", getStatus);
363     auto finalize = [](napi_env env, void * data, void * hint) {
364         UploadTaskNapi *proxy = reinterpret_cast<UploadTaskNapi *>(data);
365         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "UploadTaskNapi. delete.");
366         proxy->napiUploadTask_->Remove();
367         delete proxy;
368     };
369     UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "UploadTaskNapi. napi_wrap OK.");
370     if (napi_wrap(env, self, proxy, finalize, nullptr, nullptr) != napi_ok) {
371         finalize(env, proxy, nullptr);
372         NAPI_ASSERT(env, false, "napi_wrap fail");
373         return nullptr;
374     }
375     return self;
376 }
377 
GetContext(napi_env env,napi_value * argv,int & paramPosition,std::shared_ptr<OHOS::AbilityRuntime::Context> & context)378 napi_status UploadTaskNapi::GetContext(napi_env env, napi_value *argv, int& paramPosition,
379     std::shared_ptr<OHOS::AbilityRuntime::Context>& context)
380 {
381     bool stageMode = false;
382     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, argv[0], stageMode);
383     if (status != napi_ok) {
384         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "GetAndSetContext. API8");
385         auto ability = OHOS::AbilityRuntime::GetCurrentAbility(env);
386         if (ability == nullptr) {
387             UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "GetAndSetContext. API8. GetCurrentAbility ability == nullptr.");
388             return napi_generic_failure;
389         }
390         context = ability->GetAbilityContext();
391     } else {
392         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "GetAndSetContext. API9");
393         paramPosition = 1;
394         if (stageMode) {
395             context = OHOS::AbilityRuntime::GetStageModeContext(env, argv[0]);
396             if (context == nullptr) {
397                 UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI,
398                     "GetAndSetContext. API9. GetStageModeContext contextRtm == nullptr.");
399                 return napi_generic_failure;
400             }
401         } else {
402             auto ability = OHOS::AbilityRuntime::GetCurrentAbility(env);
403             if (ability == nullptr) {
404                 UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "GetAndSetContext. API9. GetCurrentAbility ability == nullptr.");
405                 return napi_generic_failure;
406             }
407             context = ability->GetAbilityContext();
408         }
409     }
410     if (context == nullptr) {
411         UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "GetAndSetContext failed. context is nullptr.");
412         return napi_generic_failure;
413     }
414     return napi_ok;
415 }
416 } // namespace OHOS::Request::UploadNapi
417 
418