Skip to content

Commit

Permalink
feat: Throw errors if set or recrypt failed (#706)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrousavy authored Jul 22, 2024
1 parent 5a63632 commit 0fde8a5
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 37 deletions.
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

0 comments on commit 0fde8a5

Please sign in to comment.