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