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
16 #include "js_storage.h"
17
18 static std::map<std::string, std::string> g_keyValueStorage;
19
20 using namespace StorageBufferSize;
21
Add(napi_env env,napi_value handler)22 void EventListener::Add(napi_env env, napi_value handler)
23 {
24 if (Find(env, handler) != nullptr) {
25 return;
26 }
27
28 if (handlers_ == nullptr) {
29 handlers_ = new EventHandler();
30 handlers_->next = nullptr;
31 } else {
32 auto temp = new EventHandler();
33 temp->next = handlers_;
34 handlers_ = temp;
35 }
36 napi_create_reference(env, handler, 1, &handlers_->callbackRef);
37 }
38
Del(napi_env env,napi_value handler)39 void EventListener::Del(napi_env env, napi_value handler)
40 {
41 EventHandler* temp = nullptr;
42 for (EventHandler* i = handlers_; i != nullptr; i = handlers_) {
43 napi_value callback = nullptr;
44 napi_get_reference_value(env, i->callbackRef, &callback);
45 bool isEquals = false;
46 napi_strict_equals(env, handler, callback, &isEquals);
47 if (isEquals) {
48 if (temp == nullptr) {
49 handlers_ = i->next;
50 } else {
51 temp->next = i->next;
52 }
53 napi_delete_reference(env, i->callbackRef);
54 delete i;
55 } else {
56 temp = i;
57 }
58 }
59 }
60
Clear(napi_env env)61 void EventListener::Clear(napi_env env)
62 {
63 for (EventHandler* i = handlers_; i != nullptr; i = handlers_) {
64 handlers_ = i->next;
65 delete i;
66 }
67 }
68
Find(napi_env env,napi_value handler)69 EventHandler* EventListener::Find(napi_env env, napi_value handler)
70 {
71 EventHandler* result = nullptr;
72 for (EventHandler* i = handlers_; i != nullptr; i = i->next) {
73 napi_value callback = nullptr;
74 napi_get_reference_value(env, i->callbackRef, &callback);
75 bool isEquals = false;
76 napi_strict_equals(env, handler, callback, &isEquals);
77 if (isEquals) {
78 result = i;
79 }
80 }
81 return result;
82 }
83
StorageObjectInfo(napi_env env)84 StorageObjectInfo::StorageObjectInfo(napi_env env) : env_(env), listeners_()
85 {
86 listeners_[STORAGE_EVENT_CHANGE].type_ = "change";
87 listeners_[STORAGE_EVENT_CLEAR].type_ = "clear";
88 listeners_[STORAGE_EVENT_ERROR].type_ = "error";
89 }
90
~StorageObjectInfo()91 StorageObjectInfo::~StorageObjectInfo()
92 {
93 listeners_[STORAGE_EVENT_CHANGE].Clear(env_);
94 listeners_[STORAGE_EVENT_CLEAR].Clear(env_);
95 listeners_[STORAGE_EVENT_ERROR].Clear(env_);
96 }
97
On(const char * type,napi_value handler)98 void StorageObjectInfo::On(const char* type, napi_value handler)
99 {
100 StorageEvent event = Find(type);
101 if (event == STORAGE_EVENT_UNKNOWN) {
102 return;
103 }
104 listeners_[event].Add(env_, handler);
105 }
106
Off(const char * type,napi_value handler)107 void StorageObjectInfo::Off(const char* type, napi_value handler)
108 {
109 StorageEvent event = Find(type);
110 if (event == STORAGE_EVENT_UNKNOWN) {
111 return;
112 }
113 if (handler == nullptr) {
114 listeners_[event].Clear(env_);
115 } else {
116 listeners_[event].Del(env_, handler);
117 }
118 }
119
Emit(napi_value thisArg,const char * type)120 void StorageObjectInfo::Emit(napi_value thisArg, const char* type)
121 {
122 StorageEvent event = Find(type);
123 if (event == STORAGE_EVENT_UNKNOWN) {
124 return;
125 }
126 for (EventHandler* handler = listeners_[event].handlers_; handler != nullptr; handler = handler->next) {
127 if (thisArg == nullptr) {
128 napi_get_undefined(env_, &thisArg);
129 }
130 napi_value callback = nullptr;
131 napi_value result = nullptr;
132 napi_get_reference_value(env_, handler->callbackRef, &callback);
133 napi_call_function(env_, thisArg, callback, 0, nullptr, &result);
134 }
135 }
136
Find(const char * type) const137 StorageEvent StorageObjectInfo::Find(const char* type) const
138 {
139 StorageEvent result = STORAGE_EVENT_UNKNOWN;
140 if (!strcmp(listeners_[STORAGE_EVENT_CHANGE].type_, type)) {
141 result = STORAGE_EVENT_CHANGE;
142 } else if (!strcmp(listeners_[STORAGE_EVENT_CLEAR].type_, type)) {
143 result = STORAGE_EVENT_CLEAR;
144 } else if (!strcmp(listeners_[STORAGE_EVENT_ERROR].type_, type)) {
145 result = STORAGE_EVENT_ERROR;
146 }
147 return result;
148 }
149
GetParameOfGet(napi_env env,size_t argc,napi_value * argv,StorageAsyncContext * asyncContext)150 bool GetParameOfGet(napi_env env, size_t argc, napi_value* argv, StorageAsyncContext* asyncContext)
151 {
152 for (size_t i = 0; i < argc; i++) {
153 napi_valuetype valueType = napi_undefined;
154 napi_typeof(env, argv[i], &valueType);
155 if ((i == 0) && (valueType == napi_string)) {
156 napi_get_value_string_utf8(env, argv[i], asyncContext->key, KEY_BUFFER_SIZE, &asyncContext->keyLen);
157 } else if (valueType == napi_string) {
158 napi_get_value_string_utf8(env, argv[i], asyncContext->value, VALUE_BUFFER_SIZE, &asyncContext->valueLen);
159 } else if (valueType == napi_function) {
160 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
161 break;
162 } else {
163 return false;
164 }
165 }
166 return true;
167 }
168
JSStorageGetParameterFromArg(napi_env env,size_t argc,napi_value * argv,StorageAsyncContext * asyncContext,GetParaType paraType)169 bool JSStorageGetParameterFromArg(napi_env env,
170 size_t argc,
171 napi_value* argv,
172 StorageAsyncContext* asyncContext,
173 GetParaType paraType)
174 {
175 if (paraType == GetParaType::GET) {
176 return GetParameOfGet(env, argc, argv, asyncContext);
177 }
178 for (size_t i = FIRST_ARG; i < argc; i++) {
179 napi_valuetype valueType = napi_undefined;
180 napi_typeof(env, argv[i], &valueType);
181
182 if (i == FIRST_ARG) {
183 if (paraType == GetParaType::CLEAR && valueType == napi_function) {
184 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
185 return true;
186 } else if (valueType == napi_string) {
187 napi_get_value_string_utf8(env, argv[i], asyncContext->key, KEY_BUFFER_SIZE, &asyncContext->keyLen);
188 continue;
189 }
190 return false;
191 } else if (i == SECOND_ARG) {
192 if (paraType == GetParaType::DELETE && valueType == napi_function) {
193 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
194 return true;
195 } else if (valueType == napi_string) {
196 napi_get_value_string_utf8(env, argv[i], asyncContext->value, VALUE_BUFFER_SIZE,
197 &asyncContext->valueLen);
198 continue;
199 }
200 return false;
201 } else if (i == THIRD_ARG && valueType == napi_function) {
202 napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef);
203 } else {
204 return false;
205 }
206 }
207 return true;
208 }
209
CreateAsyncWorkOfGet(napi_env env,StorageAsyncContext * asyncContext,napi_value resource,napi_value result)210 void CreateAsyncWorkOfGet(napi_env env, StorageAsyncContext* asyncContext, napi_value resource, napi_value result)
211 {
212 napi_create_async_work(
213 env, nullptr, resource,
214 [](napi_env env, void* data) {
215 StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
216 auto itr = g_keyValueStorage.find(asyncContext->key);
217 if (itr != g_keyValueStorage.end()) {
218 if (strncpy_s(asyncContext->value, VALUE_BUFFER_SIZE, itr->second.c_str(), itr->second.length()) !=
219 EOK) {
220 asyncContext->status = 1;
221 } else {
222 asyncContext->status = 0;
223 }
224 } else {
225 asyncContext->status = 1;
226 }
227 },
228 [](napi_env env, napi_status status, void* data) {
229 StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
230 napi_value result[2] = { 0 };
231 if (!asyncContext->status) {
232 napi_get_undefined(env, &result[0]);
233 napi_create_string_utf8(env, asyncContext->value, strlen(asyncContext->value), &result[1]);
234 } else {
235 napi_value message = nullptr;
236 napi_create_string_utf8(env, "key does not exist", NAPI_AUTO_LENGTH, &message);
237 napi_create_error(env, nullptr, message, &result[0]);
238 napi_get_undefined(env, &result[1]);
239 asyncContext->objectInfo->Emit(nullptr, "error");
240 }
241 if (asyncContext->deferred) {
242 if (!asyncContext->status) {
243 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
244 } else {
245 napi_reject_deferred(env, asyncContext->deferred, result[0]);
246 }
247 } else {
248 napi_value callback = nullptr;
249 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
250 napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr);
251 napi_delete_reference(env, asyncContext->callbackRef);
252 }
253 napi_delete_async_work(env, asyncContext->work);
254 delete asyncContext;
255 },
256 (void*)asyncContext, &asyncContext->work);
257 napi_queue_async_work(env, asyncContext->work);
258 }
259
CreateAsyncWorkOfSet(napi_env env,StorageAsyncContext * asyncContext,napi_value resource,napi_value result)260 void CreateAsyncWorkOfSet(napi_env env, StorageAsyncContext* asyncContext, napi_value resource, napi_value result)
261 {
262 napi_create_async_work(
263 env, nullptr, resource,
264 [](napi_env env, void* data) {
265 StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
266 auto itr = g_keyValueStorage.find(asyncContext->key);
267 if (itr == g_keyValueStorage.end()) {
268 g_keyValueStorage.insert(std::pair<std::string, std::string>(asyncContext->key, asyncContext->value));
269 asyncContext->status = 0;
270 } else {
271 asyncContext->status = 1;
272 }
273 },
274 [](napi_env env, napi_status status, void* data) {
275 StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
276 napi_value result[2] = { 0 };
277 if (!asyncContext->status) {
278 napi_get_undefined(env, &result[0]);
279 napi_get_undefined(env, &result[1]);
280 asyncContext->objectInfo->Emit(nullptr, "change");
281 } else {
282 napi_value message = nullptr;
283 napi_create_string_utf8(env, "key already exists", NAPI_AUTO_LENGTH, &message);
284 napi_create_error(env, nullptr, message, &result[0]);
285 napi_get_undefined(env, &result[1]);
286 asyncContext->objectInfo->Emit(nullptr, "error");
287 }
288
289 if (asyncContext->deferred) {
290 if (!asyncContext->status) {
291 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
292 } else {
293 napi_reject_deferred(env, asyncContext->deferred, result[0]);
294 }
295 } else {
296 napi_value callback = nullptr;
297 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
298 napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr);
299 napi_delete_reference(env, asyncContext->callbackRef);
300 }
301 napi_delete_async_work(env, asyncContext->work);
302 delete asyncContext;
303 },
304 (void*)asyncContext, &asyncContext->work);
305 napi_queue_async_work(env, asyncContext->work);
306 }
307
CreateAsyncWorkOfDelete(napi_env env,StorageAsyncContext * asyncContext,napi_value resource,napi_value result)308 void CreateAsyncWorkOfDelete(napi_env env, StorageAsyncContext* asyncContext, napi_value resource, napi_value result)
309 {
310 napi_create_async_work(
311 env, nullptr, resource,
312 [](napi_env env, void* data) {
313 StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
314 auto itr = g_keyValueStorage.find(asyncContext->key);
315 if (itr != g_keyValueStorage.end()) {
316 g_keyValueStorage.erase(itr);
317 asyncContext->status = 0;
318 } else {
319 asyncContext->status = 1;
320 }
321 },
322 [](napi_env env, napi_status status, void* data) {
323 StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
324 napi_value result[2] = { 0 };
325 if (!asyncContext->status) {
326 napi_get_undefined(env, &result[0]);
327 napi_get_undefined(env, &result[1]);
328 asyncContext->objectInfo->Emit(nullptr, "change");
329 } else {
330 napi_value message = nullptr;
331 napi_create_string_utf8(env, "key does not exist", NAPI_AUTO_LENGTH, &message);
332 napi_create_error(env, nullptr, message, &result[0]);
333 napi_get_undefined(env, &result[1]);
334 asyncContext->objectInfo->Emit(nullptr, "error");
335 }
336
337 if (asyncContext->deferred) {
338 if (!asyncContext->status) {
339 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
340 } else {
341 napi_reject_deferred(env, asyncContext->deferred, result[0]);
342 }
343 } else {
344 napi_value callback = nullptr;
345 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
346 napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr);
347 napi_delete_reference(env, asyncContext->callbackRef);
348 }
349 napi_delete_async_work(env, asyncContext->work);
350 delete asyncContext;
351 },
352 (void*)asyncContext, &asyncContext->work);
353 napi_queue_async_work(env, asyncContext->work);
354 }
355
CreateAsyncWorkOfClear(napi_env env,StorageAsyncContext * asyncContext,napi_value resource,napi_value result)356 void CreateAsyncWorkOfClear(napi_env env, StorageAsyncContext* asyncContext, napi_value resource, napi_value result)
357 {
358 napi_create_async_work(
359 env, nullptr, resource,
360 [](napi_env env, void* data) {
361 StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
362 auto itr = g_keyValueStorage.find(asyncContext->key);
363 if (itr != g_keyValueStorage.end()) {
364 g_keyValueStorage.erase(itr);
365 asyncContext->status = 0;
366 } else {
367 asyncContext->status = 1;
368 }
369 },
370 [](napi_env env, napi_status status, void* data) {
371 StorageAsyncContext* asyncContext = (StorageAsyncContext*)data;
372 napi_value result[2] = { 0 };
373 if (!asyncContext->status) {
374 napi_get_undefined(env, &result[0]);
375 napi_get_undefined(env, &result[1]);
376 asyncContext->objectInfo->Emit(nullptr, "change");
377 } else {
378 napi_value message = nullptr;
379 napi_create_string_utf8(env, "key does not exist", NAPI_AUTO_LENGTH, &message);
380 napi_create_error(env, nullptr, message, &result[0]);
381 napi_get_undefined(env, &result[1]);
382 asyncContext->objectInfo->Emit(nullptr, "error");
383 }
384
385 if (asyncContext->deferred) {
386 if (!asyncContext->status) {
387 napi_resolve_deferred(env, asyncContext->deferred, result[1]);
388 } else {
389 napi_reject_deferred(env, asyncContext->deferred, result[0]);
390 }
391 } else {
392 napi_value callback = nullptr;
393 napi_get_reference_value(env, asyncContext->callbackRef, &callback);
394 napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr);
395 napi_delete_reference(env, asyncContext->callbackRef);
396 }
397 napi_delete_async_work(env, asyncContext->work);
398 delete asyncContext;
399 },
400 (void*)asyncContext, &asyncContext->work);
401 napi_queue_async_work(env, asyncContext->work);
402 }
403
JSStorageConstructor(napi_env env,napi_callback_info info)404 static napi_value JSStorageConstructor(napi_env env, napi_callback_info info)
405 {
406 napi_value thisVar = nullptr;
407 void* data = nullptr;
408 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
409
410 auto objectInfo = new StorageObjectInfo(env);
411 auto status = napi_wrap(
412 env, thisVar, objectInfo,
413 [](napi_env env, void* data, void* hint) {
414 auto objectInfo = (StorageObjectInfo*)data;
415 if (objectInfo != nullptr) {
416 delete objectInfo;
417 }
418 },
419 nullptr, nullptr);
420 if (status != napi_ok) {
421 delete objectInfo;
422 }
423
424 return thisVar;
425 }
426
427 /***********************************************
428 * Async Function Set
429 ***********************************************/
430
431 // storage.get(key: string, defaultValue?: string, callback?: Function): void | Promise<string>
JSStorageGet(napi_env env,napi_callback_info info)432 static napi_value JSStorageGet(napi_env env, napi_callback_info info)
433 {
434 size_t requireArgc = 1;
435 size_t argc = 3;
436 napi_value argv[3] = { 0 };
437 napi_value thisVar = nullptr;
438 void* data = nullptr;
439 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
440
441 NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter");
442
443 auto asyncContext = new StorageAsyncContext();
444
445 asyncContext->env = env;
446
447 if (!JSStorageGetParameterFromArg(env, argc, argv, asyncContext, GetParaType::GET)) {
448 NAPI_ASSERT(env, false, "type mismatch");
449 }
450
451 napi_value result = nullptr;
452
453 if (asyncContext->callbackRef == nullptr) {
454 napi_create_promise(env, &asyncContext->deferred, &result);
455 } else {
456 napi_get_undefined(env, &result);
457 }
458
459 napi_unwrap(env, thisVar, (void**)&asyncContext->objectInfo);
460
461 napi_value resource = nullptr;
462 napi_create_string_utf8(env, "JSStorageGet", NAPI_AUTO_LENGTH, &resource);
463
464 CreateAsyncWorkOfGet(env, asyncContext, resource, result);
465
466 return result;
467 }
468
469 // storage.set(key: string, value: string, callback?: Function): void | Promise<void>
JSStorageSet(napi_env env,napi_callback_info info)470 static napi_value JSStorageSet(napi_env env, napi_callback_info info)
471 {
472 size_t requireArgc = 2;
473 size_t argc = 3;
474 napi_value argv[3] = { 0 };
475 napi_value thisVar = nullptr;
476 void* data = nullptr;
477 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
478
479 NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameters");
480 auto asyncContext = new StorageAsyncContext();
481 asyncContext->env = env;
482
483 if (!JSStorageGetParameterFromArg(env, argc, argv, asyncContext, GetParaType::SET)) {
484 NAPI_ASSERT(env, false, "type mismatch");
485 }
486
487 napi_value result = nullptr;
488
489 if (asyncContext->callbackRef == nullptr) {
490 napi_create_promise(env, &asyncContext->deferred, &result);
491 } else {
492 napi_get_undefined(env, &result);
493 }
494
495 napi_unwrap(env, thisVar, (void**)&asyncContext->objectInfo);
496
497 napi_value resource = nullptr;
498 napi_create_string_utf8(env, "JStorageSet", NAPI_AUTO_LENGTH, &resource);
499
500 CreateAsyncWorkOfSet(env, asyncContext, resource, result);
501
502 return result;
503 }
504
505 // storage.delete(key: string, callback?: Function): void | Promise<void>
JSStorageDelete(napi_env env,napi_callback_info info)506 static napi_value JSStorageDelete(napi_env env, napi_callback_info info)
507 {
508 size_t requireArgc = 1;
509 size_t argc = 2;
510 napi_value argv[2] = { 0 };
511 napi_value thisVar = nullptr;
512 void* data = nullptr;
513 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
514
515 NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter");
516
517 auto asyncContext = new StorageAsyncContext();
518
519 asyncContext->env = env;
520
521 if (!JSStorageGetParameterFromArg(env, argc, argv, asyncContext, GetParaType::DELETE)) {
522 NAPI_ASSERT(env, false, "type mismatch");
523 }
524
525 napi_value result = nullptr;
526
527 if (asyncContext->callbackRef == nullptr) {
528 napi_create_promise(env, &asyncContext->deferred, &result);
529 } else {
530 napi_get_undefined(env, &result);
531 }
532
533 napi_unwrap(env, thisVar, (void**)&asyncContext->objectInfo);
534
535 napi_value resource = nullptr;
536 napi_create_string_utf8(env, "JSStorageDelete", NAPI_AUTO_LENGTH, &resource);
537
538 CreateAsyncWorkOfDelete(env, asyncContext, resource, result);
539
540 return result;
541 }
542
543 // storage.clear(callback?: Function): void | Promise<void>
JSStorageClear(napi_env env,napi_callback_info info)544 static napi_value JSStorageClear(napi_env env, napi_callback_info info)
545 {
546 size_t argc = 1;
547 napi_value argv[1] = { 0 };
548 napi_value thisVar = nullptr;
549 void* data = nullptr;
550 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
551
552 auto asyncContext = new StorageAsyncContext();
553
554 asyncContext->env = env;
555
556 if (!JSStorageGetParameterFromArg(env, argc, argv, asyncContext, GetParaType::CLEAR)) {
557 NAPI_ASSERT(env, false, "type mismatch");
558 }
559
560 napi_value result = nullptr;
561
562 if (asyncContext->callbackRef == nullptr) {
563 napi_create_promise(env, &asyncContext->deferred, &result);
564 } else {
565 napi_get_undefined(env, &result);
566 }
567
568 napi_unwrap(env, thisVar, (void**)&asyncContext->objectInfo);
569
570 napi_value resource = nullptr;
571 napi_create_string_utf8(env, "JSStorageClear", NAPI_AUTO_LENGTH, &resource);
572
573 CreateAsyncWorkOfClear(env, asyncContext, resource, result);
574
575 return result;
576 }
577
578 /***********************************************
579 * Sync Function Set
580 ***********************************************/
581 // storage.getSync(key: string, defaultValue?: string): string
JSStorageGetSync(napi_env env,napi_callback_info info)582 static napi_value JSStorageGetSync(napi_env env, napi_callback_info info)
583 {
584 size_t requireArgc = 1;
585 size_t argc = 2;
586 napi_value argv[2] = { 0 };
587 napi_value thisVar = nullptr;
588 void* data = nullptr;
589 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
590
591 NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter");
592
593 char key[KEY_BUFFER_SIZE] = { 0 };
594 size_t keyLen = 0;
595 char value[VALUE_BUFFER_SIZE] = { 0 };
596 size_t valueLen = 0;
597 for (size_t i = 0; i < argc; i++) {
598 napi_valuetype valueType = napi_undefined;
599 napi_typeof(env, argv[i], &valueType);
600
601 if (i == FIRST_ARG && valueType == napi_string) {
602 napi_get_value_string_utf8(env, argv[i], key, KEY_BUFFER_SIZE, &keyLen);
603 } else if (i == SECOND_ARG && valueType == napi_string) {
604 napi_get_value_string_utf8(env, argv[i], value, VALUE_BUFFER_SIZE, &valueLen);
605 break;
606 } else {
607 NAPI_ASSERT(env, false, "type mismatch");
608 }
609 }
610 StorageObjectInfo* objectInfo = nullptr;
611 napi_unwrap(env, thisVar, (void**)&objectInfo);
612 auto itr = g_keyValueStorage.find(key);
613 napi_value result = nullptr;
614 if (itr != g_keyValueStorage.end()) {
615 napi_create_string_utf8(env, itr->second.c_str(), itr->second.length(), &result);
616 } else if (valueLen > 0) {
617 napi_create_string_utf8(env, value, valueLen, &result);
618 } else {
619 if (objectInfo != nullptr) {
620 objectInfo->Emit(nullptr, "error");
621 }
622 NAPI_ASSERT(env, false, "key does not exist");
623 }
624 return result;
625 }
626
627 // storage.setSync(key: string, value: string): void
JSStorageSetSync(napi_env env,napi_callback_info info)628 static napi_value JSStorageSetSync(napi_env env, napi_callback_info info)
629 {
630 size_t requireArgc = 2;
631 size_t argc = 2;
632 napi_value argv[2] = { 0 };
633 napi_value thisVar = nullptr;
634 void* data = nullptr;
635 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
636
637 NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameters");
638
639 char key[KEY_BUFFER_SIZE] = { 0 };
640 size_t keyLen = 0;
641 char value[VALUE_BUFFER_SIZE] = { 0 };
642 size_t valueLen = 0;
643 for (size_t i = 0; i < argc; i++) {
644 napi_valuetype valueType = napi_undefined;
645 napi_typeof(env, argv[i], &valueType);
646
647 if (i == FIRST_ARG && valueType == napi_string) {
648 napi_get_value_string_utf8(env, argv[i], key, KEY_BUFFER_SIZE, &keyLen);
649 } else if (i == SECOND_ARG && valueType == napi_string) {
650 napi_get_value_string_utf8(env, argv[i], value, VALUE_BUFFER_SIZE, &valueLen);
651 break;
652 } else {
653 NAPI_ASSERT(env, false, "type mismatch");
654 }
655 }
656 StorageObjectInfo* objectInfo = nullptr;
657 napi_unwrap(env, thisVar, (void**)&objectInfo);
658 auto itr = g_keyValueStorage.find(key);
659 if (itr == g_keyValueStorage.end()) {
660 g_keyValueStorage.insert(std::pair<std::string, std::string>(key, value));
661 objectInfo->Emit(nullptr, "change");
662 } else {
663 objectInfo->Emit(nullptr, "error");
664 NAPI_ASSERT(env, false, "key already exists");
665 }
666 napi_value result = nullptr;
667 napi_get_undefined(env, &result);
668 return result;
669 }
670
671 // storage.deleteSync(key: string): void
JSStorageDeleteSync(napi_env env,napi_callback_info info)672 static napi_value JSStorageDeleteSync(napi_env env, napi_callback_info info)
673 {
674 size_t requireArgc = 1;
675 size_t argc = 2;
676 napi_value argv[2] = { 0 };
677 napi_value thisVar = nullptr;
678 void* data = nullptr;
679 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
680
681 NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter");
682
683 char key[KEY_BUFFER_SIZE] = { 0 };
684 size_t keyLen = 0;
685
686 napi_valuetype keyType = napi_undefined;
687 napi_typeof(env, argv[0], &keyType);
688 NAPI_ASSERT(env, keyType == napi_string, "type mismatch");
689 napi_get_value_string_utf8(env, argv[0], key, KEY_BUFFER_SIZE, &keyLen);
690
691 StorageObjectInfo* objectInfo = nullptr;
692 napi_unwrap(env, thisVar, (void**)&objectInfo);
693
694 auto itr = g_keyValueStorage.find(key);
695 if (itr != g_keyValueStorage.end()) {
696 g_keyValueStorage.erase(itr);
697 objectInfo->Emit(nullptr, "change");
698 } else {
699 objectInfo->Emit(nullptr, "error");
700 NAPI_ASSERT(env, itr != g_keyValueStorage.end(), "key does not exist");
701 }
702
703 napi_value result = nullptr;
704 napi_get_undefined(env, &result);
705 return result;
706 }
707
708 // storage.clearSync(): void
JSStorageClearSync(napi_env env,napi_callback_info info)709 static napi_value JSStorageClearSync(napi_env env, napi_callback_info info)
710 {
711 napi_value thisVar = nullptr;
712 void* data = nullptr;
713 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data);
714
715 StorageObjectInfo* objectInfo = nullptr;
716 napi_unwrap(env, thisVar, (void**)&objectInfo);
717 g_keyValueStorage.clear();
718 objectInfo->Emit(nullptr, "clear");
719 napi_value result = nullptr;
720 napi_get_undefined(env, &result);
721 return result;
722 }
723
724 /***********************************************
725 * Event Function Set
726 ***********************************************/
727 // storage.on(event: "change" | "clear", callback: Function): void
JSStorageOn(napi_env env,napi_callback_info info)728 static napi_value JSStorageOn(napi_env env, napi_callback_info info)
729 {
730 size_t requireArgc = 2;
731 size_t argc = 2;
732 napi_value argv[2] = { 0 };
733 napi_value thisVar = nullptr;
734 void* data = nullptr;
735 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
736
737 NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameters");
738
739 char eventType[EVENT_TYPE_SIZE] = { 0 };
740 size_t eventTypeLen = 0;
741 napi_valuetype eventValueType = napi_undefined;
742 napi_typeof(env, argv[0], &eventValueType);
743 NAPI_ASSERT(env, eventValueType == napi_string, "parameter 1 type mismatch");
744 napi_get_value_string_utf8(env, argv[0], eventType, EVENT_TYPE_SIZE, &eventTypeLen);
745
746 napi_valuetype callbackType = napi_undefined;
747 napi_typeof(env, argv[1], &callbackType);
748 NAPI_ASSERT(env, callbackType == napi_function, "parameter 2 type mismatch");
749
750 StorageObjectInfo* objectInfo = nullptr;
751 napi_unwrap(env, thisVar, (void**)&objectInfo);
752
753 objectInfo->On(eventType, argv[1]);
754
755 napi_value result = nullptr;
756 napi_get_undefined(env, &result);
757 return result;
758 }
759
760 // storage.off(event: "change" | "clear", callback?: Function): void
JSStorageOff(napi_env env,napi_callback_info info)761 static napi_value JSStorageOff(napi_env env, napi_callback_info info)
762 {
763 size_t requireArgc = 1;
764 size_t argc = 2;
765 napi_value argv[2] = { 0 };
766 napi_value thisVar = nullptr;
767 void* data = nullptr;
768 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
769
770 NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter");
771
772 char eventType[EVENT_TYPE_SIZE] = { 0 };
773 size_t eventTypeLen = 0;
774 napi_valuetype eventValueType = napi_undefined;
775 napi_typeof(env, argv[0], &eventValueType);
776 NAPI_ASSERT(env, eventValueType == napi_string, "parameter 1 type mismatch");
777 napi_get_value_string_utf8(env, argv[0], eventType, EVENT_TYPE_SIZE, &eventTypeLen);
778
779 StorageObjectInfo* objectInfo = nullptr;
780 napi_unwrap(env, thisVar, (void**)&objectInfo);
781
782 if (argc > requireArgc) {
783 napi_valuetype callbackType = napi_undefined;
784 napi_typeof(env, argv[1], &callbackType);
785 NAPI_ASSERT(env, callbackType == napi_function, "parameter 2 type mismatch");
786 objectInfo->Off(eventType, argv[1]);
787 } else {
788 objectInfo->Off(eventType);
789 }
790
791 napi_value result = nullptr;
792 napi_get_undefined(env, &result);
793 return result;
794 }
795
796 /***********************************************
797 * Module export and register
798 ***********************************************/
StorageExport(napi_env env,napi_value exports)799 static napi_value StorageExport(napi_env env, napi_value exports)
800 {
801 const char* storageClassName = "Storage";
802 napi_value storageClass = nullptr;
803 static napi_property_descriptor storageDesc[] = {
804 DECLARE_NAPI_FUNCTION("get", JSStorageGet),
805 DECLARE_NAPI_FUNCTION("set", JSStorageSet),
806 DECLARE_NAPI_FUNCTION("delete", JSStorageDelete),
807 DECLARE_NAPI_FUNCTION("clear", JSStorageClear),
808 DECLARE_NAPI_FUNCTION("getSync", JSStorageGetSync),
809 DECLARE_NAPI_FUNCTION("setSync", JSStorageSetSync),
810 DECLARE_NAPI_FUNCTION("deleteSync", JSStorageDeleteSync),
811 DECLARE_NAPI_FUNCTION("clearSync", JSStorageClearSync),
812 DECLARE_NAPI_FUNCTION("on", JSStorageOn),
813 DECLARE_NAPI_FUNCTION("off", JSStorageOff),
814 };
815 napi_define_class(env, storageClassName, strlen(storageClassName), JSStorageConstructor, nullptr,
816 sizeof(storageDesc) / sizeof(storageDesc[0]), storageDesc, &storageClass);
817
818 static napi_property_descriptor desc[] = {
819 DECLARE_NAPI_PROPERTY("Storage", storageClass),
820 };
821
822 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
823 return exports;
824 }
825
826 // storage module define
827 static napi_module storageModule = {
828 .nm_version = 1,
829 .nm_flags = 0,
830 .nm_filename = nullptr,
831 .nm_register_func = StorageExport,
832 .nm_modname = "storage",
833 .nm_priv = ((void*)0),
834 .reserved = { 0 },
835 };
836
837 // storage module register
StorageRegister()838 extern "C" __attribute__((constructor)) void StorageRegister()
839 {
840 napi_module_register(&storageModule);
841 }
842