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