Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Throw errors if set or recrypt failed #706

Merged
merged 1 commit into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion package/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@ module.exports = {
ignorePatterns: ['scripts', 'lib'],
rules: {
'prettier/prettier': ['warn'],
'@typescript-eslint/consistent-type-imports': 'warn',
},
};
72 changes: 35 additions & 37 deletions package/cpp/MmkvHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ MmkvHostObject::MmkvHostObject(const facebook::react::MMKVConfig& config) {
instance = MMKV::mmkvWithID(config.id, DEFAULT_MMAP_SIZE, mode, encryptionKeyPtr, pathPtr);
#endif

if (instance == nullptr) {
if (instance == nullptr) [[unlikely]] {
// Check if instanceId is invalid
if (config.id.empty()) {
if (config.id.empty()) [[unlikely]] {
throw std::runtime_error("Failed to create MMKV instance! `id` cannot be empty!");
}

// Check if encryptionKey is invalid
if (encryptionKey.size() > 16) {
if (encryptionKey.size() > 16) [[unlikely]] {
throw std::runtime_error(
"Failed to create MMKV instance! `encryptionKey` cannot be longer than 16 bytes!");
}
Expand Down Expand Up @@ -76,7 +76,7 @@ MMKVMode MmkvHostObject::getMMKVMode(const facebook::react::MMKVConfig& config)
case react::MmkvCxxMode::MULTI_PROCESS:
return MMKVMode::MMKV_MULTI_PROCESS;
default:
throw std::runtime_error("Invalid MMKV Mode value!");
[[unlikely]] throw std::runtime_error("Invalid MMKV Mode value!");
}
}

Expand All @@ -90,45 +90,49 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
2, // key, value
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 2 || !arguments[0].isString()) {
[[unlikely]];
if (count != 2 || !arguments[0].isString()) [[unlikely]] {
throw jsi::JSError(runtime,
"MMKV::set: First argument ('key') has to be of type string!");
}

std::string keyName = arguments[0].asString(runtime).utf8(runtime);

bool successful = false;
if (arguments[1].isBool()) {
// bool
instance->set(arguments[1].getBool(), keyName);
successful = instance->set(arguments[1].getBool(), keyName);
} else if (arguments[1].isNumber()) {
// number
instance->set(arguments[1].getNumber(), keyName);
successful = instance->set(arguments[1].getNumber(), keyName);
} else if (arguments[1].isString()) {
// string
std::string stringValue = arguments[1].asString(runtime).utf8(runtime);
instance->set(stringValue, keyName);
successful = instance->set(stringValue, keyName);
} else if (arguments[1].isObject()) {
// object
jsi::Object object = arguments[1].asObject(runtime);
if (object.isArrayBuffer(runtime)) {
// ArrayBuffer
jsi::ArrayBuffer arrayBuffer = object.getArrayBuffer(runtime);
MMBuffer data(arrayBuffer.data(runtime), arrayBuffer.size(runtime), MMBufferNoCopy);
instance->set(data, keyName);
} else {
successful = instance->set(data, keyName);
} else [[unlikely]] {
// unknown object
throw jsi::JSError(
runtime,
"MMKV::set: 'value' argument is an object, but not of type ArrayBuffer!");
}
} else {
} else [[unlikely]] {
// unknown type
throw jsi::JSError(
runtime,
"MMKV::set: 'value' argument is not of type bool, number, string or buffer!");
}

if (!successful) [[unlikely]] {
throw std::runtime_error("Failed to set " + keyName + "!");
}

return jsi::Value::undefined();
});
}
Expand All @@ -140,16 +144,14 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
1, // key
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 1 || !arguments[0].isString()) {
[[unlikely]];
if (count != 1 || !arguments[0].isString()) [[unlikely]] {
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
}

std::string keyName = arguments[0].asString(runtime).utf8(runtime);
bool hasValue;
bool value = instance->getBool(keyName, false, &hasValue);
if (!hasValue) {
[[unlikely]];
if (!hasValue) [[unlikely]] {
return jsi::Value::undefined();
}
return jsi::Value(value);
Expand All @@ -163,16 +165,14 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
1, // key
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 1 || !arguments[0].isString()) {
[[unlikely]];
if (count != 1 || !arguments[0].isString()) [[unlikely]] {
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
}

std::string keyName = arguments[0].asString(runtime).utf8(runtime);
bool hasValue;
double value = instance->getDouble(keyName, 0.0, &hasValue);
if (!hasValue) {
[[unlikely]];
if (!hasValue) [[unlikely]] {
return jsi::Value::undefined();
}
return jsi::Value(value);
Expand All @@ -186,16 +186,14 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
1, // key
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 1 || !arguments[0].isString()) {
[[unlikely]];
if (count != 1 || !arguments[0].isString()) [[unlikely]] {
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
}

std::string keyName = arguments[0].asString(runtime).utf8(runtime);
std::string result;
bool hasValue = instance->getString(keyName, result);
if (!hasValue) {
[[unlikely]];
if (!hasValue) [[unlikely]] {
return jsi::Value::undefined();
}
return jsi::Value(runtime, jsi::String::createFromUtf8(runtime, result));
Expand All @@ -209,16 +207,14 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
1, // key
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 1 || !arguments[0].isString()) {
[[unlikely]];
if (count != 1 || !arguments[0].isString()) [[unlikely]] {
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
}

std::string keyName = arguments[0].asString(runtime).utf8(runtime);
mmkv::MMBuffer buffer;
bool hasValue = instance->getBytes(keyName, buffer);
if (!hasValue) {
[[unlikely]];
if (!hasValue) [[unlikely]] {
return jsi::Value::undefined();
}
auto mutableData = std::make_shared<MMKVManagedBuffer>(std::move(buffer));
Expand All @@ -233,8 +229,7 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
1, // key
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 1 || !arguments[0].isString()) {
[[unlikely]];
if (count != 1 || !arguments[0].isString()) [[unlikely]] {
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
}

Expand All @@ -251,8 +246,7 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
1, // key
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 1 || !arguments[0].isString()) {
[[unlikely]];
if (count != 1 || !arguments[0].isString()) [[unlikely]] {
throw jsi::JSError(runtime, "First argument ('key') has to be of type string!");
}

Expand Down Expand Up @@ -295,26 +289,30 @@ jsi::Value MmkvHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& pro
1, // encryptionKey
[this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments,
size_t count) -> jsi::Value {
if (count != 1) {
[[unlikely]];
if (count != 1) [[unlikely]] {
throw jsi::JSError(runtime, "Expected 1 argument (encryptionKey), but received " +
std::to_string(count) + "!");
}

bool successful = false;
if (arguments[0].isUndefined()) {
// reset encryption key to "no encryption"
instance->reKey(std::string());
successful = instance->reKey(std::string());
} else if (arguments[0].isString()) {
// reKey(..) with new encryption-key
std::string encryptionKey = arguments[0].getString(runtime).utf8(runtime);
instance->reKey(encryptionKey);
} else {
successful = instance->reKey(encryptionKey);
} else [[unlikely]] {
// Invalid argument (maybe object?)
throw jsi::JSError(
runtime,
"First argument ('encryptionKey') has to be of type string (or undefined)!");
}

if (!successful) [[unlikely]] {
throw std::runtime_error("Failed to recrypt MMKV instance!");
}

return jsi::Value::undefined();
});
}
Expand Down
4 changes: 4 additions & 0 deletions package/src/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
export interface NativeMMKV {
/**
* Set a value for the given `key`.
*
* @throws an Error if the value cannot be set.
*/
set: (key: string, value: boolean | string | number | ArrayBuffer) => void;
/**
Expand Down Expand Up @@ -54,6 +56,8 @@ export interface NativeMMKV {
* To remove encryption, pass `undefined` as a key.
*
* Encryption keys can have a maximum length of 16 bytes.
*
* @throws an Error if the instance cannot be recrypted.
*/
recrypt: (key: string | undefined) => void;
/**
Expand Down
Loading