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