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