Skip to content

Commit

Permalink
Split connection state machines
Browse files Browse the repository at this point in the history
Signed-off-by: Patrik Stas <patrik.stas@absa.africa>
  • Loading branch information
Patrik-Stas committed Sep 29, 2020
1 parent 3003985 commit fc233c8
Show file tree
Hide file tree
Showing 22 changed files with 918 additions and 582 deletions.
5 changes: 3 additions & 2 deletions libvcx/src/api/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1283,7 +1283,7 @@ mod tests {
use std::ptr;

use api::{return_types_u32, VcxStateType};
use connection::tests::{build_test_connection_inviter_requested, build_test_connection_inviter_invited};
use connection::tests::{build_test_connection_inviter_requested, build_test_connection_inviter_invited, build_test_connection_inviter_null};
use utils::constants::{DELETE_CONNECTION_DECRYPTED_RESPONSE, GET_MESSAGES_DECRYPTED_RESPONSE};
use utils::devsetup::*;
use utils::error;
Expand Down Expand Up @@ -1331,7 +1331,8 @@ mod tests {
let cb = return_types_u32::Return_U32_STR::new().unwrap();
let rc = vcx_connection_connect(cb.command_handle, 0, CString::new("{}").unwrap().into_raw(), Some(cb.get_callback()));
assert_eq!(rc, error::INVALID_CONNECTION_HANDLE.code_num);
let handle = build_test_connection_inviter_requested();

let handle = build_test_connection_inviter_null();
assert!(handle > 0);

let cb = return_types_u32::Return_U32_STR::new().unwrap();
Expand Down
71 changes: 57 additions & 14 deletions libvcx/src/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ use serde_json;

use error::prelude::*;
use messages;
use messages::SerializableObjectWithState;
use messages::get_message::Message;
use messages::SerializableObjectWithState;
use object_cache::ObjectCache;
use settings;
use settings::ProtocolTypes;
use utils::error;
use v3::handlers::connection::connection::Connection as ConnectionV3;
use v3::handlers::connection::agent_info::AgentInfo;
use v3::handlers::connection::connection::{Connection as ConnectionV3, SmConnection, SmConnectionState};
use v3::messages::a2a::A2AMessage;
use v3::messages::connection::did_doc::DidDoc;
use v3::messages::connection::invite::Invitation as InvitationV3;
use v3::handlers::connection::state_machine::ActorDidExchangeState;

lazy_static! {
static ref CONNECTION_MAP: ObjectCache<ConnectionV3> = ObjectCache::<ConnectionV3>::new("connections-cache");
Expand Down Expand Up @@ -99,7 +98,7 @@ fn store_connection(connection: ConnectionV3) -> VcxResult<u32> {
pub fn create_connection(source_id: &str) -> VcxResult<u32> {
trace!("create_connection >>> source_id: {}", source_id);
let connection = ConnectionV3::create(source_id);
return store_connection(connection)
return store_connection(connection);
}

pub fn create_connection_with_invite(source_id: &str, details: &str) -> VcxResult<u32> {
Expand Down Expand Up @@ -161,13 +160,13 @@ pub fn to_string(handle: u32) -> VcxResult<String> {
}

pub fn from_string(connection_data: &str) -> VcxResult<u32> {
let object: SerializableObjectWithState<AgentInfo, ActorDidExchangeState> = ::serde_json::from_str(connection_data)
let object: SerializableObjectWithState<AgentInfo, SmConnectionState> = ::serde_json::from_str(connection_data)
.map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot deserialize Connection: {:?}", err)))?;

let handle = match object {
SerializableObjectWithState::V3 { data, state, source_id } => {
CONNECTION_MAP.add((state, data, source_id).into())?
},
}
_ => return Err(VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Unexpected format of serialized connection: {:?}", object)))
};
Ok(handle)
Expand All @@ -188,14 +187,14 @@ pub fn get_invite_details(handle: u32, _abbreviated: bool) -> VcxResult<String>
}).or(Err(VcxError::from(VcxErrorKind::InvalidConnectionHandle)))
}

impl Into<(ActorDidExchangeState, AgentInfo, String)> for ConnectionV3 {
fn into(self) -> (ActorDidExchangeState, AgentInfo, String) {
(self.state_object().to_owned(), self.agent_info().to_owned(), self.source_id())
impl Into<(SmConnectionState, AgentInfo, String)> for ConnectionV3 {
fn into(self) -> (SmConnectionState, AgentInfo, String) {
(self.state_object(), self.agent_info().to_owned(), self.source_id())
}
}

impl From<(ActorDidExchangeState, AgentInfo, String)> for ConnectionV3 {
fn from((state, agent_info, source_id): (ActorDidExchangeState, AgentInfo, String)) -> ConnectionV3 {
impl From<(SmConnectionState, AgentInfo, String)> for ConnectionV3 {
fn from((state, agent_info, source_id): (SmConnectionState, AgentInfo, String)) -> ConnectionV3 {
ConnectionV3::from_parts(source_id, agent_info, state)
}
}
Expand Down Expand Up @@ -264,17 +263,25 @@ pub mod tests {
use std::thread;
use std::time::Duration;

use serde::Serialize;
use serde_json::Value;

use api::VcxStateType;
use messages::MessageStatusCode;
use messages::get_message::*;
use messages::MessageStatusCode;
use utils::constants::*;
use utils::constants;
use utils::devsetup::*;
use utils::httpclient::AgencyMockDecrypted;
use utils::mockdata::mockdata_connection::{ARIES_CONNECTION_ACK, ARIES_CONNECTION_INVITATION, ARIES_CONNECTION_REQUEST};
use utils::mockdata::mockdata_connection::{ARIES_CONNECTION_ACK, ARIES_CONNECTION_INVITATION, ARIES_CONNECTION_REQUEST, CONNECTION_SM_INVITEE_COMPLETED, CONNECTION_SM_INVITEE_INVITED, CONNECTION_SM_INVITEE_REQUESTED, CONNECTION_SM_INVITER_COMPLETED};

use super::*;

pub fn build_test_connection_inviter_null() -> u32 {
let handle = create_connection("faber_to_alice").unwrap();
handle
}

pub fn build_test_connection_inviter_invited() -> u32 {
let handle = create_connection("faber_to_alice").unwrap();
connect(handle, Some("{}".to_string())).unwrap();
Expand All @@ -283,7 +290,7 @@ pub mod tests {

pub fn build_test_connection_inviter_requested() -> u32 {
let handle = build_test_connection_inviter_invited();
let msg : A2AMessage = serde_json::from_str(ARIES_CONNECTION_REQUEST).unwrap();
let msg: A2AMessage = serde_json::from_str(ARIES_CONNECTION_REQUEST).unwrap();
update_state_with_message(handle, msg).unwrap();
handle
}
Expand Down Expand Up @@ -418,6 +425,42 @@ pub mod tests {
assert_eq!(get_invite_details(0, true).unwrap_err().kind(), VcxErrorKind::InvalidConnectionHandle);
}

#[test]
#[cfg(feature = "general_test")]
fn test_deserialize_connection_inviter_completed() {
let _setup = SetupAriesMocks::init();

let handle = from_string(CONNECTION_SM_INVITER_COMPLETED).unwrap();
let second_string = to_string(handle).unwrap();

assert_eq!(get_pw_did(handle).unwrap(), "2ZHFFhzA2XtTD6hJqzL7ux");
assert_eq!(get_pw_verkey(handle).unwrap(), "rCw3x5h1jS6gPo7rRrt3EYbXXe5nNjnGbdf1jAwUxuj");
assert_eq!(get_agent_did(handle).unwrap(), "EZrZyu4bfydm4ByNm56kPP");
assert_eq!(get_agent_verkey(handle).unwrap(), "8Ps2WosJ9AV1eXPoJKsEJdM3NchPhSyS8qFt6LQUTKv2");
assert_eq!(get_state(handle), VcxStateType::VcxStateAccepted as u32);
assert!(release(handle).is_ok());
}

fn test_deserialize_and_serialize(sm_serialized: &str) {
let mut original_object: Value = serde_json::from_str(sm_serialized).unwrap();
let handle_conn = from_string(sm_serialized).unwrap();
let reserialized = to_string(handle_conn).unwrap();
let reserialized_object: Value = serde_json::from_str(&reserialized).unwrap();

assert_eq!(original_object, reserialized_object);
}

#[test]
#[cfg(feature = "general_test")]
fn test_deserialize_and_serialize_should_produce_the_same_object() {
let _setup = SetupAriesMocks::init();

test_deserialize_and_serialize(CONNECTION_SM_INVITEE_INVITED);
test_deserialize_and_serialize(CONNECTION_SM_INVITEE_REQUESTED);
test_deserialize_and_serialize(CONNECTION_SM_INVITEE_COMPLETED);
test_deserialize_and_serialize(CONNECTION_SM_INVITER_COMPLETED);
}

#[test]
#[cfg(feature = "general_test")]
fn test_serialize_deserialize() {
Expand Down
80 changes: 18 additions & 62 deletions libvcx/src/utils/mockdata/mockdata_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,13 @@ pub const ARIES_CONNECTION_INVITATION: &str = r#"
// Alice created and serialized connection created from received invitation
pub const CONNECTION_SM_INVITEE_INVITED: &str = r#"
{
"version": "2.0",
"version": "3.0",
"source_id": "alice-670c6360-5c0e-4495-bd25-2ee58c39fc7e",
"data": {
"source_id": "alice-670c6360-5c0e-4495-bd25-2ee58c39fc7e",
"pw_did": "",
"pw_verkey": "",
"state": 2,
"uuid": "",
"endpoint": "",
"invite_detail": null,
"redirect_detail": null,
"invite_url": null,
"pw_vk": "",
"agent_did": "",
"agent_vk": "",
"their_pw_did": "18ac5f5d-c81d-451a-be20-a0df4933513a",
"their_pw_verkey": "HoNSv4aPCRQ8BsJrVXS26Za4rdEFvtCyyoQEtCS175dw",
"public_did": null,
"their_public_did": null,
"version": "2.0"
"agent_vk": ""
},
"state": {
"Invitee": {
Expand Down Expand Up @@ -104,24 +93,13 @@ pub const ARIES_CONNECTION_REQUEST: &str = r#"
// Alice sends connection request to Faber
pub const CONNECTION_SM_INVITEE_REQUESTED: &str = r#"
{
"version": "2.0",
"version": "3.0",
"source_id": "alice-670c6360-5c0e-4495-bd25-2ee58c39fc7e",
"data": {
"source_id": "alice-670c6360-5c0e-4495-bd25-2ee58c39fc7e",
"pw_did": "KC6NKcpXcpVnpjL8uKH3tV",
"pw_verkey": "Av4ZDAKgpniTnxLukLQFZ2DbdNqPub8MBxxynCZ5VuFi",
"state": 3,
"uuid": "",
"endpoint": "",
"invite_detail": null,
"redirect_detail": null,
"invite_url": null,
"pw_vk": "Av4ZDAKgpniTnxLukLQFZ2DbdNqPub8MBxxynCZ5VuFi",
"agent_did": "Gqw6t57yDgzaG79h4HUVCf",
"agent_vk": "9drH4FZk79Y4bx5jzPBaJEmB4woEGG1XQSfgF7NkyKvV",
"their_pw_did": "18ac5f5d-c81d-451a-be20-a0df4933513a",
"their_pw_verkey": "HoNSv4aPCRQ8BsJrVXS26Za4rdEFvtCyyoQEtCS175dw",
"public_did": null,
"their_public_did": null,
"version": "2.0"
"agent_vk": "9drH4FZk79Y4bx5jzPBaJEmB4woEGG1XQSfgF7NkyKvV"
},
"state": {
"Invitee": {
Expand Down Expand Up @@ -226,24 +204,13 @@ pub const ARIES_CONNECTION_RESPONSE: &str = r#"
// Alice (invitee) connection SM after Faber accepted connection by sending connection response
pub const CONNECTION_SM_INVITEE_COMPLETED: &str = r#"
{
"version": "2.0",
"version": "3.0",
"source_id": "alice-670c6360-5c0e-4495-bd25-2ee58c39fc7e",
"data": {
"source_id": "alice-670c6360-5c0e-4495-bd25-2ee58c39fc7e",
"pw_did": "KC6NKcpXcpVnpjL8uKH3tV",
"pw_verkey": "Av4ZDAKgpniTnxLukLQFZ2DbdNqPub8MBxxynCZ5VuFi",
"state": 4,
"uuid": "",
"endpoint": "",
"invite_detail": null,
"redirect_detail": null,
"invite_url": null,
"pw_vk": "Av4ZDAKgpniTnxLukLQFZ2DbdNqPub8MBxxynCZ5VuFi",
"agent_did": "Gqw6t57yDgzaG79h4HUVCf",
"agent_vk": "9drH4FZk79Y4bx5jzPBaJEmB4woEGG1XQSfgF7NkyKvV",
"their_pw_did": "2ZHFFhzA2XtTD6hJqzL7ux",
"their_pw_verkey": "rCw3x5h1jS6gPo7rRrt3EYbXXe5nNjnGbdf1jAwUxuj",
"public_did": null,
"their_public_did": null,
"version": "2.0"
"agent_vk": "9drH4FZk79Y4bx5jzPBaJEmB4woEGG1XQSfgF7NkyKvV"
},
"state": {
"Invitee": {
Expand Down Expand Up @@ -303,24 +270,13 @@ pub const ARIES_CONNECTION_ACK: &str = r#"
// Inviter (Faber) after finished connection protocol by sending connection ack
pub const CONNECTION_SM_INVITER_COMPLETED: &str = r#"
{
"version": "2.0",
"version": "3.0",
"source_id": "alice-131bc1e2-fa29-404c-a87c-69983e02084d",
"data": {
"source_id": "alice-131bc1e2-fa29-404c-a87c-69983e02084d",
"pw_did": "2ZHFFhzA2XtTD6hJqzL7ux",
"pw_verkey": "rCw3x5h1jS6gPo7rRrt3EYbXXe5nNjnGbdf1jAwUxuj",
"state": 4,
"uuid": "",
"endpoint": "",
"invite_detail": null,
"redirect_detail": null,
"invite_url": null,
"pw_vk": "rCw3x5h1jS6gPo7rRrt3EYbXXe5nNjnGbdf1jAwUxuj",
"agent_did": "EZrZyu4bfydm4ByNm56kPP",
"agent_vk": "8Ps2WosJ9AV1eXPoJKsEJdM3NchPhSyS8qFt6LQUTKv2",
"their_pw_did": "KC6NKcpXcpVnpjL8uKH3tV",
"their_pw_verkey": "Av4ZDAKgpniTnxLukLQFZ2DbdNqPub8MBxxynCZ5VuFi",
"public_did": null,
"their_public_did": null,
"version": "2.0"
"agent_vk": "8Ps2WosJ9AV1eXPoJKsEJdM3NchPhSyS8qFt6LQUTKv2"
},
"state": {
"Inviter": {
Expand Down Expand Up @@ -367,6 +323,7 @@ pub const CONNECTION_SM_INVITER_COMPLETED: &str = r#"
pub const DEFAULT_SERIALIZED_CONNECTION: &str = r#"
{
"version": "3.0",
"source_id": "test_serialize_deserialize",
"data": {
"pw_did": "",
"pw_vk": "",
Expand All @@ -377,7 +334,6 @@ pub const DEFAULT_SERIALIZED_CONNECTION: &str = r#"
"Inviter": {
"Null": {}
}
},
"source_id": "test_serialize_deserialize"
}
}"#;

15 changes: 15 additions & 0 deletions libvcx/src/v3/handlers/connection/agent_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ impl Default for AgentInfo {
}

impl AgentInfo {
/**
Create connection agent in one's agency
*/
pub fn create_agent(&self) -> VcxResult<AgentInfo> {
trace!("Agent::create_agent >>>");

Expand All @@ -49,6 +52,9 @@ impl AgentInfo {
Ok(AgentInfo { pw_did, pw_vk, agent_did, agent_vk })
}

/**
Builds one's agency's URL endpoint
*/
pub fn agency_endpoint(&self) -> VcxResult<String> {
settings::get_config_value(settings::CONFIG_AGENCY_ENDPOINT)
.map(|str| format!("{}/agency/msg", str))
Expand Down Expand Up @@ -130,20 +136,29 @@ impl AgentInfo {
EncryptionEnvelope::open(message.payload()?)
}

/**
Sends authenticated message to connection counterparty
*/
pub fn send_message(&self, message: &A2AMessage, did_dod: &DidDoc) -> VcxResult<()> {
trace!("Agent::send_message >>> message: {:?}, did_doc: {:?}", message, did_dod);
let envelope = EncryptionEnvelope::create(&message, Some(&self.pw_vk), &did_dod)?;
httpclient::post_message(&envelope.0, &did_dod.get_endpoint())?;
Ok(())
}

/**
Sends anonymous message to connection counterparty
*/
pub fn send_message_anonymously(message: &A2AMessage, did_dod: &DidDoc) -> VcxResult<()> {
trace!("Agent::send_message_anonymously >>> message: {:?}, did_doc: {:?}", message, did_dod);
let envelope = EncryptionEnvelope::create(&message, None, &did_dod)?;
httpclient::post_message(&envelope.0, &did_dod.get_endpoint())?;
Ok(())
}

/**
Sends message to one's agency signalling resources related to this connection agent can be deleted.
*/
pub fn delete(&self) -> VcxResult<()> {
trace!("Agent::delete >>>");
send_delete_connection_message(&self.pw_did, &self.pw_vk, &self.agent_did, &self.agent_vk)
Expand Down
Loading

0 comments on commit fc233c8

Please sign in to comment.