Page MenuHomePhabricator

No OneTemporary

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

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)

Event Timeline