• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "js_distributedobject.h"
17 
18 #include "js_common.h"
19 #include "js_util.h"
20 #include "logger.h"
21 #include "napi_queue.h"
22 #include "objectstore_errors.h"
23 
24 namespace OHOS::ObjectStore {
25 constexpr size_t KEY_SIZE = 64;
26 
JSConstructor(napi_env env,napi_callback_info info)27 napi_value JSDistributedObject::JSConstructor(napi_env env, napi_callback_info info)
28 {
29     LOG_INFO("start");
30     napi_value thisVar = nullptr;
31     void *data = nullptr;
32     napi_status status = napi_get_cb_info(env, info, nullptr, 0, &thisVar, &data);
33     NOT_MATCH_RETURN_NULL(status == napi_ok);
34     return thisVar;
35 }
36 
37 // get(key: string): ValueType;
JSGet(napi_env env,napi_callback_info info)38 napi_value JSDistributedObject::JSGet(napi_env env, napi_callback_info info)
39 {
40     size_t requireArgc = 1;
41     size_t argc = 1;
42     napi_value argv[1] = { 0 };
43     napi_value thisVar = nullptr;
44     void *data = nullptr;
45     char key[KEY_SIZE] = { 0 };
46     size_t keyLen = 0;
47     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
48     NOT_MATCH_RETURN_NULL(status == napi_ok && argc >= requireArgc);
49 
50     status = napi_get_value_string_utf8(env, argv[0], key, KEY_SIZE, &keyLen);
51     NOT_MATCH_RETURN_NULL(status == napi_ok);
52 
53     JSObjectWrapper *wrapper = nullptr;
54     status = napi_unwrap(env, thisVar, (void **)&wrapper);
55     NOT_MATCH_RETURN_NULL(status == napi_ok && wrapper != nullptr && wrapper->GetObject() != nullptr);
56     napi_value result = nullptr;
57     if (wrapper->IsUndefined(key)) {
58         napi_get_undefined(env, &result);
59         return result;
60     }
61     DoGet(env, wrapper, key, result);
62     return result;
63 }
64 
65 // put(key: string, value: ValueType): void;
JSPut(napi_env env,napi_callback_info info)66 napi_value JSDistributedObject::JSPut(napi_env env, napi_callback_info info)
67 {
68     size_t requireArgc = 2;
69     size_t argc = 2;
70     napi_value argv[2] = { 0 };
71     napi_value thisVar = nullptr;
72     char key[KEY_SIZE] = { 0 };
73     size_t keyLen = 0;
74     napi_valuetype valueType;
75     napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
76     NOT_MATCH_RETURN_NULL(status == napi_ok && argc >= requireArgc);
77 
78     status = napi_get_value_string_utf8(env, argv[0], key, KEY_SIZE, &keyLen);
79     NOT_MATCH_RETURN_NULL(status == napi_ok);
80 
81     JSObjectWrapper *wrapper = nullptr;
82     status = napi_unwrap(env, thisVar, (void **)&wrapper);
83     NOT_MATCH_RETURN_NULL(status == napi_ok && wrapper != nullptr && wrapper->GetObject() != nullptr);
84 
85     status = napi_typeof(env, argv[1], &valueType);
86     NOT_MATCH_RETURN_NULL(status == napi_ok);
87     if (valueType == napi_undefined) {
88         wrapper->AddUndefined(key);
89         return nullptr;
90     }
91     wrapper->DeleteUndefined(key);
92     DoPut(env, wrapper, key, valueType, argv[1]);
93     LOG_INFO("put %{public}s success", key);
94     return nullptr;
95 }
96 
GetCons(napi_env env)97 napi_value JSDistributedObject::GetCons(napi_env env)
98 {
99     static thread_local napi_ref g_instance = nullptr;
100     napi_value distributedObjectClass = nullptr;
101     if (g_instance != nullptr) {
102         napi_status status = napi_get_reference_value(env, g_instance, &distributedObjectClass);
103         NOT_MATCH_RETURN_NULL(status == napi_ok);
104         return distributedObjectClass;
105     }
106     const char *distributedObjectName = "DistributedObject";
107     napi_property_descriptor distributedObjectDesc[] = {
108         DECLARE_NAPI_FUNCTION("put", JSDistributedObject::JSPut),
109         DECLARE_NAPI_FUNCTION("get", JSDistributedObject::JSGet),
110         DECLARE_NAPI_FUNCTION("save", JSDistributedObject::JSSave),
111         DECLARE_NAPI_FUNCTION("revokeSave", JSDistributedObject::JSRevokeSave),
112         DECLARE_NAPI_FUNCTION("bindAssetStore", JSDistributedObject::JSBindAssetStore),
113     };
114 
115     napi_status status = napi_define_class(env, distributedObjectName, strlen(distributedObjectName),
116         JSDistributedObject::JSConstructor, nullptr, sizeof(distributedObjectDesc) / sizeof(distributedObjectDesc[0]),
117         distributedObjectDesc, &distributedObjectClass);
118     NOT_MATCH_RETURN_NULL(status == napi_ok);
119     if (g_instance == nullptr) {
120         status = napi_create_reference(env, distributedObjectClass, 1, &g_instance);
121         NOT_MATCH_RETURN_NULL(status == napi_ok);
122     }
123     return distributedObjectClass;
124 }
125 
DoPut(napi_env env,JSObjectWrapper * wrapper,char * key,napi_valuetype type,napi_value value)126 void JSDistributedObject::DoPut(
127     napi_env env, JSObjectWrapper *wrapper, char *key, napi_valuetype type, napi_value value)
128 {
129     std::string keyString = key;
130     switch (type) {
131         case napi_boolean: {
132             bool putValue = false;
133             napi_status status = JSUtil::GetValue(env, value, putValue);
134             NOT_MATCH_RETURN_VOID(status == napi_ok);
135             wrapper->GetObject()->PutBoolean(keyString, putValue);
136             break;
137         }
138         case napi_number: {
139             double putValue = 0;
140             napi_status status = JSUtil::GetValue(env, value, putValue);
141             NOT_MATCH_RETURN_VOID(status == napi_ok);
142             wrapper->GetObject()->PutDouble(keyString, putValue);
143             break;
144         }
145         case napi_string: {
146             std::string putValue;
147             napi_status status = JSUtil::GetValue(env, value, putValue);
148             NOT_MATCH_RETURN_VOID(status == napi_ok);
149             wrapper->GetObject()->PutString(keyString, putValue);
150             break;
151         }
152         case napi_object: {
153             std::vector<uint8_t> putValue;
154             napi_status status = JSUtil::GetValue(env, value, putValue);
155             NOT_MATCH_RETURN_VOID(status == napi_ok);
156             wrapper->GetObject()->PutComplex(keyString, putValue);
157             break;
158         }
159         default: {
160             LOG_ERROR("error type! %{public}d", type);
161             break;
162         }
163     }
164 }
165 
DoGet(napi_env env,JSObjectWrapper * wrapper,char * key,napi_value & value)166 void JSDistributedObject::DoGet(napi_env env, JSObjectWrapper *wrapper, char *key, napi_value &value)
167 {
168     std::string keyString = key;
169     Type type = TYPE_STRING;
170     wrapper->GetObject()->GetType(keyString, type);
171     LOG_DEBUG("get type %{public}s %{public}d", key, type);
172     switch (type) {
173         case TYPE_STRING: {
174             std::string result;
175             uint32_t ret = wrapper->GetObject()->GetString(keyString, result);
176             NOT_MATCH_RETURN_VOID(ret == SUCCESS);
177             napi_status status = JSUtil::SetValue(env, result, value);
178             NOT_MATCH_RETURN_VOID(status == napi_ok);
179             break;
180         }
181         case TYPE_DOUBLE: {
182             double result;
183             uint32_t ret = wrapper->GetObject()->GetDouble(keyString, result);
184             LOG_DEBUG("%{public}f", result);
185             NOT_MATCH_RETURN_VOID(ret == SUCCESS);
186             napi_status status = JSUtil::SetValue(env, result, value);
187             NOT_MATCH_RETURN_VOID(status == napi_ok);
188             break;
189         }
190         case TYPE_BOOLEAN: {
191             bool result;
192             uint32_t ret = wrapper->GetObject()->GetBoolean(keyString, result);
193             LOG_DEBUG("%{public}d", result);
194             NOT_MATCH_RETURN_VOID(ret == SUCCESS);
195             napi_status status = JSUtil::SetValue(env, result, value);
196             NOT_MATCH_RETURN_VOID(status == napi_ok);
197             break;
198         }
199         case TYPE_COMPLEX: {
200             std::vector<uint8_t> result;
201             uint32_t ret = wrapper->GetObject()->GetComplex(keyString, result);
202             NOT_MATCH_RETURN_VOID(ret == SUCCESS);
203             napi_status status = JSUtil::SetValue(env, result, value);
204             NOT_MATCH_RETURN_VOID(status == napi_ok);
205             break;
206         }
207         default: {
208             LOG_ERROR("error type! %{public}d", type);
209             break;
210         }
211     }
212 }
213 
214 // save(deviceId: string, version: number, callback?:AsyncCallback<SaveSuccessResponse>): void;
215 // save(deviceId: string, version: number): Promise<SaveSuccessResponse>;
JSSave(napi_env env,napi_callback_info info)216 napi_value JSDistributedObject::JSSave(napi_env env, napi_callback_info info)
217 {
218     LOG_DEBUG("JSSave()");
219     struct SaveContext : public ContextBase {
220         double version;
221         std::string deviceId;
222         JSObjectWrapper *wrapper;
223     };
224     auto ctxt = std::make_shared<SaveContext>();
225     std::function<void(size_t argc, napi_value * argv)> getCbOpe = [env, ctxt](size_t argc, napi_value *argv) {
226         INVALID_ARGS_RETURN_ERROR(ctxt, argc >= 2, "arguments error", std::make_shared<ParametersNum>("1 or 2"));
227         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->deviceId);
228         INVALID_ARGS_RETURN_ERROR(ctxt, ctxt->status == napi_ok, "arguments error",
229             std::make_shared<ParametersType>("deviceId", "string"));
230 
231         ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->version);
232         INVALID_STATUS_RETURN_ERROR(ctxt, "invalid arg[1], i.e. invalid version!");
233         JSObjectWrapper *wrapper = nullptr;
234         napi_status status = napi_unwrap(env, ctxt->self, (void **)&wrapper);
235         NOT_MATCH_RETURN_VOID(status == napi_ok && wrapper != nullptr && wrapper->GetObject() != nullptr);
236         ctxt->wrapper = wrapper;
237     };
238     ctxt->GetCbInfo(env, info, getCbOpe);
239     NAPI_ASSERT_ERRCODE(env, ctxt->status != napi_invalid_arg, ctxt->error);
240     auto execute = [ctxt]() {
241         LOG_INFO("start");
242         CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null");
243         CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null");
244         uint32_t status = ctxt->wrapper->GetObject()->Save(ctxt->deviceId);
245         INVALID_API_THROW_ERROR(status != ERR_PROCESSING);
246         INVALID_STATUS_THROW_ERROR(status == SUCCESS, "operation failed");
247         ctxt->status = napi_ok;
248         LOG_INFO("end");
249     };
250     auto output = [env, ctxt](napi_value &result) {
251         if (ctxt->status == napi_ok) {
252             CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null");
253             CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null");
254             std::string &sessionId = ctxt->wrapper->GetObject()->GetSessionId();
255             ctxt->status = napi_new_instance(
256                 env, GetSaveResultCons(env, sessionId, ctxt->version, ctxt->deviceId), 0, nullptr, &result);
257             INVALID_STATUS_RETURN_ERROR(ctxt, "output failed!");
258         }
259     };
260     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
261 }
262 
263 // revokeSave(callback?:AsyncCallback<RevokeSaveSuccessResponse>): void;
264 // revokeSave(): Promise<RevokeSaveSuccessResponse>;
JSRevokeSave(napi_env env,napi_callback_info info)265 napi_value JSDistributedObject::JSRevokeSave(napi_env env, napi_callback_info info)
266 {
267     LOG_DEBUG("JSRevokeSave()");
268     struct RevokeSaveContext : public ContextBase {
269         JSObjectWrapper *wrapper;
270     };
271     auto ctxt = std::make_shared<RevokeSaveContext>();
272     std::function<void(size_t argc, napi_value * argv)> getCbOpe = [env, ctxt](size_t argc, napi_value *argv) {
273         // required 1 arguments :: <key>
274         JSObjectWrapper *wrapper = nullptr;
275         napi_status status = napi_unwrap(env, ctxt->self, (void **)&wrapper);
276         NOT_MATCH_RETURN_VOID(status == napi_ok && wrapper != nullptr && wrapper->GetObject() != nullptr);
277         ctxt->wrapper = wrapper;
278     };
279     ctxt->GetCbInfo(env, info, getCbOpe);
280     if (ctxt->status != napi_ok) {
281         napi_throw_error((env), std::to_string(ctxt->error->GetCode()).c_str(), ctxt->error->GetMessage().c_str());
282         return nullptr;
283     }
284     auto execute = [ctxt]() {
285         CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null");
286         CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null");
287         uint32_t status = ctxt->wrapper->GetObject()->RevokeSave();
288         INVALID_API_THROW_ERROR(status != ERR_PROCESSING);
289         INVALID_STATUS_THROW_ERROR(status == SUCCESS, "operation failed");
290         ctxt->status = napi_ok;
291         LOG_INFO("end");
292     };
293     auto output = [env, ctxt](napi_value &result) {
294         if (ctxt->status == napi_ok) {
295             CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null");
296             CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null");
297             ctxt->status = napi_new_instance(env,
298                 JSDistributedObject::GetRevokeSaveResultCons(env, ctxt->wrapper->GetObject()->GetSessionId()), 0,
299                 nullptr, &result);
300             INVALID_STATUS_RETURN_ERROR(ctxt, "output failed!");
301         }
302     };
303     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute, output);
304 }
305 
GetSaveResultCons(napi_env env,std::string & sessionId,double version,std::string deviceId)306 napi_value JSDistributedObject::GetSaveResultCons(
307     napi_env env, std::string &sessionId, double version, std::string deviceId)
308 {
309     const char *objectName = "SaveResult";
310     napi_value napiSessionId, napiVersion, napiDeviceId;
311     napi_value result;
312 
313     napi_status status = JSUtil::SetValue(env, sessionId, napiSessionId);
314     NOT_MATCH_RETURN_NULL(status == napi_ok);
315     status = JSUtil::SetValue(env, version, napiVersion);
316     NOT_MATCH_RETURN_NULL(status == napi_ok);
317     status = JSUtil::SetValue(env, deviceId, napiDeviceId);
318     NOT_MATCH_RETURN_NULL(status == napi_ok);
319     napi_property_descriptor desc[] = {
320         DECLARE_NAPI_PROPERTY("sessionId", napiSessionId),
321         DECLARE_NAPI_PROPERTY("version", napiVersion),
322         DECLARE_NAPI_PROPERTY("deviceId", napiDeviceId)
323     };
324 
325     status = napi_define_class(env, objectName, strlen(objectName), JSDistributedObject::JSConstructor, nullptr,
326         sizeof(desc) / sizeof(desc[0]), desc, &result);
327     NOT_MATCH_RETURN_NULL(status == napi_ok);
328     return result;
329 }
330 
GetRevokeSaveResultCons(napi_env env,std::string & sessionId)331 napi_value JSDistributedObject::GetRevokeSaveResultCons(napi_env env, std::string &sessionId)
332 {
333     const char *objectName = "RevokeSaveResult";
334     napi_value napiSessionId;
335     napi_value result;
336 
337     napi_status status = JSUtil::SetValue(env, sessionId, napiSessionId);
338     NOT_MATCH_RETURN_NULL(status == napi_ok);
339     napi_property_descriptor desc[] = {
340         DECLARE_NAPI_PROPERTY("sessionId", napiSessionId)
341     };
342 
343     status = napi_define_class(env, objectName, strlen(objectName), JSDistributedObject::JSConstructor, nullptr,
344         sizeof(desc) / sizeof(desc[0]), desc, &result);
345     NOT_MATCH_RETURN_NULL(status == napi_ok);
346     return result;
347 }
348 
JSBindAssetStore(napi_env env,napi_callback_info info)349 napi_value JSDistributedObject::JSBindAssetStore(napi_env env, napi_callback_info info)
350 {
351     struct BindAssetStoreContext : public ContextBase {
352         std::string assetKey;
353         AssetBindInfo bindInfo;
354         JSObjectWrapper *wrapper;
355     };
356     auto ctxt = std::make_shared<BindAssetStoreContext>();
357     auto input = [env, ctxt](size_t argc, napi_value *argv) {
358         INVALID_ARGS_RETURN_ERROR(ctxt, argc >= 2, "arguments error", std::make_shared<ParametersNum>("2"));
359         ctxt->status = JSUtil::GetValue(env, argv[0], ctxt->assetKey);
360         INVALID_ARGS_RETURN_ERROR(ctxt, ctxt->status == napi_ok, "arguments error",
361             std::make_shared<ParametersType>("assetKey", "string"));
362 
363         ctxt->status = JSUtil::GetValue(env, argv[1], ctxt->bindInfo);
364         INVALID_ARGS_RETURN_ERROR(ctxt, ctxt->status == napi_ok, "arguments error",
365             std::make_shared<ParametersType>("bindInfo", "BindInfo"));
366         JSObjectWrapper *wrapper = nullptr;
367         napi_status status = napi_unwrap(env, ctxt->self, (void **)&wrapper);
368         NOT_MATCH_RETURN_VOID(status == napi_ok && wrapper != nullptr && wrapper->GetObject() != nullptr);
369         ctxt->wrapper = wrapper;
370     };
371     ctxt->GetCbInfo(env, info, input);
372     NAPI_ASSERT_ERRCODE(env, ctxt->status == napi_ok, ctxt->error);
373     auto execute = [ctxt]() {
374         CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper != nullptr, ctxt, "wrapper is null");
375         CHECH_STATUS_RETURN_VOID(env, ctxt->wrapper->GetObject() != nullptr, ctxt, "object is null");
376         uint32_t status = ctxt->wrapper->GetObject()->BindAssetStore(ctxt->assetKey, ctxt->bindInfo);
377         LOG_INFO("BindAssetStore return: %{public}d", status);
378         INVALID_API_THROW_ERROR(status != ERR_PROCESSING);
379         INVALID_STATUS_THROW_ERROR(status == SUCCESS, "operation failed");
380         ctxt->status = napi_ok;
381     };
382     return NapiQueue::AsyncWork(env, ctxt, std::string(__FUNCTION__), execute);
383 }
384 } // namespace OHOS::ObjectStore