• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #ifndef NAPI_BASE_H
17 #define NAPI_BASE_H
18 
19 #include <memory>
20 
21 #include "napi_common_utils.h"
22 #include "napi/native_api.h"
23 #include "napi/native_common.h"
24 
25 namespace OHOS::UpdateEngine {
26 template <typename T> class NapiBase {
27 #define GET_PARAMS(env, info, num)    \
28     size_t argc = num;                \
29     napi_value args[num] = {nullptr}; \
30     napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)
31 
32 public:
33     NapiBase() = default;
34     ~NapiBase() = default;
35 
HandleFunc(napi_env env,napi_callback_info info,std::unique_ptr<T> & clientContext)36     static napi_value HandleFunc(napi_env env, napi_callback_info info,
37         std::unique_ptr<T> &clientContext)
38     {
39         if (clientContext == nullptr) {
40             ENGINE_LOGI("HandleFunc clientContext is null");
41             return nullptr;
42         }
43         std::string method = clientContext->method_;
44         ENGINE_LOGI("HandleFunc method: %{public}s", method.c_str());
45         napi_value result = clientContext->getNapiParam_(env, info, clientContext);
46         if (result == nullptr) {
47             ENGINE_LOGE("HandleFunc GetMigrateStatusParam fail");
48             return nullptr;
49         }
50         if (!Execute(env, clientContext)) {
51             ENGINE_LOGE("HandleFunc Execute error");
52             return result;
53         }
54         ENGINE_LOGI("HandleFunc method: %{public}s complete", method.c_str());
55         return result;
56     }
57 
GetCallbackParam(napi_env env,uint32_t argNum,size_t argc,napi_value args[],std::unique_ptr<T> & clientContext)58     static napi_value GetCallbackParam(napi_env env, uint32_t argNum, size_t argc, napi_value args[],
59         std::unique_ptr<T> &clientContext)
60     {
61         // 接口调用返回值,非返回内容
62         napi_value result = nullptr;
63         if (argc >= argNum) {
64             PARAM_CHECK(argNum >= 1, return nullptr, "argNum is less than 1");
65             uint32_t callbackPosition = argNum - 1;
66             napi_valuetype callbackValueType;
67             napi_typeof(env, args[callbackPosition], &callbackValueType);
68             std::vector<std::pair<std::string, std::string>> paramInfos;
69             paramInfos.emplace_back("callback", "napi_function");
70             PARAM_CHECK(callbackValueType == napi_function, NapiCommonUtils::NapiThrowParamError(env, paramInfos);
71                return nullptr, "Failed to GetCallbackParam");
72             napi_create_reference(env, args[callbackPosition], 1, &clientContext->callbackRef_);
73             napi_get_undefined(env, &result); // 创建接口返回值对象
74         } else {
75             napi_create_promise(env, &clientContext->deferred_, &result);
76         }
77         return result;
78     }
79 
Execute(napi_env env,std::unique_ptr<T> & clientContext)80     static bool Execute(napi_env env, std::unique_ptr<T> &clientContext)
81     {
82         napi_value workName;
83         napi_create_string_utf8(env, clientContext->method_.c_str(), NAPI_AUTO_LENGTH, &workName);
84         if (napi_create_async_work(env, nullptr, workName, clientContext->executeFunc_, NapiBase::Complete,
85                                    static_cast<void *>(clientContext.get()), &clientContext->work_) != napi_ok) {
86             ENGINE_LOGE("Failed to create async work for %{public}s", clientContext->method_.c_str());
87             return false;
88         }
89         if (napi_queue_async_work_with_qos(env, clientContext->work_, napi_qos_default) != napi_ok) {
90             ENGINE_LOGE("Failed to queue async work for %{public}s", clientContext->method_.c_str());
91             return false;
92         }
93         ENGINE_LOGI("Execute finish");
94         clientContext.release(); // unique_ptr release之后,释放指针的控制权,后续由complete里面释放指针内容
95         return true;
96     }
97 
Complete(napi_env env,napi_status status,void * data)98     static void Complete(napi_env env, napi_status status, void *data)
99     {
100         if (data == nullptr) {
101             ENGINE_LOGE("Complete, data is null");
102             return;
103         }
104         constexpr size_t resultLen = 2;
105         T *clientContext = static_cast<T *>(data);
106         if (clientContext == nullptr) {
107             ENGINE_LOGE("Complete clientContext is null");
108             return;
109         }
110 
111         napi_value finalResult = nullptr;
112         if (clientContext->createValueFunc_ != nullptr) {
113             // 执行结果转换函数
114             finalResult = clientContext->createValueFunc_(env, *clientContext);
115         }
116 
117         if (clientContext->ipcRequestCode_ != 0) {
118             // ipc失败,获取失败原因
119             clientContext->getIpcBusinessError_(clientContext->method_, clientContext->ipcRequestCode_,
120                 clientContext->businessError_);
121         }
122 
123         napi_value result[resultLen] = { nullptr, nullptr };
124         bool isSuccess = BuildResult(env, clientContext, finalResult, result);
125         if (clientContext->deferred_) { // promise调用
126             ExecutePromiseFunc(env, clientContext, result, resultLen, isSuccess);
127         } else {
128             ExecuteCallbackFunc(env, clientContext, result, resultLen);
129         }
130         napi_delete_async_work(env, clientContext->work_);
131         delete clientContext; // Execute 中释放控制权的指针,在此处释放
132         clientContext = nullptr;
133     }
134 
ExecutePromiseFunc(napi_env env,T * clientContext,napi_value const * result,size_t len,bool isSuccess)135     static void ExecutePromiseFunc(napi_env env, T *clientContext, napi_value const * result, size_t len,
136         bool isSuccess)
137     {
138         constexpr size_t resultLength = 2;
139         if (len < resultLength) {
140             ENGINE_LOGE("length error:%{public}zu", len);
141             return;
142         }
143         napi_status callbackStatus = isSuccess ? napi_resolve_deferred(env, clientContext->deferred_, result[1]) :
144                                                  napi_reject_deferred(env, clientContext->deferred_, result[0]);
145         if (callbackStatus != napi_ok) {
146             ENGINE_LOGE("ExecutePromiseFunc error: %{public}d", callbackStatus);
147         }
148     }
149 
ExecuteCallbackFunc(napi_env env,T * clientContext,napi_value * result,size_t len)150     static void ExecuteCallbackFunc(napi_env env, T *clientContext, napi_value *result, size_t len)
151     {
152         napi_value callback = nullptr;
153         napi_status resultStatus = napi_get_reference_value(env, clientContext->callbackRef_, &callback);
154         if (resultStatus != napi_ok) {
155             ENGINE_LOGE("napi_get_reference_value failed result=%{public}d", resultStatus);
156             return;
157         }
158         napi_value userRet = nullptr;
159         resultStatus = napi_call_function(env, nullptr, callback, len, result, &userRet);
160         if (resultStatus != napi_ok) {
161             ENGINE_LOGE("napi_call_function failed result=%{public}d", resultStatus);
162             return;
163         }
164         resultStatus = napi_delete_reference(env, clientContext->callbackRef_);
165         if (resultStatus != napi_ok) {
166             ENGINE_LOGE("napi_delete_reference failed result=%{public}d", resultStatus);
167         }
168     }
169 
BuildResult(napi_env env,const T * clientContext,napi_value finalResult,napi_value * result)170     static bool BuildResult(napi_env env, const T *clientContext, napi_value finalResult, napi_value *result)
171     {
172         bool isSuccess = clientContext->businessError_.errorNum == CallResult::SUCCESS;
173         if (isSuccess) {
174             napi_get_undefined(env, &result[0]);
175             result[1] = finalResult;
176         } else {
177             NapiCommonUtils::BuildBusinessError(env, result[0], clientContext->businessError_);
178             napi_get_undefined(env, &result[1]);
179         }
180         return isSuccess;
181     }
182 };
183 } // namespace OHOS::UpdateEngine
184 #endif // NAPI_BASE_H