Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/typestate connections #739

Merged
merged 66 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
d1096bf
Added draft for typestate connection state machine
bobozaur Jan 19, 2023
d76bf5e
Added dummy, not functional tests, as a mere representation of the tr…
bobozaur Jan 24, 2023
598a7bc
Remove obsolete structs
bobozaur Jan 24, 2023
76f6c4f
Remove dummy tests. Will properly reimplement them later
bobozaur Jan 24, 2023
0295e46
Removed transport type from type state Connection
bobozaur Jan 25, 2023
63f7d46
Factored out build_con_request method
bobozaur Jan 25, 2023
ee571df
Moved all typestate connection related code to a different module
bobozaur Jan 25, 2023
8fff813
Refactored inner methods and simplified them
bobozaur Jan 25, 2023
ad9a6fe
Reverted changes on current code as the typestate_con is separated in…
bobozaur Jan 26, 2023
fb1260a
Added serde capabilities to typestate Connection
bobozaur Jan 26, 2023
f48c429
Added invitation processing to Invitee and moved some Connection meth…
bobozaur Jan 27, 2023
18b0f4c
Renamed SerdeCon to VagueConnection. This will be used for deserializ…
bobozaur Jan 27, 2023
6ea03e7
Added dedicated serialization types for borrowed serialization of Con…
bobozaur Jan 27, 2023
3b51586
Fixed Connection serialization trait bounds
bobozaur Jan 27, 2023
9280633
Reverted to using invitation ID as thread ID
bobozaur Jan 27, 2023
1927b5e
Added direct deserialization support to Connection through try_from i…
bobozaur Jan 27, 2023
ccbdb78
Set typestate_con states attributes pub(crate)
bobozaur Jan 27, 2023
792c4a6
Added typestate_con libvcx implementation draft
bobozaur Jan 27, 2023
0574540
Completed typestate_con implementation in libvcx
bobozaur Jan 29, 2023
6f65e34
Renamed remove_connection in libvcx to get_cloned_connection and impl…
bobozaur Jan 30, 2023
ebba648
Removed the lazy_static HTTPCLIENT in favor of using the ZST directly
bobozaur Jan 30, 2023
cf7b88b
Retro-fitted the process_request and send_response methods for backwa…
bobozaur Jan 30, 2023
ea14d58
Added ProblemReport generation and sending
bobozaur Jan 30, 2023
b81b2b6
Added test From implementations between SerializableConnection and Va…
bobozaur Jan 30, 2023
7595bbe
Added boilerplate macro for From impls for SerializationConnection
bobozaur Jan 30, 2023
ef29fbe
Modified aries-vcx-agent to use typestate connections
bobozaur Jan 31, 2023
f4e677e
Fixed method rename in libvcx
bobozaur Feb 1, 2023
6234370
Removed send_invitation method
bobozaur Feb 1, 2023
c060847
Typestate connection cosmetic changes, comments, and modules re-organ…
bobozaur Feb 1, 2023
1abda21
Removed previous non-mediated Connection in favor of newer typestate …
bobozaur Feb 1, 2023
7c932e5
Fixed state differences in Node.js wrapper
bobozaur Feb 1, 2023
695305a
Reuse request did_doc
bobozaur Feb 1, 2023
e88ce9e
Moved Transport trait and auto-implemented for references of types im…
bobozaur Feb 1, 2023
e30200d
Fix FFI wrapper to return a Promise for the async request handling
bobozaur Feb 1, 2023
b839c86
Reverting dependencies in vcxagent-core
bobozaur Feb 2, 2023
b2ce58e
Ignore dist dirs
bobozaur Feb 2, 2023
876a099
Reverted NAPI changes and mimicked old connection states more accurat…
bobozaur Feb 2, 2023
f2f8e5a
Fixed accept_invitation log comment and added more explicit logs to l…
bobozaur Feb 2, 2023
5cb9f83
processInvite is now a Promise
bobozaur Feb 2, 2023
43c8c95
Fixed thread_id handling when accepting invitation and sending reques…
bobozaur Feb 2, 2023
6e96c55
More state retro-fitting with previous implementation
bobozaur Feb 3, 2023
88e66f2
Fix thread_id usage in Request generation
bobozaur Feb 3, 2023
1324b59
Added comments
bobozaur Feb 3, 2023
ca3ddcc
Added concrete and generic connection serialization and deserializati…
bobozaur Feb 3, 2023
64fc633
Added whitespace in libcx
bobozaur Feb 3, 2023
05f0303
Ran cargo fmt
bobozaur Feb 3, 2023
2d5145a
Completely separated states between invitee and inviter
bobozaur Feb 7, 2023
1541771
Added BootstrapDidDoc trait
bobozaur Feb 7, 2023
079f742
Added non-mediated connection OOB handling
bobozaur Feb 7, 2023
2fdef4f
Improved OOB connection existence look-up and implemented libvcx non-…
bobozaur Feb 7, 2023
6ee9d09
Implemented necessary changes to node wrappers to expose non-mediated…
bobozaur Feb 7, 2023
98e4a50
Unexposed internal OOB method
bobozaur Feb 7, 2023
26a2441
Added re-export of PairwiseInfo to mediatedconnection to avoid struct…
bobozaur Feb 7, 2023
4675cb5
Ran cargo fmt
bobozaur Feb 7, 2023
ece4d8a
Fixed GenericConnection doc test and comment
bobozaur Feb 7, 2023
307ae05
Made processInvite in node wrapper async
bobozaur Feb 7, 2023
a34ff89
Fixed comments typos
bobozaur Feb 8, 2023
c960830
Added more comments to Connection::into_invited
bobozaur Feb 8, 2023
674015b
Added comments to Connection::get_invitation
bobozaur Feb 8, 2023
607b1dd
Accommodated previous send_message behavior
bobozaur Feb 8, 2023
8ff5041
Factored out read access to CONNECTION_MAP in libvcx into a closure a…
bobozaur Feb 8, 2023
3eba85b
Fixed wrapper send_message and added send_aries_message
bobozaur Feb 8, 2023
eacc08d
Fixed comment link
bobozaur Feb 8, 2023
735c302
Updated napi and napi-derive dependencies version
bobozaur Feb 8, 2023
afd198d
Made from_parts public and added into_parts method on Connection
bobozaur Feb 9, 2023
3cb83fb
Made node wrapper serialize a connection as a JSON object instead of …
bobozaur Feb 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
**/.DS_Store
**/node_modules
**/*.node
**/dist
wrappers/ios/vcx/vcx.framework/**
wrappers/ios/vcx/vcx.framework.dSYM/**
wrappers/ios_legacy/vcx/vcx.framework/**
Expand Down
23 changes: 13 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion agents/node/vcxagent-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"test:integration:out-of-band": "jest --forceExit --env=node --runInBand test/out-of-band.spec.js",
"test:integration:nonmediated-endpoint": "jest --forceExit --env=node --runInBand test/nonmediated-endpoint.spec.js",
"test:integration:nonmediated-connection": "jest --forceExit --env=node --runInBand test/nonmediated-connection.spec.js"
},
},
"dependencies": {
"axios": "^0.27.2",
"ffi-napi": "^4.0.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ module.exports.createServiceNonmediatedConnections = function createServiceNonme
logger.info(`inviteeConnectionCreateFromInvite >> connectionId=${connectionId}, invite: ${invite}`)
const connection = await NonmediatedConnection.createInvitee(invite)
logger.debug(`InviteeConnectionSM after created from invitation:\n${JSON.stringify(connection.serialize())}`)
connection.processInvite(invite)
await connection.processInvite(invite)
await connection.sendRequest(endpointInfo)
logger.debug(`InviteeConnectionSM after sending request:\n${JSON.stringify(connection.serialize())}`)
await saveNonmediatedConnection(connectionId, connection)
Expand Down
1 change: 1 addition & 0 deletions agents/rust/aries-vcx-agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition.workspace = true
[dependencies]
serde = "1.0.145"
aries-vcx = { path = "../../../aries_vcx" }
async-trait = "0.1.64"
derive_builder = "0.11.2"
serde_json = "1.0.85"
log = "0.4.17"
Expand Down
13 changes: 13 additions & 0 deletions agents/rust/aries-vcx-agent/src/http_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use aries_vcx::{agency_client::httpclient::post_message, errors::error::VcxResult, transport::Transport};

use async_trait::async_trait;

pub struct HttpClient;

#[async_trait]
impl Transport for HttpClient {
async fn send_message(&self, msg: Vec<u8>, service_endpoint: &str) -> VcxResult<()> {
post_message(msg, service_endpoint).await?;
Ok(())
}
}
1 change: 1 addition & 0 deletions agents/rust/aries-vcx-agent/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern crate uuid;

mod agent;
mod error;
mod http_client;
mod services;
mod storage;

Expand Down
131 changes: 82 additions & 49 deletions agents/rust/aries-vcx-agent/src/services/connection.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
use std::sync::{Arc, Mutex};

use crate::error::*;
use crate::http_client::HttpClient;
use crate::storage::object_cache::ObjectCache;
use crate::storage::Storage;
use aries_vcx::common::ledger::transactions::into_did_doc;
use aries_vcx::core::profile::profile::Profile;
use aries_vcx::handlers::connection::connection::{Connection, ConnectionState};
use aries_vcx::messages::a2a::A2AMessage;
use aries_vcx::messages::concepts::ack::Ack;
use aries_vcx::messages::protocols::connection::invite::Invitation;
use aries_vcx::messages::protocols::connection::request::Request;
use aries_vcx::messages::protocols::connection::response::SignedResponse;
use aries_vcx::protocols::connection::pairwise_info::PairwiseInfo;
use aries_vcx::protocols::connection::{Connection, GenericConnection, State, ThinState};

pub type ServiceEndpoint = String;

pub struct ServiceConnections {
profile: Arc<dyn Profile>,
service_endpoint: ServiceEndpoint,
connections: Arc<ObjectCache<Connection>>,
connections: Arc<ObjectCache<GenericConnection>>,
}

impl ServiceConnections {
Expand All @@ -31,93 +31,126 @@ impl ServiceConnections {
}

pub async fn create_invitation(&self, pw_info: Option<PairwiseInfo>) -> AgentResult<Invitation> {
let inviter = Connection::create_inviter(&self.profile, pw_info)
.await?
.create_invite(self.service_endpoint.clone(), vec![])
.await?;
let invite = inviter
.get_invite_details()
.ok_or_else(|| AgentError::from_kind(AgentErrorKind::InviteDetails))?
.clone();
self.connections.insert(&inviter.get_thread_id(), inviter)?;
let pw_info = pw_info.unwrap_or(PairwiseInfo::create(&self.profile.inject_wallet()).await?);
let inviter =
Connection::new_inviter("".to_owned(), pw_info).create_invitation(vec![], self.service_endpoint.clone());
let invite = inviter.get_invitation().clone();
let thread_id = inviter.thread_id().to_owned();

self.connections.insert(&thread_id, inviter.into())?;

Ok(invite)
}

pub async fn receive_invitation(&self, invite: Invitation) -> AgentResult<String> {
let did_doc = into_did_doc(&self.profile, &invite).await?;
let invitee = Connection::create_invitee(&self.profile, did_doc)
.await?
.process_invite(invite)?;
self.connections.insert(&invitee.get_thread_id(), invitee)
let pairwise_info = PairwiseInfo::create(&self.profile.inject_wallet()).await?;
let invitee = Connection::new_invitee("".to_owned(), pairwise_info)
.accept_invitation(&self.profile, invite)
.await?;

let thread_id = invitee.thread_id().to_owned();

self.connections.insert(&thread_id, invitee.into())
}

pub async fn send_request(&self, thread_id: &str) -> AgentResult<()> {
let invitee = self
.connections
.get(thread_id)?
.send_request(&self.profile, self.service_endpoint.clone(), vec![], None)
let invitee: Connection<_, _> = self.connections.get(thread_id)?.try_into()?;
let invitee = invitee
.send_request(
&self.profile.inject_wallet(),
self.service_endpoint.clone(),
vec![],
&HttpClient,
)
.await?;
self.connections.insert(thread_id, invitee)?;

self.connections.insert(thread_id, invitee.into())?;
Ok(())
}

pub async fn accept_request(&self, thread_id: &str, request: Request) -> AgentResult<()> {
let inviter = self
.connections
.get(thread_id)?
.process_request(&self.profile, request, self.service_endpoint.clone(), vec![], None)
let inviter = self.connections.get(thread_id)?;

let inviter = match inviter.state() {
ThinState::Inviter(State::Initial) => Connection::try_from(inviter)
.map_err(From::from)
.map(|c| c.into_invited(&request.id.0)),
ThinState::Inviter(State::Invited) => Connection::try_from(inviter).map_err(From::from),
s => Err(AgentError::from_msg(
AgentErrorKind::GenericAriesVcxError,
&format!(
"Connection with handle {} cannot process a request; State: {:?}",
thread_id, s
),
)),
}?;

let inviter = inviter
.handle_request(
&self.profile.inject_wallet(),
request,
self.service_endpoint.clone(),
vec![],
&HttpClient,
)
.await?;
self.connections.insert(thread_id, inviter)?;

self.connections.insert(thread_id, inviter.into())?;

Ok(())
}

pub async fn send_response(&self, thread_id: &str) -> AgentResult<()> {
let inviter = self
.connections
.get(thread_id)?
.send_response(&self.profile, None)
let inviter: Connection<_, _> = self.connections.get(thread_id)?.try_into()?;
let inviter = inviter
.send_response(&self.profile.inject_wallet(), &HttpClient)
.await?;
self.connections.insert(thread_id, inviter)?;

self.connections.insert(thread_id, inviter.into())?;

Ok(())
}

pub async fn accept_response(&self, thread_id: &str, response: SignedResponse) -> AgentResult<()> {
let invitee = self
.connections
.get(thread_id)?
.process_response(&self.profile, response, None)
let invitee: Connection<_, _> = self.connections.get(thread_id)?.try_into()?;
let invitee = invitee
.handle_response(&self.profile.inject_wallet(), response, &HttpClient)
.await?;
self.connections.insert(thread_id, invitee)?;

self.connections.insert(thread_id, invitee.into())?;

Ok(())
}

pub async fn send_ack(&self, thread_id: &str) -> AgentResult<()> {
let invitee = self.connections.get(thread_id)?.send_ack(&self.profile, None).await?;
self.connections.insert(thread_id, invitee)?;
let invitee: Connection<_, _> = self.connections.get(thread_id)?.try_into()?;
let invitee = invitee.send_ack(&self.profile.inject_wallet(), &HttpClient).await?;

self.connections.insert(thread_id, invitee.into())?;

Ok(())
}

pub async fn process_ack(&self, thread_id: &str, ack: Ack) -> AgentResult<()> {
let inviter = self
.connections
.get(thread_id)?
.process_ack(A2AMessage::Ack(ack))
.await?;
self.connections.insert(thread_id, inviter)?;
let inviter: Connection<_, _> = self.connections.get(thread_id)?.try_into()?;
let inviter = inviter.acknowledge_connection(&A2AMessage::Ack(ack))?;

self.connections.insert(thread_id, inviter.into())?;

Ok(())
}

pub fn get_state(&self, thread_id: &str) -> AgentResult<ConnectionState> {
Ok(self.connections.get(thread_id)?.get_state())
pub fn get_state(&self, thread_id: &str) -> AgentResult<ThinState> {
Ok(self.connections.get(thread_id)?.state())
}

pub(in crate::services) fn get_by_id(&self, thread_id: &str) -> AgentResult<Connection> {
pub(in crate::services) fn get_by_id(&self, thread_id: &str) -> AgentResult<GenericConnection> {
self.connections.get(thread_id)
}

pub fn get_by_their_vk(&self, their_vk: &str) -> AgentResult<Vec<String>> {
let their_vk = their_vk.to_string();
let f = |(id, m): (&String, &Mutex<Connection>)| -> Option<String> {
let f = |(id, m): (&String, &Mutex<GenericConnection>)| -> Option<String> {
let connection = m.lock().unwrap();
match connection.remote_vk() {
Ok(remote_vk) if remote_vk == their_vk => Some(id.to_string()),
Expand Down
Loading