1 /*
2  * Copyright (c) 2023 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 BASE_ASYNC_SESSION_H
17 #define BASE_ASYNC_SESSION_H
18 
19 #include "napi/native_api.h"
20 #include "node_api.h"
21 
22 #include "napi_session.h"
23 
24 namespace OHOS::UpdateEngine {
25 constexpr int32_t RESULT_ARGC = 2;
26 
27 template <typename RESULT> class BaseAsyncSession : public NapiSession {
28 public:
29     BaseAsyncSession(BaseClient *client, SessionParams &sessionParams, size_t argc, size_t callbackNumber = 1)
30         : NapiSession(client, sessionParams, argc, callbackNumber)
31     {
32         callbackRef_.resize(callbackNumber);
33     }
34 
~BaseAsyncSession()35     ~BaseAsyncSession() override
36     {
37         callbackRef_.clear();
38     }
39 
StartWork(napi_env env,size_t startIndex,const napi_value * args)40     napi_value StartWork(napi_env env, size_t startIndex, const napi_value *args) override
41     {
42         ENGINE_LOGI("BaseAsyncSession::StartWork startIndex: %{public}zu totalArgc_ %{public}zu "
43             "callbackNumber_: %{public}zu",
44             startIndex, totalArgc_, callbackNumber_);
45         PARAM_CHECK_NAPI_CALL(env, args != nullptr && totalArgc_ >= startIndex, return nullptr, "Invalid para");
46         napi_value workName = CreateWorkerName(env);
47         PARAM_CHECK_NAPI_CALL(env, workName != nullptr, return nullptr, "Failed to worker name");
48 
49         // Check whether a callback exists. Only one callback is allowed.
50         for (size_t i = 0; (i < (totalArgc_ - startIndex)) && (i < callbackNumber_); i++) {
51             ENGINE_LOGI("CreateReference index:%u", static_cast<unsigned int>(i + startIndex));
52             ClientStatus ret = NapiCommonUtils::IsTypeOf(env, args[i + startIndex], napi_function);
53             std::vector<std::pair<std::string, std::string>> paramInfos;
54             paramInfos.emplace_back("callback", "napi_function");
55             PARAM_CHECK_NAPI_CALL(env, ret == ClientStatus::CLIENT_SUCCESS,
56                 NapiCommonUtils::NapiThrowParamError(env, paramInfos);
57                 return nullptr, "invalid type");
58             ret = NapiCommonUtils::CreateReference(env, args[i + startIndex], 1, callbackRef_[i]);
59             PARAM_CHECK_NAPI_CALL(env, ret == ClientStatus::CLIENT_SUCCESS, return nullptr,
60                 "Failed to create reference");
61         }
62 
63         napi_status status = napi_ok;
64         // Create an asynchronous call.
65         status = napi_create_async_work(env, nullptr, workName, NapiSession::ExecuteWork, NapiSession::CompleteWork,
66             this, &(worker_));
67 
68         PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to create worker");
69 
70         // Put the thread in the task execution queue.
71         status = napi_queue_async_work_with_qos(env, worker_, napi_qos_default);
72         PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to queue worker");
73         napi_value result;
74         napi_create_int32(env, 0, &result);
75         return result;
76     }
77 
NotifyJS(napi_env env,napi_value thisVar,const RESULT & result)78     void NotifyJS(napi_env env, napi_value thisVar, const RESULT &result)
79     {
80         ENGINE_LOGI("BaseAsyncSession::NotifyJS callbackNumber_: %{public}d", static_cast<int32_t>(callbackNumber_));
81         napi_value callback;
82         napi_value undefined;
83         napi_value callResult;
84         napi_get_undefined(env, &undefined);
85         napi_value retArgs[RESULT_ARGC] = { 0 };
86 
87         BusinessError businessError;
88         GetBusinessError(businessError, result);
89         uint32_t ret;
90         if (businessError.errorNum != CallResult::SUCCESS) {
91             ENGINE_LOGI("BaseAsyncSession::NotifyJS error exist");
92             ret = static_cast<uint32_t>(NapiCommonUtils::BuildBusinessError(env, retArgs[0], businessError));
93         } else {
94             ret = static_cast<uint32_t>(result.buildJSObject(env, retArgs[1], result));
95         }
96         PARAM_CHECK_NAPI_CALL(env, ret == napi_ok, return, "Failed to build json");
97 
98         napi_status retStatus = napi_get_reference_value(env, callbackRef_[0], &callback);
99         PARAM_CHECK_NAPI_CALL(env, retStatus == napi_ok, return, "Failed to get reference");
100         const int callBackNumber = 2;
101         retStatus = napi_call_function(env, undefined, callback, callBackNumber, retArgs, &callResult);
102         PARAM_CHECK_NAPI_CALL(env, retStatus == napi_ok, return, "Failed to call function");
103         // Release resources.
104         for (size_t i = 0; i < callbackNumber_; i++) {
105             napi_delete_reference(env, callbackRef_[i]);
106             callbackRef_[i] = nullptr;
107         }
108         napi_delete_async_work(env, worker_);
109         worker_ = nullptr;
110     }
111 
CompleteWork(napi_env env,napi_status status)112     virtual void CompleteWork(napi_env env, napi_status status) override{};
113 
114 protected:
115     napi_async_work worker_ = nullptr;
116     std::vector<napi_ref> callbackRef_ = { 0 };
117 };
118 } // namespace OHOS::UpdateEngine
119 #endif // BASE_ASYNC_SESSION_H