• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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