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