diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.h b/native/cpp/CommonCpp/NativeModules/CommRustModule.h --- a/native/cpp/CommonCpp/NativeModules/CommRustModule.h +++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.h @@ -85,6 +85,13 @@ jsi::String authDeviceID, jsi::String authAccessToken, jsi::String keyserverID) override; + virtual jsi::Value getDeviceListForUser( + jsi::Runtime &rt, + jsi::String authUserID, + jsi::String authDeviceID, + jsi::String authAccessToken, + jsi::String userID, + std::optional sinceTimestamp) override; public: CommRustModule(std::shared_ptr jsInvoker); diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp --- a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp +++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp @@ -405,4 +405,40 @@ }); } +jsi::Value CommRustModule::getDeviceListForUser( + jsi::Runtime &rt, + jsi::String authUserID, + jsi::String authDeviceID, + jsi::String authAccessToken, + jsi::String userID, + std::optional sinceTimestamp) { + auto authUserIDRust = jsiStringToRustString(authUserID, rt); + auto authDeviceIDRust = jsiStringToRustString(authDeviceID, rt); + auto authAccessTokenRust = jsiStringToRustString(authAccessToken, rt); + auto userIDRust = jsiStringToRustString(userID, rt); + + auto timestampI64 = static_cast(sinceTimestamp.value_or(0)); + return createPromiseAsJSIValue( + rt, [=, this](jsi::Runtime &innerRt, std::shared_ptr promise) { + std::string error; + try { + auto currentID = RustPromiseManager::instance.addPromise( + {promise, this->jsInvoker_, innerRt}); + identityGetDeviceListForUser( + authUserIDRust, + authDeviceIDRust, + authAccessTokenRust, + userIDRust, + timestampI64, + currentID); + } catch (const std::exception &e) { + error = e.what(); + }; + if (!error.empty()) { + this->jsInvoker_->invokeAsync( + [error, promise]() { promise->reject(error); }); + } + }); +} + } // namespace comm diff --git a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp --- a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp +++ b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp @@ -45,6 +45,9 @@ static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_getKeyserverKeys(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { return static_cast(&turboModule)->getKeyserverKeys(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].asString(rt)); } +static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_getDeviceListForUser(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) { + return static_cast(&turboModule)->getDeviceListForUser(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].asString(rt), args[4].isNull() || args[4].isUndefined() ? std::nullopt : std::make_optional(args[4].asNumber())); +} CommRustModuleSchemaCxxSpecJSI::CommRustModuleSchemaCxxSpecJSI(std::shared_ptr jsInvoker) : TurboModule("CommRustTurboModule", jsInvoker) { @@ -59,6 +62,7 @@ methodMap_["versionSupported"] = MethodMetadata {0, __hostFunction_CommRustModuleSchemaCxxSpecJSI_versionSupported}; methodMap_["uploadOneTimeKeys"] = MethodMetadata {5, __hostFunction_CommRustModuleSchemaCxxSpecJSI_uploadOneTimeKeys}; methodMap_["getKeyserverKeys"] = MethodMetadata {4, __hostFunction_CommRustModuleSchemaCxxSpecJSI_getKeyserverKeys}; + methodMap_["getDeviceListForUser"] = MethodMetadata {5, __hostFunction_CommRustModuleSchemaCxxSpecJSI_getDeviceListForUser}; } diff --git a/native/cpp/CommonCpp/_generated/rustJSI.h b/native/cpp/CommonCpp/_generated/rustJSI.h --- a/native/cpp/CommonCpp/_generated/rustJSI.h +++ b/native/cpp/CommonCpp/_generated/rustJSI.h @@ -31,6 +31,7 @@ virtual jsi::Value versionSupported(jsi::Runtime &rt) = 0; virtual jsi::Value uploadOneTimeKeys(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::Array contentOneTimePreKeys, jsi::Array notifOneTimePreKeys) = 0; virtual jsi::Value getKeyserverKeys(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::String keyserverID) = 0; + virtual jsi::Value getDeviceListForUser(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::String userID, std::optional sinceTimestamp) = 0; }; @@ -140,6 +141,14 @@ return bridging::callFromJs( rt, &T::getKeyserverKeys, jsInvoker_, instance_, std::move(authUserID), std::move(authDeviceID), std::move(authAccessToken), std::move(keyserverID)); } + jsi::Value getDeviceListForUser(jsi::Runtime &rt, jsi::String authUserID, jsi::String authDeviceID, jsi::String authAccessToken, jsi::String userID, std::optional sinceTimestamp) override { + static_assert( + bridging::getParameterCount(&T::getDeviceListForUser) == 6, + "Expected getDeviceListForUser(...) to have 6 parameters"); + + return bridging::callFromJs( + rt, &T::getDeviceListForUser, jsInvoker_, instance_, std::move(authUserID), std::move(authDeviceID), std::move(authAccessToken), std::move(userID), std::move(sinceTimestamp)); + } private: T *instance_; 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 @@ -2,6 +2,9 @@ use comm_opaque2::client::{Login, Registration}; use comm_opaque2::grpc::opaque_error_to_grpc_status as handle_error; use ffi::{bool_callback, string_callback, void_callback}; +use grpc_clients::identity::protos::auth::{ + GetDeviceListRequest, UpdateDeviceListRequest, +}; use grpc_clients::identity::protos::authenticated::{ InboundKeyInfo, InboundKeysForUserRequest, KeyserverKeysResponse, OutboundKeyInfo, OutboundKeysForUserRequest, RefreshUserPrekeysRequest, @@ -171,6 +174,16 @@ promise_id: u32, ); + #[cxx_name = "identityGetDeviceListForUser"] + fn get_device_list_for_user( + auth_user_id: String, + auth_device_id: String, + auth_access_token: String, + user_id: String, + since_timestamp: i64, + promise_id: u32, + ); + // Argon2 #[cxx_name = "compute_backup_key"] fn compute_backup_key_str( @@ -1239,6 +1252,55 @@ Ok(()) } +fn get_device_list_for_user( + auth_user_id: String, + auth_device_id: String, + auth_access_token: String, + user_id: String, + since_timestamp: i64, + promise_id: u32, +) { + RUNTIME.spawn(async move { + let auth_info = AuthInfo { + access_token: auth_access_token, + user_id: auth_user_id, + device_id: auth_device_id, + }; + let since_timestamp = Option::from(since_timestamp).filter(|&t| t > 0); + let result = + get_device_list_for_user_helper(auth_info, user_id, since_timestamp) + .await; + handle_string_result_as_callback(result, promise_id); + }); +} + +async fn get_device_list_for_user_helper( + auth_info: AuthInfo, + user_id: String, + since_timestamp: Option, +) -> Result { + let mut identity_client = get_auth_client( + IDENTITY_SOCKET_ADDR, + auth_info.user_id, + auth_info.device_id, + auth_info.access_token, + CODE_VERSION, + DEVICE_TYPE.as_str_name().to_lowercase(), + ) + .await?; + + let response = identity_client + .get_device_list_for_user(GetDeviceListRequest { + user_id, + since_timestamp, + }) + .await? + .into_inner(); + + let payload = serde_json::to_string(&response.device_list_updates)?; + Ok(payload) +} + #[derive( Debug, derive_more::Display, derive_more::From, derive_more::Error, )] diff --git a/native/schema/CommRustModuleSchema.js b/native/schema/CommRustModuleSchema.js --- a/native/schema/CommRustModuleSchema.js +++ b/native/schema/CommRustModuleSchema.js @@ -80,6 +80,13 @@ authAccessToken: string, keyserverID: string, ) => Promise; + +getDeviceListForUser: ( + authUserID: string, + authDeviceID: string, + authAccessToken: string, + userID: string, + sinceTimestamp: ?number, + ) => Promise; } export default (TurboModuleRegistry.getEnforcing(