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 "upload/upload_task_napiV5.h"
17 
18 #include "ability.h"
19 #include "js_initialize.h"
20 #include "napi_base_context.h"
21 #include "upload/js_util.h"
22 
23 namespace OHOS::Request::Upload {
24 constexpr int FIRST_ARGV = 0;
25 constexpr int PARAM_COUNT_ZERO = 0;
26 constexpr int PARAM_COUNT_ONE = 1;
27 constexpr int PARAM_COUNT_TWO = 2;
~UploadTaskNapiV5()28 UploadTaskNapiV5::~UploadTaskNapiV5()
29 {
30     if (env_ == nullptr) {
31         return;
32     }
33 
34     RecycleRef *callbackData = new (std::nothrow)
35         RecycleRef{ .env = env_, .successRef = success_, .failRef = fail_, .completeRef = complete_ };
36     if (callbackData == nullptr) {
37         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "Failed to create callbackData");
38         return;
39     }
40     auto afterCallback = [callbackData]() {
41         if (callbackData != nullptr) {
42             UPLOAD_HILOGD(UPLOAD_MODULE_JS_NAPI, "~UploadTaskNapiV5 callbackDataPtr delete start");
43             napi_delete_reference(callbackData->env, callbackData->successRef);
44             napi_delete_reference(callbackData->env, callbackData->failRef);
45             napi_delete_reference(callbackData->env, callbackData->completeRef);
46             delete callbackData;
47         }
48     };
49     int32_t ret = napi_send_event(env_, afterCallback, napi_eprio_high);
50     if (ret != napi_ok) {
51         REQUEST_HILOGE("napi_send_event failed: %{public}d", ret);
52         delete callbackData;
53     }
54 }
55 
ParseCallback(napi_env env,napi_callback_info info)56 bool UploadTaskNapiV5::ParseCallback(napi_env env, napi_callback_info info)
57 {
58     napi_value self = nullptr;
59     size_t argc = JSUtil::MAX_ARGC;
60     napi_value argv[JSUtil::MAX_ARGC] = { nullptr };
61     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr), false);
62     bool successCb = JSUtil::ParseFunction(env, argv[FIRST_ARGV], "success", success_);
63     bool failCb = JSUtil::ParseFunction(env, argv[FIRST_ARGV], "fail", fail_);
64     bool completeCb = JSUtil::ParseFunction(env, argv[FIRST_ARGV], "complete", complete_);
65     return successCb || failCb || completeCb;
66 }
67 
AddCallbackToConfig(napi_env env,std::shared_ptr<UploadConfig> & config)68 void UploadTaskNapiV5::AddCallbackToConfig(napi_env env, std::shared_ptr<UploadConfig> &config)
69 {
70     config->fsuccess = std::bind(&UploadTaskNapiV5::OnSystemSuccess, env_, success_, std::placeholders::_1);
71     config->ffail =
72         std::bind(&UploadTaskNapiV5::OnSystemFail, env_, fail_, std::placeholders::_1, std::placeholders::_2);
73     config->fcomplete = std::bind(&UploadTaskNapiV5::OnSystemComplete, shared_from_this());
74 }
75 
JsUpload(napi_env env,napi_callback_info info)76 napi_value UploadTaskNapiV5::JsUpload(napi_env env, napi_callback_info info)
77 {
78     UPLOAD_HILOGI(UPLOAD_MODULE_JS_NAPI, "Enter JsUploadV5.");
79     napi_value self = nullptr;
80     size_t argc = JSUtil::MAX_ARGC;
81     napi_value argv[JSUtil::MAX_ARGC] = { nullptr };
82     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
83 
84     std::shared_ptr<OHOS::AbilityRuntime::Context> context = nullptr;
85     napi_status getStatus = JsInitialize::GetContext(env, argv[FIRST_ARGV], context);
86     if (getStatus != napi_ok) {
87         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "GetContext fail.");
88         NAPI_ASSERT(env, false, "GetContext fail");
89     }
90 
91     std::shared_ptr<UploadConfig> uploadConfig = JSUtil::ParseUploadConfig(env, argv[FIRST_ARGV], API3);
92     if (uploadConfig == nullptr) {
93         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "ParseUploadConfig fail.");
94         NAPI_ASSERT(env, false, "ParseUploadConfig fail");
95     }
96 
97     AddCallbackToConfig(env, uploadConfig);
98     uploadTask_ = std::make_shared<Upload::UploadTask>(uploadConfig);
99     uploadTask_->SetContext(context);
100     uploadTask_->SetUploadProxy(shared_from_this());
101     uploadTask_->ExecuteTask();
102     uploadTask_ = nullptr;
103     return nullptr;
104 }
105 
OnSystemSuccess(napi_env env,napi_ref ref,Upload::UploadResponse & response)106 void UploadTaskNapiV5::OnSystemSuccess(napi_env env, napi_ref ref, Upload::UploadResponse &response)
107 {
108     UPLOAD_HILOGI(UPLOAD_MODULE_JS_NAPI, "OnSystemSuccess enter");
109 
110     SystemSuccessCallback *successCallback = new (std::nothrow)
111         SystemSuccessCallback{ .env = env, .ref = ref, .response = response };
112     if (successCallback == nullptr) {
113         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "Failed to create successCallback");
114         return;
115     }
116     auto afterCallback = [successCallback]() {
117         napi_handle_scope scope = nullptr;
118         napi_open_handle_scope(successCallback->env, &scope);
119         napi_value callback = nullptr;
120         napi_value global = nullptr;
121         napi_value result = nullptr;
122         napi_value jsResponse = JSUtil::Convert2JSUploadResponse(successCallback->env, successCallback->response);
123         napi_value args[PARAM_COUNT_ONE] = { jsResponse };
124         napi_get_reference_value(successCallback->env, successCallback->ref, &callback);
125         napi_get_global(successCallback->env, &global);
126         napi_call_function(successCallback->env, global, callback, PARAM_COUNT_ONE, args, &result);
127         napi_close_handle_scope(successCallback->env, scope);
128         delete successCallback;
129     };
130     int32_t ret = napi_send_event(env, afterCallback, napi_eprio_high);
131     if (ret != napi_ok) {
132         REQUEST_HILOGE("napi_send_event failed: %{public}d", ret);
133         delete successCallback;
134     }
135 }
136 
OnSystemFail(napi_env env,napi_ref ref,std::string & data,int32_t & code)137 void UploadTaskNapiV5::OnSystemFail(napi_env env, napi_ref ref, std::string &data, int32_t &code)
138 {
139     UPLOAD_HILOGI(UPLOAD_MODULE_JS_NAPI, "OnSystemFail enter");
140     SystemFailCallback *failCallback = new (std::nothrow)
141         SystemFailCallback{ .data = data, .code = code, .env = env, .ref = ref };
142     if (failCallback == nullptr) {
143         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "Failed to create failCallback");
144         return;
145     }
146     auto afterCallback = [failCallback]() {
147         napi_handle_scope scope = nullptr;
148         napi_open_handle_scope(failCallback->env, &scope);
149         napi_value callback = nullptr;
150         napi_value global = nullptr;
151         napi_value result = nullptr;
152         napi_value jsData = nullptr;
153         napi_create_string_utf8(failCallback->env, failCallback->data.c_str(), failCallback->data.size(), &jsData);
154         napi_value jsCode = nullptr;
155         napi_create_int32(failCallback->env, failCallback->code, &jsCode);
156         napi_value args[PARAM_COUNT_TWO] = { jsData, jsCode };
157         napi_get_reference_value(failCallback->env, failCallback->ref, &callback);
158         napi_get_global(failCallback->env, &global);
159         napi_call_function(failCallback->env, global, callback, PARAM_COUNT_TWO, args, &result);
160         napi_close_handle_scope(failCallback->env, scope);
161         delete failCallback;
162     };
163     int32_t ret = napi_send_event(env, afterCallback, napi_eprio_high);
164     if (ret != napi_ok) {
165         REQUEST_HILOGE("napi_send_event failed: %{public}d", ret);
166         delete failCallback;
167     }
168 }
169 
OnSystemComplete(std::shared_ptr<Upload::UploadTaskNapiV5> proxy)170 void UploadTaskNapiV5::OnSystemComplete(std::shared_ptr<Upload::UploadTaskNapiV5> proxy)
171 {
172     UPLOAD_HILOGI(UPLOAD_MODULE_JS_NAPI, "OnSystemComplete enter");
173     SystemCompleteCallback *completeCallback = new (std::nothrow) SystemCompleteCallback{ .proxy = proxy };
174     if (completeCallback == nullptr) {
175         UPLOAD_HILOGE(UPLOAD_MODULE_JS_NAPI, "Failed to create completeCallback");
176         return;
177     }
178     auto afterCallback = [completeCallback]() {
179         napi_handle_scope scope = nullptr;
180         napi_open_handle_scope(completeCallback->proxy->env_, &scope);
181         napi_value callback = nullptr;
182         napi_value global = nullptr;
183         napi_value result = nullptr;
184 
185         napi_status ret =
186             napi_get_reference_value(completeCallback->proxy->env_, completeCallback->proxy->complete_, &callback);
187         if (ret == napi_ok) {
188             napi_get_global(completeCallback->proxy->env_, &global);
189             napi_call_function(completeCallback->proxy->env_, global, callback, PARAM_COUNT_ZERO, nullptr, &result);
190         }
191         UPLOAD_HILOGD(
192             UPLOAD_MODULE_JS_NAPI, "OnSystemComplete NapiV5Proxy: %{public}ld", completeCallback->proxy.use_count());
193         napi_close_handle_scope(completeCallback->proxy->env_, scope);
194         delete completeCallback;
195     };
196     int32_t ret = napi_send_event(completeCallback->proxy->env_, afterCallback, napi_eprio_high);
197     if (ret != napi_ok) {
198         REQUEST_HILOGE("napi_send_event failed: %{public}d", ret);
199         delete completeCallback;
200     }
201 }
202 } // namespace OHOS::Request::Upload