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