1 /*
2  * Copyright (c) 2023-2024 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 "js_insight_intent_driver.h"
17 
18 #include "ability_business_error.h"
19 #include "ability_manager_client.h"
20 #include "event_handler.h"
21 #include "event_runner.h"
22 #include "hilog_tag_wrapper.h"
23 #include "insight_intent_callback_interface.h"
24 #include "insight_intent_host_client.h"
25 #include "insight_intent_execute_result.h"
26 #include "js_error_utils.h"
27 #include "js_insight_intent_driver_utils.h"
28 #include "js_runtime_utils.h"
29 #include "napi_common_execute_param.h"
30 #include "napi_common_util.h"
31 #include "native_engine/native_value.h"
32 
33 #include <mutex>
34 
35 namespace OHOS {
36 namespace AbilityRuntime {
37 using namespace OHOS::AppExecFwk;
38 namespace {
39 constexpr int32_t INDEX_ZERO = 0;
40 constexpr int32_t INDEX_ONE = 1;
41 constexpr size_t ARGC_ONE = 1;
42 }
43 class JsInsightIntentExecuteCallbackClient : public InsightIntentExecuteCallbackInterface,
44     public std::enable_shared_from_this<JsInsightIntentExecuteCallbackClient> {
45 public:
JsInsightIntentExecuteCallbackClient(napi_env env,napi_deferred nativeDeferred,napi_ref callbackRef)46     JsInsightIntentExecuteCallbackClient(napi_env env, napi_deferred nativeDeferred, napi_ref callbackRef)
47         : env_(env), nativeDeferred_(nativeDeferred), callbackRef_(callbackRef) {}
48 
49     virtual ~JsInsightIntentExecuteCallbackClient() = default;
50 
ProcessInsightIntentExecute(int32_t resultCode,AppExecFwk::InsightIntentExecuteResult executeResult)51     void ProcessInsightIntentExecute(int32_t resultCode,
52         AppExecFwk::InsightIntentExecuteResult executeResult) override
53     {
54         NapiAsyncTask::CompleteCallback complete = [resultCode = resultCode, executeResult = executeResult]
55             (napi_env env, NapiAsyncTask &task, int32_t status) {
56             if (resultCode != 0) {
57                 task.Reject(env, CreateJsError(env, GetJsErrorCodeByNativeError(resultCode)));
58             } else {
59                 task.ResolveWithNoError(env, CreateJsExecuteResult(env, executeResult));
60             }
61         };
62         std::unique_ptr<NapiAsyncTask> asyncTask = nullptr;
63         if (nativeDeferred_) {
64             asyncTask = std::make_unique<NapiAsyncTask>(nativeDeferred_, nullptr,
65                 std::make_unique<NapiAsyncTask::CompleteCallback>(std::move(complete)));
66         } else {
67             asyncTask = std::make_unique<NapiAsyncTask>(callbackRef_, nullptr,
68                 std::make_unique<NapiAsyncTask::CompleteCallback>(std::move(complete)));
69         }
70         NapiAsyncTask::Schedule("JsInsightIntentDriver::OnExecute", env_, std::move(asyncTask));
71     }
72 private:
73     napi_env env_;
74     napi_deferred nativeDeferred_ = nullptr;
75     napi_ref callbackRef_ = nullptr;
76 };
77 
78 class JsInsightIntentDriver {
79 public:
80     JsInsightIntentDriver() = default;
81     ~JsInsightIntentDriver() = default;
82 
Finalizer(napi_env env,void * data,void * hint)83     static void Finalizer(napi_env env, void *data, void *hint)
84     {
85         TAG_LOGI(AAFwkTag::INTENT, "called");
86         std::unique_ptr<JsInsightIntentDriver>(static_cast<JsInsightIntentDriver*>(data));
87     }
88 
Execute(napi_env env,napi_callback_info info)89     static napi_value Execute(napi_env env, napi_callback_info info)
90     {
91         GET_NAPI_INFO_AND_CALL(env, info, JsInsightIntentDriver, OnExecute);
92     }
93 
94 private:
OnExecute(napi_env env,NapiCallbackInfo & info)95     napi_value OnExecute(napi_env env, NapiCallbackInfo& info)
96     {
97         TAG_LOGD(AAFwkTag::INTENT, "called");
98         if (info.argc < ARGC_ONE) {
99             TAG_LOGE(AAFwkTag::INTENT, "invalid argc");
100             ThrowTooFewParametersError(env);
101             return CreateJsUndefined(env);
102         }
103 
104         InsightIntentExecuteParam param;
105         if (!UnwrapExecuteParam(env, info.argv[INDEX_ZERO], param)) {
106             TAG_LOGE(AAFwkTag::INTENT, "CheckOnOffType, Parse on off type failed");
107             ThrowInvalidParamError(env, "Parameter error: Parse param failed, param must be a ExecuteParam.");
108             return CreateJsUndefined(env);
109         }
110 
111         napi_value lastParam = (info.argc == 1) ? nullptr : info.argv[INDEX_ONE];
112         napi_valuetype type = napi_undefined;
113         napi_typeof(env, lastParam, &type);
114 
115         napi_value result = nullptr;
116         napi_deferred nativeDeferred = nullptr;
117         napi_ref callbackRef = nullptr;
118         std::unique_ptr<NapiAsyncTask> asyncTask = nullptr;
119         if (lastParam == nullptr || type != napi_function) {
120             napi_create_promise(env, &nativeDeferred, &result);
121             asyncTask = std::make_unique<NapiAsyncTask>(nativeDeferred, nullptr, nullptr);
122         } else {
123             napi_get_undefined(env, &result);
124             napi_create_reference(env, lastParam, 1, &callbackRef);
125             asyncTask = std::make_unique<NapiAsyncTask>(callbackRef, nullptr, nullptr);
126         }
127 
128         if (asyncTask == nullptr) {
129             TAG_LOGE(AAFwkTag::INTENT, "asyncTask is nullptr");
130             return CreateJsUndefined(env);
131         }
132         auto client = std::make_shared<JsInsightIntentExecuteCallbackClient>(env, nativeDeferred, callbackRef);
133         uint64_t key = InsightIntentHostClient::GetInstance()->AddInsightIntentExecute(client);
134         auto err = AbilityManagerClient::GetInstance()->ExecuteIntent(key,
135             InsightIntentHostClient::GetInstance(), param);
136         if (err != 0) {
137             asyncTask->Reject(env, CreateJsError(env, GetJsErrorCodeByNativeError(err)));
138             InsightIntentHostClient::GetInstance()->RemoveInsightIntentExecute(key);
139         }
140         return result;
141     }
142 };
143 
JsInsightIntentDriverInit(napi_env env,napi_value exportObj)144 napi_value JsInsightIntentDriverInit(napi_env env, napi_value exportObj)
145 {
146     TAG_LOGD(AAFwkTag::INTENT, "called");
147     if (env == nullptr || exportObj == nullptr) {
148         TAG_LOGE(AAFwkTag::INTENT, "Invalid input parameters");
149         return nullptr;
150     }
151 
152     std::unique_ptr<JsInsightIntentDriver> jsIntentDriver = std::make_unique<JsInsightIntentDriver>();
153     napi_wrap(env, exportObj, jsIntentDriver.release(), JsInsightIntentDriver::Finalizer, nullptr, nullptr);
154 
155     const char *moduleName = "JsInsightIntentDriver";
156     BindNativeFunction(env, exportObj, "execute", moduleName, JsInsightIntentDriver::Execute);
157     return CreateJsUndefined(env);
158 }
159 } // namespace AbilityRuntime
160 } // namespace OHOS
161