• 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 "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