diff --git a/native/cpp/CommonCpp/NativeModules/CMakeLists.txt b/native/cpp/CommonCpp/NativeModules/CMakeLists.txt --- a/native/cpp/CommonCpp/NativeModules/CMakeLists.txt +++ b/native/cpp/CommonCpp/NativeModules/CMakeLists.txt @@ -21,6 +21,7 @@ "KeyserverStoreOperations.h" "CommunityStoreOperations.h" "IntegrityStoreOperations.h" + "SyncedMetadataStoreOperations.h" ) set(NATIVE_SRCS @@ -85,6 +86,7 @@ ${_data_stores_path}/KeyserverStore.h ${_data_stores_path}/CommunityStore.h ${_data_stores_path}/IntegrityStore.h + ${_data_stores_path}/SyncedMetadataStore.h ) set(DATA_STORES_SRCS ${_data_stores_path}/DraftStore.cpp @@ -95,6 +97,7 @@ ${_data_stores_path}/KeyserverStore.cpp ${_data_stores_path}/CommunityStore.cpp ${_data_stores_path}/IntegrityStore.cpp + ${_data_stores_path}/SyncedMetadataStore.cpp ) set(_backup_op_path ./PersistentStorageUtilities/BackupOperationsUtilities) diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h --- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.h +++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.h @@ -11,6 +11,7 @@ #include "PersistentStorageUtilities/DataStores/KeyserverStore.h" #include "PersistentStorageUtilities/DataStores/MessageStore.h" #include "PersistentStorageUtilities/DataStores/ReportStore.h" +#include "PersistentStorageUtilities/DataStores/SyncedMetadataStore.h" #include "PersistentStorageUtilities/DataStores/ThreadStore.h" #include "PersistentStorageUtilities/DataStores/UserStore.h" #include @@ -39,6 +40,7 @@ KeyserverStore keyserverStore; CommunityStore communityStore; IntegrityStore integrityStore; + SyncedMetadataStore syncedMetadataStore; void persistCryptoModules(bool persistContentModule, bool persistNotifsModule); @@ -83,6 +85,9 @@ virtual jsi::Value processIntegrityStoreOperations( jsi::Runtime &rt, jsi::Array operations) override; + virtual jsi::Value processSyncedMetadataStoreOperations( + jsi::Runtime &rt, + jsi::Array operations) override; virtual jsi::Value initializeCryptoAccount(jsi::Runtime &rt) override; virtual jsi::Value getUserPublicKey(jsi::Runtime &rt) override; virtual jsi::Value diff --git a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp --- a/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp +++ b/native/cpp/CommonCpp/NativeModules/CommCoreModule.cpp @@ -347,6 +347,13 @@ return this->integrityStore.processStoreOperations(rt, std::move(operations)); } +jsi::Value CommCoreModule::processSyncedMetadataStoreOperations( + jsi::Runtime &rt, + jsi::Array operations) { + return this->syncedMetadataStore.processStoreOperations( + rt, std::move(operations)); +} + void CommCoreModule::terminate(jsi::Runtime &rt) { TerminateApp::terminate(); } @@ -1326,7 +1333,8 @@ userStore(jsInvoker), keyserverStore(jsInvoker), communityStore(jsInvoker), - integrityStore(jsInvoker) { + integrityStore(jsInvoker), + syncedMetadataStore(jsInvoker) { GlobalDBSingleton::instance.enableMultithreading(); } diff --git a/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/DataStores/SyncedMetadataStore.h b/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/DataStores/SyncedMetadataStore.h new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/DataStores/SyncedMetadataStore.h @@ -0,0 +1,32 @@ +#pragma once + +#include "../../../DatabaseManagers/entities/SyncedMetadataEntry.h" +#include "BaseDataStore.h" +#include "SyncedMetadataStoreOperations.h" + +#include + +namespace comm { + +class SyncedMetadataStore : public BaseDataStore< + SyncedMetadataStoreOperationBase, + SyncedMetadataEntry> { +private: + static OperationType REMOVE_OPERATION; + static OperationType REMOVE_ALL_OPERATION; + static OperationType REPLACE_OPERATION; + +public: + SyncedMetadataStore(std::shared_ptr jsInvoker); + + std::vector> + createOperations(jsi::Runtime &rt, const jsi::Array &operations) + const override; + + jsi::Array parseDBDataStore( + jsi::Runtime &rt, + std::shared_ptr> dataVectorPtr) + const override; +}; + +} // namespace comm diff --git a/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/DataStores/SyncedMetadataStore.cpp b/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/DataStores/SyncedMetadataStore.cpp new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/DataStores/SyncedMetadataStore.cpp @@ -0,0 +1,74 @@ +#include "SyncedMetadataStore.h" + +#include +#include + +namespace comm { + +OperationType SyncedMetadataStore::REMOVE_OPERATION = "remove_synced_metadata"; +OperationType SyncedMetadataStore::REMOVE_ALL_OPERATION = + "remove_all_synced_metadata"; +OperationType SyncedMetadataStore::REPLACE_OPERATION = + "replace_synced_metadata_entry"; + +SyncedMetadataStore::SyncedMetadataStore( + std::shared_ptr jsInvoker) + : BaseDataStore(jsInvoker) { +} + +jsi::Array SyncedMetadataStore::parseDBDataStore( + jsi::Runtime &rt, + std::shared_ptr> syncedMetadataVectorPtr) + const { + jsi::Array jsiSyncedMetadata = jsi::Array(rt, 0); + return jsiSyncedMetadata; +} + +std::vector> +SyncedMetadataStore::createOperations( + jsi::Runtime &rt, + const jsi::Array &operations) const { + std::vector> + syncedMetadataStoreOps; + + 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 syncedMetadataNamesToRemove; + jsi::Object payloadObj = op.getProperty(rt, "payload").asObject(rt); + jsi::Array syncedMetadataNames = + payloadObj.getProperty(rt, "names").asObject(rt).asArray(rt); + for (int nameIdx = 0; nameIdx < syncedMetadataNames.size(rt); nameIdx++) { + syncedMetadataNamesToRemove.push_back( + syncedMetadataNames.getValueAtIndex(rt, nameIdx) + .asString(rt) + .utf8(rt)); + } + syncedMetadataStoreOps.push_back( + std::make_unique( + std::move(syncedMetadataNamesToRemove))); + } else if (opType == REMOVE_ALL_OPERATION) { + syncedMetadataStoreOps.push_back( + std::make_unique()); + } else if (opType == REPLACE_OPERATION) { + jsi::Object payloadObj = op.getProperty(rt, "payload").asObject(rt); + std::string name = + payloadObj.getProperty(rt, "name").asString(rt).utf8(rt); + std::string data = + payloadObj.getProperty(rt, "data").asString(rt).utf8(rt); + + SyncedMetadataEntry syncedMetadataEntry{name, data}; + + syncedMetadataStoreOps.push_back( + std::make_unique( + std::move(syncedMetadataEntry))); + } else { + throw std::runtime_error("unsupported operation: " + opType); + } + }; + return syncedMetadataStoreOps; +} + +} // namespace comm diff --git a/native/cpp/CommonCpp/NativeModules/SyncedMetadataStoreOperations.h b/native/cpp/CommonCpp/NativeModules/SyncedMetadataStoreOperations.h new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/NativeModules/SyncedMetadataStoreOperations.h @@ -0,0 +1,51 @@ +#pragma once + +#include "../DatabaseManagers/entities/SyncedMetadataEntry.h" +#include "DatabaseManager.h" +#include + +namespace comm { + +class SyncedMetadataStoreOperationBase { +public: + virtual void execute() = 0; + virtual ~SyncedMetadataStoreOperationBase(){}; +}; + +class RemoveSyncedMetadataOperation : public SyncedMetadataStoreOperationBase { +public: + RemoveSyncedMetadataOperation(std::vector names) : names{names} { + } + + virtual void execute() override { + DatabaseManager::getQueryExecutor().removeSyncedMetadata(this->names); + } + +private: + std::vector names; +}; + +class ReplaceSyncedMetadataOperation : public SyncedMetadataStoreOperationBase { +public: + ReplaceSyncedMetadataOperation(SyncedMetadataEntry &&syncedMetadataEntry) + : syncedMetadataEntry{std::move(syncedMetadataEntry)} { + } + + virtual void execute() override { + DatabaseManager::getQueryExecutor().replaceSyncedMetadataEntry( + this->syncedMetadataEntry); + } + +private: + SyncedMetadataEntry syncedMetadataEntry; +}; + +class RemoveAllSyncedMetadataOperation + : public SyncedMetadataStoreOperationBase { +public: + virtual void execute() override { + DatabaseManager::getQueryExecutor().removeAllSyncedMetadata(); + } +}; + +} // namespace comm diff --git a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp --- a/native/cpp/CommonCpp/_generated/commJSI-generated.cpp +++ b/native/cpp/CommonCpp/_generated/commJSI-generated.cpp @@ -69,6 +69,9 @@ static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processIntegrityStoreOperations(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->processIntegrityStoreOperations(rt, args[0].asObject(rt).asArray(rt)); } +static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processSyncedMetadataStoreOperations(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->processSyncedMetadataStoreOperations(rt, args[0].asObject(rt).asArray(rt)); +} static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeCryptoAccount(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->initializeCryptoAccount(rt); } @@ -202,6 +205,7 @@ methodMap_["processKeyserverStoreOperations"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processKeyserverStoreOperations}; methodMap_["processCommunityStoreOperations"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processCommunityStoreOperations}; methodMap_["processIntegrityStoreOperations"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processIntegrityStoreOperations}; + methodMap_["processSyncedMetadataStoreOperations"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_processSyncedMetadataStoreOperations}; methodMap_["initializeCryptoAccount"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_initializeCryptoAccount}; methodMap_["getUserPublicKey"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getUserPublicKey}; methodMap_["getOneTimeKeys"] = MethodMetadata {1, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_getOneTimeKeys}; diff --git a/native/cpp/CommonCpp/_generated/commJSI.h b/native/cpp/CommonCpp/_generated/commJSI.h --- a/native/cpp/CommonCpp/_generated/commJSI.h +++ b/native/cpp/CommonCpp/_generated/commJSI.h @@ -38,6 +38,7 @@ virtual jsi::Value processKeyserverStoreOperations(jsi::Runtime &rt, jsi::Array operations) = 0; virtual jsi::Value processCommunityStoreOperations(jsi::Runtime &rt, jsi::Array operations) = 0; virtual jsi::Value processIntegrityStoreOperations(jsi::Runtime &rt, jsi::Array operations) = 0; + virtual jsi::Value processSyncedMetadataStoreOperations(jsi::Runtime &rt, jsi::Array operations) = 0; virtual jsi::Value initializeCryptoAccount(jsi::Runtime &rt) = 0; virtual jsi::Value getUserPublicKey(jsi::Runtime &rt) = 0; virtual jsi::Value getOneTimeKeys(jsi::Runtime &rt, double oneTimeKeysAmount) = 0; @@ -239,6 +240,14 @@ return bridging::callFromJs( rt, &T::processIntegrityStoreOperations, jsInvoker_, instance_, std::move(operations)); } + jsi::Value processSyncedMetadataStoreOperations(jsi::Runtime &rt, jsi::Array operations) override { + static_assert( + bridging::getParameterCount(&T::processSyncedMetadataStoreOperations) == 2, + "Expected processSyncedMetadataStoreOperations(...) to have 2 parameters"); + + return bridging::callFromJs( + rt, &T::processSyncedMetadataStoreOperations, jsInvoker_, instance_, std::move(operations)); + } jsi::Value initializeCryptoAccount(jsi::Runtime &rt) override { static_assert( bridging::getParameterCount(&T::initializeCryptoAccount) == 1, diff --git a/native/ios/Comm.xcodeproj/project.pbxproj b/native/ios/Comm.xcodeproj/project.pbxproj --- a/native/ios/Comm.xcodeproj/project.pbxproj +++ b/native/ios/Comm.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 1F537ACC7B60DC049C0ECFA7 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 769A87FB41BCE3FEF97FD59A /* ExpoModulesProvider.swift */; }; 34329B442B9EC7EC00233438 /* IntegrityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34329B3F2B9EBFCE00233438 /* IntegrityStore.cpp */; }; + 34055C152BAD31AC0008E713 /* SyncedMetadataStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34055C142BAD31AC0008E713 /* SyncedMetadataStore.cpp */; }; 71142A7726C2650B0039DCBD /* CommSecureStoreIOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */; }; 711B408425DA97F9005F8F06 /* dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F26E81B24440D87004049C6 /* dummy.swift */; }; 71762A75270D8AAE00F565ED /* PlatformSpecificTools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */; }; @@ -143,6 +144,9 @@ 34329B3F2B9EBFCE00233438 /* IntegrityStore.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = IntegrityStore.cpp; path = PersistentStorageUtilities/DataStores/IntegrityStore.cpp; sourceTree = ""; }; 34329B402B9EBFCE00233438 /* IntegrityStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = IntegrityStore.h; path = PersistentStorageUtilities/DataStores/IntegrityStore.h; sourceTree = ""; }; 34329B452B9EC96200233438 /* IntegrityThreadHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntegrityThreadHash.h; sourceTree = ""; }; + 34055C132BAD31AB0008E713 /* SyncedMetadataStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SyncedMetadataStore.h; path = PersistentStorageUtilities/DataStores/SyncedMetadataStore.h; sourceTree = ""; }; + 34055C142BAD31AC0008E713 /* SyncedMetadataStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SyncedMetadataStore.cpp; path = PersistentStorageUtilities/DataStores/SyncedMetadataStore.cpp; sourceTree = ""; }; + 34055C162BAD31BD0008E713 /* SyncedMetadataStoreOperations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SyncedMetadataStoreOperations.h; sourceTree = ""; }; 3EE4DCB430B05EC9DE7D7B01 /* libPods-NotificationService.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NotificationService.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 3EEB3E70587B0ADAD05237B0 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Comm/ExpoModulesProvider.swift"; sourceTree = ""; }; 71142A7526C2650A0039DCBD /* CommSecureStoreIOSWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommSecureStoreIOSWrapper.h; path = Comm/CommSecureStoreIOSWrapper.h; sourceTree = ""; }; @@ -488,6 +492,7 @@ 71BE843E2636A944002849D2 /* CommCoreModule.h */, 7FBB2A7329E944FD002C6493 /* CommUtilsModule.cpp */, 7FBB2A7429E9450E002C6493 /* CommUtilsModule.h */, + 34055C162BAD31BD0008E713 /* SyncedMetadataStoreOperations.h */, B7055C6B26E477CF00BE0548 /* MessageStoreOperations.h */, B7906F692720905A009BBBF5 /* ThreadStoreOperations.h */, ); @@ -664,6 +669,8 @@ 8EA59BD42A6E8E0400EB4F53 /* DraftStore.cpp */, 8EA59BD52A6E8E0400EB4F53 /* DraftStore.h */, 8EA59BD32A6E8CB700EB4F53 /* BaseDataStore.h */, + 34055C142BAD31AC0008E713 /* SyncedMetadataStore.cpp */, + 34055C132BAD31AB0008E713 /* SyncedMetadataStore.h */, ); name = DataStores; sourceTree = ""; @@ -1141,6 +1148,7 @@ CB7EF180295C674300B17035 /* CommIOSNotificationsBridgeQueue.mm in Sources */, 7F0C6E31291C4468002AA2D9 /* ExpoModulesProvider.swift in Sources */, 8EF775682A74032C0046A385 /* CommRustModule.cpp in Sources */, + 34055C152BAD31AC0008E713 /* SyncedMetadataStore.cpp in Sources */, 8E43C32C291E5B4A009378F5 /* TerminateApp.mm in Sources */, B3B02EBF2B8538980020D118 /* CommunityStore.cpp in Sources */, 8BC9568529FC49B00060AE4A /* JSIRust.cpp in Sources */, diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js --- a/native/schema/CommCoreModuleSchema.js +++ b/native/schema/CommCoreModuleSchema.js @@ -10,6 +10,7 @@ import type { ClientDBKeyserverStoreOperation } from 'lib/ops/keyserver-store-ops'; import type { ClientDBMessageStoreOperation } from 'lib/ops/message-store-ops.js'; import type { ClientDBReportStoreOperation } from 'lib/ops/report-store-ops.js'; +import type { ClientDBSyncedMetadataStoreOperation } from 'lib/ops/synced-metadata-store-ops.js'; import type { ClientDBThreadStoreOperation } from 'lib/ops/thread-store-ops.js'; import type { ClientDBUserStoreOperation } from 'lib/ops/user-store-ops'; import type { @@ -70,6 +71,9 @@ +processIntegrityStoreOperations: ( operations: $ReadOnlyArray, ) => Promise; + +processSyncedMetadataStoreOperations: ( + operations: $ReadOnlyArray, + ) => Promise; +initializeCryptoAccount: () => Promise; +getUserPublicKey: () => Promise; +getOneTimeKeys: (oneTimeKeysAmount: number) => Promise;