Skip to content

Commit

Permalink
add controller for managing app state
Browse files Browse the repository at this point in the history
Signed-off-by: Swapnil Tripathi <swapnil06.st@gmail.com>
  • Loading branch information
gmulhearn authored and swaptr committed Sep 24, 2023
1 parent bfac035 commit 56baf4a
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 141 deletions.
15 changes: 5 additions & 10 deletions aries_vcx/tests/test_credential_retrieval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use crate::utils::migration::Migratable;
#[ignore]
// TODO: This should be a unit test
async fn test_agency_pool_retrieve_credentials_empty() {
SetupProfile::run(|mut setup| async move {
SetupProfile::run(|setup| async move {
// create skeleton proof request attachment data
let mut req = json!({
"nonce":"123432421212",
Expand Down Expand Up @@ -130,7 +130,7 @@ async fn test_agency_pool_retrieve_credentials_empty() {
#[ignore]
// TODO: This should be a unit test
async fn test_agency_pool_case_for_proof_req_doesnt_matter_for_retrieve_creds() {
SetupProfile::run(|mut setup| async move {
SetupProfile::run(|setup| async move {
let schema = create_and_write_test_schema(
&setup.profile.inject_anoncreds(),
&setup.profile.inject_anoncreds_ledger_write(),
Expand Down Expand Up @@ -312,20 +312,15 @@ async fn test_agency_pool_it_should_fail_to_select_credentials_for_predicate() {
let presentation_request_data =
create_proof_request_data(&mut institution, "[]", &requested_preds_string, "{}", None)
.await;
let mut verifier = create_verifier_from_request_data(presentation_request_data).await;
let verifier = create_verifier_from_request_data(presentation_request_data).await;

#[cfg(feature = "migration")]
consumer.migrate().await;

let presentation_request = verifier.get_presentation_request_msg().unwrap();
let mut prover = create_prover_from_request(presentation_request.clone()).await;
let selected_credentials = prover_select_credentials(
&mut prover,
&mut consumer,
presentation_request.into(),
None,
)
.await;
let selected_credentials =
prover_select_credentials(&mut prover, &mut consumer, presentation_request, None).await;

assert!(selected_credentials.credential_for_referent.is_empty());
})
Expand Down
2 changes: 1 addition & 1 deletion aries_vcx/tests/test_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ async fn test_pool_add_get_attr() {
#[tokio::test]
#[ignore]
async fn test_agency_pool_get_credential_def() {
SetupProfile::run(|mut setup| async move {
SetupProfile::run(|setup| async move {
let (_, _, cred_def_id, cred_def_json, _) = create_and_store_nonrevocable_credential_def(
&setup.profile.inject_anoncreds(),
&setup.profile.inject_anoncreds_ledger_read(),
Expand Down
2 changes: 1 addition & 1 deletion aries_vcx/tests/test_proof_presentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use crate::utils::{
#[tokio::test]
#[ignore]
async fn test_agency_pool_generate_proof_with_predicates() {
SetupProfile::run(|mut setup| async move {
SetupProfile::run(|setup| async move {
let schema = create_and_write_test_schema(
&setup.profile.inject_anoncreds(),
&setup.profile.inject_anoncreds_ledger_write(),
Expand Down
6 changes: 3 additions & 3 deletions uniffi_aries_vcx/core/src/core/unpack_message.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::sync::Arc;

use serde::{Deserialize, Serialize};

use super::profile::ProfileHolder;
use crate::{errors::error::VcxUniFFIResult, runtime::block_on};
use aries_vcx::errors::error::AriesVcxError;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct UnpackMessage {
Expand All @@ -20,7 +20,7 @@ pub fn unpack_message(
block_on(async {
let packed_bytes = packed_msg.as_bytes();
let wallet = profile_holder.inner.inject_wallet();
let unpacked_bytes = wallet.unpack_message(&packed_bytes).await?;
let unpacked_bytes = wallet.unpack_message(packed_bytes).await?;
let unpacked_string = String::from_utf8(unpacked_bytes)?;
let unpacked_message = serde_json::from_str::<UnpackMessage>(&unpacked_string)?;
Ok(unpacked_message)
Expand Down
13 changes: 8 additions & 5 deletions uniffi_aries_vcx/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ pub mod errors;
pub mod handlers;
pub mod runtime;

use crate::core::profile::*;
use crate::core::unpack_message::*;
use crate::errors::error::*;
use aries_vcx::aries_vcx_core::wallet::indy::WalletConfig;
use aries_vcx::protocols::connection::pairwise_info::PairwiseInfo;
use aries_vcx::{
aries_vcx_core::wallet::indy::WalletConfig, protocols::connection::pairwise_info::PairwiseInfo,
};
use handlers::connection::*;

use crate::{
core::{profile::*, unpack_message::*},
errors::error::*,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package org.hyperledger.ariesvcx

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import org.hyperledger.ariesvcx.utils.await

data class AppUiState(
val profileReady: Boolean = false,
val connectionInvitationReceived: Boolean = false,
val connectionCompleted: Boolean = false
)

class AppDemoController : ViewModel() {
private val httpClient = OkHttpClient()

private var profile: ProfileHolder? = null
private var connection: Connection? = null

private var onConnectionComplete: (connection: Connection) -> Unit = {}

// Expose screen UI state
private val _state = MutableStateFlow(AppUiState())
val states: StateFlow<AppUiState> = _state.asStateFlow()

private val walletConfig = WalletConfig(
walletName = "test_create_wallet_add_uuid_here",
walletKey = "8dvfYSt5d1taSd6yJdpjq4emkwsPDDLYxkNFysFD2cZY",
walletKeyDerivation = "RAW",
walletType = null,
storageConfig = null,
storageCredentials = null,
rekey = null,
rekeyDerivationMethod = null
)

suspend fun setupProfile() {
withContext(Dispatchers.IO) {
val newProfile = newIndyProfile(walletConfig)
profile = newProfile
connection = createInvitee(newProfile)
}
_state.update { current ->
current.copy(profileReady = true)
}
}

suspend fun acceptConnectionInvitation(invitation: String) {
if (connection == null || profile == null) {
throw Exception("Connection or Profile is null")
}
withContext(Dispatchers.IO) {
connection!!.acceptInvitation(
profile = profile!!,
invitation = invitation
)
_state.update { it.copy(connectionInvitationReceived = true) }

connection!!.sendRequest(
profile!!,
"$BASE_RELAY_ENDPOINT/send_user_message/$RELAY_USER_ID",
emptyList()
)

// use viewmodel scope to finish off this work
viewModelScope.launch(Dispatchers.IO) {
awaitConnectionCompletion()
}
}
}

private suspend fun awaitConnectionCompletion() {
val pollRelayRequest = Request.Builder()
.url("$BASE_RELAY_ENDPOINT/pop_user_message/$RELAY_USER_ID")
.build()
while (true) {
delay(500)
val relayResponse = httpClient.newCall(pollRelayRequest).await()
if (relayResponse.code == 200) {
val message = relayResponse.body!!.string()

val unpackedMessage = unpackMessage(
profile!!,
message
)

Log.d("AppDemoController", unpackedMessage.message)
connection!!.handleResponse(profile!!, unpackedMessage.message)
connection!!.sendAck(profile!!)

Log.d("AppDemoController", "connection state: ${connection!!.getState()}")

_state.update { it.copy(connectionCompleted = true) }
onConnectionComplete(connection!!)
break
}
}
}

fun subscribeToConnectionComplete(onComplete: (connection: Connection) -> Unit) {
onConnectionComplete = onComplete
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package org.hyperledger.ariesvcx

// Set your public IP address here, this endpoint will be used while communicating with the peer(agent).
const val BASE_RELAY_ENDPOINT = "https://b199-27-57-116-96.ngrok-free.app";
const val RELAY_USER_ID = "demo-user-1";
const val RELAY_USER_ID = "demo-user-1";
Original file line number Diff line number Diff line change
Expand Up @@ -8,67 +8,36 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavHostController
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import org.hyperledger.ariesvcx.utils.await


@Composable
fun HomeScreen(
demoController: AppDemoController,
navController: NavHostController,
setProfileHolder: (ProfileHolder) -> Unit,
profileHolder: ProfileHolder?,
connection: Connection?,
walletConfig: WalletConfig,
connectionRequestState: Boolean,
httpClient: OkHttpClient
) {

val demoState by demoController.states.collectAsState()

val scope = rememberCoroutineScope()
val context = LocalContext.current

var flagKeepFetching by remember {
mutableStateOf(true)
}

val request = Request.Builder()
.url("$BASE_RELAY_ENDPOINT/pop_user_message/$RELAY_USER_ID")
.build()


LaunchedEffect(true) {
scope.launch(Dispatchers.IO) {
while (flagKeepFetching && connectionRequestState) {
delay(500)
val response = httpClient.newCall(request).await()
if (response.code == 200) {
val message = response.body!!.string()

val unpackedMessage = unpackMessage(
profileHolder!!,
message
)

Log.d("HOMESCREEN", "HomeScreen: ${unpackedMessage.message}")
connection?.handleResponse(profileHolder, unpackedMessage.message)
flagKeepFetching = false
connection?.sendAck(profileHolder)
}
}
demoController.subscribeToConnectionComplete { newConn ->
scope.launch(Dispatchers.Main) {
Toast.makeText(
context,
"New Connection Created",
Toast.LENGTH_SHORT
).show()
}
}

Expand All @@ -78,27 +47,31 @@ fun HomeScreen(
verticalArrangement = Arrangement.Center
) {
Button(
enabled = (connection == null),
enabled = (!demoState.profileReady),
onClick = {
scope.launch(Dispatchers.IO) {
val profile = newIndyProfile(walletConfig)
setProfileHolder(profile)
scope.launch {
demoController.setupProfile()
withContext(Dispatchers.Main) {
Toast.makeText(
context,
"New Profile Created: $profile",
"New Profile Created",
Toast.LENGTH_SHORT
).show()
}
}
}) {
Text(text = "New Indy Profile")
}
Button(enabled = (profileHolder != null && connection != null),
Button(enabled = (demoState.profileReady && !demoState.connectionInvitationReceived),
onClick = {
navController.navigate(Destination.QRScan.route)
}) {
Text(text = "Scan QR Code")
}
Button(enabled = (demoState.connectionCompleted),
onClick = {
}) {
Text(text = "Receive a credential")
}
}
}
Loading

0 comments on commit 56baf4a

Please sign in to comment.