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 #ifndef NAPI_ASYNC_WORK_H
16 #define NAPI_ASYNC_WORK_H
17 
18 #include <functional>
19 #include <memory>
20 #include <string>
21 #include <uv.h>
22 
23 #include "napi/native_api.h"
24 #include "napi/native_common.h"
25 #include "napi/native_node_api.h"
26 #include "napi_param_utils.h"
27 
28 namespace OHOS {
29 namespace DrmStandard {
30 using NapiCbInfoParser = std::function<void(size_t argc, napi_value *argv)>;
31 using NapiAsyncExecute = std::function<void(void)>;
32 using NapiAsyncComplete = std::function<void(napi_value&)>;
33 
34 struct ContextBase {
35     virtual ~ContextBase();
36     void GetCbInfo(napi_env env, napi_callback_info info, NapiCbInfoParser parse = NapiCbInfoParser(),
37         bool sync = false);
38     void SignError(int32_t code);
39     napi_env env = nullptr;
40     napi_value output = nullptr;
41     napi_status status = napi_invalid_arg;
42     std::string errMessage;
43     int32_t errCode;
44     napi_value self = nullptr;
45     void* native = nullptr;
46     std::string taskName;
47 
48 private:
49     napi_deferred deferred = nullptr;
50     napi_async_work work = nullptr;
51     napi_ref callbackRef = nullptr;
52     napi_ref selfRef = nullptr;
53 
54     NapiAsyncExecute execute = nullptr;
55     NapiAsyncComplete complete = nullptr;
56     std::shared_ptr<ContextBase> hold; /* cross thread data */
57 
58     static constexpr size_t ARGC_MAX = 6;
59 
60     friend class NapiAsyncWork;
61 };
62 
63 struct NapiWorkData {
64     napi_env env_;
65     napi_ref cb_;
66 };
67 
68 struct AutoRef {
AutoRefAutoRef69     AutoRef(napi_env env, napi_ref cb)
70         : env_(env), cb_(cb)
71     {
72     }
~AutoRefAutoRef73     ~AutoRef()
74     {
75         uv_loop_s *loop = nullptr;
76         napi_get_uv_event_loop(env_, &loop);
77         if (loop == nullptr) {
78             return;
79         }
80 
81         NapiWorkData *workData = new (std::nothrow) NapiWorkData();
82         if (workData == nullptr) {
83             return;
84         }
85         workData->env_ = env_;
86         workData->cb_ = cb_;
87 
88         uv_work_t *work = new(std::nothrow) uv_work_t;
89         if (work == nullptr) {
90             delete workData;
91             workData = nullptr;
92             return;
93         }
94         work->data = (void *)workData;
95 
96         int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
97             // Js thread
98             NapiWorkData *workData = reinterpret_cast<NapiWorkData *>(work->data);
99             napi_env env = workData->env_;
100             napi_ref cb = workData->cb_;
101             if (env != nullptr && cb != nullptr) {
102                 (void)napi_delete_reference(env, cb);
103             }
104             delete workData;
105             delete work;
106         }, uv_qos_default);
107         if (ret != 0) {
108             delete work;
109             work = nullptr;
110             delete workData;
111             workData = nullptr;
112         }
113     }
114     napi_env env_;
115     napi_ref cb_;
116 };
117 
118 class NapiAsyncWork {
119 public:
120     static napi_value Enqueue(napi_env env, std::shared_ptr<ContextBase> ctxt, const std::string &name,
121         NapiAsyncExecute execute = NapiAsyncExecute(),
122         NapiAsyncComplete complete = NapiAsyncComplete());
123 
124 private:
125     enum {
126         /* AsyncCallback / Promise output result index  */
127         RESULT_ERROR = 0,
128         RESULT_DATA = 1,
129         RESULT_ALL = 2
130     };
131     static void CommonCallbackRoutine(ContextBase *ctxt);
132 };
133 } // namespace DrmStandard
134 } // namespace OHOS
135 #endif // NAPI_ASYNC_WORK_H