• 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 "napi_web_async_controller.h"
17 #include "nweb.h"
18 #include "nweb_helper.h"
19 #include "nweb_store_web_archive_callback.h"
20 #include <memory>
21 
22 #undef LOG_TAG
23 #define LOG_TAG "NapiWebAsyncController"
24 
25 namespace {
26 // Max length of string.
27 constexpr size_t MAX_WEB_STRING_LENGTH = 40960;
28 } // namespace
29 
30 namespace OHOS {
31 namespace NWeb {
Init(napi_env env,napi_value exports)32 napi_value NapiWebAsyncController::Init(napi_env env, napi_value exports)
33 {
34     const std::string WEB_ASYNC_CLIENT_CLASS_NAME = "WebAsyncController";
35     napi_property_descriptor properties[] = {
36         {"storeWebArchive", nullptr, JS_StoreWebArchive, nullptr, nullptr, nullptr,
37          napi_default, nullptr},
38     };
39     napi_value constructor = nullptr;
40     napi_define_class(env, WEB_ASYNC_CLIENT_CLASS_NAME.c_str(), WEB_ASYNC_CLIENT_CLASS_NAME.length(),
41         JS_NapiWebAsyncController, nullptr, sizeof(properties) / sizeof(properties[0]), properties, &constructor);
42     NAPI_ASSERT(env, constructor != nullptr, "define js class WebAsyncController failed");
43     napi_status status = napi_set_named_property(env, exports, "WebAsyncController", constructor);
44     NAPI_ASSERT(env, status == napi_ok, "set property WebAsyncController failed");
45     return exports;
46 }
47 
StoreWebArchiveInternal(napi_env env,napi_callback_info cbinfo,const std::string & baseName,bool autoName)48 napi_value NapiWebAsyncController::StoreWebArchiveInternal(napi_env env, napi_callback_info cbinfo,
49     const std::string &baseName, bool autoName)
50 {
51     napi_value thisVar = nullptr;
52     size_t argc = 1;
53     size_t argcPromise = 2;
54     size_t argcCallback = 3;
55     napi_value argv[3] = {0};
56 
57     napi_value result = nullptr;
58     napi_get_undefined(env, &result);
59 
60     napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
61 
62     // Get the native object of NapiWebAsyncController.
63     NapiWebAsyncController *webAsyncController = nullptr;
64     napi_unwrap(env, thisVar, (void **)&webAsyncController);
65 
66     if (!webAsyncController) {
67         return result;
68     }
69 
70     // If there are three parameters, it is considered to be called by callback,
71     // if it is one, it is considered to be called by returning a promise.
72     if (argc == argcCallback) {
73         napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
74         napi_ref jsCallback = nullptr;
75         napi_create_reference(env, argv[argcCallback - 1], 1, &jsCallback);
76 
77         if (jsCallback) {
78             webAsyncController->StoreWebArchiveCallback(baseName, autoName, env, std::move(jsCallback));
79         }
80         return result;
81     } else if (argc == argcPromise) {
82         napi_deferred deferred = nullptr;
83         napi_value promise = nullptr;
84         napi_create_promise(env, &deferred, &promise);
85         if (promise && deferred) {
86             webAsyncController->StoreWebArchivePromise(baseName, autoName, env, deferred);
87         }
88         return promise;
89     }
90 
91     return result;
92 }
93 
JS_StoreWebArchive(napi_env env,napi_callback_info cbinfo)94 napi_value NapiWebAsyncController::JS_StoreWebArchive(napi_env env, napi_callback_info cbinfo)
95 {
96     napi_value thisVar = nullptr;
97 
98     size_t argc = 1;
99     size_t argcPromise = 2;
100     size_t argcCallback = 3;
101     napi_value argv[3] = {0};
102 
103     napi_value result = nullptr;
104     napi_get_undefined(env, &result);
105 
106     napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
107     NAPI_ASSERT(env, argc == argcPromise || argc == argcCallback, "requires 2 or 3 parameter");
108 
109     // Check first param is string.
110     napi_valuetype valueType = napi_null;
111     napi_typeof(env, argv[0], &valueType);
112     NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
113 
114     // Get the first param as string.
115     size_t bufferSize = 0;
116     napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
117     NAPI_ASSERT_BASE(env, bufferSize > 0, "buffer len = 0", result);
118 
119     bufferSize = std::min(bufferSize, MAX_WEB_STRING_LENGTH);
120     char stringValue[bufferSize + 1];
121     size_t jsStringLength = 0;
122     napi_get_value_string_utf8(env, argv[0], stringValue, bufferSize + 1, &jsStringLength);
123     NAPI_ASSERT_BASE(env, jsStringLength == bufferSize, "string length wrong", result);
124     std::string baseName(stringValue);
125 
126     // Check second param is boolean.
127     napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
128     napi_typeof(env, argv[1], &valueType);
129     NAPI_ASSERT(env, valueType == napi_boolean, "type mismatch for parameter 2");
130 
131     // Get the second param as bool.
132     bool autoName = false;
133     NAPI_CALL(env, napi_get_value_bool(env, argv[1], &autoName));
134 
135     // Check third param is a function.
136     if (argc == argcCallback) {
137         napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
138         napi_typeof(env, argv[argcCallback - 1], &valueType);
139         NAPI_ASSERT(env, valueType == napi_function, "type mismatch for parameter 3");
140     }
141 
142     return StoreWebArchiveInternal(env, cbinfo, baseName, autoName);
143 }
144 
JS_NapiWebAsyncController(napi_env env,napi_callback_info info)145 napi_value NapiWebAsyncController::JS_NapiWebAsyncController(napi_env env, napi_callback_info info)
146 {
147     size_t argc = 1;
148     napi_value argv[1] = {0};
149     napi_value thisVar = nullptr;
150     void *data = nullptr;
151     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
152 
153     napi_valuetype valueType;
154     NAPI_CALL(env, napi_typeof(env, argv[0], &valueType));
155 
156     NAPI_ASSERT(env, valueType == napi_object, "Wrong type of arguments. Expects an object as first argument.");
157 
158     napi_value obj = argv[0];
159     napi_value getNWebIdFunc;
160 
161     napi_status status = napi_get_named_property(env, obj, "getWebId", &getNWebIdFunc);
162     if (status != napi_status::napi_ok) {
163         return nullptr;
164     }
165 
166     napi_value result;
167     status = napi_call_function(env, obj, getNWebIdFunc, 0, nullptr, &result);
168     if (status != napi_status::napi_ok) {
169         return nullptr;
170     }
171 
172     int32_t nwebId = -1;
173     napi_get_value_int32(env, result, &nwebId);
174 
175     NapiWebAsyncController *webAsyncController = new (std::nothrow) NapiWebAsyncController(env, thisVar, nwebId);
176     if (webAsyncController == nullptr) {
177         HILOG_ERROR(LOG_APP, "new webAsyncController failed");
178         return nullptr;
179     }
180 
181     napi_wrap(
182         env, thisVar, webAsyncController,
183         [](napi_env env, void *data, void *hint) {
184             NapiWebAsyncController *webAsyncController = static_cast<NapiWebAsyncController *>(data);
185             delete webAsyncController;
186         },
187         nullptr, nullptr);
188 
189     return thisVar;
190 }
191 
NapiWebAsyncController(napi_env env,napi_value thisVar,int32_t nwebId)192 NapiWebAsyncController::NapiWebAsyncController(napi_env env, napi_value thisVar, int32_t nwebId) : nwebId_(nwebId) {}
193 
StoreWebArchiveCallback(const std::string & baseName,bool autoName,napi_env env,napi_ref jsCallback)194 void NapiWebAsyncController::StoreWebArchiveCallback(const std::string &baseName, bool autoName, napi_env env,
195     napi_ref jsCallback)
196 {
197     std::weak_ptr<NWeb> nweb_weak = OHOS::NWeb::NWebHelper::Instance().GetNWeb(nwebId_);
198     auto nweb = nweb_weak.lock();
199     if (!nweb) {
200         HILOG_ERROR(LOG_APP, "not found a valid nweb");
201         napi_value callback = nullptr;
202         napi_value jsResult = nullptr;
203         napi_value callbackResult = nullptr;
204 
205         napi_get_reference_value(env, jsCallback, &callback);
206         napi_get_null(env, &jsResult);
207         napi_call_function(env, nullptr, callback, 1, &jsResult, &callbackResult);
208         napi_delete_reference(env, jsCallback);
209         return;
210     }
211 
212     if (jsCallback == nullptr) {
213         return;
214     }
215 
216     auto callbackImpl = std::make_shared<OHOS::NWeb::NWebStoreWebArchiveCallback>();
217     callbackImpl->SetCallBack([env, jCallback = std::move(jsCallback)](std::string result) {
218         if (!env) {
219             return;
220         }
221         napi_handle_scope scope = nullptr;
222         napi_open_handle_scope(env, &scope);
223         if (scope == nullptr) {
224             return;
225         }
226 
227         napi_value callback = nullptr;
228         napi_get_reference_value(env, jCallback, &callback);
229 
230         napi_value jsResult = nullptr;
231         napi_value callbackResult = nullptr;
232         if (result.empty()) {
233             napi_get_null(env, &jsResult);
234         } else {
235             napi_create_string_utf8(env, result.c_str(), NAPI_AUTO_LENGTH, &jsResult);
236         }
237         napi_call_function(env, nullptr, callback, 1, &jsResult, &callbackResult);
238 
239         napi_delete_reference(env, jCallback);
240         napi_close_handle_scope(env, scope);
241     });
242     nweb->StoreWebArchive(baseName, autoName, callbackImpl);
243 
244     return;
245 }
246 
StoreWebArchivePromise(const std::string & baseName,bool autoName,napi_env env,napi_deferred deferred)247 void NapiWebAsyncController::StoreWebArchivePromise(const std::string &baseName, bool autoName, napi_env env,
248     napi_deferred deferred)
249 {
250     std::weak_ptr<NWeb> nweb_weak = OHOS::NWeb::NWebHelper::Instance().GetNWeb(nwebId_);
251     auto nweb = nweb_weak.lock();
252     if (!nweb) {
253         HILOG_ERROR(LOG_APP, "not found a valid nweb");
254         napi_value jsResult = nullptr;
255         napi_get_null(env, &jsResult);
256         napi_reject_deferred(env, deferred, jsResult);
257         return;
258     }
259 
260     if (deferred == nullptr) {
261         return;
262     }
263 
264     auto callbackImpl = std::make_shared<OHOS::NWeb::NWebStoreWebArchiveCallback>();
265     callbackImpl->SetCallBack([env, deferred](std::string result) {
266         if (!env) {
267             return;
268         }
269         napi_handle_scope scope = nullptr;
270         napi_open_handle_scope(env, &scope);
271         if (scope == nullptr) {
272             return;
273         }
274 
275         napi_value jsResult = nullptr;
276         if (!result.empty()) {
277             napi_create_string_utf8(env, result.c_str(), NAPI_AUTO_LENGTH, &jsResult);
278             napi_resolve_deferred(env, deferred, jsResult);
279         } else {
280             napi_get_null(env, &jsResult);
281             napi_reject_deferred(env, deferred, jsResult);
282         }
283         napi_close_handle_scope(env, scope);
284     });
285     nweb->StoreWebArchive(baseName, autoName, callbackImpl);
286     return;
287 }
288 } // namespace NWeb
289 } // namespace OHOS
290