• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include "napi_distributed_account.h"
17 #include <map>
18 #include <string>
19 #include <unistd.h>
20 #include "account_log_wrapper.h"
21 #include "js_native_api.h"
22 #include "js_native_api_types.h"
23 #include "napi_account_common.h"
24 #include "napi/native_api.h"
25 #include "napi/native_common.h"
26 #include "napi/native_node_api.h"
27 #include "node_api.h"
28 #include "ohos_account_kits.h"
29 #include "os_account_info.h"
30 #include "napi_account_error.h"
31 #include "napi_common.h"
32 
33 using namespace OHOS::AccountSA;
34 
35 namespace OHOS {
36 namespace AccountJsKit {
37 constexpr std::int32_t QUERY_ARGC = 1;
38 constexpr std::int32_t UPDATE_ARGC = 2;
39 constexpr int RESULT_COUNT = 2;
40 const std::string DISTRIBUTED_ACCOUNT_CLASS_NAME = "DistributedAccountAbility";
41 const std::string PROPERTY_KEY_NAME = "name";
42 const std::string PROPERTY_KEY_ID = "id";
43 const std::string PROPERTY_KEY_EVENT = "event";
44 const std::string PROPERTY_KEY_NICKNAME = "nickname";
45 const std::string PROPERTY_KEY_AVATAR = "avatar";
46 const std::string PROPERTY_KEY_SCALABLE = "scalableData";
47 
48 struct DistributedAccountAsyncContext {
DistributedAccountAsyncContextOHOS::AccountJsKit::DistributedAccountAsyncContext49     explicit DistributedAccountAsyncContext(napi_env napiEnv) : env(napiEnv) {}
50     napi_env env = nullptr;
51     napi_async_work work = nullptr;
52 
53     bool throwErr = false;
54     int32_t errCode = 0;
55 
56     std::string event;
57     AccountSA::OhosAccountInfo ohosAccountInfo;
58 
59     napi_deferred deferred = nullptr;
60     napi_ref callbackRef = nullptr;
61     napi_status status = napi_generic_failure;
62 };
63 
ParseQueryOhosAccountInfoAsyncContext(napi_env env,napi_callback_info cbInfo,DistributedAccountAsyncContext * asyncContext)64 bool ParseQueryOhosAccountInfoAsyncContext(napi_env env, napi_callback_info cbInfo,
65                                            DistributedAccountAsyncContext *asyncContext)
66 {
67     size_t argc = QUERY_ARGC;
68     napi_value argv[QUERY_ARGC] = {nullptr};
69     napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr);
70     if (argc >= QUERY_ARGC) {
71         if (!GetCallbackProperty(env, argv[0], asyncContext->callbackRef, 2)) { // 2: the second parameter
72             std::string errMsg = "The type of arg 1 must be function";
73             AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
74             return false;
75         }
76     }
77     return true;
78 }
79 
GetAccountInfo(napi_env env,napi_value object,DistributedAccountAsyncContext * asyncContext)80 bool GetAccountInfo(napi_env env, napi_value object, DistributedAccountAsyncContext *asyncContext)
81 {
82     if (!GetStringPropertyByKey(env, object, PROPERTY_KEY_NAME, asyncContext->ohosAccountInfo.name_)) {
83         ACCOUNT_LOGE("Failed to get DistributedInfo's %{public}s property", PROPERTY_KEY_NAME.c_str());
84         std::string errMsg = "The type of " + PROPERTY_KEY_NAME + " must be string";
85         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
86         return false;
87     }
88     if (!GetStringPropertyByKey(env, object, PROPERTY_KEY_ID, asyncContext->ohosAccountInfo.uid_)) {
89         ACCOUNT_LOGE("Failed to get DistributedInfo's %{public}s property", PROPERTY_KEY_ID.c_str());
90         std::string errMsg = "The type of " + PROPERTY_KEY_ID + " must be string";
91         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
92         return false;
93     }
94     if (!GetOptionalStringPropertyByKey(env, object, PROPERTY_KEY_NICKNAME, asyncContext->ohosAccountInfo.nickname_)) {
95         ACCOUNT_LOGE("Failed to get DistributedInfo's %{public}s property", PROPERTY_KEY_NICKNAME.c_str());
96         std::string errMsg = "The type of " + PROPERTY_KEY_NICKNAME + " must be string";
97         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
98         return false;
99     }
100     if (!GetOptionalStringPropertyByKey(env, object, PROPERTY_KEY_AVATAR, asyncContext->ohosAccountInfo.avatar_)) {
101         ACCOUNT_LOGE("Failed to get DistributedInfo's %{public}s property", PROPERTY_KEY_AVATAR.c_str());
102         std::string errMsg = "The type of " + PROPERTY_KEY_AVATAR + " must be string";
103         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
104         return false;
105     }
106     bool hasProp = false;
107     napi_has_named_property(env, object, "scalableData", &hasProp);
108     AAFwk::WantParams params;
109     if (hasProp) {
110         napi_value value = nullptr;
111         napi_get_named_property(env, object, "scalableData", &value);
112         if (!AppExecFwk::UnwrapWantParams(env, value, params)) {
113             ACCOUNT_LOGE("Failed to get DistributedInfo's %{public}s property", PROPERTY_KEY_SCALABLE.c_str());
114             std::string errMsg = "The type of " + PROPERTY_KEY_SCALABLE + " must be object";
115             AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
116             return false;
117         }
118     }
119     asyncContext->ohosAccountInfo.scalableData_.SetParams(params);
120     return true;
121 }
122 
ParseUpdateOhosAccountInfoAsyncContext(napi_env env,napi_callback_info cbInfo,DistributedAccountAsyncContext * asyncContext)123 bool ParseUpdateOhosAccountInfoAsyncContext(napi_env env, napi_callback_info cbInfo,
124                                             DistributedAccountAsyncContext *asyncContext)
125 {
126     size_t argc = UPDATE_ARGC;
127     napi_value argv[UPDATE_ARGC] = {nullptr};
128     napi_get_cb_info(env, cbInfo, &argc, argv, nullptr, nullptr);
129     if (argc >= UPDATE_ARGC) {
130         if (!GetCallbackProperty(env, argv[1], asyncContext->callbackRef, 2)) { // 2: the second parameter
131             ACCOUNT_LOGE("Failed to get callback property");
132             std::string errMsg = "The type of arg 2 must be function";
133             AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
134             return false;
135         }
136     }
137     napi_valuetype valueType = napi_undefined;
138     napi_typeof(env, argv[0], &valueType);
139     if (valueType == napi_object) {
140         if (!GetAccountInfo(env, argv[0], asyncContext)) {
141             return false;
142         }
143         if (!GetStringPropertyByKey(env, argv[0], PROPERTY_KEY_EVENT, asyncContext->event)) {
144             ACCOUNT_LOGE("Failed to get DistributedInfo's %{public}s property", PROPERTY_KEY_EVENT.c_str());
145             std::string errMsg = "The type of " + PROPERTY_KEY_EVENT + " must be string";
146             AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
147             return false;
148         }
149     } else {
150         std::string errMsg = "The type of arg 1 must be object";
151         ACCOUNT_LOGE("Failed to get DistributedInfo property");
152         AccountNapiThrow(env, ERR_JS_PARAMETER_ERROR, errMsg, asyncContext->throwErr);
153         return false;
154     }
155     return true;
156 }
157 
ProcessCallbackOrPromise(napi_env env,const DistributedAccountAsyncContext * asyncContext,napi_value err,napi_value data)158 void ProcessCallbackOrPromise(
159     napi_env env, const DistributedAccountAsyncContext *asyncContext, napi_value err, napi_value data)
160 {
161     if (asyncContext->deferred != nullptr) {
162         if (asyncContext->errCode == ERR_OK) {
163             napi_resolve_deferred(env, asyncContext->deferred, data);
164         } else {
165             napi_reject_deferred(env, asyncContext->deferred, err);
166         }
167     } else {
168         napi_value args[RESULT_COUNT] = { err, data };
169         napi_value callback = nullptr;
170         napi_get_reference_value(env, asyncContext->callbackRef, &callback);
171         napi_value returnVal = nullptr;
172         napi_call_function(env, nullptr, callback, RESULT_COUNT, args, &returnVal);
173         napi_delete_reference(env, asyncContext->callbackRef);
174     }
175 }
176 
ProcessSetNamedProperty(napi_env env,const DistributedAccountAsyncContext * asyncContext)177 void ProcessSetNamedProperty(napi_env env, const DistributedAccountAsyncContext *asyncContext)
178 {
179     napi_value result[RESULT_COUNT] = {0};
180     if (asyncContext->errCode == ERR_OK) {
181         if (asyncContext->throwErr) {
182             napi_get_null(env, &result[0]);
183         } else {
184             napi_get_undefined(env, &result[0]);
185         }
186         napi_create_object(env, &result[1]);
187         napi_value value = nullptr;
188         napi_create_string_utf8(env, asyncContext->ohosAccountInfo.name_.c_str(),
189                                 asyncContext->ohosAccountInfo.name_.size(), &value);
190         napi_set_named_property(env, result[1], PROPERTY_KEY_NAME.c_str(), value);
191         napi_create_string_utf8(env, asyncContext->ohosAccountInfo.uid_.c_str(),
192                                 asyncContext->ohosAccountInfo.uid_.size(), &value);
193         napi_set_named_property(env, result[1], PROPERTY_KEY_ID.c_str(), value);
194         napi_create_string_utf8(env, asyncContext->event.c_str(), asyncContext->event.size(), &value);
195         napi_set_named_property(env, result[1], PROPERTY_KEY_EVENT.c_str(), value);
196         napi_create_string_utf8(env, asyncContext->ohosAccountInfo.nickname_.c_str(),
197                                 asyncContext->ohosAccountInfo.nickname_.size(), &value);
198         napi_set_named_property(env, result[1], PROPERTY_KEY_NICKNAME.c_str(), value);
199         napi_create_string_utf8(env, asyncContext->ohosAccountInfo.avatar_.c_str(),
200                                 asyncContext->ohosAccountInfo.avatar_.size(), &value);
201         napi_set_named_property(env, result[1], PROPERTY_KEY_AVATAR.c_str(), value);
202         napi_value scalable = nullptr;
203         napi_create_object(env, &scalable);
204         scalable = AppExecFwk::WrapWantParams(env, (asyncContext->ohosAccountInfo.scalableData_).GetParams());
205         napi_set_named_property(env, result[1], PROPERTY_KEY_SCALABLE.c_str(), scalable);
206     } else {
207         if (asyncContext->throwErr) {
208             result[0] = GenerateBusinessError(env, asyncContext->errCode);
209             napi_get_null(env, &result[1]);
210         } else {
211             napi_value message = nullptr;
212             napi_create_string_utf8(env, "query ohos account info failed", NAPI_AUTO_LENGTH, &message);
213             napi_create_error(env, nullptr, message, &result[0]);
214             napi_get_undefined(env, &result[1]);
215         }
216     }
217     ProcessCallbackOrPromise(env, asyncContext, result[0], result[1]);
218 }
219 
Init(napi_env env,napi_value exports)220 napi_value NapiDistributedAccount::Init(napi_env env, napi_value exports)
221 {
222     napi_property_descriptor descriptor[] = {
223         DECLARE_NAPI_FUNCTION("getDistributedAccountAbility", GetDistributedAccountAbility),
224     };
225     napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor);
226 
227     napi_property_descriptor properties[] = {
228         DECLARE_NAPI_FUNCTION("queryOsAccountDistributedInfo", QueryOsAccountDistributedInfo),
229         DECLARE_NAPI_FUNCTION("getOsAccountDistributedInfo", GetOsAccountDistributedInfo),
230         DECLARE_NAPI_FUNCTION("updateOsAccountDistributedInfo", UpdateOsAccountDistributedInfo),
231         DECLARE_NAPI_FUNCTION("setOsAccountDistributedInfo", SetOsAccountDistributedInfo),
232     };
233     napi_value cons = nullptr;
234     napi_define_class(env, DISTRIBUTED_ACCOUNT_CLASS_NAME.c_str(), DISTRIBUTED_ACCOUNT_CLASS_NAME.size(),
235         JsConstructor, nullptr, sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons);
236     napi_create_reference(env, cons, 1, &distributedAccountRef_);
237     napi_set_named_property(env, exports, DISTRIBUTED_ACCOUNT_CLASS_NAME.c_str(), cons);
238 
239     return exports;
240 }
241 
JsConstructor(napi_env env,napi_callback_info cbinfo)242 napi_value NapiDistributedAccount::JsConstructor(napi_env env, napi_callback_info cbinfo)
243 {
244     napi_value thisVar = nullptr;
245     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
246     return thisVar;
247 }
248 
GetDistributedAccountAbility(napi_env env,napi_callback_info cbInfo)249 napi_value NapiDistributedAccount::GetDistributedAccountAbility(napi_env env, napi_callback_info cbInfo)
250 {
251     napi_value instance = nullptr;
252     napi_value cons = nullptr;
253     if (napi_get_reference_value(env, distributedAccountRef_, &cons) != napi_ok) {
254         return nullptr;
255     }
256 
257     if (napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok) {
258         return nullptr;
259     }
260 
261     return instance;
262 }
263 
QueryOsAccountDistributedInfo(napi_env env,napi_callback_info cbInfo)264 napi_value NapiDistributedAccount::QueryOsAccountDistributedInfo(napi_env env, napi_callback_info cbInfo)
265 {
266     return QueryOhosAccountInfo(env, cbInfo, false);
267 }
268 
GetOsAccountDistributedInfo(napi_env env,napi_callback_info cbInfo)269 napi_value NapiDistributedAccount::GetOsAccountDistributedInfo(napi_env env, napi_callback_info cbInfo)
270 {
271     return QueryOhosAccountInfo(env, cbInfo, true);
272 }
273 
QueryOhosAccountInfo(napi_env env,napi_callback_info cbInfo,bool throwErr)274 napi_value NapiDistributedAccount::QueryOhosAccountInfo(napi_env env, napi_callback_info cbInfo, bool throwErr)
275 {
276     auto *asyncContext = new (std::nothrow) DistributedAccountAsyncContext(env);
277     if (asyncContext == nullptr) {
278         ACCOUNT_LOGE("insufficient memory for asyncContext!");
279         return nullptr;
280     }
281     asyncContext->throwErr = throwErr;
282     if (!ParseQueryOhosAccountInfoAsyncContext(env, cbInfo, asyncContext) && throwErr) {
283         delete asyncContext;
284         return nullptr;
285     }
286     napi_value result = nullptr;
287     if (asyncContext->callbackRef == nullptr) {
288         napi_create_promise(env, &asyncContext->deferred, &result);
289     }
290     napi_value resource = nullptr;
291     napi_create_string_utf8(env, "QueryOhosAccountInfo", NAPI_AUTO_LENGTH, &resource);
292     napi_create_async_work(env, nullptr, resource,
293         [](napi_env env, void *data) {
294             DistributedAccountAsyncContext *asyncContext = reinterpret_cast<DistributedAccountAsyncContext *>(data);
295             if (asyncContext->throwErr) {
296                 asyncContext->errCode = OhosAccountKits::GetInstance().GetOhosAccountInfo(
297                     asyncContext->ohosAccountInfo);
298             } else {
299                 std::pair<bool, OhosAccountInfo> accountInfo = OhosAccountKits::GetInstance().QueryOhosAccountInfo();
300                 if (accountInfo.first) {
301                     asyncContext->ohosAccountInfo.name_ = accountInfo.second.name_;
302                     asyncContext->ohosAccountInfo.uid_ = accountInfo.second.uid_;
303                     asyncContext->errCode = napi_ok;
304                 } else {
305                     asyncContext->errCode = napi_generic_failure;
306                 }
307             }
308         },
309         [](napi_env env, napi_status status, void *data) {
310             DistributedAccountAsyncContext *asyncContext = reinterpret_cast<DistributedAccountAsyncContext *>(data);
311             ProcessSetNamedProperty(env, asyncContext);
312             napi_delete_async_work(env, asyncContext->work);
313             delete asyncContext;
314         }, reinterpret_cast<void *>(asyncContext), &asyncContext->work);
315     napi_queue_async_work(env, asyncContext->work);
316     return result;
317 }
318 
UpdateOsAccountDistributedInfo(napi_env env,napi_callback_info cbInfo)319 napi_value NapiDistributedAccount::UpdateOsAccountDistributedInfo(napi_env env, napi_callback_info cbInfo)
320 {
321     return UpdateOhosAccountInfo(env, cbInfo, false);
322 }
323 
SetOsAccountDistributedInfo(napi_env env,napi_callback_info cbInfo)324 napi_value NapiDistributedAccount::SetOsAccountDistributedInfo(napi_env env, napi_callback_info cbInfo)
325 {
326     return UpdateOhosAccountInfo(env, cbInfo, true);
327 }
328 
UpdateOhosAccountInfo(napi_env env,napi_callback_info cbInfo,bool throwErr)329 napi_value NapiDistributedAccount::UpdateOhosAccountInfo(napi_env env, napi_callback_info cbInfo, bool throwErr)
330 {
331     auto *asyncContext = new (std::nothrow) DistributedAccountAsyncContext(env);
332     if (asyncContext == nullptr) {
333         ACCOUNT_LOGE("insufficient memory for asyncContext!");
334         return nullptr;
335     }
336     asyncContext->throwErr = throwErr;
337     if (!ParseUpdateOhosAccountInfoAsyncContext(env, cbInfo, asyncContext) && throwErr) {
338         delete asyncContext;
339         return nullptr;
340     }
341     napi_value result = nullptr;
342     if (asyncContext->callbackRef == nullptr) {
343         napi_create_promise(env, &asyncContext->deferred, &result);
344     }
345     napi_value resource = nullptr;
346     napi_create_string_utf8(env, "UpdateOhosAccountInfo", NAPI_AUTO_LENGTH, &resource);
347     napi_create_async_work(env, nullptr, resource,
348         [](napi_env env, void *data) {
349             DistributedAccountAsyncContext *context = reinterpret_cast<DistributedAccountAsyncContext *>(data);
350             if (context->throwErr) {
351                 context->errCode = OhosAccountKits::GetInstance().SetOhosAccountInfo(
352                     context->ohosAccountInfo, context->event);
353             } else {
354                 context->errCode = OhosAccountKits::GetInstance().UpdateOhosAccountInfo(context->ohosAccountInfo.name_,
355                     context->ohosAccountInfo.uid_, context->event) ? napi_ok : napi_generic_failure;
356             }
357         },
358         [](napi_env env, napi_status status, void *data) {
359             DistributedAccountAsyncContext *asyncContext = reinterpret_cast<DistributedAccountAsyncContext *>(data);
360             napi_value result[RESULT_COUNT] = {0};
361             if (asyncContext->errCode == ERR_OK) {
362                 if (asyncContext->throwErr) {
363                     napi_get_null(env, &result[0]);
364                     napi_get_null(env, &result[1]);
365                 } else {
366                     napi_get_undefined(env, &result[1]);
367                 }
368             } else if (asyncContext->throwErr) {
369                 result[0] = GenerateBusinessError(env, asyncContext->errCode);
370             } else {
371                 napi_value message = nullptr;
372                 napi_create_string_utf8(env, "Update distributed account info failed", NAPI_AUTO_LENGTH, &message);
373                 napi_create_error(env, nullptr, message, &result[0]);
374             }
375             ProcessCallbackOrPromise(env, asyncContext, result[0], result[1]);
376             napi_delete_async_work(env, asyncContext->work);
377             delete asyncContext;
378         }, reinterpret_cast<void *>(asyncContext), &asyncContext->work);
379     napi_queue_async_work(env, asyncContext->work);
380     return result;
381 }
382 } // namespace AccountJsKit
383 } // namespace OHOS
384 
385 EXTERN_C_START
386 /*
387  * function for module exports
388  */
Init(napi_env env,napi_value exports)389 static napi_value Init(napi_env env, napi_value exports)
390 {
391     return OHOS::AccountJsKit::NapiDistributedAccount::Init(env, exports);
392 }
393 EXTERN_C_END
394 
395 /*
396  * module define
397  */
398 static napi_module _module = {
399     .nm_version = 1,
400     .nm_flags = 0,
401     .nm_filename = nullptr,
402     .nm_register_func = Init,
403     .nm_modname = "account.distributedAccount",
404     .nm_priv = ((void*)0),
405     .reserved = {0}
406 };
407 /*
408  * module register
409  */
Register()410 extern "C" __attribute__((constructor)) void Register()
411 {
412     napi_module_register(&_module);
413 }
414