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(loop, work, [](uv_work_t *work) {}, UvAfterWorkCb);
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 return;
173 }
174 }
175 }
176 napi_value args[INTEGER_TWO] = {setResult[INTEGER_ZERO], setResult[INTEGER_ONE]};
177 napi_value callback = nullptr;
178 napi_value callbackResult = nullptr;
179
180 napi_get_reference_value(env, callbackRef, &callback);
181 napi_call_function(env, nullptr, callback, INTEGER_TWO, args, &callbackResult);
182 napi_delete_reference(env, callbackRef);
183 }
184
UvAfterWorkCbPromise(napi_env env,napi_deferred deferred,std::shared_ptr<NWebMessage> result,bool extention)185 void WebviewJavaScriptExecuteCallback::UvAfterWorkCbPromise(napi_env env, napi_deferred deferred,
186 std::shared_ptr<NWebMessage> result, bool extention)
187 {
188 WVLOG_D("WebviewJavaScriptExecuteCallback::UvAfterWorkCbPromise");
189 napi_value setResult[INTEGER_TWO] = {0};
190 setResult[INTEGER_ZERO] = NWebError::BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
191 if (!extention) {
192 OHOS::NWeb::NapiParseUtils::ConvertNWebToNapiValue(env, result, setResult[INTEGER_ONE]);
193 } else {
194 napi_value jsMsgExt = nullptr;
195 napi_status status = napi_get_reference_value(env, g_jsMsgExtClassRef, &jsMsgExt);
196 if (status != napi_status::napi_ok) {
197 WVLOG_E("napi_get_reference_value failed.");
198 return;
199 }
200 status = napi_new_instance(env, jsMsgExt, 0, NULL, &setResult[INTEGER_ONE]);
201 if (status != napi_status::napi_ok) {
202 WVLOG_E("napi_new_instance failed.");
203 return;
204 }
205 WebJsMessageExt *webJsMessageExt = new (std::nothrow) WebJsMessageExt(result);
206 if (webJsMessageExt == nullptr) {
207 WVLOG_E("new WebJsMessageExt failed.");
208 return;
209 }
210
211 status = napi_wrap(env, setResult[INTEGER_ONE], webJsMessageExt,
212 [](napi_env env, void *data, void *hint) {
213 WebJsMessageExt *webJsMessageExt = static_cast<WebJsMessageExt *>(data);
214 delete webJsMessageExt;
215 webJsMessageExt = nullptr;
216 },
217 nullptr, nullptr);
218 if (status != napi_status::napi_ok) {
219 WVLOG_E("napi_wrap failed.");
220 return;
221 }
222 }
223
224 napi_value args[INTEGER_TWO] = {setResult[INTEGER_ZERO], setResult[INTEGER_ONE]};
225 if (result->GetType() == NWebValue::Type::STRING && result->GetString().empty()) {
226 napi_reject_deferred(env, deferred, args[INTEGER_ZERO]);
227 } else {
228 napi_resolve_deferred(env, deferred, args[INTEGER_ONE]);
229 }
230 }
231
JsConstructor(napi_env env,napi_callback_info info)232 napi_value NapiJsMessageExt::JsConstructor(napi_env env, napi_callback_info info)
233 {
234 napi_value thisVar = nullptr;
235 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
236 return thisVar;
237 }
238
ConvertToJsType(NWebValue::Type type)239 int32_t WebJsMessageExt::ConvertToJsType(NWebValue::Type type)
240 {
241 JsMessageType jsMessageType = JsMessageType::NOTSUPPORT;
242 switch (type) {
243 case NWebValue::Type::STRING:
244 jsMessageType = JsMessageType::STRING;
245 break;
246 case NWebValue::Type::INTEGER:
247 case NWebValue::Type::DOUBLE:
248 jsMessageType = JsMessageType::NUMBER;
249 break;
250 case NWebValue::Type::BOOLEAN:
251 jsMessageType = JsMessageType::BOOLEAN;
252 break;
253 case NWebValue::Type::BINARY:
254 jsMessageType = JsMessageType::ARRAYBUFFER;
255 break;
256 case NWebValue::Type::STRINGARRAY:
257 case NWebValue::Type::BOOLEANARRAY:
258 case NWebValue::Type::DOUBLEARRAY:
259 case NWebValue::Type::INT64ARRAY:
260 jsMessageType = JsMessageType::ARRAY;
261 break;
262 default:
263 jsMessageType = JsMessageType::NOTSUPPORT;
264 break;
265 }
266 return static_cast<int32_t>(jsMessageType);
267 }
268
GetType()269 int32_t WebJsMessageExt::GetType()
270 {
271 if (value_) {
272 return ConvertToJsType(value_->GetType());
273 }
274 return static_cast<int32_t>(JsMessageType::NOTSUPPORT);
275 }
276
GetString()277 std::string WebJsMessageExt::GetString()
278 {
279 if (value_) {
280 return value_->GetString();
281 }
282 return "";
283 }
284
GetNumber()285 double WebJsMessageExt::GetNumber()
286 {
287 if (value_) {
288 return value_->GetDouble();
289 }
290 return 0;
291 }
292
GetBoolean()293 bool WebJsMessageExt::GetBoolean()
294 {
295 if (value_) {
296 return value_->GetBoolean();
297 }
298 return false;
299 }
300
GetType(napi_env env,napi_callback_info info)301 napi_value NapiJsMessageExt::GetType(napi_env env, napi_callback_info info)
302 {
303 WVLOG_D("GetType webJsMessageExt start");
304 napi_value thisVar = nullptr;
305 napi_value result = nullptr;
306 size_t argc = INTEGER_ONE;
307 napi_value argv[INTEGER_ONE] = { 0 };
308
309 WebJsMessageExt *webJsMessageExt = nullptr;
310 napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
311 if (status != napi_status::napi_ok) {
312 WVLOG_E("napi_get_cb_info failed.");
313 return result;
314 }
315 status = napi_unwrap(env, thisVar, (void **)&webJsMessageExt);
316 if (status != napi_status::napi_ok) {
317 WVLOG_E("napi_unwrap failed.");
318 return result;
319 }
320 if (webJsMessageExt == nullptr) {
321 WVLOG_E("unwrap webJsMessageExt failed.");
322 return result;
323 }
324
325 int32_t type = webJsMessageExt->GetType();
326 status = napi_create_int32(env, type, &result);
327 if (status != napi_status::napi_ok) {
328 WVLOG_E("napi_create_int32 failed.");
329 return result;
330 }
331 return result;
332 }
333
GetString(napi_env env,napi_callback_info info)334 napi_value NapiJsMessageExt::GetString(napi_env env, napi_callback_info info)
335 {
336 WVLOG_D("GetString webJsMessageExt");
337 napi_value thisVar = nullptr;
338 napi_value result = nullptr;
339 size_t argc = INTEGER_ONE;
340 napi_value argv[INTEGER_ONE] = { 0 };
341
342 WebJsMessageExt *webJsMessageExt = nullptr;
343 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
344 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
345 if (webJsMessageExt == nullptr) {
346 WVLOG_E("unwrap webJsMessageExt failed.");
347 return result;
348 }
349
350 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::STRING)) {
351 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
352 return nullptr;
353 }
354
355 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
356 return result;
357 }
358
GetNumber(napi_env env,napi_callback_info info)359 napi_value NapiJsMessageExt::GetNumber(napi_env env, napi_callback_info info)
360 {
361 WVLOG_D("GetNumber webJsMessageExt");
362 napi_value thisVar = nullptr;
363 napi_value result = nullptr;
364 size_t argc = INTEGER_ONE;
365 napi_value argv[INTEGER_ONE] = { 0 };
366
367 WebJsMessageExt *webJsMessageExt = nullptr;
368 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
369 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
370 if (webJsMessageExt == nullptr) {
371 WVLOG_E("unwrap webJsMessageExt failed.");
372 return result;
373 }
374
375 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::NUMBER)) {
376 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
377 WVLOG_E("GetNumber webJsMessageExt failed not match");
378 return nullptr;
379 }
380
381 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
382 return result;
383 }
384
GetBoolean(napi_env env,napi_callback_info info)385 napi_value NapiJsMessageExt::GetBoolean(napi_env env, napi_callback_info info)
386 {
387 napi_value thisVar = nullptr;
388 napi_value result = nullptr;
389 size_t argc = INTEGER_ONE;
390 napi_value argv[INTEGER_ONE] = { 0 };
391
392 WebJsMessageExt *webJsMessageExt = nullptr;
393 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
394 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
395 if (webJsMessageExt == nullptr) {
396 WVLOG_E("unwrap webJsMessageExt failed.");
397 return result;
398 }
399
400 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::BOOLEAN)) {
401 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
402 return nullptr;
403 }
404
405 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
406 return result;
407 }
408
GetArrayBuffer(napi_env env,napi_callback_info info)409 napi_value NapiJsMessageExt::GetArrayBuffer(napi_env env, napi_callback_info info)
410 {
411 napi_value thisVar = nullptr;
412 napi_value result = nullptr;
413 size_t argc = INTEGER_ONE;
414 napi_value argv[INTEGER_ONE] = { 0 };
415
416 WebJsMessageExt *webJsMessageExt = nullptr;
417 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
418 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
419 if (webJsMessageExt == nullptr) {
420 WVLOG_E("unwrap webJsMessageExt failed.");
421 return result;
422 }
423
424 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::ARRAYBUFFER)) {
425 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
426 return nullptr;
427 }
428 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
429 return result;
430 }
431
GetArray(napi_env env,napi_callback_info info)432 napi_value NapiJsMessageExt::GetArray(napi_env env, napi_callback_info info)
433 {
434 napi_value thisVar = nullptr;
435 napi_value result = nullptr;
436 size_t argc = INTEGER_ONE;
437 napi_value argv[INTEGER_ONE] = { 0 };
438
439 WebJsMessageExt *webJsMessageExt = nullptr;
440 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
441 NAPI_CALL(env, napi_unwrap(env, thisVar, (void **)&webJsMessageExt));
442 if (webJsMessageExt == nullptr) {
443 WVLOG_E("unwrap webJsMessageExt failed.");
444 return result;
445 }
446
447 if (webJsMessageExt->GetType() != static_cast<int32_t>(JsMessageType::ARRAY)) {
448 BusinessError::ThrowErrorByErrcode(env, TYPE_NOT_MATCH_WITCH_VALUE);
449 return nullptr;
450 }
451
452 NapiParseUtils::ConvertNWebToNapiValue(env, webJsMessageExt->GetJsMsgResult(), result);
453 return result;
454 }
455
456 } // namespace OHOS::NWeb
457