Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3509002
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
72 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
index 029d970ba..8046d2471 100644
--- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
+++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp
@@ -1,1035 +1,1021 @@
#include "CommCoreModule.h"
#include "DatabaseManager.h"
#include "GRPCStreamHostObject.h"
#include "InternalModules/GlobalNetworkSingleton.h"
#include "InternalModules/NetworkModule.h"
#include "Logger.h"
#include "MessageStoreOperations.h"
#include "ThreadStoreOperations.h"
#include <folly/Optional.h>
#include "../DatabaseManagers/entities/Media.h"
#include <ReactCommon/TurboModuleUtils.h>
#include <future>
namespace comm {
using namespace facebook::react;
template <class T>
T CommCoreModule::runSyncOrThrowJSError(
jsi::Runtime &rt,
std::function<T()> task) {
std::promise<T> promise;
this->databaseThread->scheduleTask([&promise, &task]() {
try {
- promise.set_value(task());
+ if constexpr (std::is_void<T>::value) {
+ task();
+ promise.set_value();
+ } else {
+ promise.set_value(task());
+ }
} catch (const std::exception &e) {
promise.set_exception(std::make_exception_ptr(e));
}
});
// We cannot instantiate JSError on database thread, so
// on the main thread we re-throw C++ error, catch it and
// transform to informative JSError on the main thread
try {
return promise.get_future().get();
} catch (const std::exception &e) {
throw jsi::JSError(rt, e.what());
}
}
jsi::Value CommCoreModule::getDraft(jsi::Runtime &rt, const jsi::String &key) {
std::string keyStr = key.utf8(rt);
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=, &innerRt]() {
std::string error;
std::string draftStr;
try {
draftStr = DatabaseManager::getQueryExecutor().getDraft(keyStr);
} catch (std::system_error &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([=, &innerRt]() {
if (error.size()) {
promise->reject(error);
return;
}
jsi::String draft = jsi::String::createFromUtf8(innerRt, draftStr);
promise->resolve(std::move(draft));
});
};
this->databaseThread->scheduleTask(job);
});
}
jsi::Value
CommCoreModule::updateDraft(jsi::Runtime &rt, const jsi::Object &draft) {
std::string keyStr = draft.getProperty(rt, "key").asString(rt).utf8(rt);
std::string textStr = draft.getProperty(rt, "text").asString(rt).utf8(rt);
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=]() {
std::string error;
try {
DatabaseManager::getQueryExecutor().updateDraft(keyStr, textStr);
} catch (std::system_error &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([=]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(true);
}
});
};
this->databaseThread->scheduleTask(job);
});
}
jsi::Value CommCoreModule::moveDraft(
jsi::Runtime &rt,
const jsi::String &oldKey,
const jsi::String &newKey) {
std::string oldKeyStr = oldKey.utf8(rt);
std::string newKeyStr = newKey.utf8(rt);
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=]() {
std::string error;
bool result = false;
try {
result = DatabaseManager::getQueryExecutor().moveDraft(
oldKeyStr, newKeyStr);
} catch (std::system_error &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([=]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(result);
}
});
};
this->databaseThread->scheduleTask(job);
});
}
jsi::Value CommCoreModule::getAllDrafts(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=, &innerRt]() {
std::string error;
std::vector<Draft> draftsVector;
size_t numDrafts;
try {
draftsVector = DatabaseManager::getQueryExecutor().getAllDrafts();
numDrafts = count_if(
draftsVector.begin(), draftsVector.end(), [](Draft draft) {
return !draft.text.empty();
});
} catch (std::system_error &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([=, &innerRt]() {
if (error.size()) {
promise->reject(error);
return;
}
jsi::Array jsiDrafts = jsi::Array(innerRt, numDrafts);
size_t writeIndex = 0;
for (Draft draft : draftsVector) {
if (draft.text.empty()) {
continue;
}
auto jsiDraft = jsi::Object(innerRt);
jsiDraft.setProperty(innerRt, "key", draft.key);
jsiDraft.setProperty(innerRt, "text", draft.text);
jsiDrafts.setValueAtIndex(innerRt, writeIndex++, jsiDraft);
}
promise->resolve(std::move(jsiDrafts));
});
};
this->databaseThread->scheduleTask(job);
});
}
jsi::Value CommCoreModule::removeAllDrafts(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=]() {
std::string error;
try {
DatabaseManager::getQueryExecutor().removeAllDrafts();
} catch (std::system_error &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([=]() {
if (error.size()) {
promise->reject(error);
return;
}
promise->resolve(jsi::Value::undefined());
});
};
this->databaseThread->scheduleTask(job);
});
}
jsi::Array CommCoreModule::getAllMessagesSync(jsi::Runtime &rt) {
auto messagesVector = this->runSyncOrThrowJSError<
std::vector<std::pair<Message, std::vector<Media>>>>(rt, []() {
return DatabaseManager::getQueryExecutor().getAllMessages();
});
size_t numMessages{messagesVector.size()};
jsi::Array jsiMessages = jsi::Array(rt, numMessages);
size_t writeIndex = 0;
for (const auto &[message, media] : messagesVector) {
auto jsiMessage = jsi::Object(rt);
jsiMessage.setProperty(rt, "id", message.id);
if (message.local_id) {
auto local_id = message.local_id.get();
jsiMessage.setProperty(rt, "local_id", *local_id);
}
jsiMessage.setProperty(rt, "thread", message.thread);
jsiMessage.setProperty(rt, "user", message.user);
jsiMessage.setProperty(rt, "type", std::to_string(message.type));
if (message.future_type) {
auto future_type = message.future_type.get();
jsiMessage.setProperty(rt, "future_type", std::to_string(*future_type));
}
if (message.content) {
auto content = message.content.get();
jsiMessage.setProperty(rt, "content", *content);
}
jsiMessage.setProperty(rt, "time", std::to_string(message.time));
size_t media_idx = 0;
jsi::Array jsiMediaArray = jsi::Array(rt, media.size());
for (const auto &media_info : media) {
auto jsiMedia = jsi::Object(rt);
jsiMedia.setProperty(rt, "id", media_info.id);
jsiMedia.setProperty(rt, "uri", media_info.uri);
jsiMedia.setProperty(rt, "type", media_info.type);
jsiMedia.setProperty(rt, "extras", media_info.extras);
jsiMediaArray.setValueAtIndex(rt, media_idx++, jsiMedia);
}
jsiMessage.setProperty(rt, "media_infos", jsiMediaArray);
jsiMessages.setValueAtIndex(rt, writeIndex++, jsiMessage);
}
return jsiMessages;
}
jsi::Value CommCoreModule::getAllMessages(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=, &innerRt]() {
std::string error;
std::vector<std::pair<Message, std::vector<Media>>> messagesVector;
size_t numMessages;
try {
messagesVector =
DatabaseManager::getQueryExecutor().getAllMessages();
numMessages = messagesVector.size();
} catch (std::system_error &e) {
error = e.what();
}
auto messagesVectorPtr = std::make_shared<
std::vector<std::pair<Message, std::vector<Media>>>>(
std::move(messagesVector));
this->jsInvoker_->invokeAsync(
[messagesVectorPtr, &innerRt, promise, error, numMessages]() {
if (error.size()) {
promise->reject(error);
return;
}
jsi::Array jsiMessages = jsi::Array(innerRt, numMessages);
size_t writeIndex = 0;
for (const auto &[message, media] : *messagesVectorPtr) {
auto jsiMessage = jsi::Object(innerRt);
jsiMessage.setProperty(innerRt, "id", message.id);
if (message.local_id) {
auto local_id = message.local_id.get();
jsiMessage.setProperty(innerRt, "local_id", *local_id);
}
jsiMessage.setProperty(innerRt, "thread", message.thread);
jsiMessage.setProperty(innerRt, "user", message.user);
jsiMessage.setProperty(
innerRt, "type", std::to_string(message.type));
if (message.future_type) {
auto future_type = message.future_type.get();
jsiMessage.setProperty(
innerRt, "future_type", std::to_string(*future_type));
}
if (message.content) {
auto content = message.content.get();
jsiMessage.setProperty(innerRt, "content", *content);
}
jsiMessage.setProperty(
innerRt, "time", std::to_string(message.time));
size_t media_idx = 0;
jsi::Array jsiMediaArray = jsi::Array(innerRt, media.size());
for (const auto &media_info : media) {
auto jsiMedia = jsi::Object(innerRt);
jsiMedia.setProperty(innerRt, "id", media_info.id);
jsiMedia.setProperty(innerRt, "uri", media_info.uri);
jsiMedia.setProperty(innerRt, "type", media_info.type);
jsiMedia.setProperty(innerRt, "extras", media_info.extras);
jsiMediaArray.setValueAtIndex(
innerRt, media_idx++, jsiMedia);
}
jsiMessage.setProperty(innerRt, "media_infos", jsiMediaArray);
jsiMessages.setValueAtIndex(
innerRt, writeIndex++, jsiMessage);
}
promise->resolve(std::move(jsiMessages));
});
};
this->databaseThread->scheduleTask(job);
});
}
#define REKEY_OPERATION "rekey"
#define REMOVE_OPERATION "remove"
#define REPLACE_OPERATION "replace"
#define REMOVE_MSGS_FOR_THREADS_OPERATION "remove_messages_for_threads"
#define REMOVE_ALL_OPERATION "remove_all"
std::vector<std::unique_ptr<MessageStoreOperationBase>>
createMessageStoreOperations(jsi::Runtime &rt, const jsi::Array &operations) {
std::vector<std::unique_ptr<MessageStoreOperationBase>> messageStoreOps;
for (auto idx = 0; idx < operations.size(rt); idx++) {
auto op = operations.getValueAtIndex(rt, idx).asObject(rt);
auto op_type = op.getProperty(rt, "type").asString(rt).utf8(rt);
if (op_type == REMOVE_ALL_OPERATION) {
messageStoreOps.push_back(std::make_unique<RemoveAllMessagesOperation>());
continue;
}
auto payload_obj = op.getProperty(rt, "payload").asObject(rt);
if (op_type == REMOVE_OPERATION) {
messageStoreOps.push_back(
std::make_unique<RemoveMessagesOperation>(rt, payload_obj));
} else if (op_type == REMOVE_MSGS_FOR_THREADS_OPERATION) {
messageStoreOps.push_back(
std::make_unique<RemoveMessagesForThreadsOperation>(rt, payload_obj));
} else if (op_type == REPLACE_OPERATION) {
messageStoreOps.push_back(
std::make_unique<ReplaceMessageOperation>(rt, payload_obj));
} else if (op_type == REKEY_OPERATION) {
messageStoreOps.push_back(
std::make_unique<RekeyMessageOperation>(rt, payload_obj));
} else {
throw std::runtime_error("unsupported operation: " + op_type);
}
}
return messageStoreOps;
}
jsi::Value CommCoreModule::processMessageStoreOperations(
jsi::Runtime &rt,
const jsi::Array &operations) {
std::string createOperationsError;
std::shared_ptr<std::vector<std::unique_ptr<MessageStoreOperationBase>>>
messageStoreOpsPtr;
try {
auto messageStoreOps = createMessageStoreOperations(rt, operations);
messageStoreOpsPtr = std::make_shared<
std::vector<std::unique_ptr<MessageStoreOperationBase>>>(
std::move(messageStoreOps));
} catch (std::runtime_error &e) {
createOperationsError = e.what();
}
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=]() {
std::string error = createOperationsError;
if (!error.size()) {
try {
DatabaseManager::getQueryExecutor().beginTransaction();
for (const auto &operation : *messageStoreOpsPtr) {
operation->execute();
}
DatabaseManager::getQueryExecutor().commitTransaction();
} catch (std::system_error &e) {
error = e.what();
DatabaseManager::getQueryExecutor().rollbackTransaction();
}
}
this->jsInvoker_->invokeAsync([=]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(jsi::Value::undefined());
}
});
};
this->databaseThread->scheduleTask(job);
});
}
-bool CommCoreModule::processMessageStoreOperationsSync(
+void CommCoreModule::processMessageStoreOperationsSync(
jsi::Runtime &rt,
const jsi::Array &operations) {
-
- std::promise<bool> operationsResult;
- std::future<bool> operationsResultFuture = operationsResult.get_future();
-
std::vector<std::unique_ptr<MessageStoreOperationBase>> messageStoreOps;
- std::string operationsError;
try {
messageStoreOps = createMessageStoreOperations(rt, operations);
- } catch (std::runtime_error &e) {
- return false;
+ } catch (const std::exception &e) {
+ throw jsi::JSError(rt, e.what());
}
- this->databaseThread->scheduleTask(
- [=, &messageStoreOps, &operationsResult, &rt]() {
- std::string error = operationsError;
- if (!error.size()) {
- try {
- DatabaseManager::getQueryExecutor().beginTransaction();
- for (const auto &operation : messageStoreOps) {
- operation->execute();
- }
- DatabaseManager::getQueryExecutor().commitTransaction();
- } catch (std::system_error &e) {
- error = e.what();
- DatabaseManager::getQueryExecutor().rollbackTransaction();
- }
- }
- operationsResult.set_value(error.size() == 0);
- });
- return operationsResultFuture.get();
+ this->runSyncOrThrowJSError<void>(rt, [&messageStoreOps]() {
+ try {
+ DatabaseManager::getQueryExecutor().beginTransaction();
+ for (const auto &operation : messageStoreOps) {
+ operation->execute();
+ }
+ DatabaseManager::getQueryExecutor().commitTransaction();
+ } catch (const std::exception &e) {
+ DatabaseManager::getQueryExecutor().rollbackTransaction();
+ throw e;
+ }
+ });
}
jsi::Value CommCoreModule::getAllThreads(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->databaseThread->scheduleTask([=, &innerRt]() {
std::string error;
std::vector<Thread> threadsVector;
size_t numThreads;
try {
threadsVector = DatabaseManager::getQueryExecutor().getAllThreads();
numThreads = threadsVector.size();
} catch (std::system_error &e) {
error = e.what();
}
auto threadsVectorPtr =
std::make_shared<std::vector<Thread>>(std::move(threadsVector));
this->jsInvoker_->invokeAsync([=, &innerRt]() {
if (error.size()) {
promise->reject(error);
return;
}
jsi::Array jsiThreads = jsi::Array(innerRt, numThreads);
size_t writeIdx = 0;
for (const Thread &thread : *threadsVectorPtr) {
jsi::Object jsiThread = jsi::Object(innerRt);
jsiThread.setProperty(innerRt, "id", thread.id);
jsiThread.setProperty(innerRt, "type", thread.type);
jsiThread.setProperty(
innerRt,
"name",
thread.name
? jsi::String::createFromUtf8(innerRt, *thread.name)
: jsi::Value::null());
jsiThread.setProperty(
innerRt,
"description",
thread.description ? jsi::String::createFromUtf8(
innerRt, *thread.description)
: jsi::Value::null());
jsiThread.setProperty(innerRt, "color", thread.color);
jsiThread.setProperty(
innerRt,
"creationTime",
std::to_string(thread.creation_time));
jsiThread.setProperty(
innerRt,
"parentThreadID",
thread.parent_thread_id
? jsi::String::createFromUtf8(
innerRt, *thread.parent_thread_id)
: jsi::Value::null());
jsiThread.setProperty(
innerRt,
"containingThreadID",
thread.containing_thread_id
? jsi::String::createFromUtf8(
innerRt, *thread.containing_thread_id)
: jsi::Value::null());
jsiThread.setProperty(
innerRt,
"community",
thread.community
? jsi::String::createFromUtf8(innerRt, *thread.community)
: jsi::Value::null());
jsiThread.setProperty(innerRt, "members", thread.members);
jsiThread.setProperty(innerRt, "roles", thread.roles);
jsiThread.setProperty(
innerRt, "currentUser", thread.current_user);
jsiThread.setProperty(
innerRt,
"sourceMessageID",
thread.source_message_id
? jsi::String::createFromUtf8(
innerRt, *thread.source_message_id)
: jsi::Value::null());
jsiThread.setProperty(
innerRt, "repliesCount", thread.replies_count);
jsiThreads.setValueAtIndex(innerRt, writeIdx++, jsiThread);
}
promise->resolve(std::move(jsiThreads));
});
});
});
};
jsi::Array CommCoreModule::getAllThreadsSync(jsi::Runtime &rt) {
auto threadsVector = this->runSyncOrThrowJSError<std::vector<Thread>>(
rt, []() { return DatabaseManager::getQueryExecutor().getAllThreads(); });
size_t numThreads{threadsVector.size()};
jsi::Array jsiThreads = jsi::Array(rt, numThreads);
size_t writeIdx = 0;
for (const Thread &thread : threadsVector) {
jsi::Object jsiThread = jsi::Object(rt);
jsiThread.setProperty(rt, "id", thread.id);
jsiThread.setProperty(rt, "type", thread.type);
jsiThread.setProperty(
rt,
"name",
thread.name ? jsi::String::createFromUtf8(rt, *thread.name)
: jsi::Value::null());
jsiThread.setProperty(
rt,
"description",
thread.description
? jsi::String::createFromUtf8(rt, *thread.description)
: jsi::Value::null());
jsiThread.setProperty(rt, "color", thread.color);
jsiThread.setProperty(
rt, "creationTime", std::to_string(thread.creation_time));
jsiThread.setProperty(
rt,
"parentThreadID",
thread.parent_thread_id
? jsi::String::createFromUtf8(rt, *thread.parent_thread_id)
: jsi::Value::null());
jsiThread.setProperty(
rt,
"containingThreadID",
thread.containing_thread_id
? jsi::String::createFromUtf8(rt, *thread.containing_thread_id)
: jsi::Value::null());
jsiThread.setProperty(
rt,
"community",
thread.community ? jsi::String::createFromUtf8(rt, *thread.community)
: jsi::Value::null());
jsiThread.setProperty(rt, "members", thread.members);
jsiThread.setProperty(rt, "roles", thread.roles);
jsiThread.setProperty(rt, "currentUser", thread.current_user);
jsiThread.setProperty(
rt,
"sourceMessageID",
thread.source_message_id
? jsi::String::createFromUtf8(rt, *thread.source_message_id)
: jsi::Value::null());
jsiThread.setProperty(rt, "repliesCount", thread.replies_count);
jsiThreads.setValueAtIndex(rt, writeIdx++, jsiThread);
}
return jsiThreads;
}
std::vector<std::unique_ptr<ThreadStoreOperationBase>>
createThreadStoreOperations(jsi::Runtime &rt, const jsi::Array &operations) {
std::vector<std::unique_ptr<ThreadStoreOperationBase>> threadStoreOps;
for (size_t idx = 0; idx < operations.size(rt); idx++) {
jsi::Object op = operations.getValueAtIndex(rt, idx).asObject(rt);
std::string opType = op.getProperty(rt, "type").asString(rt).utf8(rt);
if (opType == REMOVE_OPERATION) {
std::vector<std::string> threadIDsToRemove;
jsi::Object payloadObj = op.getProperty(rt, "payload").asObject(rt);
jsi::Array threadIDs =
payloadObj.getProperty(rt, "ids").asObject(rt).asArray(rt);
for (int threadIdx = 0; threadIdx < threadIDs.size(rt); threadIdx++) {
threadIDsToRemove.push_back(
threadIDs.getValueAtIndex(rt, threadIdx).asString(rt).utf8(rt));
}
threadStoreOps.push_back(std::make_unique<RemoveThreadsOperation>(
std::move(threadIDsToRemove)));
} else if (opType == REMOVE_ALL_OPERATION) {
threadStoreOps.push_back(std::make_unique<RemoveAllThreadsOperation>());
} else if (opType == REPLACE_OPERATION) {
jsi::Object threadObj = op.getProperty(rt, "payload").asObject(rt);
std::string threadID =
threadObj.getProperty(rt, "id").asString(rt).utf8(rt);
int type = std::lround(threadObj.getProperty(rt, "type").asNumber());
jsi::Value maybeName = threadObj.getProperty(rt, "name");
std::unique_ptr<std::string> name = maybeName.isString()
? std::make_unique<std::string>(maybeName.asString(rt).utf8(rt))
: nullptr;
jsi::Value maybeDescription = threadObj.getProperty(rt, "description");
std::unique_ptr<std::string> description = maybeDescription.isString()
? std::make_unique<std::string>(
maybeDescription.asString(rt).utf8(rt))
: nullptr;
std::string color =
threadObj.getProperty(rt, "color").asString(rt).utf8(rt);
int64_t creationTime = std::stoll(
threadObj.getProperty(rt, "creationTime").asString(rt).utf8(rt));
jsi::Value maybeParentThreadID =
threadObj.getProperty(rt, "parentThreadID");
std::unique_ptr<std::string> parentThreadID =
maybeParentThreadID.isString()
? std::make_unique<std::string>(
maybeParentThreadID.asString(rt).utf8(rt))
: nullptr;
jsi::Value maybeContainingThreadID =
threadObj.getProperty(rt, "containingThreadID");
std::unique_ptr<std::string> containingThreadID =
maybeContainingThreadID.isString()
? std::make_unique<std::string>(
maybeContainingThreadID.asString(rt).utf8(rt))
: nullptr;
jsi::Value maybeCommunity = threadObj.getProperty(rt, "community");
std::unique_ptr<std::string> community = maybeCommunity.isString()
? std::make_unique<std::string>(maybeCommunity.asString(rt).utf8(rt))
: nullptr;
std::string members =
threadObj.getProperty(rt, "members").asString(rt).utf8(rt);
std::string roles =
threadObj.getProperty(rt, "roles").asString(rt).utf8(rt);
std::string currentUser =
threadObj.getProperty(rt, "currentUser").asString(rt).utf8(rt);
jsi::Value maybeSourceMessageID =
threadObj.getProperty(rt, "sourceMessageID");
std::unique_ptr<std::string> sourceMessageID =
maybeSourceMessageID.isString()
? std::make_unique<std::string>(
maybeSourceMessageID.asString(rt).utf8(rt))
: nullptr;
int repliesCount =
std::lround(threadObj.getProperty(rt, "repliesCount").asNumber());
Thread thread{
threadID,
type,
std::move(name),
std::move(description),
color,
creationTime,
std::move(parentThreadID),
std::move(containingThreadID),
std::move(community),
members,
roles,
currentUser,
std::move(sourceMessageID),
repliesCount};
threadStoreOps.push_back(
std::make_unique<ReplaceThreadOperation>(std::move(thread)));
} else {
throw std::runtime_error("unsupported operation: " + opType);
}
};
return threadStoreOps;
}
jsi::Value CommCoreModule::processThreadStoreOperations(
jsi::Runtime &rt,
const jsi::Array &operations) {
std::string operationsError;
std::shared_ptr<std::vector<std::unique_ptr<ThreadStoreOperationBase>>>
threadStoreOpsPtr;
try {
auto threadStoreOps = createThreadStoreOperations(rt, operations);
threadStoreOpsPtr = std::make_shared<
std::vector<std::unique_ptr<ThreadStoreOperationBase>>>(
std::move(threadStoreOps));
} catch (std::runtime_error &e) {
operationsError = e.what();
}
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->databaseThread->scheduleTask([=]() {
std::string error = operationsError;
if (!error.size()) {
try {
DatabaseManager::getQueryExecutor().beginTransaction();
for (const auto &operation : *threadStoreOpsPtr) {
operation->execute();
}
DatabaseManager::getQueryExecutor().commitTransaction();
} catch (std::system_error &e) {
error = e.what();
DatabaseManager::getQueryExecutor().rollbackTransaction();
}
}
this->jsInvoker_->invokeAsync([=]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(jsi::Value::undefined());
}
});
});
});
}
-bool CommCoreModule::processThreadStoreOperationsSync(
+void CommCoreModule::processThreadStoreOperationsSync(
jsi::Runtime &rt,
const jsi::Array &operations) {
-
- std::promise<bool> operationsResult;
- std::future<bool> operationsResultFuture = operationsResult.get_future();
std::vector<std::unique_ptr<ThreadStoreOperationBase>> threadStoreOps;
- std::string operationsError;
+
try {
threadStoreOps = createThreadStoreOperations(rt, operations);
- } catch (std::runtime_error &e) {
- return false;
+ } catch (const std::exception &e) {
+ throw jsi::JSError(rt, e.what());
}
- this->databaseThread->scheduleTask(
- [=, &threadStoreOps, &operationsResult, &rt]() {
- std::string error = operationsError;
- if (!error.size()) {
- try {
- DatabaseManager::getQueryExecutor().beginTransaction();
- for (const auto &operation : threadStoreOps) {
- operation->execute();
- }
- DatabaseManager::getQueryExecutor().commitTransaction();
- } catch (std::system_error &e) {
- error = e.what();
- DatabaseManager::getQueryExecutor().rollbackTransaction();
- }
- }
- operationsResult.set_value(error.size() == 0);
- });
- return operationsResultFuture.get();
+
+ this->runSyncOrThrowJSError<void>(rt, [&threadStoreOps]() {
+ try {
+ DatabaseManager::getQueryExecutor().beginTransaction();
+ for (const auto &operation : threadStoreOps) {
+ operation->execute();
+ }
+ DatabaseManager::getQueryExecutor().commitTransaction();
+ } catch (const std::exception &e) {
+ DatabaseManager::getQueryExecutor().rollbackTransaction();
+ throw e;
+ }
+ });
}
jsi::Value CommCoreModule::initializeCryptoAccount(
jsi::Runtime &rt,
const jsi::String &userId) {
std::string userIdStr = userId.utf8(rt);
folly::Optional<std::string> storedSecretKey =
this->secureStore.get(this->secureStoreAccountDataKey);
if (!storedSecretKey.hasValue()) {
storedSecretKey = crypto::Tools::generateRandomString(64);
this->secureStore.set(
this->secureStoreAccountDataKey, storedSecretKey.value());
}
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->databaseThread->scheduleTask([=]() {
crypto::Persist persist;
std::string error;
try {
folly::Optional<std::string> accountData =
DatabaseManager::getQueryExecutor().getOlmPersistAccountData();
if (accountData.hasValue()) {
persist.account =
crypto::OlmBuffer(accountData->begin(), accountData->end());
// handle sessions data
std::vector<OlmPersistSession> sessionsData =
DatabaseManager::getQueryExecutor()
.getOlmPersistSessionsData();
for (OlmPersistSession &sessionsDataItem : sessionsData) {
crypto::OlmBuffer sessionDataBuffer(
sessionsDataItem.session_data.begin(),
sessionsDataItem.session_data.end());
persist.sessions.insert(std::make_pair(
sessionsDataItem.target_user_id, sessionDataBuffer));
}
}
} catch (std::system_error &e) {
error = e.what();
}
this->cryptoThread->scheduleTask([=]() {
std::string error;
this->cryptoModule.reset(new crypto::CryptoModule(
userIdStr, storedSecretKey.value(), persist));
if (persist.isEmpty()) {
crypto::Persist newPersist =
this->cryptoModule->storeAsB64(storedSecretKey.value());
this->databaseThread->scheduleTask([=]() {
std::string error;
try {
DatabaseManager::getQueryExecutor().storeOlmPersistData(
newPersist);
} catch (std::system_error &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([=]() {
if (error.size()) {
promise->reject(error);
return;
}
promise->resolve(jsi::Value::undefined());
});
});
} else {
this->cryptoModule->restoreFromB64(
storedSecretKey.value(), persist);
this->jsInvoker_->invokeAsync([=]() {
if (error.size()) {
promise->reject(error);
return;
}
promise->resolve(jsi::Value::undefined());
});
}
});
});
});
}
void CommCoreModule::initializeNetworkModule(
const std::string &userId,
const std::string &deviceToken,
const std::string &hostname) {
GlobalNetworkSingleton::instance.scheduleOrRun(
[=](NetworkModule &networkModule) {
networkModule.initializeNetworkModule(userId, deviceToken, hostname);
});
}
jsi::Value CommCoreModule::getUserPublicKey(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=, &innerRt]() {
std::string error;
std::string result;
if (this->cryptoModule == nullptr) {
error = "user has not been initialized";
} else {
result = this->cryptoModule->getIdentityKeys();
}
this->jsInvoker_->invokeAsync([=, &innerRt]() {
if (error.size()) {
promise->reject(error);
return;
}
promise->resolve(jsi::String::createFromUtf8(innerRt, result));
});
};
this->cryptoThread->scheduleTask(job);
});
}
jsi::Value CommCoreModule::getUserOneTimeKeys(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [=](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
taskType job = [=, &innerRt]() {
std::string error;
std::string result;
if (this->cryptoModule == nullptr) {
error = "user has not been initialized";
} else {
result = this->cryptoModule->getOneTimeKeys();
}
this->jsInvoker_->invokeAsync([=, &innerRt]() {
if (error.size()) {
promise->reject(error);
return;
}
promise->resolve(jsi::String::createFromUtf8(innerRt, result));
});
};
this->cryptoThread->scheduleTask(job);
});
}
jsi::Object
CommCoreModule::openSocket(jsi::Runtime &rt, const jsi::String &endpoint) {
auto hostObject =
std::make_shared<GRPCStreamHostObject>(rt, this->jsInvoker_);
return jsi::Object::createFromHostObject(rt, hostObject);
}
CommCoreModule::CommCoreModule(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker)
: facebook::react::CommCoreModuleSchemaCxxSpecJSI(jsInvoker),
databaseThread(std::make_unique<WorkerThread>("database")),
cryptoThread(std::make_unique<WorkerThread>("crypto")) {
GlobalNetworkSingleton::instance.enableMultithreading();
}
double CommCoreModule::getCodeVersion(jsi::Runtime &rt) {
return this->codeVersion;
}
jsi::Value
CommCoreModule::setNotifyToken(jsi::Runtime &rt, const jsi::String &token) {
auto notifyToken{token.utf8(rt)};
return createPromiseAsJSIValue(
rt,
[this,
notifyToken](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->databaseThread->scheduleTask([this, notifyToken, promise]() {
std::string error;
try {
DatabaseManager::getQueryExecutor().setNotifyToken(notifyToken);
} catch (std::system_error &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([error, promise]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(jsi::Value::undefined());
}
});
});
});
}
jsi::Value CommCoreModule::clearNotifyToken(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [this](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->databaseThread->scheduleTask([this, promise]() {
std::string error;
try {
DatabaseManager::getQueryExecutor().clearNotifyToken();
} catch (std::system_error &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([error, promise]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(jsi::Value::undefined());
}
});
});
});
};
jsi::Value
CommCoreModule::setCurrentUserID(jsi::Runtime &rt, const jsi::String &userID) {
auto currentUserID{userID.utf8(rt)};
return createPromiseAsJSIValue(
rt,
[this,
currentUserID](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->databaseThread->scheduleTask([this, promise, currentUserID]() {
std::string error;
try {
DatabaseManager::getQueryExecutor().setCurrentUserID(currentUserID);
} catch (const std::exception &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([error, promise]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(jsi::Value::undefined());
}
});
});
});
}
jsi::Value CommCoreModule::getCurrentUserID(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [this](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->databaseThread->scheduleTask([this, &innerRt, promise]() {
std::string error;
std::string result;
try {
result = DatabaseManager::getQueryExecutor().getCurrentUserID();
} catch (const std::exception &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([&innerRt, error, result, promise]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(jsi::String::createFromUtf8(innerRt, result));
}
});
});
});
}
jsi::Value CommCoreModule::clearSensitiveData(jsi::Runtime &rt) {
return createPromiseAsJSIValue(
rt, [this](jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
this->databaseThread->scheduleTask([this, promise]() {
std::string error;
try {
DatabaseManager::getQueryExecutor().clearSensitiveData();
} catch (const std::exception &e) {
error = e.what();
}
this->jsInvoker_->invokeAsync([error, promise]() {
if (error.size()) {
promise->reject(error);
} else {
promise->resolve(jsi::Value::undefined());
}
});
});
});
}
} // namespace comm
diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h
index 0e13ab957..e243dbbc7 100644
--- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h
+++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h
@@ -1,77 +1,77 @@
#pragma once
#include "../CryptoTools/CryptoModule.h"
#include "../Tools/CommSecureStore.h"
#include "../Tools/WorkerThread.h"
#include "../_generated/NativeModules.h"
#include "../grpc/Client.h"
#include <jsi/jsi.h>
#include <memory>
namespace comm {
namespace jsi = facebook::jsi;
class CommCoreModule : public facebook::react::CommCoreModuleSchemaCxxSpecJSI {
const int codeVersion{147};
std::unique_ptr<WorkerThread> databaseThread;
std::unique_ptr<WorkerThread> cryptoThread;
CommSecureStore secureStore;
const std::string secureStoreAccountDataKey = "cryptoAccountDataKey";
std::unique_ptr<crypto::CryptoModule> cryptoModule;
std::unique_ptr<network::Client> networkClient;
template <class T>
T runSyncOrThrowJSError(jsi::Runtime &rt, std::function<T()> task);
jsi::Value getDraft(jsi::Runtime &rt, const jsi::String &key) override;
jsi::Value updateDraft(jsi::Runtime &rt, const jsi::Object &draft) override;
jsi::Value moveDraft(
jsi::Runtime &rt,
const jsi::String &oldKey,
const jsi::String &newKey) override;
jsi::Value getAllDrafts(jsi::Runtime &rt) override;
jsi::Value removeAllDrafts(jsi::Runtime &rt) override;
jsi::Value getAllMessages(jsi::Runtime &rt) override;
jsi::Array getAllMessagesSync(jsi::Runtime &rt) override;
jsi::Value processMessageStoreOperations(
jsi::Runtime &rt,
const jsi::Array &operations) override;
- bool processMessageStoreOperationsSync(
+ void processMessageStoreOperationsSync(
jsi::Runtime &rt,
const jsi::Array &operations) override;
jsi::Value getAllThreads(jsi::Runtime &rt) override;
jsi::Array getAllThreadsSync(jsi::Runtime &rt) override;
jsi::Value processThreadStoreOperations(
jsi::Runtime &rt,
const jsi::Array &operations) override;
- bool processThreadStoreOperationsSync(
+ void processThreadStoreOperationsSync(
jsi::Runtime &rt,
const jsi::Array &operations) override;
jsi::Value
initializeCryptoAccount(jsi::Runtime &rt, const jsi::String &userId) override;
jsi::Value getUserPublicKey(jsi::Runtime &rt) override;
jsi::Value getUserOneTimeKeys(jsi::Runtime &rt) override;
jsi::Object
openSocket(jsi::Runtime &rt, const jsi::String &endpoint) override;
double getCodeVersion(jsi::Runtime &rt) override;
jsi::Value
setNotifyToken(jsi::Runtime &rt, const jsi::String &token) override;
jsi::Value clearNotifyToken(jsi::Runtime &rt) override;
jsi::Value
setCurrentUserID(jsi::Runtime &rt, const jsi::String &userID) override;
jsi::Value getCurrentUserID(jsi::Runtime &rt) override;
jsi::Value clearSensitiveData(jsi::Runtime &rt) override;
public:
CommCoreModule(std::shared_ptr<facebook::react::CallInvoker> jsInvoker);
void initializeNetworkModule(
const std::string &userId,
const std::string &deviceToken,
const std::string &hostname = "");
};
} // namespace comm
diff --git a/native/cpp/CommonCpp/_generated/NativeModules.cpp b/native/cpp/CommonCpp/_generated/NativeModules.cpp
index c9586d814..e179f7181 100644
--- a/native/cpp/CommonCpp/_generated/NativeModules.cpp
+++ b/native/cpp/CommonCpp/_generated/NativeModules.cpp
@@ -1,114 +1,116 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated by codegen project: GenerateModuleH.js
*/
#include "NativeModules.h"
namespace facebook {
namespace react {
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getDraft(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getDraft(rt, args[0].getString(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_updateDraft(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->updateDraft(rt, args[0].getObject(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_moveDraft(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->moveDraft(rt, args[0].getString(rt), args[1].getString(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllDrafts(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getAllDrafts(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeAllDrafts(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->removeAllDrafts(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllMessages(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getAllMessages(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllMessagesSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getAllMessagesSync(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processMessageStoreOperations(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->processMessageStoreOperations(rt, args[0].getObject(rt).getArray(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processMessageStoreOperationsSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
- return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->processMessageStoreOperationsSync(rt, args[0].getObject(rt).getArray(rt));
+ static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->processMessageStoreOperationsSync(rt, args[0].getObject(rt).getArray(rt));
+ return jsi::Value::undefined();
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllThreads(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getAllThreads(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllThreadsSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getAllThreadsSync(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processThreadStoreOperations(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->processThreadStoreOperations(rt, args[0].getObject(rt).getArray(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processThreadStoreOperationsSync(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
- return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->processThreadStoreOperationsSync(rt, args[0].getObject(rt).getArray(rt));
+ static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->processThreadStoreOperationsSync(rt, args[0].getObject(rt).getArray(rt));
+ return jsi::Value::undefined();
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeCryptoAccount(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->initializeCryptoAccount(rt, args[0].getString(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUserPublicKey(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getUserPublicKey(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUserOneTimeKeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getUserOneTimeKeys(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_openSocket(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->openSocket(rt, args[0].getString(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getCodeVersion(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getCodeVersion(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setNotifyToken(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->setNotifyToken(rt, args[0].getString(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearNotifyToken(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->clearNotifyToken(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setCurrentUserID(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->setCurrentUserID(rt, args[0].getString(rt));
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getCurrentUserID(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->getCurrentUserID(rt);
}
static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearSensitiveData(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
return static_cast<CommCoreModuleSchemaCxxSpecJSI *>(&turboModule)->clearSensitiveData(rt);
}
CommCoreModuleSchemaCxxSpecJSI::CommCoreModuleSchemaCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
: TurboModule("CommTurboModule", jsInvoker) {
methodMap_["getDraft"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getDraft};
methodMap_["updateDraft"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_updateDraft};
methodMap_["moveDraft"] = MethodMetadata {2, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_moveDraft};
methodMap_["getAllDrafts"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllDrafts};
methodMap_["removeAllDrafts"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_removeAllDrafts};
methodMap_["getAllMessages"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllMessages};
methodMap_["getAllMessagesSync"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllMessagesSync};
methodMap_["processMessageStoreOperations"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processMessageStoreOperations};
methodMap_["processMessageStoreOperationsSync"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processMessageStoreOperationsSync};
methodMap_["getAllThreads"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllThreads};
methodMap_["getAllThreadsSync"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getAllThreadsSync};
methodMap_["processThreadStoreOperations"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processThreadStoreOperations};
methodMap_["processThreadStoreOperationsSync"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processThreadStoreOperationsSync};
methodMap_["initializeCryptoAccount"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeCryptoAccount};
methodMap_["getUserPublicKey"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUserPublicKey};
methodMap_["getUserOneTimeKeys"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUserOneTimeKeys};
methodMap_["openSocket"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_openSocket};
methodMap_["getCodeVersion"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getCodeVersion};
methodMap_["setNotifyToken"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setNotifyToken};
methodMap_["clearNotifyToken"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearNotifyToken};
methodMap_["setCurrentUserID"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_setCurrentUserID};
methodMap_["getCurrentUserID"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getCurrentUserID};
methodMap_["clearSensitiveData"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearSensitiveData};
}
} // namespace react
} // namespace facebook
diff --git a/native/cpp/CommonCpp/_generated/NativeModules.h b/native/cpp/CommonCpp/_generated/NativeModules.h
index e6c120b45..54c53d00f 100644
--- a/native/cpp/CommonCpp/_generated/NativeModules.h
+++ b/native/cpp/CommonCpp/_generated/NativeModules.h
@@ -1,48 +1,48 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated by codegen project: GenerateModuleH.js
*/
#pragma once
#include <ReactCommon/TurboModule.h>
namespace facebook {
namespace react {
class JSI_EXPORT CommCoreModuleSchemaCxxSpecJSI : public TurboModule {
protected:
CommCoreModuleSchemaCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker);
public:
virtual jsi::Value getDraft(jsi::Runtime &rt, const jsi::String &key) = 0;
virtual jsi::Value updateDraft(jsi::Runtime &rt, const jsi::Object &draft) = 0;
virtual jsi::Value moveDraft(jsi::Runtime &rt, const jsi::String &oldKey, const jsi::String &newKey) = 0;
virtual jsi::Value getAllDrafts(jsi::Runtime &rt) = 0;
virtual jsi::Value removeAllDrafts(jsi::Runtime &rt) = 0;
virtual jsi::Value getAllMessages(jsi::Runtime &rt) = 0;
virtual jsi::Array getAllMessagesSync(jsi::Runtime &rt) = 0;
virtual jsi::Value processMessageStoreOperations(jsi::Runtime &rt, const jsi::Array &operations) = 0;
-virtual bool processMessageStoreOperationsSync(jsi::Runtime &rt, const jsi::Array &operations) = 0;
+virtual void processMessageStoreOperationsSync(jsi::Runtime &rt, const jsi::Array &operations) = 0;
virtual jsi::Value getAllThreads(jsi::Runtime &rt) = 0;
virtual jsi::Array getAllThreadsSync(jsi::Runtime &rt) = 0;
virtual jsi::Value processThreadStoreOperations(jsi::Runtime &rt, const jsi::Array &operations) = 0;
-virtual bool processThreadStoreOperationsSync(jsi::Runtime &rt, const jsi::Array &operations) = 0;
+virtual void processThreadStoreOperationsSync(jsi::Runtime &rt, const jsi::Array &operations) = 0;
virtual jsi::Value initializeCryptoAccount(jsi::Runtime &rt, const jsi::String &userId) = 0;
virtual jsi::Value getUserPublicKey(jsi::Runtime &rt) = 0;
virtual jsi::Value getUserOneTimeKeys(jsi::Runtime &rt) = 0;
virtual jsi::Object openSocket(jsi::Runtime &rt, const jsi::String &endpoint) = 0;
virtual double getCodeVersion(jsi::Runtime &rt) = 0;
virtual jsi::Value setNotifyToken(jsi::Runtime &rt, const jsi::String &token) = 0;
virtual jsi::Value clearNotifyToken(jsi::Runtime &rt) = 0;
virtual jsi::Value setCurrentUserID(jsi::Runtime &rt, const jsi::String &userID) = 0;
virtual jsi::Value getCurrentUserID(jsi::Runtime &rt) = 0;
virtual jsi::Value clearSensitiveData(jsi::Runtime &rt) = 0;
};
} // namespace react
} // namespace facebook
diff --git a/native/redux/persist.js b/native/redux/persist.js
index 17d9da075..80fc5ae7c 100644
--- a/native/redux/persist.js
+++ b/native/redux/persist.js
@@ -1,456 +1,458 @@
// @flow
import AsyncStorage from '@react-native-community/async-storage';
import invariant from 'invariant';
import { Platform } from 'react-native';
import Orientation from 'react-native-orientation-locker';
import { createMigrate, createTransform } from 'redux-persist';
import type { Transform } from 'redux-persist/es/types';
import { highestLocalIDSelector } from 'lib/selectors/local-id-selectors';
import { inconsistencyResponsesToReports } from 'lib/shared/report-utils';
import { getContainingThreadID, getCommunity } from 'lib/shared/thread-utils';
import { unshimMessageStore } from 'lib/shared/unshim-utils';
import { defaultEnabledApps } from 'lib/types/enabled-apps';
import { defaultCalendarFilters } from 'lib/types/filter-types';
import {
type LocalMessageInfo,
type MessageStore,
messageTypes,
type ClientDBMessageStoreOperation,
type RawMessageInfo,
} from 'lib/types/message-types';
import { defaultConnectionInfo } from 'lib/types/socket-types';
import { translateRawMessageInfoToClientDBMessageInfo } from 'lib/utils/message-ops-utils';
import { convertThreadStoreOperationsToClientDBOperations } from 'lib/utils/thread-ops-utils';
import { commCoreModule } from '../native-modules';
import { defaultNotifPermissionAlertInfo } from '../push/alerts';
import { defaultDeviceCameraInfo } from '../types/camera';
import { defaultGlobalThemeInfo } from '../types/themes';
import { migrateThreadStoreForEditThreadPermissions } from './edit-thread-permission-migration';
import type { AppState } from './state-types';
const migrations = {
[1]: (state: AppState) => ({
...state,
notifPermissionAlertInfo: defaultNotifPermissionAlertInfo,
}),
[2]: (state: AppState) => ({
...state,
messageSentFromRoute: [],
}),
[3]: state => ({
currentUserInfo: state.currentUserInfo,
entryStore: state.entryStore,
threadInfos: state.threadInfos,
userInfos: state.userInfos,
messageStore: {
...state.messageStore,
currentAsOf: state.currentAsOf,
},
updatesCurrentAsOf: state.currentAsOf,
cookie: state.cookie,
deviceToken: state.deviceToken,
urlPrefix: state.urlPrefix,
customServer: state.customServer,
threadIDsToNotifIDs: state.threadIDsToNotifIDs,
notifPermissionAlertInfo: state.notifPermissionAlertInfo,
messageSentFromRoute: state.messageSentFromRoute,
_persist: state._persist,
}),
[4]: (state: AppState) => ({
...state,
pingTimestamps: undefined,
activeServerRequests: undefined,
}),
[5]: (state: AppState) => ({
...state,
calendarFilters: defaultCalendarFilters,
}),
[6]: state => ({
...state,
threadInfos: undefined,
threadStore: {
threadInfos: state.threadInfos,
inconsistencyResponses: [],
},
}),
[7]: state => ({
...state,
lastUserInteraction: undefined,
sessionID: undefined,
entryStore: {
...state.entryStore,
inconsistencyResponses: [],
},
}),
[8]: (state: AppState) => ({
...state,
pingTimestamps: undefined,
activeServerRequests: undefined,
connection: defaultConnectionInfo(Platform.OS),
watchedThreadIDs: [],
entryStore: {
...state.entryStore,
actualizedCalendarQuery: undefined,
},
}),
[9]: (state: AppState) => ({
...state,
connection: {
...state.connection,
lateResponses: [],
},
}),
[10]: (state: AppState) => ({
...state,
nextLocalID: highestLocalIDSelector(state) + 1,
connection: {
...state.connection,
showDisconnectedBar: false,
},
messageStore: {
...state.messageStore,
local: {},
},
}),
[11]: (state: AppState) => ({
...state,
messageStore: unshimMessageStore(state.messageStore, [messageTypes.IMAGES]),
}),
[12]: (state: AppState) => ({
...state,
globalThemeInfo: defaultGlobalThemeInfo,
}),
[13]: (state: AppState) => ({
...state,
deviceCameraInfo: defaultDeviceCameraInfo,
deviceOrientation: Orientation.getInitialOrientation(),
}),
[14]: (state: AppState) => state,
[15]: state => ({
...state,
threadStore: {
...state.threadStore,
inconsistencyReports: inconsistencyResponsesToReports(
state.threadStore.inconsistencyResponses,
),
inconsistencyResponses: undefined,
},
entryStore: {
...state.entryStore,
inconsistencyReports: inconsistencyResponsesToReports(
state.entryStore.inconsistencyResponses,
),
inconsistencyResponses: undefined,
},
queuedReports: [],
}),
[16]: state => {
const result = {
...state,
messageSentFromRoute: undefined,
dataLoaded: !!state.currentUserInfo && !state.currentUserInfo.anonymous,
};
if (state.navInfo) {
result.navInfo = {
...state.navInfo,
navigationState: undefined,
};
}
return result;
},
[17]: state => ({
...state,
userInfos: undefined,
userStore: {
userInfos: state.userInfos,
inconsistencyResponses: [],
},
}),
[18]: state => ({
...state,
userStore: {
userInfos: state.userStore.userInfos,
inconsistencyReports: [],
},
}),
[19]: state => {
const threadInfos = {};
for (const threadID in state.threadStore.threadInfos) {
const threadInfo = state.threadStore.threadInfos[threadID];
const { visibilityRules, ...rest } = threadInfo;
threadInfos[threadID] = rest;
}
return {
...state,
threadStore: {
...state.threadStore,
threadInfos,
},
};
},
[20]: (state: AppState) => ({
...state,
messageStore: unshimMessageStore(state.messageStore, [
messageTypes.UPDATE_RELATIONSHIP,
]),
}),
[21]: (state: AppState) => ({
...state,
messageStore: unshimMessageStore(state.messageStore, [
messageTypes.CREATE_SIDEBAR,
messageTypes.SIDEBAR_SOURCE,
]),
}),
[22]: state => {
for (const key in state.drafts) {
const value = state.drafts[key];
commCoreModule.updateDraft({
key,
text: value,
});
}
return {
...state,
drafts: undefined,
};
},
[23]: state => ({
...state,
globalThemeInfo: defaultGlobalThemeInfo,
}),
[24]: state => ({
...state,
enabledApps: defaultEnabledApps,
}),
[25]: state => ({
...state,
crashReportsEnabled: __DEV__,
}),
[26]: state => {
const { currentUserInfo } = state;
if (currentUserInfo.anonymous) {
return state;
}
return {
...state,
crashReportsEnabled: undefined,
currentUserInfo: {
id: currentUserInfo.id,
username: currentUserInfo.username,
},
enabledReports: {
crashReports: __DEV__,
inconsistencyReports: __DEV__,
mediaReports: __DEV__,
},
};
},
[27]: state => ({
...state,
queuedReports: undefined,
enabledReports: undefined,
threadStore: {
...state.threadStore,
inconsistencyReports: undefined,
},
entryStore: {
...state.entryStore,
inconsistencyReports: undefined,
},
reportStore: {
enabledReports: {
crashReports: __DEV__,
inconsistencyReports: __DEV__,
mediaReports: __DEV__,
},
queuedReports: [
...state.entryStore.inconsistencyReports,
...state.threadStore.inconsistencyReports,
...state.queuedReports,
],
},
}),
[28]: state => {
const threadParentToChildren = {};
for (const threadID in state.threadStore.threadInfos) {
const threadInfo = state.threadStore.threadInfos[threadID];
const parentThreadInfo = threadInfo.parentThreadID
? state.threadStore.threadInfos[threadInfo.parentThreadID]
: null;
const parentIndex = parentThreadInfo ? parentThreadInfo.id : '-1';
if (!threadParentToChildren[parentIndex]) {
threadParentToChildren[parentIndex] = [];
}
threadParentToChildren[parentIndex].push(threadID);
}
const rootIDs = threadParentToChildren['-1'];
if (!rootIDs) {
// This should never happen, but if it somehow does we'll let the state
// check mechanism resolve it...
return state;
}
const threadInfos = {};
const stack = [...rootIDs];
while (stack.length > 0) {
const threadID = stack.shift();
const threadInfo = state.threadStore.threadInfos[threadID];
const parentThreadInfo = threadInfo.parentThreadID
? threadInfos[threadInfo.parentThreadID]
: null;
threadInfos[threadID] = {
...threadInfo,
containingThreadID: getContainingThreadID(
parentThreadInfo,
threadInfo.type,
),
community: getCommunity(parentThreadInfo),
};
const children = threadParentToChildren[threadID];
if (children) {
stack.push(...children);
}
}
return { ...state, threadStore: { ...state.threadStore, threadInfos } };
},
[29]: (state: AppState) => {
const updatedThreadInfos = migrateThreadStoreForEditThreadPermissions(
state.threadStore.threadInfos,
);
return {
...state,
threadStore: {
...state.threadStore,
threadInfos: updatedThreadInfos,
},
};
},
[30]: (state: AppState) => {
const threadInfos = state.threadStore.threadInfos;
const operations = [
{
type: 'remove_all',
},
...Object.keys(threadInfos).map((id: string) => ({
type: 'replace',
payload: { id, threadInfo: threadInfos[id] },
})),
];
- const processingResult: boolean = commCoreModule.processThreadStoreOperationsSync(
- convertThreadStoreOperationsToClientDBOperations(operations),
- );
- if (!processingResult) {
+ try {
+ commCoreModule.processThreadStoreOperationsSync(
+ convertThreadStoreOperationsToClientDBOperations(operations),
+ );
+ } catch (exception) {
+ console.log(exception);
return { ...state, cookie: null };
}
return state;
},
[31]: (state: AppState) => {
const messages = state.messageStore.messages;
const operations: $ReadOnlyArray<ClientDBMessageStoreOperation> = [
{
type: 'remove_all',
},
...Object.keys(messages).map((id: string) => ({
type: 'replace',
payload: translateRawMessageInfoToClientDBMessageInfo(messages[id]),
})),
];
- const processingResult: boolean = commCoreModule.processMessageStoreOperationsSync(
- operations,
- );
- if (!processingResult) {
+ try {
+ commCoreModule.processMessageStoreOperationsSync(operations);
+ } catch (exception) {
+ console.log(exception);
return { ...state, cookie: null };
}
return state;
},
};
// After migration 31, we'll no longer want to persist `messageStore.messages`
// via redux-persist. However, we DO want to continue persisting everything in
// `messageStore` EXCEPT for `messages`. The `blacklist` property in
// `persistConfig` allows us to specify top-level keys that shouldn't be
// persisted. However, we aren't able to specify nested keys in `blacklist`.
// As a result, if we want to prevent nested keys from being persisted we'll
// need to use `createTransform(...)` to specify an `inbound` function that
// allows us to modify the `state` object before it's passed through
// `JSON.stringify(...)` and written to disk. We specify the keys for which
// this transformation should be executed in the `whitelist` property of the
// `config` object that's passed to `createTransform(...)`.
// eslint-disable-next-line no-unused-vars
type PersistedThreadMessageInfo = {
+startReached: boolean,
+lastNavigatedTo: number,
+lastPruned: number,
};
type PersistedMessageStore = {
+local: { +[id: string]: LocalMessageInfo },
+currentAsOf: number,
+threads: { +[threadID: string]: PersistedThreadMessageInfo },
};
type RehydratedMessageStore = $Diff<
MessageStore,
{ +messages: { +[id: string]: RawMessageInfo } },
>;
const messageStoreMessagesBlocklistTransform: Transform = createTransform(
(state: MessageStore): PersistedMessageStore => {
const { messages, threads, ...messageStoreSansMessages } = state;
// We also do not want to persist `messageStore.threads[ID].messageIDs`
// because they can be deterministically computed based on messages we have
// from SQLite
const threadsToPersist = {};
for (const threadID in threads) {
const { messageIDs, ...threadsData } = threads[threadID];
threadsToPersist[threadID] = threadsData;
}
return { ...messageStoreSansMessages, threads: threadsToPersist };
},
(state: PersistedMessageStore): RehydratedMessageStore => {
const { threads: persistedThreads, ...messageStore } = state;
const threads = {};
for (const threadID in persistedThreads) {
threads[threadID] = { ...persistedThreads[threadID], messageIDs: [] };
}
return { ...messageStore, threads };
},
{ whitelist: ['messageStore'] },
);
const persistConfig = {
key: 'root',
storage: AsyncStorage,
blacklist: [
'loadingStatuses',
'lifecycleState',
'dimensions',
'connectivity',
'deviceOrientation',
'frozen',
'threadStore',
],
debug: __DEV__,
version: 31,
transforms: [messageStoreMessagesBlocklistTransform],
migrate: (createMigrate(migrations, { debug: __DEV__ }): any),
timeout: ((__DEV__ ? 0 : undefined): number | void),
};
const codeVersion: number = commCoreModule.getCodeVersion();
// This local exists to avoid a circular dependency where redux-setup needs to
// import all the navigation and screen stuff, but some of those screens want to
// access the persistor to purge its state.
let storedPersistor = null;
function setPersistor(persistor: *) {
storedPersistor = persistor;
}
function getPersistor(): empty {
invariant(storedPersistor, 'should be set');
return storedPersistor;
}
export { persistConfig, codeVersion, setPersistor, getPersistor };
diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js
index 73e1073b2..95b0baa80 100644
--- a/native/schema/CommCoreModuleSchema.js
+++ b/native/schema/CommCoreModuleSchema.js
@@ -1,58 +1,58 @@
// @flow
'use strict';
import { TurboModuleRegistry } from 'react-native';
import type { TurboModule } from 'react-native/Libraries/TurboModule/RCTExport';
import type {
ClientDBMessageInfo,
ClientDBMessageStoreOperation,
} from 'lib/types/message-types';
import type {
ClientDBThreadInfo,
ClientDBThreadStoreOperation,
} from 'lib/types/thread-types';
type ClientDBDraftInfo = {
+key: string,
+text: string,
};
export interface Spec extends TurboModule {
+getDraft: (key: string) => Promise<string>;
+updateDraft: (draft: ClientDBDraftInfo) => Promise<boolean>;
+moveDraft: (oldKey: string, newKey: string) => Promise<boolean>;
+getAllDrafts: () => Promise<$ReadOnlyArray<ClientDBDraftInfo>>;
+removeAllDrafts: () => Promise<void>;
+getAllMessages: () => Promise<$ReadOnlyArray<ClientDBMessageInfo>>;
+getAllMessagesSync: () => $ReadOnlyArray<ClientDBMessageInfo>;
+processMessageStoreOperations: (
operations: $ReadOnlyArray<ClientDBMessageStoreOperation>,
) => Promise<void>;
+processMessageStoreOperationsSync: (
operations: $ReadOnlyArray<ClientDBMessageStoreOperation>,
- ) => boolean;
+ ) => void;
+getAllThreads: () => Promise<$ReadOnlyArray<ClientDBThreadInfo>>;
+getAllThreadsSync: () => $ReadOnlyArray<ClientDBThreadInfo>;
+processThreadStoreOperations: (
operations: $ReadOnlyArray<ClientDBThreadStoreOperation>,
) => Promise<void>;
+processThreadStoreOperationsSync: (
operations: $ReadOnlyArray<ClientDBThreadStoreOperation>,
- ) => boolean;
+ ) => void;
+initializeCryptoAccount: (userId: string) => Promise<string>;
+getUserPublicKey: () => Promise<string>;
+getUserOneTimeKeys: () => Promise<string>;
+openSocket: (endpoint: string) => Object;
+getCodeVersion: () => number;
+setNotifyToken: (token: string) => Promise<void>;
+clearNotifyToken: () => Promise<void>;
+setCurrentUserID: (userID: string) => Promise<void>;
+getCurrentUserID: () => Promise<string>;
+clearSensitiveData: () => Promise<void>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'CommTurboModule',
): Spec);
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Dec 23, 12:29 AM (3 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2690058
Default Alt Text
(72 KB)
Attached To
Mode
rCOMM Comm
Attached
Detach File
Event Timeline
Log In to Comment