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 #define LOG_TAG "JSConfig"
16 #include "js_config.h"
17 
18 #include <cstddef>
19 #include <memory>
20 
21 #include "cloud_manager.h"
22 #include "cloud_service.h"
23 #include "js_error_utils.h"
24 #include "js_utils.h"
25 #include "js_cloud_utils.h"
26 #include "js_strategy_context.h"
27 #include "logger.h"
28 #include "napi_queue.h"
29 
30 using namespace OHOS::Rdb;
31 using namespace OHOS::CloudData;
32 using namespace OHOS::AppDataMgrJsKit;
JsConfig()33 JsConfig::JsConfig()
34 {
35 }
36 
~JsConfig()37 JsConfig::~JsConfig()
38 {
39 }
40 
41 /*
42  * [JS API Prototype]
43  * [AsyncCallback]
44  *      enableCloud(accountId: string, switches: {[bundleName: string]: boolean}, callback: AsyncCallback<void>): void;
45  * [Promise]
46  *      enableCloud(accountId: string, switches: {[bundleName: string]: boolean}): Promise<void>;
47  */
EnableCloud(napi_env env,napi_callback_info info)48 napi_value JsConfig::EnableCloud(napi_env env, napi_callback_info info)
49 {
50     struct EnableCloudContext : public ContextBase {
51         std::string accountId;
52         std::map<std::string, bool> tempSwitches;
53         std::map<std::string, int32_t> switches;
54     };
55     auto ctxt = std::make_shared<EnableCloudContext>();
56     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
57         // required 2 arguments :: <accountId> <switches>
58         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
59         // 0 is the index of argument accountId, 1 is the index of argument switches
60         int status = JSUtils::Convert2Value(env, argv[0], ctxt->accountId);
61         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->accountId.empty(), Status::INVALID_ARGUMENT,
62             "The type of accountId must be string and not empty.");
63         status = JSUtils::Convert2Value(env, argv[1], ctxt->tempSwitches);
64         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT,
65             "The type of switches must be {[bundleName: string]: boolean}.");
66         for (auto item : ctxt->tempSwitches) {
67             ctxt->switches[item.first] = item.second ? CloudService::Switch::SWITCH_ON
68                                                      : CloudService::Switch::SWITCH_OFF;
69         }
70     });
71 
72     ASSERT_NULL(!ctxt->isThrowError, "EnableCloud exit");
73 
74     auto execute = [ctxt]() {
75         auto [state, proxy] = CloudManager::GetInstance().GetCloudService();
76         if (proxy == nullptr) {
77             if (state != CloudService::SERVER_UNAVAILABLE) {
78                 state = CloudService::NOT_SUPPORT;
79             }
80             ctxt->status = (GenerateNapiError(state, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
81                                ? napi_ok
82                                : napi_generic_failure;
83             return;
84         }
85         int32_t cStatus = proxy->EnableCloud(ctxt->accountId, ctxt->switches);
86         LOG_DEBUG("EnableCloud return %{public}d", cStatus);
87         ctxt->status = (GenerateNapiError(cStatus, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
88                            ? napi_ok
89                            : napi_generic_failure;
90     };
91     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
92 }
93 
94 /*
95  * [JS API Prototype]
96  * [AsyncCallback]
97  *      disableCloud(accountId: string, callback: AsyncCallback<void>): void;
98  * [Promise]
99  *      disableCloud(accountId: string): Promise<void>;
100  */
DisableCloud(napi_env env,napi_callback_info info)101 napi_value JsConfig::DisableCloud(napi_env env, napi_callback_info info)
102 {
103     struct DisableCloudContext : public ContextBase {
104         std::string accountId;
105     };
106     auto ctxt = std::make_shared<DisableCloudContext>();
107     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
108         // required 1 arguments :: <accountId>
109         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
110         // 0 is the index of argument accountId
111         int status = JSUtils::Convert2Value(env, argv[0], ctxt->accountId);
112         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->accountId.empty(), Status::INVALID_ARGUMENT,
113             "The type of accountId must be string and not empty.");
114     });
115 
116     ASSERT_NULL(!ctxt->isThrowError, "DisableCloud exit");
117 
118     auto execute = [ctxt]() {
119         auto [state, proxy] = CloudManager::GetInstance().GetCloudService();
120         if (proxy == nullptr) {
121             if (state != CloudService::SERVER_UNAVAILABLE) {
122                 state = CloudService::NOT_SUPPORT;
123             }
124             ctxt->status = (GenerateNapiError(state, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
125                                ? napi_ok
126                                : napi_generic_failure;
127             return;
128         }
129         int32_t cStatus = proxy->DisableCloud(ctxt->accountId);
130         LOG_DEBUG("DisableCloud return %{public}d", cStatus);
131         ctxt->status = (GenerateNapiError(cStatus, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
132                            ? napi_ok
133                            : napi_generic_failure;
134     };
135     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
136 }
137 
138 /*
139  * [JS API Prototype]
140  * [AsyncCallback]
141  *      changeAppCloudSwitch(accountId: string, bundleName: string, status :boolean,
142  *      callback: AsyncCallback<void>): void;
143  * [Promise]
144  *      changeAppCloudSwitch(accountId: string, bundleName: string, status :boolean): Promise<void>;
145  */
146 
ChangeAppCloudSwitch(napi_env env,napi_callback_info info)147 napi_value JsConfig::ChangeAppCloudSwitch(napi_env env, napi_callback_info info)
148 {
149     struct ChangeAppSwitchContext : public ContextBase {
150         std::string accountId;
151         std::string bundleName;
152         CloudService::Switch state;
153     };
154     auto ctxt = std::make_shared<ChangeAppSwitchContext>();
155     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
156         // required 3 arguments :: <accountId> <bundleName> <state>
157         ASSERT_BUSINESS_ERR(ctxt, argc >= 3, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
158         // 0 is the index of argument accountId
159         int status = JSUtils::Convert2Value(env, argv[0], ctxt->accountId);
160         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->accountId.empty(), Status::INVALID_ARGUMENT,
161             "The type of accountId must be string and not empty.");
162         // 1 is the index of argument bundleName
163         status = JSUtils::Convert2Value(env, argv[1], ctxt->bundleName);
164         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->bundleName.empty(), Status::INVALID_ARGUMENT,
165             "The type of bundleName must be string and not empty.");
166         bool state = false;
167         // 2 is the index of argument state
168         status = JSUtils::Convert2Value(env, argv[2], state);
169         ASSERT_BUSINESS_ERR(
170             ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT, "The type of status must be boolean.");
171         ctxt->state = state ? CloudService::Switch::SWITCH_ON : CloudService::Switch::SWITCH_OFF;
172     });
173 
174     ASSERT_NULL(!ctxt->isThrowError, "ChangeAppCloudSwitch exit");
175 
176     auto execute = [ctxt]() {
177         auto [state, proxy] = CloudManager::GetInstance().GetCloudService();
178         if (proxy == nullptr) {
179             if (state != CloudService::SERVER_UNAVAILABLE) {
180                 state = CloudService::NOT_SUPPORT;
181             }
182             ctxt->status = (GenerateNapiError(state, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
183                                ? napi_ok
184                                : napi_generic_failure;
185             return;
186         }
187         int32_t cStatus = proxy->ChangeAppSwitch(ctxt->accountId, ctxt->bundleName, ctxt->state);
188         LOG_DEBUG("ChangeAppCloudSwitch return %{public}d", cStatus);
189         ctxt->status = (GenerateNapiError(cStatus, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
190                            ? napi_ok
191                            : napi_generic_failure;
192     };
193     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
194 }
195 
196 /*
197  * [JS API Prototype]
198  * [AsyncCallback]
199  *      clean(accountId: string, appActions: {[bundleName: string]: Action}, callback: AsyncCallback<void>): void;
200  * [Promise]
201  *      clean(accountId: string, appActions: {[bundleName: string]: Action}): Promise<void>;
202  */
Clean(napi_env env,napi_callback_info info)203 napi_value JsConfig::Clean(napi_env env, napi_callback_info info)
204 {
205     struct CleanContext : public ContextBase {
206         std::string accountId;
207         std::map<std::string, int32_t> appActions;
208     };
209     auto ctxt = std::make_shared<CleanContext>();
210     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
211         // required 2 arguments :: <accountId> <appActions>
212         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
213         // 0 is the index of argument accountId, 1 is the index of argument
214         int status = JSUtils::Convert2Value(env, argv[0], ctxt->accountId);
215         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->accountId.empty(), Status::INVALID_ARGUMENT,
216             "The type of accountId must be string and not empty.");
217         status = JSUtils::Convert2Value(env, argv[1], ctxt->appActions);
218         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT,
219             "The type of actions must be {[bundleName: string]: int32_t}.");
220         for (auto item : ctxt->appActions) {
221             ASSERT_BUSINESS_ERR(ctxt, ValidSubscribeType(item.second), Status::INVALID_ARGUMENT,
222                 "Action in map appActions is incorrect.");
223         }
224     });
225 
226     ASSERT_NULL(!ctxt->isThrowError, "Clean exit");
227 
228     auto execute = [ctxt]() {
229         auto [state, proxy] = CloudManager::GetInstance().GetCloudService();
230         if (proxy == nullptr) {
231             if (state != CloudService::SERVER_UNAVAILABLE) {
232                 state = CloudService::NOT_SUPPORT;
233             }
234             ctxt->status = (GenerateNapiError(state, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
235                                ? napi_ok
236                                : napi_generic_failure;
237             return;
238         }
239         int32_t cStatus = proxy->Clean(ctxt->accountId, ctxt->appActions);
240         LOG_DEBUG("Clean return %{public}d", cStatus);
241         ctxt->status = (GenerateNapiError(cStatus, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
242                            ? napi_ok
243                            : napi_generic_failure;
244     };
245     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
246 }
247 
248 /*
249  * [JS API Prototype]
250  * [AsyncCallback]
251  *      notifyDataChange(accountId: string, bundleName: string, callback: AsyncCallback<void>): void;
252  *      notifyDataChange(extInfo: ExtraData, callback: AsyncCallback<void>): void;
253  *      notifyDataChange(extInfo: ExtraData, userId: number,callback: AsyncCallback<void>): void;
254  * [Promise]
255  *      notifyDataChange(accountId: string, bundleName: string): Promise<void>;
256  *      notifyDataChange(extInfo: ExtraData, userId?: number): Promise<void>;
257  */
258 struct ChangeAppSwitchContext : public ContextBase {
259     std::string accountId;
260     std::string bundleName;
261     int32_t userId = CloudService::INVALID_USER_ID;
262     bool notifyStatus = false;
263     OHOS::CloudData::JsConfig::ExtraData extInfo;
264 };
NotifyDataChange(napi_env env,napi_callback_info info)265 napi_value JsConfig::NotifyDataChange(napi_env env, napi_callback_info info)
266 {
267     auto ctxt = std::make_shared<ChangeAppSwitchContext>();
268     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
269         // required 2 arguments :: <accountId> <bundleName>
270         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
271         napi_valuetype type = napi_undefined;
272         if (argc > 1 && napi_typeof(env, argv[0], &type) == napi_ok && type != napi_object) {
273             // 0 is the index of argument accountId, 1 is the index of argument bundleName
274             int status = JSUtils::Convert2Value(env, argv[0], ctxt->accountId);
275             ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->accountId.empty(), Status::INVALID_ARGUMENT,
276                 "The type of accountId must be string and not empty.");
277             status = JSUtils::Convert2Value(env, argv[1], ctxt->bundleName);
278             ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->bundleName.empty(), Status::INVALID_ARGUMENT,
279                 "The type of bundleName must be string and not empty.");
280         } else {
281             int status = JSUtils::Convert2Value(env, argv[0], ctxt->extInfo);
282             ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && VerifyExtraData(ctxt->extInfo), Status::INVALID_ARGUMENT,
283                 "The type of extInfo must be Extradata and not empty.");
284             if (argc > 1) {
285                 status = JSUtils::Convert2ValueExt(env, argv[1], ctxt->userId);
286                 ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT,
287                     "The type of user must be number.");
288             }
289             ctxt->notifyStatus = true;
290         }
291     });
292 
293     ASSERT_NULL(!ctxt->isThrowError, "NotifyDataChange exit");
294 
295     auto execute = [ctxt]() {
296         auto [state, proxy] = CloudManager::GetInstance().GetCloudService();
297         if (proxy == nullptr) {
298             if (state != CloudService::SERVER_UNAVAILABLE) {
299                 state = CloudService::NOT_SUPPORT;
300             }
301             ctxt->status = (GenerateNapiError(state, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
302                 ? napi_ok : napi_generic_failure;
303             return;
304         }
305         int32_t status ;
306         if (ctxt->notifyStatus == true) {
307             status = proxy->NotifyDataChange(ctxt->extInfo.eventId, ctxt->extInfo.extraData, ctxt->userId);
308         } else {
309             status = proxy->NotifyDataChange(ctxt->accountId, ctxt->bundleName);
310         }
311         LOG_DEBUG("NotifyDataChange return %{public}d", status);
312         ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
313             ? napi_ok : napi_generic_failure;
314         if (status == Status::INVALID_ARGUMENT) {
315             ctxt->error += "The parameter required is a valid value.";
316         }
317     };
318     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
319 }
320 
321 /*
322  * [JS API Prototype]
323  * [Promise]
324  *      QueryStatistics(accountId: string, bundleName: string,
325  *      storeId?: number): Promise<Record<string, Array<StatisticInfo>>>;
326  */
QueryStatistics(napi_env env,napi_callback_info info)327 napi_value JsConfig::QueryStatistics(napi_env env, napi_callback_info info)
328 {
329     struct QueryStatisticsContext : public ContextBase {
330         std::string accountId;
331         std::string bundleName;
332         std::string storeId = "";
333         std::map<std::string, StatisticInfos> result;
334     };
335     auto ctxt = std::make_shared<QueryStatisticsContext>();
336     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value* argv) {
337         // required 2 arguments :: <accountId> <bundleName>
338         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
339         // 0 is the index of argument accountId
340         int status = JSUtils::Convert2Value(env, argv[0], ctxt->accountId);
341         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->accountId.empty(), Status::INVALID_ARGUMENT,
342             "The type of accountId must be string and not empty.");
343         // 1 is the index of argument bundleName
344         status = JSUtils::Convert2Value(env, argv[1], ctxt->bundleName);
345         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && !ctxt->bundleName.empty(), Status::INVALID_ARGUMENT,
346             "The type of bundleName must be string and not empty.");
347         // 2 is the index of argument storeId
348         if (argc > 2 && !JSUtils::IsNull(ctxt->env, argv[2])) {
349             // 2 is the index of argument storeId
350             status = JSUtils::Convert2Value(env, argv[2], ctxt->storeId);
351             ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT,
352                 "The type of storeId must be string.");
353         }
354     });
355 
356     ASSERT_NULL(!ctxt->isThrowError, "QueryStatistics exit");
357 
358     auto execute = [ctxt]() {
359         auto [state, proxy] = CloudManager::GetInstance().GetCloudService();
360         if (proxy == nullptr) {
361             if (state != CloudService::SERVER_UNAVAILABLE) {
362                 state = CloudService::NOT_SUPPORT;
363             }
364             ctxt->status = (GenerateNapiError(state, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
365                                ? napi_ok
366                                : napi_generic_failure;
367             return;
368         }
369         auto [status, result] = proxy->QueryStatistics(ctxt->accountId, ctxt->bundleName, ctxt->storeId);
370         ctxt->status =
371             (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure;
372         ctxt->result = std::move(result);
373     };
374     auto output = [env, ctxt](napi_value& result) {
375         result = JSUtils::Convert2JSValue(env, ctxt->result);
376         ASSERT_VALUE(ctxt,  result != nullptr, napi_generic_failure, "output failed");
377     };
378     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
379 }
380 
SetGlobalCloudStrategy(napi_env env,napi_callback_info info)381 napi_value JsConfig::SetGlobalCloudStrategy(napi_env env, napi_callback_info info)
382 {
383     auto ctxt = std::make_shared<CloudStrategyContext>();
384     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
385         // strategy 1 required parameter, param 1 Optional parameter
386         ASSERT_BUSINESS_ERR(ctxt, argc >= 1, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
387         int32_t strategy = -1;
388         int status = JSUtils::Convert2ValueExt(env, argv[0], strategy);
389         ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK && strategy >= 0 &&
390             strategy < static_cast<int32_t>(Strategy::STRATEGY_BUTT), Status::INVALID_ARGUMENT,
391             "The type of strategy must be StrategyType.");
392         ctxt->strategy = static_cast<Strategy>(strategy);
393         // 'argv[1]' represents a vector<CommonType::Value> param or null
394         if (argc == 1 || JSUtils::IsNull(env, argv[1])) {
395             ctxt->SetDefault();
396         } else {
397             // 'argv[1]' represents a vector<CommonType::Value> param
398             status = JSUtils::Convert2Value(env, argv[1], ctxt->param);
399             ASSERT_BUSINESS_ERR(ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT,
400                 "The type of param must be Array<commonType.ValueType>");
401             auto res = ctxt->CheckParam();
402             ASSERT_BUSINESS_ERR(ctxt, res.first == JSUtils::OK, Status::INVALID_ARGUMENT, res.second);
403         }
404     });
405     ASSERT_NULL(!ctxt->isThrowError, "SetGlobalCloudStrategy exit");
406     auto execute = [env, ctxt]() {
407         auto [status, proxy] = CloudManager::GetInstance().GetCloudService();
408         if (proxy == nullptr) {
409             if (status != CloudService::SERVER_UNAVAILABLE) {
410                 status = CloudService::NOT_SUPPORT;
411             }
412             ctxt->status = (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
413                                ? napi_ok: napi_generic_failure;
414             return;
415         }
416         LOG_DEBUG("SetGlobalCloudStrategy execute.");
417 
418         auto res = proxy->SetGlobalCloudStrategy(ctxt->strategy, ctxt->param);
419         ctxt->status =
420             (GenerateNapiError(res, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure;
421     };
422     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
423 }
424 
New(napi_env env,napi_callback_info info)425 napi_value JsConfig::New(napi_env env, napi_callback_info info)
426 {
427     napi_value self = nullptr;
428     size_t argc = ARGC_MAX;
429     napi_value argv[ARGC_MAX] = { 0 };
430     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
431     if (self == nullptr) {
432         napi_new_instance(env, JSUtils::GetClass(env, "ohos.cloudData", "Config"), argc, argv, &self);
433         return self;
434     }
435 
436     auto finalize = [](napi_env env, void *data, void *hint) {
437         LOG_DEBUG("cloudConfig finalize.");
438         auto *config = reinterpret_cast<JsConfig *>(data);
439         ASSERT_VOID(config != nullptr, "finalize null!");
440         delete config;
441     };
442     JsConfig *cloudConfig = new (std::nothrow) JsConfig();
443     ASSERT_ERR(env, cloudConfig != nullptr, Status::INVALID_ARGUMENT, "no memory for cloudConfig.");
444     napi_status status = napi_wrap(env, self, cloudConfig, finalize, nullptr, nullptr);
445     if (status != napi_ok) {
446         LOG_ERROR("JsConfig::Initialize napi_wrap failed! code:%{public}d!", status);
447         finalize(env, cloudConfig, nullptr);
448         return nullptr;
449     }
450     return self;
451 }
452 
QueryLastSyncInfo(napi_env env,napi_callback_info info)453 napi_value JsConfig::QueryLastSyncInfo(napi_env env, napi_callback_info info)
454 {
455     struct QueryLastSyncInfoContext : public ContextBase {
456         std::string accountId;
457         std::string bundleName;
458         std::string storeId;
459         QueryLastResults results;
460     };
461     auto ctxt = std::make_shared<QueryLastSyncInfoContext>();
462     ctxt->GetCbInfo(env, info, [env, ctxt](size_t argc, napi_value *argv) {
463         // less required 2 arguments :: <accountId> <bundleName> , <storeId> is optional
464         ASSERT_BUSINESS_ERR(ctxt, argc >= 2, Status::INVALID_ARGUMENT, "The number of parameters is incorrect.");
465         // 0 is the index of argument accountId
466         int status = JSUtils::Convert2Value(env, argv[0], ctxt->accountId);
467         ASSERT_BUSINESS_ERR(
468             ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT, "The type of accountId must be string.");
469         // 1 is the index of argument bundleName
470         status = JSUtils::Convert2Value(env, argv[1], ctxt->bundleName);
471         ASSERT_BUSINESS_ERR(
472             ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT, "The type of bundleName must be string.");
473 
474         // 3 means <storeId> param exist
475         if (argc >= 3) {
476             napi_valuetype valueType = napi_undefined;
477             // 2 is the index of argument storeId
478             napi_typeof(env, argv[2], &valueType);
479             if (valueType == napi_string) {
480                 // 2 is the index of argument storeId
481                 status = JSUtils::Convert2Value(env, argv[2], ctxt->storeId);
482                 ASSERT_BUSINESS_ERR(
483                     ctxt, status == JSUtils::OK, Status::INVALID_ARGUMENT, "The type of storeId must be string.");
484             }
485         }
486     });
487 
488     ASSERT_NULL(!ctxt->isThrowError, "QueryLastSyncInfo exit");
489 
490     auto execute = [ctxt]() {
491         auto [state, proxy] = CloudManager::GetInstance().GetCloudService();
492         if (proxy == nullptr) {
493             if (state != CloudService::SERVER_UNAVAILABLE) {
494                 state = CloudService::NOT_SUPPORT;
495             }
496             ctxt->status = (GenerateNapiError(state, ctxt->jsCode, ctxt->error) == Status::SUCCESS)
497                                ? napi_ok
498                                : napi_generic_failure;
499             return;
500         }
501         auto [status, results] = proxy->QueryLastSyncInfo(ctxt->accountId, ctxt->bundleName, ctxt->storeId);
502         ctxt->status =
503             (GenerateNapiError(status, ctxt->jsCode, ctxt->error) == Status::SUCCESS) ? napi_ok : napi_generic_failure;
504         ctxt->results = std::move(results);
505     };
506     auto output = [env, ctxt](napi_value &result) {
507         result = JSUtils::Convert2JSValue(env, ctxt->results);
508         ASSERT_VALUE(ctxt, result != nullptr, napi_generic_failure, "output failed");
509     };
510     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
511 }
512 
InitConfig(napi_env env,napi_value exports)513 napi_value JsConfig::InitConfig(napi_env env, napi_value exports)
514 {
515     auto lambda = []() -> std::vector<napi_property_descriptor> {
516         std::vector<napi_property_descriptor> properties = {
517             DECLARE_NAPI_STATIC_FUNCTION("enableCloud", JsConfig::EnableCloud),
518             DECLARE_NAPI_STATIC_FUNCTION("disableCloud", JsConfig::DisableCloud),
519             DECLARE_NAPI_STATIC_FUNCTION("changeAppCloudSwitch", JsConfig::ChangeAppCloudSwitch),
520             DECLARE_NAPI_STATIC_FUNCTION("clear", JsConfig::Clean),
521             DECLARE_NAPI_STATIC_FUNCTION("clean", JsConfig::Clean),
522             DECLARE_NAPI_STATIC_FUNCTION("notifyDataChange", JsConfig::NotifyDataChange),
523             DECLARE_NAPI_STATIC_FUNCTION("queryStatistics", JsConfig::QueryStatistics),
524             DECLARE_NAPI_STATIC_FUNCTION("setGlobalCloudStrategy", JsConfig::SetGlobalCloudStrategy),
525             DECLARE_NAPI_STATIC_FUNCTION("queryLastSyncInfo", JsConfig::QueryLastSyncInfo),
526         };
527         return properties;
528     };
529     auto jsCtor = JSUtils::DefineClass(env, "ohos.data.cloudData", "Config", lambda, JsConfig::New);
530     NAPI_CALL(env, napi_set_named_property(env, exports, "Config", jsCtor));
531     return exports;
532 }