diff --git a/native/android/app/CMakeLists.txt b/native/android/app/CMakeLists.txt --- a/native/android/app/CMakeLists.txt +++ b/native/android/app/CMakeLists.txt @@ -126,6 +126,7 @@ file(GLOB_RECURSE MODULE_NATIVE_CODE "../../cpp/CommonCpp/NativeModules/**/*.cpp") file(GLOB MODULE_ROOT_NATIVE_CODE "../../cpp/CommonCpp/NativeModules/*.cpp") file(GLOB NOTIFICATIONS_NATIVE_CODE "../../cpp/CommonCpp/Notifications/**/*.cpp") +file(GLOB RUST_NATIVE_CODE "../../native_rust_library/*.cpp") add_library( # Sets the name of the library @@ -155,6 +156,7 @@ ${MODULE_ROOT_NATIVE_CODE} ${TOOLS_NATIVE_CODE} ${NOTIFICATIONS_NATIVE_CODE} + ${RUST_NATIVE_CODE} ) set(BUILD_DIR ${CMAKE_SOURCE_DIR}/build) diff --git a/native/android/app/build.gradle b/native/android/app/build.gradle --- a/native/android/app/build.gradle +++ b/native/android/app/build.gradle @@ -379,10 +379,30 @@ "x86_64-linux-android" } +def rustManifestPath = "../../native_rust_library/Cargo.toml" +def cargoProjectDirectory = "../../native_rust_library" +def cargoLibDirectory = '../../native_rust_library/target/cxxbridge/native_rust_library/src' +def cargoCXXDirectory = '../../native_rust_library/target/cxxbridge/rust' + +task buildNativeRustLibrary(type: Exec) { + commandLine "cargo", "build", "--manifest-path", rustManifestPath +} + +task rustDeploy(dependsOn: buildNativeRustLibrary, type: Copy) { + from(cargoLibDirectory) { + include 'lib.rs.h' + include 'lib.rs.cc' + } + from(cargoCXXDirectory) { + include 'cxx.h' + } + into cargoProjectDirectory +} + // Bind preBuild dependencies only if not 'clean' running if (!isCleanRunning()) { afterEvaluate { - preBuild.dependsOn(prepareExternalLibs, updateRustToolchain) + preBuild.dependsOn(prepareExternalLibs, updateRustToolchain, rustDeploy) } } 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/RustPromiseManager.h" #include "MessageStoreOperations.h" #include "TerminateApp.h" #include "ThreadStoreOperations.h" +#include "lib.rs.h" #include #include @@ -1166,4 +1168,18 @@ DatabaseManager::reportDBOperationsFailure(); } +jsi::Value CommCoreModule::get42(jsi::Runtime &rt) { + return createPromiseAsJSIValue( + rt, [this](jsi::Runtime &innerRt, std::shared_ptr promise) { + std::string error; + try { + auto currentID = RustPromiseManager::instance.addPromise( + promise, this->jsInvoker_, innerRt); + get_42(currentID); + } catch (const std::exception &e) { + error = e.what(); + }; + }); +} + } // 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/data/sqlite-data-handler.js b/native/data/sqlite-data-handler.js --- a/native/data/sqlite-data-handler.js +++ b/native/data/sqlite-data-handler.js @@ -75,6 +75,20 @@ `SQLite database deletion was triggered by ${triggeredBy}`, ); } + Alert.alert(new Date().toISOString()); + const foo = commCoreModule.get42(); + const bar = commCoreModule.get42(); + Alert.alert(new Date().toISOString()); + const x = await foo; + Alert.alert(new Date().toISOString()); + if (x) { + Alert.alert('Got back ' + x); + } + const y = await bar; + Alert.alert(new Date().toISOString()); + if (y) { + Alert.alert('Got back' + y); + } }, [staffCanSee, staffUserHasBeenLoggedIn], ); 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 /* RustPromiseManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8B652FA2295EA753009F8163 /* RustPromiseManager.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 /* RustPromiseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustPromiseManager.h; sourceTree = ""; }; + 8B652FA2295EA753009F8163 /* RustPromiseManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RustPromiseManager.mm; path = Comm/RustPromiseManager.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 /* RustPromiseManager.mm */, CB38B4782877177B00171182 /* TemporaryMessageStorage */, 71762A74270D8AAE00F565ED /* PlatformSpecificTools.mm */, 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */, @@ -452,6 +459,7 @@ 726E5D722731A4240032361D /* InternalModules */ = { isa = PBXGroup; children = ( + 8B652FA1295EA6B8009F8163 /* RustPromiseManager.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 /* RustPromiseManager.mm in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */, 71BE844B2636A944002849D2 /* SQLiteQueryExecutor.cpp in Sources */, ); 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,36 @@ + +#include "RustCallback.h" +#include "../cpp/CommonCpp/NativeModules/CommCoreModule.h" +#include "../cpp/CommonCpp/NativeModules/InternalModules/RustPromiseManager.h" +#include "../cpp/CommonCpp/Tools/Logger.h" +#include +#include +#include + +namespace comm { + +void get42Callback(rust::String error, uint32_t counter, double ret) { + auto it = RustPromiseManager::instance.promises.find(counter); + if (it == RustPromiseManager::instance.promises.end()) { + Logger::log("VARUN got not found"); + return; + } else { + Logger::log("VARUN got found"); + } + + if (error.size()) { + std::cout << error; + RustPromiseManager::instance.rejectPromise(counter, std::string(error)); + } else { + folly::dynamic retDyn; + retDyn = ret; + if (retDyn.isDouble()) { + Logger::log("retDyn: " + retDyn.asString() + "!"); + } else { + Logger::log(retDyn.typeName()); + } + RustPromiseManager::instance.resolvePromise(counter, retDyn); + } +} + +} // 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,8 @@ ) target_include_directories(${_LIB_PATH_STEM}_cxxbridge PUBLIC ${cxx_binding_include_dir} + # Try to pick up any other headers exposed by target + ${CMAKE_CURRENT_LIST_DIR}/${rust_lib_PATH} ) # Create total target with alias with given namespace