• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 PREFERENCES_JSKIT_NAPI_ASYNC_PROXY_H
16 #define PREFERENCES_JSKIT_NAPI_ASYNC_PROXY_H
17 #include <vector>
18 
19 #include "napi/native_api.h"
20 #include "napi/native_common.h"
21 #include "napi/native_node_api.h"
22 #include "securec.h"
23 
24 namespace OHOS {
25 namespace AppDataMgrJsKit {
26 constexpr int MAX_INPUT_COUNT = 10;
27 constexpr int OK = 0;
28 constexpr int ERR = -1;
29 
30 // T inherits AysncContext
31 template<class T> class NapiAsyncProxy {
32 public:
33     constexpr static int RESULT_COUNT = 2;
34     using InputParser = void (*)(const napi_env &, const napi_value &, T *);
35     using NapiAsyncExecute = int (*)(T *);
36     using NapiAsyncComplete = int (*)(T *, napi_value &);
37 
38     // AsyncContext base
39     struct AysncContext {
AysncContextAysncContext40         AysncContext()
41         {
42         }
~AysncContextAysncContext43         virtual ~AysncContext()
44         {
45             if (env == nullptr) {
46                 return;
47             }
48             napi_delete_async_work(env, work);
49             napi_delete_reference(env, callbackRef);
50         }
51         napi_env env = nullptr;
52         napi_callback_info info = nullptr;
53         napi_async_work work = nullptr;
54         napi_deferred deferred = nullptr;
55         napi_ref callbackRef = nullptr;
56         NapiAsyncExecute execFunc = nullptr;
57         int execStatus = ERR;
58         NapiAsyncComplete completeFunc = nullptr;
59         void *boundObj = nullptr;
60     };
61 
62 public:
Init(napi_env env,napi_callback_info info)63     void Init(napi_env env, napi_callback_info info)
64     {
65         asyncContext = new T();
66         if (asyncContext == nullptr) {
67             return;
68         }
69         asyncContext->env = env;
70         asyncContext->info = info;
71     }
72 
~NapiAsyncProxy()73     ~NapiAsyncProxy()
74     {
75         if (asyncContext == nullptr) {
76             return;
77         }
78 
79         delete asyncContext;
80         asyncContext = nullptr;
81     }
82 
DefParserThis(const napi_env & env,const napi_value & self,T * context)83     static void DefParserThis(const napi_env &env, const napi_value &self, T *context)
84     {
85         napi_unwrap(env, self, &context->boundObj);
86     }
87 
88     void ParseInputs(const std::vector<InputParser> &parsers, InputParser parserThis = DefParserThis)
89     {
90         if (asyncContext == nullptr) {
91             return;
92         }
93 
94         napi_value thisObj = nullptr;
95         size_t argc = parsers.size() + 1;
96         napi_value args[MAX_INPUT_COUNT] = { 0 };
97         napi_get_cb_info(asyncContext->env, asyncContext->info, &argc, args, &thisObj, nullptr);
98         for (size_t i = 0; i < argc && argc <= MAX_INPUT_COUNT; i++) {
99             if (i >= parsers.size()) {
100                 napi_valuetype valueType = napi_undefined;
101                 napi_typeof(asyncContext->env, args[i], &valueType);
102                 if (valueType == napi_function) {
103                     napi_create_reference(asyncContext->env, args[i], 1, &asyncContext->callbackRef);
104                 }
105                 break;
106             }
107             auto *parserFunction = parsers[i];
108             if (parserFunction != nullptr) {
109                 parserFunction(asyncContext->env, args[i], this->asyncContext);
110             }
111         }
112         parserThis(asyncContext->env, thisObj, asyncContext);
113     }
114 
DoAsyncWork(std::string resourceName,NapiAsyncExecute execFunc,NapiAsyncComplete completeFunc)115     napi_value DoAsyncWork(std::string resourceName, NapiAsyncExecute execFunc, NapiAsyncComplete completeFunc)
116     {
117         if (asyncContext == nullptr) {
118             return nullptr;
119         }
120 
121         napi_value ret = nullptr;
122         if (asyncContext->callbackRef == nullptr) {
123             napi_create_promise(asyncContext->env, &asyncContext->deferred, &ret);
124         } else {
125             napi_get_undefined(asyncContext->env, &ret);
126         }
127 
128         napi_value resource = nullptr;
129         napi_create_string_utf8(asyncContext->env, resourceName.c_str(), NAPI_AUTO_LENGTH, &resource);
130         asyncContext->execFunc = execFunc;
131         asyncContext->completeFunc = completeFunc;
132         NAPI_CALL_BASE(asyncContext->env, napi_create_async_work(asyncContext->env, nullptr, resource,
133             [](napi_env env, void *data) {
134                 T *context = (T *)data;
135                 context->execStatus = context->execFunc(context);
136             },
137             [](napi_env env, napi_status status, void *data) {
138                 T *context = (T *)data;
139                 napi_value output = nullptr;
140                 int completeStatus = context->completeFunc(context, output);
141                 napi_value result[RESULT_COUNT] = { 0 };
142                 if (context->execStatus == OK && completeStatus == OK) {
143                     napi_get_undefined(env, &result[0]);
144                     result[1] = output;
145                 } else {
146                     napi_value message = nullptr;
147                     napi_create_string_utf8(env, "async call failed", NAPI_AUTO_LENGTH, &message);
148                     napi_create_error(env, nullptr, message, &result[0]);
149                     napi_get_undefined(env, &result[1]);
150                 }
151                 if (context->deferred) {
152                     // promise
153                     if (context->execStatus == OK && completeStatus == OK) {
154                         napi_resolve_deferred(env, context->deferred, result[1]);
155                     } else {
156                         napi_reject_deferred(env, context->deferred, result[0]);
157                     }
158                 } else {
159                     // callback
160                     napi_value callback = nullptr;
161                     napi_get_reference_value(env, context->callbackRef, &callback);
162                     napi_value callbackResult = nullptr;
163                     napi_call_function(env, nullptr, callback, RESULT_COUNT, result, &callbackResult);
164                 }
165                 delete context;
166             },
167             (void *)asyncContext, &asyncContext->work), ret);
168         NAPI_CALL_BASE(asyncContext->env, napi_queue_async_work(asyncContext->env, asyncContext->work), ret);
169         return ret;
170     }
171 
172 private:
173     T *asyncContext;
174 };
175 } // namespace AppDataMgrJsKit
176 } // namespace OHOS
177 #endif
178