• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 <cstdint>
17 #include <memory>
18 #include <string>
19 
20 #include "interfaces/napi/kits/utils/napi_utils.h"
21 #include "js_native_api.h"
22 #include "js_native_api_types.h"
23 #include "napi/native_api.h"
24 #include "napi/native_engine/native_value.h"
25 #include "napi/native_node_api.h"
26 #include "uv.h"
27 
28 #include "frameworks/base/log/log.h"
29 #include "frameworks/bridge/common/utils/engine_helper.h"
30 #include "frameworks/bridge/js_frontend/engine/common/js_engine.h"
31 
32 namespace OHOS::Ace::Napi {
33 const char EN_ALERT_APPROVE[] = "enableAlertBeforeBackPage:ok";
34 const char EN_ALERT_REJECT[] = "enableAlertBeforeBackPage:fail cancel";
35 const char DIS_ALERT_SUCCESS[] = "disableAlertBeforeBackPage:ok";
36 
37 static constexpr size_t ARGC_WITH_MODE = 2;
38 static constexpr size_t ARGC_WITH_MODE_AND_CALLBACK = 3;
39 static constexpr uint32_t STANDARD = 0;
40 static constexpr uint32_t SINGLE = 1;
41 
ParseUri(napi_env env,napi_value uriNApi,std::string & uriString)42 static void ParseUri(napi_env env, napi_value uriNApi, std::string& uriString)
43 {
44     if (uriNApi != nullptr) {
45         auto nativeUri = reinterpret_cast<NativeValue*>(uriNApi);
46         auto resultUri = nativeUri->ToString();
47         auto nativeStringUri = reinterpret_cast<NativeString*>(resultUri->GetInterface(NativeString::INTERFACE_ID));
48         size_t uriLen = nativeStringUri->GetLength() + 1;
49         std::unique_ptr<char[]> uri = std::make_unique<char[]>(uriLen);
50         size_t retLen = 0;
51         napi_get_value_string_utf8(env, uriNApi, uri.get(), uriLen, &retLen);
52         uriString = uri.get();
53     }
54 }
55 
ParseParams(napi_env env,napi_value params,std::string & paramsString)56 static void ParseParams(napi_env env, napi_value params, std::string& paramsString)
57 {
58     // TODO: Save the original data instead of making the serial number.
59     if (params == nullptr) {
60         return;
61     }
62     napi_value globalValue;
63     napi_get_global(env, &globalValue);
64     napi_value jsonValue;
65     napi_get_named_property(env, globalValue, "JSON", &jsonValue);
66     napi_value stringifyValue;
67     napi_get_named_property(env, jsonValue, "stringify", &stringifyValue);
68     napi_value funcArgv[1] = { params };
69     napi_value returnValue;
70     napi_call_function(env, jsonValue, stringifyValue, 1, funcArgv, &returnValue);
71     auto nativeValue = reinterpret_cast<NativeValue*>(returnValue);
72     auto resultValue = nativeValue->ToString();
73     auto nativeString = reinterpret_cast<NativeString*>(resultValue->GetInterface(NativeString::INTERFACE_ID));
74     size_t len = nativeString->GetLength() + 1;
75     std::unique_ptr<char[]> paramsChar = std::make_unique<char[]>(len);
76     size_t ret = 0;
77     napi_get_value_string_utf8(env, returnValue, paramsChar.get(), len, &ret);
78     paramsString = paramsChar.get();
79 }
80 
81 struct RouterAsyncContext {
82     napi_env env = nullptr;
83     napi_ref callbackSuccess = nullptr;
84     napi_ref callbackFail = nullptr;
85     napi_ref callbackComplete = nullptr;
86     int32_t callbackType = 0;
87     std::set<std::string> callbacks;
88     std::string paramsString;
89     std::string uriString;
90     uint32_t mode;
91     bool isModeType = false;
92     napi_deferred deferred = nullptr;
93     napi_ref callbackRef = nullptr;
94     napi_async_work work = nullptr;
~RouterAsyncContextOHOS::Ace::Napi::RouterAsyncContext95     ~RouterAsyncContext()
96     {
97         if (callbackSuccess) {
98             napi_delete_reference(env, callbackSuccess);
99         }
100         if (callbackFail) {
101             napi_delete_reference(env, callbackFail);
102         }
103         if (callbackComplete) {
104             napi_delete_reference(env, callbackComplete);
105         }
106     }
107 };
JSRouterPush(napi_env env,napi_callback_info info)108 static napi_value JSRouterPush(napi_env env, napi_callback_info info)
109 {
110     LOGI("NAPI router push called");
111     size_t requireArgc = 1;
112     size_t argc = ARGC_WITH_MODE;
113     napi_value argv[ARGC_WITH_MODE] = { 0 };
114     napi_value thisVar = nullptr;
115     void* data = nullptr;
116     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
117     if (argc < requireArgc) {
118         LOGE("params number err");
119         return nullptr;
120     }
121     napi_value uriNApi = nullptr;
122     napi_value params = nullptr;
123     napi_valuetype valueType = napi_undefined;
124     napi_typeof(env, argv[0], &valueType);
125     if (valueType == napi_object) {
126         napi_get_named_property(env, argv[0], "url", &uriNApi);
127         napi_typeof(env, uriNApi, &valueType);
128         if (valueType != napi_string) {
129             LOGE("url is invalid");
130             return nullptr;
131         }
132         napi_get_named_property(env, argv[0], "params", &params);
133     }
134     std::string paramsString;
135     ParseParams(env, params, paramsString);
136     std::string uriString;
137     napi_typeof(env, uriNApi, &valueType);
138     if (valueType == napi_string) {
139         ParseUri(env, uriNApi, uriString);
140     } else {
141         LOGW("The parameter type is incorrect.");
142     }
143     auto delegate = EngineHelper::GetCurrentDelegate();
144     if (!delegate) {
145         LOGE("can not get delegate.");
146         return nullptr;
147     }
148 
149     napi_typeof(env, argv[1], &valueType);
150     if (argc == ARGC_WITH_MODE && valueType == napi_number) {
151         uint32_t mode = STANDARD;
152         napi_get_value_uint32(env, argv[1], &mode);
153         LOGI("router mode with single");
154         delegate->PushWithMode(uriString, paramsString, mode);
155         return nullptr;
156     }
157     delegate->Push(uriString, paramsString);
158     return nullptr;
159 }
160 
ParseParamWithCallback(napi_env env,RouterAsyncContext * asyncContext,const size_t argc,napi_value * argv)161 bool ParseParamWithCallback(napi_env env, RouterAsyncContext* asyncContext, const size_t argc, napi_value* argv)
162 {
163     asyncContext->env = env;
164     for (size_t i = 0; i < argc; i++) {
165         napi_valuetype valueType = napi_undefined;
166         napi_typeof(env, argv[i], &valueType);
167         if (i == 0) {
168             if (valueType != napi_object) {
169                 delete asyncContext;
170                 asyncContext = nullptr;
171                 NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
172                 return false;
173             }
174             napi_value uriNApi = nullptr;
175             napi_value params = nullptr;
176             napi_get_named_property(env, argv[i], "url", &uriNApi);
177             napi_typeof(env, uriNApi, &valueType);
178             if (valueType == napi_undefined) {
179                 delete asyncContext;
180                 asyncContext = nullptr;
181                 NapiThrow(env, "The required url parameter is missing.", Framework::ERROR_CODE_PARAM_INVALID);
182                 return false;
183             }
184             if (valueType != napi_string) {
185                 delete asyncContext;
186                 asyncContext = nullptr;
187                 LOGE("url is invalid");
188                 NapiThrow(env, "The type of the url parameter is not string.", Framework::ERROR_CODE_PARAM_INVALID);
189                 return false;
190             }
191             napi_get_named_property(env, argv[i], "params", &params);
192             std::string paramsString;
193             ParseParams(env, params, paramsString);
194             asyncContext->paramsString = paramsString;
195             std::string uriString;
196             napi_typeof(env, uriNApi, &valueType);
197             if (valueType == napi_string) {
198                 ParseUri(env, uriNApi, uriString);
199                 asyncContext->uriString = uriString;
200             } else {
201                 LOGW("The parameter type is incorrect.");
202             }
203         } else if (valueType == napi_number) {
204             uint32_t mode = STANDARD;
205             napi_get_value_uint32(env, argv[i], &mode);
206             LOGI("router mode with single");
207             asyncContext->mode = mode;
208             asyncContext->isModeType = true;
209         } else if (valueType == napi_function) {
210             napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
211         } else {
212             delete asyncContext;
213             asyncContext = nullptr;
214             NapiThrow(env, "The type of parameters is incorrect.", Framework::ERROR_CODE_PARAM_INVALID);
215             return false;
216         }
217     }
218     return true;
219 }
220 
JSRouterPushWithCallback(napi_env env,napi_callback_info info)221 static napi_value JSRouterPushWithCallback(napi_env env, napi_callback_info info)
222 {
223     napi_escapable_handle_scope scope = nullptr;
224     napi_open_escapable_handle_scope(env, &scope);
225 
226     napi_value result = nullptr;
227     size_t requireArgc = 1;
228     size_t largestArgc = 3;
229     size_t largestArgcPromise = 2;
230     size_t argc = ARGC_WITH_MODE_AND_CALLBACK;
231     napi_value argv[ARGC_WITH_MODE_AND_CALLBACK] = { nullptr };
232     napi_value thisVar = nullptr;
233     void* data = nullptr;
234     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
235     if (argc < requireArgc) {
236         LOGE("params number err");
237         NapiThrow(
238             env, "The number of parameters must be greater than or equal to 1.", Framework::ERROR_CODE_PARAM_INVALID);
239         napi_close_escapable_handle_scope(env, scope);
240         return result;
241     } else if (argc > largestArgc) {
242         LOGE("params number err");
243         NapiThrow(env, "The largest number of parameters is 3.", Framework::ERROR_CODE_PARAM_INVALID);
244         napi_close_escapable_handle_scope(env, scope);
245         return result;
246     }
247     auto* asyncContext = new RouterAsyncContext();
248     if (!ParseParamWithCallback(env, asyncContext, argc, argv)) {
249         LOGE("parse params failed");
250         napi_close_escapable_handle_scope(env, scope);
251         return result;
252     }
253 
254     if (asyncContext->callbackRef == nullptr) {
255         if (argc > largestArgcPromise) {
256             delete asyncContext;
257             NapiThrow(env, "The largest number of parameters is 2 in Promise.", Framework::ERROR_CODE_PARAM_INVALID);
258             napi_close_escapable_handle_scope(env, scope);
259             return result;
260         }
261         napi_create_promise(env, &asyncContext->deferred, &result);
262     } else {
263         asyncContext->deferred = nullptr;
264         napi_get_undefined(env, &result);
265     }
266     napi_value resource = nullptr;
267     napi_create_string_utf8(env, "JSRouterPush", NAPI_AUTO_LENGTH, &resource);
268     napi_create_async_work(
269         env, nullptr, resource, [](napi_env env, void* data) {},
270         [](napi_env env, napi_status /* status */, void* data) {
271             napi_handle_scope scope = nullptr;
272             napi_open_handle_scope(env, &scope);
273             if (scope == nullptr) {
274                 return;
275             }
276             auto* asyncContext = static_cast<RouterAsyncContext*>(data);
277             auto errorCallback = [env, asyncContext](const std::string& message, int32_t errCode) {
278                 napi_handle_scope scope = nullptr;
279                 napi_open_handle_scope(env, &scope);
280                 if (scope == nullptr) {
281                     return;
282                 }
283                 if (errCode == Framework::ERROR_CODE_NO_ERROR) {
284                     if (asyncContext->deferred) {
285                         napi_value success = nullptr;
286                         napi_create_object(env, &success);
287                         napi_set_named_property(env, success, "then", nullptr);
288                         napi_resolve_deferred(env, asyncContext->deferred, success);
289                     }
290                     napi_delete_async_work(env, asyncContext->work);
291                     delete asyncContext;
292                     napi_close_handle_scope(env, scope);
293                     return;
294                 }
295 
296                 napi_value ret = nullptr;
297                 napi_value code = nullptr;
298                 std::string strCode = std::to_string(errCode);
299                 napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
300 
301                 napi_value msg = nullptr;
302                 std::string strMsg = ErrorToMessage(errCode) + message;
303                 LOGE("napi throw errCode %d strMsg %s", errCode, strMsg.c_str());
304                 napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
305 
306                 napi_value error = nullptr;
307                 napi_create_error(env, code, msg, &error);
308                 if (asyncContext->deferred) {
309                     napi_reject_deferred(env, asyncContext->deferred, error);
310                 } else {
311                     napi_value callback = nullptr;
312                     napi_get_reference_value(env, asyncContext->callbackRef, &callback);
313                     napi_call_function(env, nullptr, callback, 1, &error, &ret);
314                     napi_delete_reference(env, asyncContext->callbackRef);
315                 }
316                 napi_delete_async_work(env, asyncContext->work);
317                 delete asyncContext;
318                 napi_close_handle_scope(env, scope);
319             };
320             auto delegate = EngineHelper::GetCurrentDelegate();
321             std::string uriString = asyncContext->uriString;
322             std::string paramsString = asyncContext->paramsString;
323             if (delegate) {
324                 if (asyncContext->isModeType) {
325                     uint32_t mode = asyncContext->mode;
326                     delegate->PushWithCallback(uriString, paramsString, errorCallback, mode);
327                 } else {
328                     delegate->PushWithCallback(uriString, paramsString, errorCallback);
329                 }
330             } else {
331                 LOGE("delegate is null");
332                 napi_value code = nullptr;
333                 std::string strCode = std::to_string(Framework::ERROR_CODE_INTERNAL_ERROR);
334                 napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
335                 napi_value msg = nullptr;
336                 std::string strMsg =
337                     ErrorToMessage(Framework::ERROR_CODE_INTERNAL_ERROR) + "UI execution context not found.";
338                 napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
339                 napi_value error = nullptr;
340                 napi_create_error(env, code, msg, &error);
341 
342                 if (asyncContext->deferred) {
343                     napi_reject_deferred(env, asyncContext->deferred, error);
344                 } else {
345                     napi_value ret1;
346                     napi_value callback = nullptr;
347                     napi_get_reference_value(env, asyncContext->callbackRef, &callback);
348                     napi_call_function(env, nullptr, callback, 1, &error, &ret1);
349                     napi_delete_reference(env, asyncContext->callbackRef);
350                 }
351                 napi_delete_async_work(env, asyncContext->work);
352                 delete asyncContext;
353             }
354             napi_close_handle_scope(env, scope);
355         },
356         (void*)asyncContext, &asyncContext->work);
357     napi_queue_async_work(env, asyncContext->work);
358 
359     napi_value newResult = nullptr;
360     napi_escape_handle(env, scope, result, &newResult);
361     napi_close_escapable_handle_scope(env, scope);
362     return newResult;
363 }
364 
JSRouterReplace(napi_env env,napi_callback_info info)365 static napi_value JSRouterReplace(napi_env env, napi_callback_info info)
366 {
367     size_t requireArgc = 1;
368     size_t argc = ARGC_WITH_MODE;
369     napi_value argv[ARGC_WITH_MODE] = { 0 };
370     napi_value thisVar = nullptr;
371     void* data = nullptr;
372     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
373     if (argc < requireArgc) {
374         LOGE("params number err");
375         return nullptr;
376     }
377     napi_value uriNApi = nullptr;
378     napi_value params = nullptr;
379     napi_valuetype valueType = napi_undefined;
380     napi_typeof(env, argv[0], &valueType);
381     if (valueType == napi_object) {
382         napi_get_named_property(env, argv[0], "url", &uriNApi);
383         napi_typeof(env, uriNApi, &valueType);
384         if (valueType != napi_string) {
385             LOGE("url is invalid");
386             return nullptr;
387         }
388         napi_get_named_property(env, argv[0], "params", &params);
389     }
390     std::string paramsString;
391     ParseParams(env, params, paramsString);
392     std::string uriString;
393     napi_typeof(env, uriNApi, &valueType);
394     if (valueType == napi_string) {
395         ParseUri(env, uriNApi, uriString);
396     } else {
397         LOGW("The parameter type is incorrect.");
398     }
399 
400     auto delegate = EngineHelper::GetCurrentDelegate();
401     if (!delegate) {
402         LOGE("can not get delegate.");
403         return nullptr;
404     }
405 
406     napi_typeof(env, argv[1], &valueType);
407     if (argc == ARGC_WITH_MODE && valueType == napi_number) {
408         uint32_t mode = STANDARD;
409         napi_get_value_uint32(env, argv[1], &mode);
410         LOGI("router mode with single");
411         delegate->ReplaceWithMode(uriString, paramsString, mode);
412         return nullptr;
413     }
414 
415     delegate->Replace(uriString, paramsString);
416     return nullptr;
417 }
418 
JSRouterReplaceWithCallback(napi_env env,napi_callback_info info)419 static napi_value JSRouterReplaceWithCallback(napi_env env, napi_callback_info info)
420 {
421     napi_escapable_handle_scope scope = nullptr;
422     napi_open_escapable_handle_scope(env, &scope);
423 
424     napi_value result = nullptr;
425     size_t requireArgc = 1;
426     size_t largestArgc = 3;
427     size_t largestArgcPromise = 2;
428     size_t argc = ARGC_WITH_MODE_AND_CALLBACK;
429     napi_value argv[ARGC_WITH_MODE_AND_CALLBACK] = { 0 };
430     napi_value thisVar = nullptr;
431     void* data = nullptr;
432     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
433     if (argc < requireArgc) {
434         LOGE("params number err");
435         NapiThrow(
436             env, "The number of parameters must be greater than or equal to 1.", Framework::ERROR_CODE_PARAM_INVALID);
437         napi_close_escapable_handle_scope(env, scope);
438         return result;
439     } else if (argc > largestArgc) {
440         LOGE("params number err");
441         NapiThrow(env, "The largest number of parameters is 3.", Framework::ERROR_CODE_PARAM_INVALID);
442         return result;
443     }
444     auto* asyncContext = new RouterAsyncContext();
445     if (!ParseParamWithCallback(env, asyncContext, argc, argv)) {
446         LOGE("parse params failed");
447         napi_close_escapable_handle_scope(env, scope);
448         return result;
449     }
450 
451     if (asyncContext->callbackRef == nullptr) {
452         if (argc > largestArgcPromise) {
453             delete asyncContext;
454             NapiThrow(env, "The largest number of parameters is 2 in Promise.", Framework::ERROR_CODE_PARAM_INVALID);
455             napi_close_escapable_handle_scope(env, scope);
456             return result;
457         }
458         napi_create_promise(env, &asyncContext->deferred, &result);
459     } else {
460         asyncContext->deferred = nullptr;
461         napi_get_undefined(env, &result);
462     }
463     napi_value resource = nullptr;
464     napi_create_string_utf8(env, "JSRouterReplace", NAPI_AUTO_LENGTH, &resource);
465     napi_create_async_work(
466         env, nullptr, resource, [](napi_env env, void* data) {},
467         [](napi_env env, napi_status /* status */, void* data) {
468             napi_handle_scope scope = nullptr;
469             napi_open_handle_scope(env, &scope);
470             if (scope == nullptr) {
471                 return;
472             }
473             auto* asyncContext = static_cast<RouterAsyncContext*>(data);
474             auto errorCallback = [env, asyncContext](const std::string& message, int32_t errCode) {
475                 napi_handle_scope scope = nullptr;
476                 napi_open_handle_scope(env, &scope);
477                 if (scope == nullptr) {
478                     return;
479                 }
480                 if (errCode == Framework::ERROR_CODE_NO_ERROR) {
481                     if (asyncContext->deferred) {
482                         napi_value success = nullptr;
483                         napi_create_object(env, &success);
484                         napi_set_named_property(env, success, "then", nullptr);
485                         napi_resolve_deferred(env, asyncContext->deferred, success);
486                     }
487                     napi_delete_async_work(env, asyncContext->work);
488                     delete asyncContext;
489                     napi_close_handle_scope(env, scope);
490                     return;
491                 }
492 
493                 napi_value ret = nullptr;
494                 napi_value code = nullptr;
495                 std::string strCode = std::to_string(errCode);
496                 napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
497 
498                 napi_value msg = nullptr;
499                 std::string strMsg = ErrorToMessage(errCode) + message;
500                 LOGE("napi throw errCode %{public}d strMsg %{public}s", errCode, strMsg.c_str());
501                 napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
502 
503                 napi_value error = nullptr;
504                 napi_create_error(env, code, msg, &error);
505                 if (asyncContext->deferred) {
506                     napi_reject_deferred(env, asyncContext->deferred, error);
507                 } else {
508                     napi_value callback = nullptr;
509                     napi_get_reference_value(env, asyncContext->callbackRef, &callback);
510                     napi_call_function(env, nullptr, callback, 1, &error, &ret);
511                     napi_delete_reference(env, asyncContext->callbackRef);
512                 }
513                 napi_delete_async_work(env, asyncContext->work);
514                 delete asyncContext;
515                 napi_close_handle_scope(env, scope);
516             };
517             auto delegate = EngineHelper::GetCurrentDelegate();
518             std::string uriString = asyncContext->uriString;
519             std::string paramsString = asyncContext->paramsString;
520             if (delegate) {
521                 if (asyncContext->isModeType) {
522                     uint32_t mode = asyncContext->mode;
523                     delegate->ReplaceWithCallback(uriString, paramsString, errorCallback, mode);
524                 } else {
525                     delegate->ReplaceWithCallback(uriString, paramsString, errorCallback);
526                 }
527             } else {
528                 LOGE("delegate is null");
529                 napi_value code = nullptr;
530                 std::string strCode = std::to_string(Framework::ERROR_CODE_INTERNAL_ERROR);
531                 napi_create_string_utf8(env, strCode.c_str(), strCode.length(), &code);
532                 napi_value msg = nullptr;
533                 std::string strMsg =
534                     ErrorToMessage(Framework::ERROR_CODE_INTERNAL_ERROR) + "UI execution context not found.";
535                 napi_create_string_utf8(env, strMsg.c_str(), strMsg.length(), &msg);
536                 napi_value error = nullptr;
537                 napi_create_error(env, code, msg, &error);
538 
539                 if (asyncContext->deferred) {
540                     napi_reject_deferred(env, asyncContext->deferred, error);
541                 } else {
542                     napi_value ret1 = nullptr;
543                     napi_value callback = nullptr;
544                     napi_get_reference_value(env, asyncContext->callbackRef, &callback);
545                     napi_call_function(env, nullptr, callback, 1, &error, &ret1);
546                     napi_delete_reference(env, asyncContext->callbackRef);
547                 }
548                 napi_delete_async_work(env, asyncContext->work);
549                 delete asyncContext;
550             }
551             napi_close_handle_scope(env, scope);
552         },
553         (void*)asyncContext, &asyncContext->work);
554     napi_queue_async_work(env, asyncContext->work);
555 
556     napi_value newResult = nullptr;
557     napi_escape_handle(env, scope, result, &newResult);
558     napi_close_escapable_handle_scope(env, scope);
559     return newResult;
560 }
561 
JSRouterBack(napi_env env,napi_callback_info info)562 static napi_value JSRouterBack(napi_env env, napi_callback_info info)
563 {
564     size_t argc = 1;
565     napi_value argv = nullptr;
566     napi_value thisVar = nullptr;
567     void* data = nullptr;
568     napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
569 
570     auto delegate = EngineHelper::GetCurrentDelegate();
571     if (!delegate) {
572         LOGE("can not get delegate.");
573         NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
574         return nullptr;
575     }
576     std::string uriString = "";
577     std::string paramsString = "";
578     napi_value uriNApi = nullptr;
579     napi_value params = nullptr;
580     napi_valuetype valueType = napi_undefined;
581     napi_typeof(env, argv, &valueType);
582     if (valueType == napi_object) {
583         napi_get_named_property(env, argv, "url", &uriNApi);
584         napi_typeof(env, uriNApi, &valueType);
585         if (valueType == napi_undefined) {
586             napi_get_named_property(env, argv, "path", &uriNApi);
587             napi_typeof(env, uriNApi, &valueType);
588         }
589         if (valueType == napi_string) {
590             ParseUri(env, uriNApi, uriString);
591         } else {
592             LOGW("the url and path is all invalid");
593         }
594 
595         napi_get_named_property(env, argv, "params", &params);
596         napi_typeof(env, params, &valueType);
597         if (valueType == napi_object) {
598             ParseParams(env, params, paramsString);
599         } else {
600             LOGW("The parameter type is incorrect.");
601         }
602     }
603     delegate->Back(uriString, paramsString);
604     return nullptr;
605 }
606 
JSRouterClear(napi_env env,napi_callback_info info)607 static napi_value JSRouterClear(napi_env env, napi_callback_info info)
608 {
609     auto delegate = EngineHelper::GetCurrentDelegate();
610     if (!delegate) {
611         LOGE("can not get delegate.");
612         NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
613         return nullptr;
614     }
615     delegate->Clear();
616     return nullptr;
617 }
618 
JSRouterGetLength(napi_env env,napi_callback_info info)619 static napi_value JSRouterGetLength(napi_env env, napi_callback_info info)
620 {
621     auto delegate = EngineHelper::GetCurrentDelegate();
622     if (!delegate) {
623         LOGE("can not get delegate.");
624         NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
625         return nullptr;
626     }
627     int32_t routeNumber = delegate->GetStackSize();
628     napi_value routeNApiNum = nullptr;
629     napi_create_int32(env, routeNumber, &routeNApiNum);
630     napi_value result = nullptr;
631     napi_coerce_to_string(env, routeNApiNum, &result);
632     return result;
633 }
634 
JSRouterGetState(napi_env env,napi_callback_info info)635 static napi_value JSRouterGetState(napi_env env, napi_callback_info info)
636 {
637     int32_t routeIndex = 0;
638     std::string routeName;
639     std::string routePath;
640     auto delegate = EngineHelper::GetCurrentDelegate();
641     if (!delegate) {
642         LOGE("can not get delegate.");
643         NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
644         return nullptr;
645     }
646     delegate->GetState(routeIndex, routeName, routePath);
647     size_t routeNameLen = routeName.length();
648     size_t routePathLen = routePath.length();
649 
650     napi_value resultArray[3] = { 0 };
651     napi_create_int32(env, routeIndex, &resultArray[0]);
652     napi_create_string_utf8(env, routeName.c_str(), routeNameLen, &resultArray[1]);
653     napi_create_string_utf8(env, routePath.c_str(), routePathLen, &resultArray[2]);
654 
655     napi_value result = nullptr;
656     napi_create_object(env, &result);
657     napi_set_named_property(env, result, "index", resultArray[0]);
658     napi_set_named_property(env, result, "name", resultArray[1]);
659     napi_set_named_property(env, result, "path", resultArray[2]);
660     return result;
661 }
662 
CallBackToJSTread(RouterAsyncContext * context)663 void CallBackToJSTread(RouterAsyncContext* context)
664 {
665     uv_loop_s* loop = nullptr;
666     napi_get_uv_event_loop(context->env, &loop);
667 
668     uv_work_t* work = new uv_work_t;
669     work->data = (void*)context;
670 
671     uv_queue_work(
672         loop, work, [](uv_work_t* work) {},
673         [](uv_work_t* work, int status) {
674             RouterAsyncContext* context = (RouterAsyncContext*)work->data;
675             napi_handle_scope scope = nullptr;
676             napi_open_handle_scope(context->env, &scope);
677             if (scope == nullptr) {
678                 return;
679             }
680 
681             napi_value result = nullptr;
682             napi_value callback = nullptr;
683             napi_value ret = nullptr;
684             if (Framework::AlertState(context->callbackType) == Framework::AlertState::USER_CONFIRM) {
685                 if (context->callbackSuccess) {
686                     napi_create_string_utf8(context->env, EN_ALERT_APPROVE, NAPI_AUTO_LENGTH, &result);
687                     napi_value argv[1] = { result };
688                     napi_get_reference_value(context->env, context->callbackSuccess, &callback);
689                     napi_call_function(context->env, nullptr, callback, 1, argv, &ret);
690                 }
691                 if (context->callbackComplete) {
692                     napi_get_reference_value(context->env, context->callbackComplete, &callback);
693                     napi_call_function(context->env, nullptr, callback, 0, nullptr, &ret);
694                 }
695             }
696             if (Framework::AlertState(context->callbackType) == Framework::AlertState::USER_CANCEL) {
697                 if (context->callbackFail) {
698                     napi_create_string_utf8(context->env, EN_ALERT_REJECT, NAPI_AUTO_LENGTH, &result);
699                     napi_value argv[1] = { result };
700                     napi_get_reference_value(context->env, context->callbackFail, &callback);
701                     napi_call_function(context->env, nullptr, callback, 1, argv, &ret);
702                 }
703                 if (context->callbackComplete) {
704                     napi_get_reference_value(context->env, context->callbackComplete, &callback);
705                     napi_call_function(context->env, nullptr, callback, 0, nullptr, &ret);
706                 }
707             }
708 
709             napi_close_handle_scope(context->env, scope);
710 
711             if (work != nullptr) {
712                 delete work;
713             }
714         });
715 }
716 
JSRouterEnableAlertBeforeBackPage(napi_env env,napi_callback_info info)717 static napi_value JSRouterEnableAlertBeforeBackPage(napi_env env, napi_callback_info info)
718 {
719     size_t argc = 1;
720     napi_value argv = nullptr;
721     napi_value thisVar = nullptr;
722     void* data = nullptr;
723     napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
724 
725     napi_valuetype valueType = napi_undefined;
726     napi_typeof(env, argv, &valueType);
727     if (valueType != napi_object) {
728         LOGW("EnableAlertBeforeBackPage: params is null");
729         NapiThrow(env, "The type of the parameter is not object.", Framework::ERROR_CODE_PARAM_INVALID);
730         return nullptr;
731     }
732 
733     napi_value messageNapi = nullptr;
734     std::unique_ptr<char[]> messageChar;
735     napi_get_named_property(env, argv, "message", &messageNapi);
736     napi_typeof(env, messageNapi, &valueType);
737     if (valueType == napi_string) {
738         size_t length = 0;
739         napi_get_value_string_utf8(env, messageNapi, nullptr, 0, &length);
740         messageChar = std::make_unique<char[]>(length + 1);
741         napi_get_value_string_utf8(env, messageNapi, messageChar.get(), length + 1, &length);
742     } else {
743         LOGW("EnableAlertBeforeBackPage: message is null");
744         NapiThrow(env, "The type of the message is not string.", Framework::ERROR_CODE_PARAM_INVALID);
745         return nullptr;
746     }
747 
748     auto delegate = EngineHelper::GetCurrentDelegate();
749     if (!delegate) {
750         LOGW("EnableAlertBeforeBackPage: delegate is null");
751         NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
752         return nullptr;
753     }
754 
755     auto routerAsyncContext = new RouterAsyncContext();
756     routerAsyncContext->env = env;
757     napi_value successFunc = nullptr;
758     napi_value failFunc = nullptr;
759     napi_value completeFunc = nullptr;
760     napi_get_named_property(env, argv, "success", &successFunc);
761     napi_get_named_property(env, argv, "cancel", &failFunc);
762     napi_get_named_property(env, argv, "complete", &completeFunc);
763     napi_typeof(env, successFunc, &valueType);
764     if (valueType == napi_function) {
765         napi_create_reference(env, successFunc, 1, &routerAsyncContext->callbackSuccess);
766     }
767 
768     napi_typeof(env, failFunc, &valueType);
769     if (valueType == napi_function) {
770         napi_create_reference(env, failFunc, 1, &routerAsyncContext->callbackFail);
771     }
772     napi_typeof(env, completeFunc, &valueType);
773     if (valueType == napi_function) {
774         napi_create_reference(env, completeFunc, 1, &routerAsyncContext->callbackComplete);
775     }
776 
777     auto dilogCallback = [routerAsyncContext](int32_t callbackType) {
778         LOGI("callback after dialog click, callbackType = %{public}d", callbackType);
779         if (routerAsyncContext && Framework::AlertState(callbackType) == Framework::AlertState::RECOVERY) {
780             delete routerAsyncContext;
781             return;
782         }
783         if (routerAsyncContext) {
784             routerAsyncContext->callbackType = callbackType;
785         }
786         CallBackToJSTread(routerAsyncContext);
787     };
788     delegate->EnableAlertBeforeBackPage(messageChar.get(), std::move(dilogCallback));
789 
790     return nullptr;
791 }
792 
JSRouterDisableAlertBeforeBackPage(napi_env env,napi_callback_info info)793 static napi_value JSRouterDisableAlertBeforeBackPage(napi_env env, napi_callback_info info)
794 {
795     auto delegate = EngineHelper::GetCurrentDelegate();
796     if (delegate) {
797         delegate->DisableAlertBeforeBackPage();
798     } else {
799         LOGW("DisableAlertBeforeBackPage: delegate is null");
800         NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
801         return nullptr;
802     }
803 
804     size_t argc = 1;
805     napi_value argv = nullptr;
806     napi_value thisVar = nullptr;
807     void* data = nullptr;
808     napi_get_cb_info(env, info, &argc, &argv, &thisVar, &data);
809     napi_valuetype valueType = napi_undefined;
810     napi_typeof(env, argv, &valueType);
811     if (valueType == napi_object) {
812         napi_value successFunc = nullptr;
813         napi_value completeFunc = nullptr;
814         napi_get_named_property(env, argv, "success", &successFunc);
815         napi_get_named_property(env, argv, "complete", &completeFunc);
816 
817         napi_value result = nullptr;
818         napi_value ret = nullptr;
819         napi_create_string_utf8(env, DIS_ALERT_SUCCESS, NAPI_AUTO_LENGTH, &result);
820         napi_value argv[1] = { result };
821 
822         napi_typeof(env, successFunc, &valueType);
823         if (valueType == napi_function) {
824             napi_call_function(env, nullptr, successFunc, 1, argv, &ret);
825         }
826         napi_typeof(env, completeFunc, &valueType);
827         if (valueType == napi_function) {
828             napi_call_function(env, nullptr, completeFunc, 1, argv, &ret);
829         }
830     }
831     return nullptr;
832 }
833 
JSRouterGetParams(napi_env env,napi_callback_info info)834 static napi_value JSRouterGetParams(napi_env env, napi_callback_info info)
835 {
836     auto delegate = EngineHelper::GetCurrentDelegate();
837     if (!delegate) {
838         LOGE("can not get delegate.");
839         NapiThrow(env, "UI execution context not found.", Framework::ERROR_CODE_INTERNAL_ERROR);
840         return nullptr;
841     }
842     std::string paramsStr = delegate->GetParams();
843     if (paramsStr.empty()) {
844         LOGI("PageGetParams params is null");
845         return nullptr;
846     }
847     napi_value globalValue;
848     napi_get_global(env, &globalValue);
849     napi_value jsonValue;
850     napi_get_named_property(env, globalValue, "JSON", &jsonValue);
851     napi_value parseValue;
852     napi_get_named_property(env, jsonValue, "parse", &parseValue);
853     napi_value routerParamsNApi;
854     napi_create_string_utf8(env, paramsStr.c_str(), NAPI_AUTO_LENGTH, &routerParamsNApi);
855     napi_value funcArgv[1] = { routerParamsNApi };
856     napi_value result;
857     napi_call_function(env, jsonValue, parseValue, 1, funcArgv, &result);
858     napi_valuetype valueType = napi_undefined;
859     napi_typeof(env, result, &valueType);
860     if (valueType != napi_object) {
861         LOGE("parse result fail");
862         return nullptr;
863     }
864     return result;
865 }
866 
RouterExport(napi_env env,napi_value exports)867 static napi_value RouterExport(napi_env env, napi_value exports)
868 {
869     napi_value routerMode = nullptr;
870     napi_create_object(env, &routerMode);
871     napi_value prop = nullptr;
872     napi_create_uint32(env, STANDARD, &prop);
873     napi_set_named_property(env, routerMode, "Standard", prop);
874     napi_create_uint32(env, SINGLE, &prop);
875     napi_set_named_property(env, routerMode, "Single", prop);
876 
877     napi_property_descriptor routerDesc[] = {
878         DECLARE_NAPI_FUNCTION("push", JSRouterPush),
879         DECLARE_NAPI_FUNCTION("pushUrl", JSRouterPushWithCallback),
880         DECLARE_NAPI_FUNCTION("replace", JSRouterReplace),
881         DECLARE_NAPI_FUNCTION("replaceUrl", JSRouterReplaceWithCallback),
882         DECLARE_NAPI_FUNCTION("back", JSRouterBack),
883         DECLARE_NAPI_FUNCTION("clear", JSRouterClear),
884         DECLARE_NAPI_FUNCTION("getLength", JSRouterGetLength),
885         DECLARE_NAPI_FUNCTION("getState", JSRouterGetState),
886         DECLARE_NAPI_FUNCTION("enableAlertBeforeBackPage", JSRouterEnableAlertBeforeBackPage),
887         DECLARE_NAPI_FUNCTION("enableBackPageAlert", JSRouterEnableAlertBeforeBackPage),
888         DECLARE_NAPI_FUNCTION("showAlertBeforeBackPage", JSRouterEnableAlertBeforeBackPage),
889         DECLARE_NAPI_FUNCTION("disableAlertBeforeBackPage", JSRouterDisableAlertBeforeBackPage),
890         DECLARE_NAPI_FUNCTION("hideAlertBeforeBackPage", JSRouterDisableAlertBeforeBackPage),
891         DECLARE_NAPI_FUNCTION("getParams", JSRouterGetParams),
892         DECLARE_NAPI_PROPERTY("RouterMode", routerMode),
893     };
894     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(routerDesc) / sizeof(routerDesc[0]), routerDesc));
895 
896     return exports;
897 }
898 
899 static napi_module routerModule = {
900     .nm_version = 1,
901     .nm_flags = 0,
902     .nm_filename = nullptr,
903     .nm_register_func = RouterExport,
904     .nm_modname = "router",
905     .nm_priv = ((void*)0),
906     .reserved = { 0 },
907 };
908 
RouterRegister()909 extern "C" __attribute__((constructor)) void RouterRegister()
910 {
911     napi_module_register(&routerModule);
912 }
913 
914 } // namespace OHOS::Ace::Napi
915