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