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 "webview_javascript_execute_callback.h"
17
18 #include "business_error.h"
19 #include "napi_parse_utils.h"
20 #include "nweb_log.h"
21 #include "web_errors.h"
22
23 namespace OHOS::NWeb {
24 using namespace NWebError;
25 const std::string JS_EXCUTE_MSG_ENUM_NAME = "JsMessageType";
26 const std::string JS_EXT_MSG_CLASS_NAME = "JsMessageExt";
27 thread_local napi_ref g_jsMsgExtClassRef;
28 // static
InitJSExcute(napi_env env,napi_value exports)29 void WebviewJavaScriptExecuteCallback::InitJSExcute(napi_env env, napi_value exports)
30 {
31 napi_value jsMsgTypeEnum = nullptr;
32 napi_property_descriptor jsMsgTypeProperties[] = {
33 DECLARE_NAPI_STATIC_PROPERTY("NOT_SUPPORT", NapiParseUtils::ToInt32Value(env,
34 static_cast<int32_t>(JsMessageType::NOTSUPPORT))),
35 DECLARE_NAPI_STATIC_PROPERTY("STRING", NapiParseUtils::ToInt32Value(env,
36 static_cast<int32_t>(JsMessageType::STRING))),
37 DECLARE_NAPI_STATIC_PROPERTY("NUMBER", NapiParseUtils::ToInt32Value(env,
38 static_cast<int32_t>(JsMessageType::NUMBER))),
39 DECLARE_NAPI_STATIC_PROPERTY("BOOLEAN", NapiParseUtils::ToInt32Value(env,
40 static_cast<int32_t>(JsMessageType::BOOLEAN))),
41 DECLARE_NAPI_STATIC_PROPERTY("ARRAY_BUFFER", NapiParseUtils::ToInt32Value(env,
42 static_cast<int32_t>(JsMessageType::ARRAYBUFFER))),
43 DECLARE_NAPI_STATIC_PROPERTY("ARRAY", NapiParseUtils::ToInt32Value(env,
44 static_cast<int32_t>(JsMessageType::ARRAY)))
45 };
46 napi_define_class(env, JS_EXCUTE_MSG_ENUM_NAME.c_str(), JS_EXCUTE_MSG_ENUM_NAME.length(),
47 NapiParseUtils::CreateEnumConstructor, nullptr, sizeof(jsMsgTypeProperties) /
48 sizeof(jsMsgTypeProperties[0]), jsMsgTypeProperties, &jsMsgTypeEnum);
49 napi_set_named_property(env, exports, JS_EXCUTE_MSG_ENUM_NAME.c_str(), jsMsgTypeEnum);
50
51 napi_value jsMsgExtClass = nullptr;
52 napi_property_descriptor jsMsgExtClsProperties[] = {
53 DECLARE_NAPI_FUNCTION("getType", NapiJsMessageExt::GetType),
54 DECLARE_NAPI_FUNCTION("getString", NapiJsMessageExt::GetString),
55 DECLARE_NAPI_FUNCTION("getNumber", NapiJsMessageExt::GetNumber),
56 DECLARE_NAPI_FUNCTION("getBoolean", NapiJsMessageExt::GetBoolean),
57 DECLARE_NAPI_FUNCTION("getArrayBuffer", NapiJsMessageExt::GetArrayBuffer),
58 DECLARE_NAPI_FUNCTION("getArray", NapiJsMessageExt::GetArray)
59 };
60 napi_define_class(env, JS_EXT_MSG_CLASS_NAME.c_str(), JS_EXT_MSG_CLASS_NAME.length(),
61 NapiJsMessageExt::JsConstructor, nullptr, sizeof(jsMsgExtClsProperties) / sizeof(jsMsgExtClsProperties[0]),
62 jsMsgExtClsProperties, &jsMsgExtClass);
63 napi_create_reference(env, jsMsgExtClass, 1, &g_jsMsgExtClassRef);
64 napi_set_named_property(env, exports, JS_EXT_MSG_CLASS_NAME.c_str(), jsMsgExtClass);
65 }
66
OnReceiveValue(std::shared_ptr<NWebMessage> result)67 void WebviewJavaScriptExecuteCallback::OnReceiveValue(std::shared_ptr<NWebMessage> result)
68 {
69 WVLOG_D("WebviewJavaScriptExecuteCallback::OnReceiveValue start");
70 uv_loop_s *loop = nullptr;
71 uv_work_t *work = nullptr;
72
73 napi_get_uv_event_loop(env_, &loop);
74 if (loop == nullptr) {
75 return;
76 }
77 work = new (std::nothrow) uv_work_t;
78 if (work == nullptr) {
79 return;
80 }
81
82 JavaScriptExecuteParam *param = new (std::nothrow) JavaScriptExecuteParam();
83 if (param == nullptr) {
84 delete work;
85 return;
86 }
87 param->env_ = env_;
88 param->callbackRef_ = callbackRef_;
89 param->deferred_ = deferred_;
90 param->result_ = result;
91 param->extention_ = extention_;
92
93 work->data = reinterpret_cast<void*>(param);
94
95 int ret = uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {}, UvAfterWorkCb, uv_qos_user_initiated);
96 if (ret != 0) {
97 if (param != nullptr) {
98 delete param;
99 param = nullptr;
100 }
101 if (work != nullptr) {
102 delete work;
103 work = nullptr;
104 }
105 }
106 }
107
UvAfterWorkCb(uv_work_t * work,int status)108 void WebviewJavaScriptExecuteCallback::UvAfterWorkCb(uv_work_t* work, int status)
109 {
110 WVLOG_D("WebviewJavaScriptExecuteCallback::UvAfterWorkCb");
111 (void)status;
112 if (!work) {
113 return;
114 }
115 JavaScriptExecuteParam *param = reinterpret_cast<JavaScriptExecuteParam*>(work->data);
116 if (!param) {
117 delete work;
118 work = nullptr;
119 return;
120 }
121 napi_handle_scope scope = nullptr;
122 napi_open_handle_scope(param->env_, &scope);
123 if (scope == nullptr) {
124 return;
125 }
126
127 if (param->callbackRef_) {
128 UvAfterWorkCbAsync(param->env_, param->callbackRef_, param->result_, param->extention_);
129 } else if (param->deferred_) {
130 UvAfterWorkCbPromise(param->env_, param->deferred_, param->result_, param->extention_);
131 }
132
133 napi_close_handle_scope(param->env_, scope);
134 delete param;
135 param = nullptr;
136 delete work;
137 work = nullptr;
138 }
139
UvAfterWorkCbAsync(napi_env env,napi_ref callbackRef,std::shared_ptr<NWebMessage> result,bool extention)140 void WebviewJavaScriptExecuteCallback::UvAfterWorkCbAsync(napi_env env, napi_ref callbackRef,
141 std::shared_ptr<NWebMessage> result, bool extention)
142 {
143 WVLOG_D("WebviewJavaScriptExecuteCallback::UvAfterWorkCbAsync");
144 napi_value setResult[INTEGER_TWO] = {0};
145 if (result->GetType() == NWebValue::Type::STRING && result->GetString().empty()) {
146 setResult[INTEGER_ZERO] = BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
147 napi_get_null(env, &setResult[INTEGER_ONE]);
148 } else {
149 napi_get_undefined(env, &setResult[INTEGER_ZERO]);
150 if (!extention) {
151 OHOS::NWeb::NapiParseUtils::ConvertNWebToNapiValue(env, result, setResult[INTEGER_ONE]);
152 } else {
153 napi_value jsMsgExt = nullptr;
154 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, g_jsMsgExtClassRef, &jsMsgExt));
155 NAPI_CALL_RETURN_VOID(env, napi_new_instance(env, jsMsgExt, 0, NULL, &setResult[INTEGER_ONE]));
156
157 WebJsMessageExt *webJsMessageExt = new (std::nothrow) WebJsMessageExt(result);
158 if (webJsMessageExt == nullptr) {
159 WVLOG_E("new WebJsMessageExt failed.");
160 return;
161 }
162
163 napi_status status = napi_wrap(env, setResult[INTEGER_ONE], webJsMessageExt,
164 [](napi_env env, void *data, void *hint) {
165 WebJsMessageExt *webJsMessageExt = static_cast<WebJsMessageExt *>(data);
166 delete webJsMessageExt;
167 webJsMessageExt = nullptr;
168 },
169 nullptr, nullptr);
170 if (status != napi_status::napi_ok) {
171 WVLOG_E("napi_wrap failed");
172 delete webJsMessageExt;
173 webJsMessageExt = nullptr;
174 return;
175 }
176 }
177 }
178 napi_value args[INTEGER_TWO] = {setResult[INTEGER_ZERO], setResult[INTEGER_ONE]};
179 napi_value callback = nullptr;
180 napi_value callbackResult = nullptr;
181
182 napi_get_reference_value(env, callbackRef, &callback);
183 napi_call_function(env, nullptr, callback, INTEGER_TWO, args, &callbackResult);
184 napi_delete_reference(env, callbackRef);
185 }
186
UvAfterWorkCbPromise(napi_env env,napi_deferred deferred,std::shared_ptr<NWebMessage> result,bool extention)187 void WebviewJavaScriptExecuteCallback::UvAfterWorkCbPromise(napi_env env, napi_deferred deferred,
188 std::shared_ptr<NWebMessage> result, bool extention)
189 {
190 WVLOG_D("WebviewJavaScriptExecuteCallback::UvAfterWorkCbPromise");
191 napi_value setResult[INTEGER_TWO] = {0};
192 setResult[INTEGER_ZERO] = NWebError::BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
193 if (!extention) {
194 OHOS::NWeb::NapiParseUtils::ConvertNWebToNapiValue(env, result, setResult[INTEGER_ONE]);
195 } else {
196 napi_value jsMsgExt = nullptr;
197 napi_status status = napi_get_reference_value(env, g_jsMsgExtClassRef, &jsMsgExt);
198 if (status != napi_status::napi_ok) {
199 WVLOG_E("napi_get_reference_value failed.");
200 return;
201 }
202 status = napi_new_instance(env, jsMsgExt, 0, NULL, &setResult[INTEGER_ONE]);
203 if (status != napi_status::napi_ok) {
204 WVLOG_E("napi_new_instance failed.");
205 return;
206 }
207 WebJsMessageExt *webJsMessageExt = new (std::nothrow) WebJsMessageExt(result);
208 if (webJsMessageExt == nullptr) {
209 WVLOG_E("new WebJsMessageExt failed.");
210 return;
211 }
212
213 status = napi_wrap(env, setResult[INTEGER_ONE], webJsMessageExt,
214 [](napi_env env, void *data, void *hint) {
215 WebJsMessageExt *webJsMessageExt = static_cast<WebJsMessageExt *>(data);
216 delete webJsMessageExt;
217 webJsMessageExt = nullptr;
218 },
219 nullptr, nullptr);
220 if (status != napi_status::napi_ok) {
221 WVLOG_E("napi_wrap failed.");
222 return;
223 }
224 }
225
226 napi_value args[INTEGER_TWO] = {setResult[INTEGER_ZERO], setResult[INTEGER_ONE]};
227 if (result->GetType() == NWebValue::Type::STRING && result->GetString().empty()) {
228 napi_reject_deferred(env, deferred, args[INTEGER_ZERO]);
229 } else {
230 napi_resolve_deferred(env, deferred, args[INTEGER_ONE]);
231 }
232 }
233
JsConstructor(napi_env env,napi_callback_info info)234 napi_value NapiJsMessageExt::JsConstructor(napi_env env, napi_callback_info info)
235 {
236 napi_value thisVar = nullptr;
237 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
238 return thisVar;
239 }
240
ConvertToJsType(NWebValue::Type type)241 int32_t WebJsMessageExt::ConvertToJsType(NWebValue::Type type)
242 {
243 JsMessageType jsMessageType = JsMessageType::NOTSUPPORT;
244 switch (type) {
245 case NWebValue::Type::STRING:
246 jsMessageType = JsMessageType::STRING;
247 break;
248 case NWebValue::Type::INTEGER:
249 case NWebValue::Type::DOUBLE:
250 jsMessageType = JsMessageType::NUMBER;
251 break;
252 case NWebValue::Type::BOOLEAN:
253 jsMessageType = JsMessageType::BOOLEAN;
254 break;
255 case NWebValue::Type::BINARY:
256 jsMessageType = JsMessageType::ARRAYBUFFER;
257 break;
258 case NWebValue::Type::STRINGARRAY:
259 case NWebValue::Type::BOOLEANARRAY:
260 case NWebValue::Type::DOUBLEARRAY:
261 case NWebValue::Type::INT64ARRAY:
262 jsMessageType = JsMessageType::ARRAY;
263 break;
264 default:
265 jsMessageType = JsMessageType::NOTSUPPORT;
266 break;
267 }
268 return static_cast<int32_t>(jsMessageType);
269 }
270
GetType()271 int32_t WebJsMessageExt::GetType()
272 {
273 if (value_) {
274 return ConvertToJsType(value_->GetType());
275 }
276 return static_cast<int32_t>(JsMessageType::NOTSUPPORT);
277 }
278
GetString()279 std::string WebJsMessageExt::GetString()
280 {
281 if (value_) {
282 return value_->GetString();
283 }
284 return "";
285 }
286
GetNumber()287 double WebJsMessageExt::GetNumber()
288 {
289 if (value_) {
290 return value_->GetDouble();
291 }
292 return 0;
293 }
294
GetBoolean()295 bool WebJsMessageExt::GetBoolean()
296 {
297 if (value_) {
298 return value_->GetBoolean();
299 }
300 return false;
301 }
302
GetType(napi_env env,napi_callback_info info)303 napi_value NapiJsMessageExt::GetType(napi_env env, napi_callback_info info)
304 {
305 WVLOG_D("GetType webJsMessageExt start");
306 napi_value thisVar = nullptr;
307 napi_value result = nullptr;
308 size_t argc = INTEGER_ONE;
309 napi_value argv[INTEGER_ONE] = { 0 };
310
311 WebJsMessageExt *webJsMessageExt = nullptr;
312 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
313 if (status != napi_status::napi_ok) {
314 WVLOG_E("napi_get_cb_info failed.");
315 return result;
316 }
317 status = napi_unwrap(env, thisVar, (void **)&webJsMessageExt);
318 if (status != napi_status::napi_ok) {
319 WVLOG_E("napi_unwrap failed.");
320 return result;
321 }
322 if (webJsMessageExt == nullptr) {
323 WVLOG_E("unwrap webJsMessageExt failed.");
324 return result;
325 }
326
327 int32_t type = webJsMessageExt->GetType();
328 status = napi_create_int32(env, type, &result);
329 if (status != napi_status::napi_ok) {
330 WVLOG_E("napi_create_int32 failed.");
331 return result;
332 }
333 return result;
334 }
335
GetString(napi_env env,napi_callback_info info)336 napi_value NapiJsMessageExt::GetString(napi_env env, napi_callback_info info)
337 {
338 WVLOG_D("GetString webJsMessageExt");
339 napi_value thisVar = nullptr;
340 napi_value result = nullptr;
341 size_t argc = INTEGER_ONE;
342 napi_value argv[INTEGER_ONE] = { 0 };
343
344 WebJsMessageExt *webJsMessageExt = nullptr;
345 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
346 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
347 if (webJsMessageExt == nullptr) {
348 WVLOG_E("unwrap webJsMessageExt failed.");
349 return result;
350 }
351
352 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::STRING)) {
353 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
354 return nullptr;
355 }
356
357 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
358 return result;
359 }
360
GetNumber(napi_env env,napi_callback_info info)361 napi_value NapiJsMessageExt::GetNumber(napi_env env, napi_callback_info info)
362 {
363 WVLOG_D("GetNumber webJsMessageExt");
364 napi_value thisVar = nullptr;
365 napi_value result = nullptr;
366 size_t argc = INTEGER_ONE;
367 napi_value argv[INTEGER_ONE] = { 0 };
368
369 WebJsMessageExt *webJsMessageExt = nullptr;
370 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
371 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
372 if (webJsMessageExt == nullptr) {
373 WVLOG_E("unwrap webJsMessageExt failed.");
374 return result;
375 }
376
377 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::NUMBER)) {
378 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
379 WVLOG_E("GetNumber webJsMessageExt failed not match");
380 return nullptr;
381 }
382
383 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
384 return result;
385 }
386
GetBoolean(napi_env env,napi_callback_info info)387 napi_value NapiJsMessageExt::GetBoolean(napi_env env, napi_callback_info info)
388 {
389 napi_value thisVar = nullptr;
390 napi_value result = nullptr;
391 size_t argc = INTEGER_ONE;
392 napi_value argv[INTEGER_ONE] = { 0 };
393
394 WebJsMessageExt *webJsMessageExt = nullptr;
395 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
396 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
397 if (webJsMessageExt == nullptr) {
398 WVLOG_E("unwrap webJsMessageExt failed.");
399 return result;
400 }
401
402 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::BOOLEAN)) {
403 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
404 return nullptr;
405 }
406
407 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
408 return result;
409 }
410
GetArrayBuffer(napi_env env,napi_callback_info info)411 napi_value NapiJsMessageExt::GetArrayBuffer(napi_env env, napi_callback_info info)
412 {
413 napi_value thisVar = nullptr;
414 napi_value result = nullptr;
415 size_t argc = INTEGER_ONE;
416 napi_value argv[INTEGER_ONE] = { 0 };
417
418 WebJsMessageExt *webJsMessageExt = nullptr;
419 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
420 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
421 if (webJsMessageExt == nullptr) {
422 WVLOG_E("unwrap webJsMessageExt failed.");
423 return result;
424 }
425
426 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::ARRAYBUFFER)) {
427 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
428 return nullptr;
429 }
430 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
431 return result;
432 }
433
GetArray(napi_env env,napi_callback_info info)434 napi_value NapiJsMessageExt::GetArray(napi_env env, napi_callback_info info)
435 {
436 napi_value thisVar = nullptr;
437 napi_value result = nullptr;
438 size_t argc = INTEGER_ONE;
439 napi_value argv[INTEGER_ONE] = { 0 };
440
441 WebJsMessageExt *webJsMessageExt = nullptr;
442 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
443 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
444 if (webJsMessageExt == nullptr) {
445 WVLOG_E("unwrap webJsMessageExt failed.");
446 return result;
447 }
448
449 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::ARRAY)) {
450 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
451 return nullptr;
452 }
453
454 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
455 return result;
456 }
457
458 } // namespace OHOS::NWeb
459