/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "js_storage.h" static std::map<std::string, std::string> g_keyValueStorage; using namespace StorageBufferSize; void EventListener::Add(napi_env env, napi_value handler) { if (Find(env, handler) != nullptr) { return; } if (handlers_ == nullptr) { handlers_ = new EventHandler(); handlers_->next = nullptr; } else { auto temp = new EventHandler(); temp->next = handlers_; handlers_ = temp; } napi_create_reference(env, handler, 1, &handlers_->callbackRef); } void EventListener::Del(napi_env env, napi_value handler) { EventHandler* temp = nullptr; for (EventHandler* i = handlers_; i != nullptr; i = handlers_) { napi_value callback = nullptr; napi_get_reference_value(env, i->callbackRef, &callback); bool isEquals = false; napi_strict_equals(env, handler, callback, &isEquals); if (isEquals) { if (temp == nullptr) { handlers_ = i->next; } else { temp->next = i->next; } napi_delete_reference(env, i->callbackRef); delete i; } else { temp = i; } } } void EventListener::Clear(napi_env env) { for (EventHandler* i = handlers_; i != nullptr; i = handlers_) { handlers_ = i->next; delete i; } } EventHandler* EventListener::Find(napi_env env, napi_value handler) { EventHandler* result = nullptr; for (EventHandler* i = handlers_; i != nullptr; i = i->next) { napi_value callback = nullptr; napi_get_reference_value(env, i->callbackRef, &callback); bool isEquals = false; napi_strict_equals(env, handler, callback, &isEquals); if (isEquals) { result = i; } } return result; } StorageObjectInfo::StorageObjectInfo(napi_env env) : env_(env), listeners_() { listeners_[STORAGE_EVENT_CHANGE].type_ = "change"; listeners_[STORAGE_EVENT_CLEAR].type_ = "clear"; listeners_[STORAGE_EVENT_ERROR].type_ = "error"; } StorageObjectInfo::~StorageObjectInfo() { listeners_[STORAGE_EVENT_CHANGE].Clear(env_); listeners_[STORAGE_EVENT_CLEAR].Clear(env_); listeners_[STORAGE_EVENT_ERROR].Clear(env_); } void StorageObjectInfo::On(const char* type, napi_value handler) { StorageEvent event = Find(type); if (event == STORAGE_EVENT_UNKNOWN) { return; } listeners_[event].Add(env_, handler); } void StorageObjectInfo::Off(const char* type, napi_value handler) { StorageEvent event = Find(type); if (event == STORAGE_EVENT_UNKNOWN) { return; } if (handler == nullptr) { listeners_[event].Clear(env_); } else { listeners_[event].Del(env_, handler); } } void StorageObjectInfo::Emit(napi_value thisArg, const char* type) { StorageEvent event = Find(type); if (event == STORAGE_EVENT_UNKNOWN) { return; } for (EventHandler* handler = listeners_[event].handlers_; handler != nullptr; handler = handler->next) { if (thisArg == nullptr) { napi_get_undefined(env_, &thisArg); } napi_value callback = nullptr; napi_value result = nullptr; napi_get_reference_value(env_, handler->callbackRef, &callback); napi_call_function(env_, thisArg, callback, 0, nullptr, &result); } } StorageEvent StorageObjectInfo::Find(const char* type) const { StorageEvent result = STORAGE_EVENT_UNKNOWN; if (!strcmp(listeners_[STORAGE_EVENT_CHANGE].type_, type)) { result = STORAGE_EVENT_CHANGE; } else if (!strcmp(listeners_[STORAGE_EVENT_CLEAR].type_, type)) { result = STORAGE_EVENT_CLEAR; } else if (!strcmp(listeners_[STORAGE_EVENT_ERROR].type_, type)) { result = STORAGE_EVENT_ERROR; } return result; } bool GetParameOfGet(napi_env env, size_t argc, napi_value* argv, StorageAsyncContext* asyncContext) { for (size_t i = 0; i < argc; i++) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv[i], &valueType); if ((i == 0) && (valueType == napi_string)) { napi_get_value_string_utf8(env, argv[i], asyncContext->key, KEY_BUFFER_SIZE, &asyncContext->keyLen); } else if (valueType == napi_string) { napi_get_value_string_utf8(env, argv[i], asyncContext->value, VALUE_BUFFER_SIZE, &asyncContext->valueLen); } else if (valueType == napi_function) { napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef); break; } else { return false; } } return true; } bool JSStorageGetParameterFromArg(napi_env env, size_t argc, napi_value* argv, StorageAsyncContext* asyncContext, GetParaType paraType) { if (paraType == GetParaType::GET) { return GetParameOfGet(env, argc, argv, asyncContext); } for (size_t i = FIRST_ARG; i < argc; i++) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv[i], &valueType); if (i == FIRST_ARG) { if (paraType == GetParaType::CLEAR && valueType == napi_function) { napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef); return true; } else if (valueType == napi_string) { napi_get_value_string_utf8(env, argv[i], asyncContext->key, KEY_BUFFER_SIZE, &asyncContext->keyLen); continue; } return false; } else if (i == SECOND_ARG) { if (paraType == GetParaType::DELETE && valueType == napi_function) { napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef); return true; } else if (valueType == napi_string) { napi_get_value_string_utf8(env, argv[i], asyncContext->value, VALUE_BUFFER_SIZE, &asyncContext->valueLen); continue; } return false; } else if (i == THIRD_ARG && valueType == napi_function) { napi_create_reference(env, argv[i], 1, &asyncContext->callbackRef); } else { return false; } } return true; } void CreateAsyncWorkOfGet(napi_env env, StorageAsyncContext* asyncContext, napi_value resource, napi_value result) { napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; auto itr = g_keyValueStorage.find(asyncContext->key); if (itr != g_keyValueStorage.end()) { if (strncpy_s(asyncContext->value, VALUE_BUFFER_SIZE, itr->second.c_str(), itr->second.length()) != EOK) { asyncContext->status = 1; } else { asyncContext->status = 0; } } else { asyncContext->status = 1; } }, [](napi_env env, napi_status status, void* data) { StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; napi_value result[2] = { 0 }; if (!asyncContext->status) { napi_get_undefined(env, &result[0]); napi_create_string_utf8(env, asyncContext->value, strlen(asyncContext->value), &result[1]); } else { napi_value message = nullptr; napi_create_string_utf8(env, "key does not exist", NAPI_AUTO_LENGTH, &message); napi_create_error(env, nullptr, message, &result[0]); napi_get_undefined(env, &result[1]); asyncContext->objectInfo->Emit(nullptr, "error"); } if (asyncContext->deferred) { if (!asyncContext->status) { napi_resolve_deferred(env, asyncContext->deferred, result[1]); } else { napi_reject_deferred(env, asyncContext->deferred, result[0]); } } else { napi_value callback = nullptr; napi_get_reference_value(env, asyncContext->callbackRef, &callback); napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr); napi_delete_reference(env, asyncContext->callbackRef); } napi_delete_async_work(env, asyncContext->work); delete asyncContext; }, (void*)asyncContext, &asyncContext->work); napi_queue_async_work(env, asyncContext->work); } void CreateAsyncWorkOfSet(napi_env env, StorageAsyncContext* asyncContext, napi_value resource, napi_value result) { napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; auto itr = g_keyValueStorage.find(asyncContext->key); if (itr == g_keyValueStorage.end()) { g_keyValueStorage.insert(std::pair<std::string, std::string>(asyncContext->key, asyncContext->value)); asyncContext->status = 0; } else { asyncContext->status = 1; } }, [](napi_env env, napi_status status, void* data) { StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; napi_value result[2] = { 0 }; if (!asyncContext->status) { napi_get_undefined(env, &result[0]); napi_get_undefined(env, &result[1]); asyncContext->objectInfo->Emit(nullptr, "change"); } else { napi_value message = nullptr; napi_create_string_utf8(env, "key already exists", NAPI_AUTO_LENGTH, &message); napi_create_error(env, nullptr, message, &result[0]); napi_get_undefined(env, &result[1]); asyncContext->objectInfo->Emit(nullptr, "error"); } if (asyncContext->deferred) { if (!asyncContext->status) { napi_resolve_deferred(env, asyncContext->deferred, result[1]); } else { napi_reject_deferred(env, asyncContext->deferred, result[0]); } } else { napi_value callback = nullptr; napi_get_reference_value(env, asyncContext->callbackRef, &callback); napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr); napi_delete_reference(env, asyncContext->callbackRef); } napi_delete_async_work(env, asyncContext->work); delete asyncContext; }, (void*)asyncContext, &asyncContext->work); napi_queue_async_work(env, asyncContext->work); } void CreateAsyncWorkOfDelete(napi_env env, StorageAsyncContext* asyncContext, napi_value resource, napi_value result) { napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; auto itr = g_keyValueStorage.find(asyncContext->key); if (itr != g_keyValueStorage.end()) { g_keyValueStorage.erase(itr); asyncContext->status = 0; } else { asyncContext->status = 1; } }, [](napi_env env, napi_status status, void* data) { StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; napi_value result[2] = { 0 }; if (!asyncContext->status) { napi_get_undefined(env, &result[0]); napi_get_undefined(env, &result[1]); asyncContext->objectInfo->Emit(nullptr, "change"); } else { napi_value message = nullptr; napi_create_string_utf8(env, "key does not exist", NAPI_AUTO_LENGTH, &message); napi_create_error(env, nullptr, message, &result[0]); napi_get_undefined(env, &result[1]); asyncContext->objectInfo->Emit(nullptr, "error"); } if (asyncContext->deferred) { if (!asyncContext->status) { napi_resolve_deferred(env, asyncContext->deferred, result[1]); } else { napi_reject_deferred(env, asyncContext->deferred, result[0]); } } else { napi_value callback = nullptr; napi_get_reference_value(env, asyncContext->callbackRef, &callback); napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr); napi_delete_reference(env, asyncContext->callbackRef); } napi_delete_async_work(env, asyncContext->work); delete asyncContext; }, (void*)asyncContext, &asyncContext->work); napi_queue_async_work(env, asyncContext->work); } void CreateAsyncWorkOfClear(napi_env env, StorageAsyncContext* asyncContext, napi_value resource, napi_value result) { napi_create_async_work( env, nullptr, resource, [](napi_env env, void* data) { StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; auto itr = g_keyValueStorage.find(asyncContext->key); if (itr != g_keyValueStorage.end()) { g_keyValueStorage.erase(itr); asyncContext->status = 0; } else { asyncContext->status = 1; } }, [](napi_env env, napi_status status, void* data) { StorageAsyncContext* asyncContext = (StorageAsyncContext*)data; napi_value result[2] = { 0 }; if (!asyncContext->status) { napi_get_undefined(env, &result[0]); napi_get_undefined(env, &result[1]); asyncContext->objectInfo->Emit(nullptr, "change"); } else { napi_value message = nullptr; napi_create_string_utf8(env, "key does not exist", NAPI_AUTO_LENGTH, &message); napi_create_error(env, nullptr, message, &result[0]); napi_get_undefined(env, &result[1]); asyncContext->objectInfo->Emit(nullptr, "error"); } if (asyncContext->deferred) { if (!asyncContext->status) { napi_resolve_deferred(env, asyncContext->deferred, result[1]); } else { napi_reject_deferred(env, asyncContext->deferred, result[0]); } } else { napi_value callback = nullptr; napi_get_reference_value(env, asyncContext->callbackRef, &callback); napi_call_function(env, nullptr, callback, sizeof(result) / sizeof(result[0]), result, nullptr); napi_delete_reference(env, asyncContext->callbackRef); } napi_delete_async_work(env, asyncContext->work); delete asyncContext; }, (void*)asyncContext, &asyncContext->work); napi_queue_async_work(env, asyncContext->work); } static napi_value JSStorageConstructor(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data); auto objectInfo = new StorageObjectInfo(env); auto status = napi_wrap( env, thisVar, objectInfo, [](napi_env env, void* data, void* hint) { auto objectInfo = (StorageObjectInfo*)data; if (objectInfo != nullptr) { delete objectInfo; } }, nullptr, nullptr); if (status != napi_ok) { delete objectInfo; } return thisVar; } /*********************************************** * Async Function Set ***********************************************/ // storage.get(key: string, defaultValue?: string, callback?: Function): void | Promise<string> static napi_value JSStorageGet(napi_env env, napi_callback_info info) { size_t requireArgc = 1; size_t argc = 3; napi_value argv[3] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter"); auto asyncContext = new StorageAsyncContext(); asyncContext->env = env; if (!JSStorageGetParameterFromArg(env, argc, argv, asyncContext, GetParaType::GET)) { NAPI_ASSERT(env, false, "type mismatch"); } napi_value result = nullptr; if (asyncContext->callbackRef == nullptr) { napi_create_promise(env, &asyncContext->deferred, &result); } else { napi_get_undefined(env, &result); } napi_unwrap(env, thisVar, (void**)&asyncContext->objectInfo); napi_value resource = nullptr; napi_create_string_utf8(env, "JSStorageGet", NAPI_AUTO_LENGTH, &resource); CreateAsyncWorkOfGet(env, asyncContext, resource, result); return result; } // storage.set(key: string, value: string, callback?: Function): void | Promise<void> static napi_value JSStorageSet(napi_env env, napi_callback_info info) { size_t requireArgc = 2; size_t argc = 3; napi_value argv[3] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameters"); auto asyncContext = new StorageAsyncContext(); asyncContext->env = env; if (!JSStorageGetParameterFromArg(env, argc, argv, asyncContext, GetParaType::SET)) { NAPI_ASSERT(env, false, "type mismatch"); } napi_value result = nullptr; if (asyncContext->callbackRef == nullptr) { napi_create_promise(env, &asyncContext->deferred, &result); } else { napi_get_undefined(env, &result); } napi_unwrap(env, thisVar, (void**)&asyncContext->objectInfo); napi_value resource = nullptr; napi_create_string_utf8(env, "JStorageSet", NAPI_AUTO_LENGTH, &resource); CreateAsyncWorkOfSet(env, asyncContext, resource, result); return result; } // storage.delete(key: string, callback?: Function): void | Promise<void> static napi_value JSStorageDelete(napi_env env, napi_callback_info info) { size_t requireArgc = 1; size_t argc = 2; napi_value argv[2] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter"); auto asyncContext = new StorageAsyncContext(); asyncContext->env = env; if (!JSStorageGetParameterFromArg(env, argc, argv, asyncContext, GetParaType::DELETE)) { NAPI_ASSERT(env, false, "type mismatch"); } napi_value result = nullptr; if (asyncContext->callbackRef == nullptr) { napi_create_promise(env, &asyncContext->deferred, &result); } else { napi_get_undefined(env, &result); } napi_unwrap(env, thisVar, (void**)&asyncContext->objectInfo); napi_value resource = nullptr; napi_create_string_utf8(env, "JSStorageDelete", NAPI_AUTO_LENGTH, &resource); CreateAsyncWorkOfDelete(env, asyncContext, resource, result); return result; } // storage.clear(callback?: Function): void | Promise<void> static napi_value JSStorageClear(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value argv[1] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); auto asyncContext = new StorageAsyncContext(); asyncContext->env = env; if (!JSStorageGetParameterFromArg(env, argc, argv, asyncContext, GetParaType::CLEAR)) { NAPI_ASSERT(env, false, "type mismatch"); } napi_value result = nullptr; if (asyncContext->callbackRef == nullptr) { napi_create_promise(env, &asyncContext->deferred, &result); } else { napi_get_undefined(env, &result); } napi_unwrap(env, thisVar, (void**)&asyncContext->objectInfo); napi_value resource = nullptr; napi_create_string_utf8(env, "JSStorageClear", NAPI_AUTO_LENGTH, &resource); CreateAsyncWorkOfClear(env, asyncContext, resource, result); return result; } /*********************************************** * Sync Function Set ***********************************************/ // storage.getSync(key: string, defaultValue?: string): string static napi_value JSStorageGetSync(napi_env env, napi_callback_info info) { size_t requireArgc = 1; size_t argc = 2; napi_value argv[2] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter"); char key[KEY_BUFFER_SIZE] = { 0 }; size_t keyLen = 0; char value[VALUE_BUFFER_SIZE] = { 0 }; size_t valueLen = 0; for (size_t i = 0; i < argc; i++) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv[i], &valueType); if (i == FIRST_ARG && valueType == napi_string) { napi_get_value_string_utf8(env, argv[i], key, KEY_BUFFER_SIZE, &keyLen); } else if (i == SECOND_ARG && valueType == napi_string) { napi_get_value_string_utf8(env, argv[i], value, VALUE_BUFFER_SIZE, &valueLen); break; } else { NAPI_ASSERT(env, false, "type mismatch"); } } StorageObjectInfo* objectInfo = nullptr; napi_unwrap(env, thisVar, (void**)&objectInfo); auto itr = g_keyValueStorage.find(key); napi_value result = nullptr; if (itr != g_keyValueStorage.end()) { napi_create_string_utf8(env, itr->second.c_str(), itr->second.length(), &result); } else if (valueLen > 0) { napi_create_string_utf8(env, value, valueLen, &result); } else { objectInfo->Emit(nullptr, "error"); NAPI_ASSERT(env, false, "key does not exist"); } return result; } // storage.setSync(key: string, value: string): void static napi_value JSStorageSetSync(napi_env env, napi_callback_info info) { size_t requireArgc = 2; size_t argc = 2; napi_value argv[2] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameters"); char key[KEY_BUFFER_SIZE] = { 0 }; size_t keyLen = 0; char value[VALUE_BUFFER_SIZE] = { 0 }; size_t valueLen = 0; for (size_t i = 0; i < argc; i++) { napi_valuetype valueType = napi_undefined; napi_typeof(env, argv[i], &valueType); if (i == FIRST_ARG && valueType == napi_string) { napi_get_value_string_utf8(env, argv[i], key, KEY_BUFFER_SIZE, &keyLen); } else if (i == SECOND_ARG && valueType == napi_string) { napi_get_value_string_utf8(env, argv[i], value, VALUE_BUFFER_SIZE, &valueLen); break; } else { NAPI_ASSERT(env, false, "type mismatch"); } } StorageObjectInfo* objectInfo = nullptr; napi_unwrap(env, thisVar, (void**)&objectInfo); auto itr = g_keyValueStorage.find(key); if (itr == g_keyValueStorage.end()) { g_keyValueStorage.insert(std::pair<std::string, std::string>(key, value)); objectInfo->Emit(nullptr, "change"); } else { objectInfo->Emit(nullptr, "error"); NAPI_ASSERT(env, false, "key already exists"); } napi_value result = nullptr; napi_get_undefined(env, &result); return result; } // storage.deleteSync(key: string): void static napi_value JSStorageDeleteSync(napi_env env, napi_callback_info info) { size_t requireArgc = 1; size_t argc = 2; napi_value argv[2] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter"); char key[KEY_BUFFER_SIZE] = { 0 }; size_t keyLen = 0; napi_valuetype keyType = napi_undefined; napi_typeof(env, argv[0], &keyType); NAPI_ASSERT(env, keyType == napi_string, "type mismatch"); napi_get_value_string_utf8(env, argv[0], key, KEY_BUFFER_SIZE, &keyLen); StorageObjectInfo* objectInfo = nullptr; napi_unwrap(env, thisVar, (void**)&objectInfo); auto itr = g_keyValueStorage.find(key); if (itr != g_keyValueStorage.end()) { g_keyValueStorage.erase(itr); objectInfo->Emit(nullptr, "change"); } else { objectInfo->Emit(nullptr, "error"); NAPI_ASSERT(env, itr != g_keyValueStorage.end(), "key does not exist"); } napi_value result = nullptr; napi_get_undefined(env, &result); return result; } // storage.clearSync(): void static napi_value JSStorageClearSync(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, &data); StorageObjectInfo* objectInfo = nullptr; napi_unwrap(env, thisVar, (void**)&objectInfo); g_keyValueStorage.clear(); objectInfo->Emit(nullptr, "clear"); napi_value result = nullptr; napi_get_undefined(env, &result); return result; } /*********************************************** * Event Function Set ***********************************************/ // storage.on(event: "change" | "clear", callback: Function): void static napi_value JSStorageOn(napi_env env, napi_callback_info info) { size_t requireArgc = 2; size_t argc = 2; napi_value argv[2] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); NAPI_ASSERT(env, argc >= requireArgc, "requires 2 parameters"); char eventType[EVENT_TYPE_SIZE] = { 0 }; size_t eventTypeLen = 0; napi_valuetype eventValueType = napi_undefined; napi_typeof(env, argv[0], &eventValueType); NAPI_ASSERT(env, eventValueType == napi_string, "parameter 1 type mismatch"); napi_get_value_string_utf8(env, argv[0], eventType, EVENT_TYPE_SIZE, &eventTypeLen); napi_valuetype callbackType = napi_undefined; napi_typeof(env, argv[1], &callbackType); NAPI_ASSERT(env, callbackType == napi_function, "parameter 2 type mismatch"); StorageObjectInfo* objectInfo = nullptr; napi_unwrap(env, thisVar, (void**)&objectInfo); objectInfo->On(eventType, argv[1]); napi_value result = nullptr; napi_get_undefined(env, &result); return result; } // storage.off(event: "change" | "clear", callback?: Function): void static napi_value JSStorageOff(napi_env env, napi_callback_info info) { size_t requireArgc = 1; size_t argc = 2; napi_value argv[2] = { 0 }; napi_value thisVar = nullptr; void* data = nullptr; napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); NAPI_ASSERT(env, argc >= requireArgc, "requires 1 parameter"); char eventType[EVENT_TYPE_SIZE] = { 0 }; size_t eventTypeLen = 0; napi_valuetype eventValueType = napi_undefined; napi_typeof(env, argv[0], &eventValueType); NAPI_ASSERT(env, eventValueType == napi_string, "parameter 1 type mismatch"); napi_get_value_string_utf8(env, argv[0], eventType, EVENT_TYPE_SIZE, &eventTypeLen); StorageObjectInfo* objectInfo = nullptr; napi_unwrap(env, thisVar, (void**)&objectInfo); if (argc > requireArgc) { napi_valuetype callbackType = napi_undefined; napi_typeof(env, argv[1], &callbackType); NAPI_ASSERT(env, callbackType == napi_function, "parameter 2 type mismatch"); objectInfo->Off(eventType, argv[1]); } else { objectInfo->Off(eventType); } napi_value result = nullptr; napi_get_undefined(env, &result); return result; } /*********************************************** * Module export and register ***********************************************/ static napi_value StorageExport(napi_env env, napi_value exports) { const char* storageClassName = "Storage"; napi_value storageClass = nullptr; static napi_property_descriptor storageDesc[] = { DECLARE_NAPI_FUNCTION("get", JSStorageGet), DECLARE_NAPI_FUNCTION("set", JSStorageSet), DECLARE_NAPI_FUNCTION("delete", JSStorageDelete), DECLARE_NAPI_FUNCTION("clear", JSStorageClear), DECLARE_NAPI_FUNCTION("getSync", JSStorageGetSync), DECLARE_NAPI_FUNCTION("setSync", JSStorageSetSync), DECLARE_NAPI_FUNCTION("deleteSync", JSStorageDeleteSync), DECLARE_NAPI_FUNCTION("clearSync", JSStorageClearSync), DECLARE_NAPI_FUNCTION("on", JSStorageOn), DECLARE_NAPI_FUNCTION("off", JSStorageOff), }; napi_define_class(env, storageClassName, strlen(storageClassName), JSStorageConstructor, nullptr, sizeof(storageDesc) / sizeof(storageDesc[0]), storageDesc, &storageClass); static napi_property_descriptor desc[] = { DECLARE_NAPI_PROPERTY("Storage", storageClass), }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; } // storage module define static napi_module storageModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, .nm_register_func = StorageExport, .nm_modname = "storage", .nm_priv = ((void*)0), .reserved = { 0 }, }; // storage module register extern "C" __attribute__((constructor)) void StorageRegister() { napi_module_register(&storageModule); }