• 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 
DefParserThis(const napi_env & env,const napi_value & self,T * context)73     static void DefParserThis(const napi_env &env, const napi_value &self, T *context)
74     {
75         napi_unwrap(env, self, &context->boundObj);
76     }
77 
78     void ParseInputs(const std::vector<InputParser> &parsers, InputParser parserThis = DefParserThis)
79     {
80         if (asyncContext == nullptr) {
81             return;
82         }
83 
84         napi_value thisObj = nullptr;
85         size_t argc = parsers.size() + 1;
86         napi_value args[MAX_INPUT_COUNT] = { 0 };
87         napi_get_cb_info(asyncContext->env, asyncContext->info, &argc, args, &thisObj, nullptr);
88         for (size_t i = 0; i < argc && argc <= MAX_INPUT_COUNT; i++) {
89             if (i >= parsers.size()) {
90                 napi_valuetype valueType = napi_undefined;
91                 napi_typeof(asyncContext->env, args[i], &valueType);
92                 if (valueType == napi_function) {
93                     napi_create_reference(asyncContext->env, args[i], 1, &asyncContext->callbackRef);
94                 }
95                 break;
96             }
97             auto *parserFunction = parsers[i];
98             if (parserFunction != nullptr) {
99                 parserFunction(asyncContext->env, args[i], this->asyncContext);
100             }
101         }
102         parserThis(asyncContext->env, thisObj, asyncContext);
103     }
104 
DoAsyncWork(std::string resourceName,NapiAsyncExecute execFunc,NapiAsyncComplete completeFunc)105     napi_value DoAsyncWork(std::string resourceName, NapiAsyncExecute execFunc, NapiAsyncComplete completeFunc)
106     {
107         if (asyncContext == nullptr) {
108             return nullptr;
109         }
110 
111         napi_value ret = nullptr;
112         if (asyncContext->callbackRef == nullptr) {
113             napi_create_promise(asyncContext->env, &asyncContext->deferred, &ret);
114         } else {
115             napi_get_undefined(asyncContext->env, &ret);
116         }
117 
118         napi_value resource = nullptr;
119         napi_create_string_utf8(asyncContext->env, resourceName.c_str(), NAPI_AUTO_LENGTH, &resource);
120 
121         asyncContext->execFunc = execFunc;
122         asyncContext->completeFunc = completeFunc;
123         napi_create_async_work(
124             asyncContext->env, nullptr, resource,
125             [](napi_env env, void *data) {
126                 T *context = (T *)data;
127                 context->execStatus = context->execFunc(context);
128             },
129             [](napi_env env, napi_status status, void *data) {
130                 T *context = (T *)data;
131                 napi_value output = nullptr;
132                 int completeStatus = context->completeFunc(context, output);
133                 napi_value result[RESULT_COUNT] = { 0 };
134                 if (context->execStatus == OK && completeStatus == OK) {
135                     napi_get_undefined(env, &result[0]);
136                     result[1] = output;
137                 } else {
138                     napi_value message = nullptr;
139                     napi_create_string_utf8(env, "async call failed", NAPI_AUTO_LENGTH, &message);
140                     napi_create_error(env, nullptr, message, &result[0]);
141                     napi_get_undefined(env, &result[1]);
142                 }
143                 if (context->deferred) {
144                     // promise
145                     if (context->execStatus == OK && completeStatus == OK) {
146                         napi_resolve_deferred(env, context->deferred, result[1]);
147                     } else {
148                         napi_reject_deferred(env, context->deferred, result[0]);
149                     }
150                 } else {
151                     // callback
152                     napi_value callback = nullptr;
153                     napi_get_reference_value(env, context->callbackRef, &callback);
154                     napi_value callbackResult = nullptr;
155                     napi_call_function(env, nullptr, callback, RESULT_COUNT, result, &callbackResult);
156                 }
157                 delete context;
158             },
159             (void *)asyncContext, &asyncContext->work);
160 
161         napi_queue_async_work(asyncContext->env, asyncContext->work);
162         return ret;
163     }
164 
165 private:
166     T *asyncContext;
167 };
168 } // namespace AppDataMgrJsKit
169 } // namespace OHOS
170 #endif
171