diff --git a/native/android/app/src/cpp/RustNetworkingSingleton.cpp b/native/android/app/src/cpp/RustNetworkingSingleton.cpp new file mode 100644 --- /dev/null +++ b/native/android/app/src/cpp/RustNetworkingSingleton.cpp @@ -0,0 +1,67 @@ +#include +#include + +namespace comm { +RustNetworkingSingleton RustNetworkingSingleton::instance; + +RustNetworkingSingleton::RustNetworkingSingleton() + : multithreadingEnabled(true), + rustNetworkingThread(std::make_unique("rust-networking")) { +} + +void RustNetworkingSingleton::schedule(const taskType task) { + this->scheduleCommonImpl(task); +} + +void RustNetworkingSingleton::enableMultithreading() { + this->enableMultithreadingCommonImpl(); +} + +uint32_t RustNetworkingSingleton::addPromise( + std::shared_ptr promise, + std::shared_ptr jsInvoker) { + return addPromiseCommonImpl(promise, jsInvoker); +} + +void RustNetworkingSingleton::removePromise(uint32_t id) { + removePromiseCommonImpl(id); +} + +void RustNetworkingSingleton::resolvePromise(uint32_t id, double ret) { + resolvePromiseCommonImpl(id, ret); +} + +void RustNetworkingSingleton::rejectPromise( + uint32_t id, + const std::string &error) { + rejectPromiseCommonImpl(id, error); +} + +void RustNetworkingSingletonJNIHelper::schedule( + facebook::jni::alias_ref jThis, + facebook::jni::alias_ref task) { + auto globalTaskRef = facebook::jni::make_global(task); + RustNetworkingSingleton::instance.schedule( + [globalTaskRef = std::move(globalTaskRef)]() mutable { + auto runTask = [globalTaskRef = std::move(globalTaskRef)]() mutable { + globalTaskRef->run(); + globalTaskRef.release(); + }; + facebook::jni::ThreadScope::WithClassLoader(std::move(runTask)); + }); +} + +void RustNetworkingSingletonJNIHelper::enableMultithreading( + facebook::jni::alias_ref jThis) { + RustNetworkingSingleton::instance.enableMultithreading(); +} + +void RustNetworkingSingletonJNIHelper::registerNatives() { + javaClassStatic()->registerNatives({ + makeNativeMethod("schedule", RustNetworkingSingletonJNIHelper::schedule), + makeNativeMethod( + "enableMultithreading", + RustNetworkingSingletonJNIHelper::enableMultithreading), + }); +} +} // namespace comm diff --git a/native/cpp/CommonCpp/CryptoTools/DeviceID.h b/native/cpp/CommonCpp/CryptoTools/DeviceID.h --- a/native/cpp/CommonCpp/CryptoTools/DeviceID.h +++ b/native/cpp/CommonCpp/CryptoTools/DeviceID.h @@ -1,3 +1,5 @@ +#pragma once + #include "lib.rs.h" #include #include 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 @@ -63,6 +63,7 @@ virtual jsi::Value clearSensitiveData(jsi::Runtime &rt) override; virtual bool checkIfDatabaseNeedsDeletion(jsi::Runtime &rt) override; virtual void reportDBOperationsFailure(jsi::Runtime &rt) override; + virtual jsi::Value get42(jsi::Runtime &rt) override; public: CommCoreModule(std::shared_ptr jsInvoker); 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 @@ -4,9 +4,11 @@ #include "DatabaseManager.h" #include "DraftStoreOperations.h" #include "InternalModules/GlobalDBSingleton.h" +#include "InternalModules/RustNetworkingSingleton.h" #include "MessageStoreOperations.h" #include "TerminateApp.h" #include "ThreadStoreOperations.h" +#include "lib.rs.h" #include #include @@ -960,6 +962,7 @@ : facebook::react::CommCoreModuleSchemaCxxSpecJSI(jsInvoker), cryptoThread(std::make_unique("crypto")) { GlobalDBSingleton::instance.enableMultithreading(); + RustNetworkingSingleton::instance.enableMultithreading(); } double CommCoreModule::getCodeVersion(jsi::Runtime &rt) { @@ -1166,4 +1169,20 @@ DatabaseManager::reportDBOperationsFailure(); } +jsi::Value CommCoreModule::get42(jsi::Runtime &rt) { + return createPromiseAsJSIValue( + rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { + RustNetworkingSingleton::instance.schedule([this, promise]() { + std::string error; + try { + auto currentID = RustNetworkingSingleton::instance.addPromise( + promise, this->jsInvoker_); + get_42(currentID); + } catch (const std::exception &e) { + error = e.what(); + } + }); + }); +} + } // namespace comm diff --git a/native/cpp/CommonCpp/NativeModules/InternalModules/RustNetworkingSingleton.h b/native/cpp/CommonCpp/NativeModules/InternalModules/RustNetworkingSingleton.h new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/NativeModules/InternalModules/RustNetworkingSingleton.h @@ -0,0 +1,97 @@ +#pragma once + +#include "../../Tools/WorkerThread.h" +#include + +#include + +namespace comm { + +using namespace facebook::react; + +class RustNetworkingSingleton { + std::atomic multithreadingEnabled; + std::unique_ptr rustNetworkingThread; + std::atomic id{0}; + + RustNetworkingSingleton(); + + void scheduleCommonImpl(const taskType task) { + if (this->rustNetworkingThread == nullptr) { + return; + } + this->rustNetworkingThread->scheduleTask(task); + } + + void enableMultithreadingCommonImpl() { + if (this->rustNetworkingThread == nullptr) { + this->rustNetworkingThread = + std::make_unique("rust-networking"); + this->multithreadingEnabled.store(true); + } + } + uint32_t getNextID() { + return this->id++; + }; + + uint32_t addPromiseCommonImpl( + std::shared_ptr promise, + std::shared_ptr jsInvoker) { + uint32_t id = getNextID(); + PromiseInfo info = {promise, jsInvoker}; + promises.insert({id, info}); + return id; + }; + + void removePromiseCommonImpl(uint32_t id) { + promises.erase(id); + }; + + void resolvePromiseCommonImpl(uint32_t id, double ret) { + auto it = promises.find(id); + if (it != promises.end()) { + if (it->second.jsInvoker) { + auto promiseInfo = it->second; + it->second.jsInvoker->invokeAsync([promiseInfo2 = promiseInfo, ret]() { + promiseInfo2.promise->resolve(facebook::jsi::Value(ret)); + }); + } else { + it->second.promise->resolve(facebook::jsi::Value(ret)); + } + removePromise(id); + } + }; + + void rejectPromiseCommonImpl(uint32_t id, const std::string &error) { + auto it = promises.find(id); + if (it != promises.end()) { + if (it->second.jsInvoker) { + it->second.jsInvoker->invokeAsync( + [promise = it->second.promise, error]() { + promise->reject(error); + }); + } else { + it->second.promise->reject(error); + } + removePromise(id); + } + }; + +public: + static RustNetworkingSingleton instance; + void schedule(const taskType task); + void enableMultithreading(); + uint32_t addPromise( + std::shared_ptr promise, + std::shared_ptr jsInvoker); + void removePromise(uint32_t id); + void resolvePromise(uint32_t id, double ret); + void rejectPromise(uint32_t id, const std::string &error); + + struct PromiseInfo { + std::shared_ptr promise; + std::shared_ptr jsInvoker; + }; + std::unordered_map promises; +}; +} // namespace comm diff --git a/native/cpp/CommonCpp/NativeModules/InternalModules/RustNetworkingSingletonJNIHelper.h b/native/cpp/CommonCpp/NativeModules/InternalModules/RustNetworkingSingletonJNIHelper.h new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/NativeModules/InternalModules/RustNetworkingSingletonJNIHelper.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include +#include + +namespace comm { +class RustNetworkingSingletonJNIHelper + : public facebook::jni::JavaClass { +public: + static auto constexpr kJavaDescriptor = + "Lapp/comm/android/fbjni/RustNetworkingSingleton;"; + static void schedule( + facebook::jni::alias_ref jThis, + facebook::jni::alias_ref task); + static void enableMultithreading( + facebook::jni::alias_ref jThis); + static void registerNatives(); +}; +} // 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 @@ -94,6 +94,9 @@ static_cast(&turboModule)->reportDBOperationsFailure(rt); return jsi::Value::undefined(); } +static jsi::Value __hostFunction_CommCoreModuleSchemaCxxSpecJSI_get42(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->get42(rt); +} CommCoreModuleSchemaCxxSpecJSI::CommCoreModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule("CommTurboModule", jsInvoker) { @@ -123,6 +126,7 @@ methodMap_["clearSensitiveData"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_clearSensitiveData}; methodMap_["checkIfDatabaseNeedsDeletion"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_checkIfDatabaseNeedsDeletion}; methodMap_["reportDBOperationsFailure"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_reportDBOperationsFailure}; + methodMap_["get42"] = MethodMetadata {0, __hostFunction_CommCoreModuleSchemaCxxSpecJSI_get42}; } 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 @@ -46,6 +46,7 @@ virtual jsi::Value clearSensitiveData(jsi::Runtime &rt) = 0; virtual bool checkIfDatabaseNeedsDeletion(jsi::Runtime &rt) = 0; virtual void reportDBOperationsFailure(jsi::Runtime &rt) = 0; + virtual jsi::Value get42(jsi::Runtime &rt) = 0; }; @@ -275,6 +276,14 @@ return bridging::callFromJs( rt, &T::reportDBOperationsFailure, jsInvoker_, instance_); } + jsi::Value get42(jsi::Runtime &rt) override { + static_assert( + bridging::getParameterCount(&T::get42) == 1, + "Expected get42(...) to have 1 parameters"); + + return bridging::callFromJs( + rt, &T::get42, jsInvoker_, instance_); + } private: T *instance_; 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 @@ -39,6 +39,8 @@ 7FA2DCDE293E62F500991BA4 /* CommIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7FA2DCDC293E62F500991BA4 /* CommIcons.ttf */; }; 7FA2DCDF293E62F500991BA4 /* SWMansionIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7FA2DCDD293E62F500991BA4 /* SWMansionIcons.ttf */; }; 7FE4D9F5291DFE9300667BF6 /* commJSI-generated.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7FE4D9F4291DFE9300667BF6 /* commJSI-generated.cpp */; }; + 8B652FA3295EA753009F8163 /* RustNetworkingSingleton.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B652FA2295EA753009F8163 /* RustNetworkingSingleton.mm */; }; + 8B652FA6295EAA5B009F8163 /* RustCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B652FA5295EAA5B009F8163 /* RustCallback.cpp */; }; 8B99BAAC28D50F3000EB5ADB /* libnative_rust_library.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B99BAAB28D50F3000EB5ADB /* libnative_rust_library.a */; }; 8B99BAAE28D511FF00EB5ADB /* lib.rs.cc in Sources */ = {isa = PBXBuildFile; fileRef = 8B99BAAD28D511FF00EB5ADB /* lib.rs.cc */; }; 8E43C32C291E5B4A009378F5 /* TerminateApp.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8E43C32B291E5B4A009378F5 /* TerminateApp.mm */; }; @@ -167,6 +169,10 @@ 7FE4D9F3291DFE9300667BF6 /* commJSI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = commJSI.h; sourceTree = ""; }; 7FE4D9F4291DFE9300667BF6 /* commJSI-generated.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "commJSI-generated.cpp"; sourceTree = ""; }; 891D1495EE1F375F3AF6C7ED /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = ""; }; + 8B652FA1295EA6B8009F8163 /* RustNetworkingSingleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustNetworkingSingleton.h; sourceTree = ""; }; + 8B652FA2295EA753009F8163 /* RustNetworkingSingleton.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RustNetworkingSingleton.mm; path = Comm/RustNetworkingSingleton.mm; sourceTree = ""; }; + 8B652FA4295EA9F1009F8163 /* RustCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustCallback.h; sourceTree = ""; }; + 8B652FA5295EAA5B009F8163 /* RustCallback.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RustCallback.cpp; sourceTree = ""; }; 8B99AF6D28D50D4800EB5ADB /* lib.rs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lib.rs.h; sourceTree = ""; }; 8B99B59928D50D4900EB5ADB /* cxx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cxx.h; sourceTree = ""; }; 8B99BAAB28D50F3000EB5ADB /* libnative_rust_library.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libnative_rust_library.a; path = ../native_rust_library/target/universal/release/libnative_rust_library.a; sourceTree = ""; }; @@ -310,6 +316,7 @@ 8E43C32E291E5B9D009378F5 /* TerminateApp.h */, 8E43C32B291E5B4A009378F5 /* TerminateApp.mm */, CBDEC69A28ED867000C17588 /* GlobalDBSingleton.mm */, + 8B652FA2295EA753009F8163 /* RustNetworkingSingleton.mm */, CB38B4782877177B00171182 /* TemporaryMessageStorage */, 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */, 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */, @@ -452,6 +459,7 @@ 726E5D722731A4240032361D /* InternalModules */ = { isa = PBXGroup; children = ( + 8B652FA1295EA6B8009F8163 /* RustNetworkingSingleton.h */, CBDEC69928ED859600C17588 /* GlobalDBSingleton.h */, ); path = InternalModules; @@ -502,9 +510,11 @@ 8B99AF6B28D50D4800EB5ADB /* native_rust_library */ = { isa = PBXGroup; children = ( + 8B652FA4295EA9F1009F8163 /* RustCallback.h */, 8B99BAAD28D511FF00EB5ADB /* lib.rs.cc */, 8B99AF6D28D50D4800EB5ADB /* lib.rs.h */, 8B99B59928D50D4900EB5ADB /* cxx.h */, + 8B652FA5295EAA5B009F8163 /* RustCallback.cpp */, ); name = native_rust_library; path = ../native_rust_library; @@ -969,6 +979,7 @@ 71BF5B7526B401D300EDE27D /* Tools.cpp in Sources */, 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, 7FE4D9F5291DFE9300667BF6 /* commJSI-generated.cpp in Sources */, + 8B652FA6295EAA5B009F8163 /* RustCallback.cpp in Sources */, 71142A7726C2650B0039DCBD /* CommSecureStoreIOSWrapper.mm in Sources */, CB38F2B1286C6C870010535C /* MessageOperationsUtilities.cpp in Sources */, 71CA4A64262DA8E500835C89 /* Logger.mm in Sources */, @@ -979,6 +990,7 @@ 711B408425DA97F9005F8F06 /* dummy.swift in Sources */, 8E86A6D329537EBB000BBE7D /* DatabaseManager.cpp in Sources */, CBDEC69B28ED867000C17588 /* GlobalDBSingleton.mm in Sources */, + 8B652FA3295EA753009F8163 /* RustNetworkingSingleton.mm in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */, 71BE844B2636A944002849D2 /* SQLiteQueryExecutor.cpp in Sources */, ); diff --git a/native/ios/Comm/RustNetworkingSingleton.mm b/native/ios/Comm/RustNetworkingSingleton.mm new file mode 100644 --- /dev/null +++ b/native/ios/Comm/RustNetworkingSingleton.mm @@ -0,0 +1,54 @@ +#import "RustNetworkingSingleton.h" +#import +#include + +namespace comm { +RustNetworkingSingleton RustNetworkingSingleton::instance; + +RustNetworkingSingleton::RustNetworkingSingleton() + : multithreadingEnabled(false), rustNetworkingThread(nullptr) { +} + +void RustNetworkingSingleton::schedule(const taskType task) { + if (NSThread.isMainThread || this->multithreadingEnabled.load()) { + this->scheduleCommonImpl(task); + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + this->scheduleCommonImpl(task); + }); +} + +void RustNetworkingSingleton::enableMultithreading() { + if (NSThread.isMainThread) { + this->enableMultithreadingCommonImpl(); + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + this->enableMultithreadingCommonImpl(); + }); +} + +uint32_t RustNetworkingSingleton::addPromise( + std::shared_ptr promise, + std::shared_ptr jsInvoker) { + return addPromiseCommonImpl(promise, jsInvoker); +} + +void RustNetworkingSingleton::removePromise(uint32_t id) { + removePromiseCommonImpl(id); +} + +void RustNetworkingSingleton::resolvePromise(uint32_t id, double ret) { + resolvePromiseCommonImpl(id, ret); +} + +void RustNetworkingSingleton::rejectPromise( + uint32_t id, + const std::string &error) { + rejectPromiseCommonImpl(id, error); +} + +} // namespace comm diff --git a/native/native_rust_library/RustCallback.h b/native/native_rust_library/RustCallback.h new file mode 100644 --- /dev/null +++ b/native/native_rust_library/RustCallback.h @@ -0,0 +1,9 @@ +#pragma once + +#include "cxx.h" + +namespace comm { + +void get42Callback(rust::String error, uint32_t counter, double ret); + +} // namespace comm diff --git a/native/native_rust_library/RustCallback.cpp b/native/native_rust_library/RustCallback.cpp new file mode 100644 --- /dev/null +++ b/native/native_rust_library/RustCallback.cpp @@ -0,0 +1,31 @@ + +#include "../cpp/CommonCpp/NativeModules/CommCoreModule.h" +#include "../cpp/CommonCpp/NativeModules/InternalModules/RustNetworkingSingleton.h" +#include "../cpp/CommonCpp/Tools/Logger.h" +#include "cxx.h" +#include +#include +#include + +namespace comm { + +void get42Callback(rust::String error, uint32_t counter, double ret) { + auto it = + RustNetworkingSingleton::instance.promises.find(counter); + if (it == RustNetworkingSingleton::instance.promises.end()) { + Logger::log("VARUN got not found"); + return; + } else { + Logger::log("VARUN got found"); + std::cout << it->first << " is " << it->second->promise; + } + + if (error.size()) { + std::cout << error; + RustNetworkingSingleton::instance.rejectPromise(counter, std::string(error)); + } else { + RustNetworkingSingleton::instance.resolvePromise(counter, jsi::Value(ret)); + } +} + +} // namespace comm diff --git a/native/native_rust_library/src/lib.rs b/native/native_rust_library/src/lib.rs --- a/native/native_rust_library/src/lib.rs +++ b/native/native_rust_library/src/lib.rs @@ -1,6 +1,10 @@ +use crate::ffi::get42Callback; use lazy_static::lazy_static; use std::sync::Arc; use tokio::runtime::{Builder, Runtime}; +use tokio::sync::mpsc::{Receiver, Sender}; +use tokio::sync::Mutex; +use tokio::time::{sleep, Duration}; use tonic::{transport::Channel, Status}; use tracing::instrument; use tunnelbroker::tunnelbroker_service_client::TunnelbrokerServiceClient; @@ -26,6 +30,8 @@ .build() .unwrap() ); + pub static ref CHANNEL: Mutex<(Sender<(f64, u32)>, Receiver<(f64, u32)>)> = + Mutex::new(tokio::sync::mpsc::channel(100)); } #[cxx::bridge] @@ -93,7 +99,28 @@ // Crypto Tools fn generate_device_id(device_type: DeviceType) -> Result; + // Test + fn get_42(counter: u32); } + + unsafe extern "C++" { + include!("RustCallback.h"); + #[namespace = "comm"] + fn get42Callback(error: String, counter: u32, ret: f64); + } +} + +fn get_42(counter: u32) { + println!("I SEE YOU!!!"); + get_42_helper(counter); +} + +fn get_42_helper(counter: u32) { + RUNTIME.spawn(async move { + sleep(Duration::from_secs(10)).await; + println!("awake now!"); + get42Callback("".to_string(), counter, 42.0); + }); } #[derive(Debug)] diff --git a/native/schema/CommCoreModuleSchema.js b/native/schema/CommCoreModuleSchema.js --- a/native/schema/CommCoreModuleSchema.js +++ b/native/schema/CommCoreModuleSchema.js @@ -74,6 +74,7 @@ +clearSensitiveData: () => Promise; +checkIfDatabaseNeedsDeletion: () => boolean; +reportDBOperationsFailure: () => void; + +get42: () => Promise; } export default (TurboModuleRegistry.getEnforcing( diff --git a/shared/cmake/corrosion-cxx.cmake b/shared/cmake/corrosion-cxx.cmake --- a/shared/cmake/corrosion-cxx.cmake +++ b/shared/cmake/corrosion-cxx.cmake @@ -99,6 +99,7 @@ ) target_include_directories(${_LIB_PATH_STEM}_cxxbridge PUBLIC ${cxx_binding_include_dir} + ${CMAKE_CURRENT_LIST_DIR}/${rust_lib_PATH} ) # Create total target with alias with given namespace