Skip to content

Commit 67284d1

Browse files
authored
Add function 'vcx_connection_handle_message' to libvcx (#543)
Signed-off-by: Patrik Stas <[email protected]> Signed-off-by: Patrik Stas <[email protected]>
1 parent a8bbc6f commit 67284d1

File tree

13 files changed

+276
-127
lines changed

13 files changed

+276
-127
lines changed

agents/node/vcxagent-core/src/services/service-connections.js

+8
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ module.exports.createServiceConnections = function createServiceConnections ({ l
8282
return state
8383
}
8484

85+
async function handleMessage (connectionId, ariesMsg) {
86+
const connection = await loadConnection(connectionId)
87+
const state = await connection.handleMessage(ariesMsg)
88+
await saveConnection(connectionId, connection)
89+
return state
90+
}
91+
8592
async function connectionAutoupdate (connectionId, updateAttemptsThreshold = 20, timeoutMs = 500) {
8693
const connection = await loadConnection(connectionId)
8794
await _progressConnectionToAcceptedState(connection, updateAttemptsThreshold, timeoutMs)
@@ -187,6 +194,7 @@ module.exports.createServiceConnections = function createServiceConnections ({ l
187194
// universal
188195
connectionAutoupdate,
189196
connectionUpdate,
197+
handleMessage,
190198
getConnectionPwDid,
191199

192200
signData,

agents/node/vcxagent-core/test/trustping.spec.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,13 @@ describe('trustping', () => {
1919
expect(faberMessages1.length).toBe(1)
2020
expect(JSON.parse(faberMessages1[0].decryptedMsg)['@type'].match(/trust_ping\/1.0\/ping/))
2121
const pingMsgId = JSON.parse(faberMessages1[0].decryptedMsg)['@id']
22-
await faber.updateConnection(4)
23-
const faberMessages2 = await faber.downloadReceivedMessagesV2()
24-
expect(faberMessages2.length).toBe(0)
22+
await faber.handleMessage(faberMessages1[0].decryptedMsg)
2523

2624
const aliceMessages1 = await alice.downloadReceivedMessagesV2()
2725
expect(aliceMessages1.length).toBe(1)
2826
expect(JSON.parse(aliceMessages1[0].decryptedMsg)['@type'].match(/trust_ping\/1.0\/ping_response/))
2927
expect(JSON.parse(aliceMessages1[0].decryptedMsg)['~thread'].thid).toBe(pingMsgId)
30-
await alice.updateConnection(4)
31-
const aliceMessages2 = await alice.downloadReceivedMessagesV2()
32-
expect(aliceMessages2.length).toBe(0)
28+
await alice.handleMessage(aliceMessages1[0].decryptedMsg)
3329
} catch (err) {
3430
console.error(`err = ${err.message} stack = ${err.stack}`)
3531
await sleep(2000)

agents/node/vcxagent-core/test/utils/alice.js

+10
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ module.exports.createAlice = async function createAlice () {
6565
await vcxAgent.agentShutdownVcx()
6666
}
6767

68+
async function handleMessage (ariesMsg) {
69+
logger.info(`Alice is going to try handle incoming messages`)
70+
await vcxAgent.agentInitVcx()
71+
72+
await vcxAgent.serviceConnections.handleMessage(connectionId, ariesMsg)
73+
74+
await vcxAgent.agentShutdownVcx()
75+
}
76+
6877
async function acceptCredentialOffer () {
6978
await vcxAgent.agentInitVcx()
7079
logger.info('Alice accepting credential offer')
@@ -201,6 +210,7 @@ module.exports.createAlice = async function createAlice () {
201210
createOrReuseConnectionUsingOobMsg,
202211
acceptOobCredentialOffer,
203212
updateConnection,
213+
handleMessage,
204214
acceptCredentialOffer,
205215
updateStateCredentialV2,
206216
sendHolderProof,

agents/node/vcxagent-core/test/utils/faber.js

+10
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,15 @@ module.exports.createFaber = async function createFaber () {
128128
await vcxAgent.agentShutdownVcx()
129129
}
130130

131+
async function handleMessage (ariesMsg) {
132+
logger.info(`Faber is going to try handle incoming messages`)
133+
await vcxAgent.agentInitVcx()
134+
135+
await vcxAgent.serviceConnections.handleMessage(connectionId, ariesMsg)
136+
137+
await vcxAgent.agentShutdownVcx()
138+
}
139+
131140
async function buildLedgerPrimitivesV2 (revocationDetails) {
132141
await vcxAgent.agentInitVcx()
133142

@@ -329,6 +338,7 @@ module.exports.createFaber = async function createFaber () {
329338
createOobProofRequest,
330339
createConnectionFromReceivedRequest,
331340
updateConnection,
341+
handleMessage,
332342
sendConnectionResponse,
333343
sendCredentialOfferV2,
334344
createOobCredOffer,

aries_vcx/src/protocols/connection/inviter/state_machine.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,9 @@ pub mod unit_tests {
556556

557557
let routing_keys: Vec<String> = vec!["verkey123".into()];
558558
let service_endpoint = String::from("https://example.org/agent");
559-
did_exchange_sm = did_exchange_sm.create_invitation(routing_keys, service_endpoint).unwrap();
559+
did_exchange_sm = did_exchange_sm
560+
.create_invitation(routing_keys, service_endpoint)
561+
.unwrap();
560562

561563
assert_match!(InviterFullState::Invited(_), did_exchange_sm.state);
562564
}
@@ -661,7 +663,9 @@ pub mod unit_tests {
661663

662664
let routing_keys: Vec<String> = vec!["verkey123".into()];
663665
let service_endpoint = String::from("https://example.org/agent");
664-
did_exchange_sm = did_exchange_sm.create_invitation(routing_keys, service_endpoint).unwrap();
666+
did_exchange_sm = did_exchange_sm
667+
.create_invitation(routing_keys, service_endpoint)
668+
.unwrap();
665669
assert_match!(InviterFullState::Invited(_), did_exchange_sm.state);
666670

667671
did_exchange_sm = did_exchange_sm
@@ -722,7 +726,9 @@ pub mod unit_tests {
722726

723727
let routing_keys: Vec<String> = vec!["verkey123".into()];
724728
let service_endpoint = String::from("https://example.org/agent");
725-
did_exchange_sm = did_exchange_sm.create_invitation(routing_keys, service_endpoint).unwrap();
729+
did_exchange_sm = did_exchange_sm
730+
.create_invitation(routing_keys, service_endpoint)
731+
.unwrap();
726732

727733
assert_match!(InviterFullState::Responded(_), did_exchange_sm.state);
728734
}

libvcx/src/api_lib/api_c/connection.rs

+53
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,59 @@ pub extern "C" fn vcx_connection_update_state_with_message(
689689
error::SUCCESS.code_num
690690
}
691691

692+
/// Update the state of the connection based on the given message.
693+
///
694+
/// #Params
695+
/// command_handle: command handle to map callback to user context.
696+
///
697+
/// connection_handle: was provided during creation. Used to identify connection object
698+
///
699+
/// message: message to process.
700+
///
701+
/// cb: Callback that provides most current state of the connection and error status of request
702+
///
703+
/// #Returns
704+
/// Error code as a u32
705+
#[no_mangle]
706+
pub extern "C" fn vcx_connection_handle_message(
707+
command_handle: CommandHandle,
708+
connection_handle: u32,
709+
message: *const c_char,
710+
cb: Option<extern "C" fn(xcommand_handle: CommandHandle, err: u32)>,
711+
) -> u32 {
712+
info!("vcx_connection_handle_message >>>");
713+
714+
check_useful_c_callback!(cb, VcxErrorKind::InvalidOption);
715+
check_useful_c_str!(message, VcxErrorKind::InvalidOption);
716+
717+
let source_id = get_source_id(connection_handle).unwrap_or_default();
718+
trace!(
719+
"vcx_connection_handle_message(command_handle: {}, connection_handle: {}), source_id: {:?}",
720+
command_handle,
721+
connection_handle,
722+
source_id
723+
);
724+
725+
execute_async::<BoxFuture<'static, Result<(), ()>>>(Box::pin(async move {
726+
let rc = match handle_message(connection_handle, &message).await {
727+
Ok(err) => {
728+
trace!("vcx_connection_handle_message_cb(command_handle: {}, rc: {}, connection_handle: {}), source_id: {:?}", command_handle, error::SUCCESS.message, connection_handle, source_id);
729+
err
730+
}
731+
Err(err) => {
732+
set_current_error_vcx(&err);
733+
error!("vcx_connection_handle_message_cb(command_handle: {}, rc: {}, connection_handle: {}), source_id: {:?}", command_handle, err, connection_handle, source_id);
734+
err.into()
735+
}
736+
};
737+
738+
cb(command_handle, rc);
739+
Ok(())
740+
}));
741+
742+
error::SUCCESS.code_num
743+
}
744+
692745
/// Returns the current internal state of the connection. Does NOT query agency for state updates.
693746
/// Possible states:
694747
/// 1 - Initialized

libvcx/src/api_lib/api_handle/connection.rs

+16
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,22 @@ pub async fn update_state_with_message(handle: u32, message: &str) -> VcxResult<
173173
Ok(error::SUCCESS.code_num)
174174
}
175175

176+
pub async fn handle_message(handle: u32, message: &str) -> VcxResult<u32> {
177+
let mut connection = CONNECTION_MAP.get_cloned(handle)?;
178+
let message: A2AMessage = serde_json::from_str(message).map_err(|err| {
179+
VcxError::from_msg(
180+
VcxErrorKind::InvalidJson,
181+
format!(
182+
"Failed to deserialize message {} into A2AMessage, err: {:?}",
183+
message, err
184+
),
185+
)
186+
})?;
187+
connection.handle_message(message, get_main_wallet_handle()).await?;
188+
CONNECTION_MAP.insert(handle, connection)?;
189+
Ok(error::SUCCESS.code_num)
190+
}
191+
176192
pub async fn update_state(handle: u32) -> VcxResult<u32> {
177193
let mut connection = CONNECTION_MAP.get_cloned(handle)?;
178194
let res = if connection.is_in_final_state() {

wrappers/node/src/api/connection.ts

+44
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,50 @@ export class Connection extends VCXBaseWithState<IConnectionData, ConnectionStat
456456
}
457457
}
458458

459+
/**
460+
*
461+
* Answers message if it there's "easy" way to do so (ping, disclose query, handshake-reuse)
462+
*
463+
* Example:
464+
* ```
465+
* await object.handleMessage(message)
466+
* ```
467+
* @returns {Promise<void>}
468+
*/
469+
public async handleMessage(message: string) {
470+
try {
471+
const commandHandle = 0;
472+
const state = await createFFICallbackPromise<number>(
473+
(resolve, reject, cb) => {
474+
const rc = rustAPI().vcx_connection_handle_message(
475+
commandHandle,
476+
this.handle,
477+
message,
478+
cb,
479+
);
480+
if (rc) {
481+
reject(rc);
482+
}
483+
},
484+
(resolve, reject) =>
485+
ffi.Callback(
486+
'void',
487+
['uint32', 'uint32'],
488+
(handle: number, err: number) => {
489+
if (err) {
490+
reject(err);
491+
}
492+
resolve();
493+
},
494+
),
495+
);
496+
return state;
497+
} catch (err) {
498+
throw new VCXInternalError(err);
499+
}
500+
}
501+
502+
459503
/**
460504
*
461505
* Communicates with the agent service for polling and setting the state of the entity.

wrappers/node/src/rustlib.ts

+10
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,12 @@ export interface IFFIEntryPoint {
189189
message: string,
190190
cb: ICbRef,
191191
) => number;
192+
vcx_connection_handle_message: (
193+
commandId: number,
194+
handle: number,
195+
message: string,
196+
cb: ICbRef,
197+
) => number;
192198
vcx_connection_get_state: (commandId: number, handle: number, cb: ICbRef) => number;
193199
vcx_connection_invite_details: (
194200
commandId: number,
@@ -727,6 +733,10 @@ export const FFIConfiguration: { [Key in keyof IFFIEntryPoint]: any } = {
727733
FFI_ERROR_CODE,
728734
[FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE, FFI_STRING_DATA, FFI_CALLBACK_PTR],
729735
],
736+
vcx_connection_handle_message: [
737+
FFI_ERROR_CODE,
738+
[FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE, FFI_STRING_DATA, FFI_CALLBACK_PTR],
739+
],
730740
vcx_connection_get_state: [
731741
FFI_ERROR_CODE,
732742
[FFI_COMMAND_HANDLE, FFI_CONNECTION_HANDLE, FFI_CALLBACK_PTR],

wrappers/node/test/helpers/entities.ts

+9-40
Original file line numberDiff line numberDiff line change
@@ -25,46 +25,7 @@ import {
2525
Schema,
2626
} from 'src'
2727
import * as uuid from 'uuid';
28-
29-
const ARIES_CONNECTION_REQUEST = {
30-
'@id': 'b5517062-303f-4267-9a29-09bc89497c06',
31-
'@type': 'did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/request',
32-
connection: {
33-
DID: '2RjtVytftf9Psbh3E8jqyq',
34-
DIDDoc: {
35-
'@context': 'https://w3id.org/did/v1',
36-
authentication: [
37-
{
38-
publicKey: '2RjtVytftf9Psbh3E8jqyq#1',
39-
type: 'Ed25519SignatureAuthentication2018',
40-
},
41-
],
42-
id: '2RjtVytftf9Psbh3E8jqyq',
43-
publicKey: [
44-
{
45-
controller: '2RjtVytftf9Psbh3E8jqyq',
46-
id: '1',
47-
publicKeyBase58: 'n6ZJrPGhbkLxQBxH11BvQHSKch58sx3MAqDTkUG4GmK',
48-
type: 'Ed25519VerificationKey2018',
49-
},
50-
],
51-
service: [
52-
{
53-
id: 'did:example:123456789abcdefghi;indy',
54-
priority: 0,
55-
recipientKeys: ['2RjtVytftf9Psbh3E8jqyq#1'],
56-
routingKeys: [
57-
'AKnC8qR9xsZZEBY7mdV6fzjmmtKxeegrNatpz4jSJhrH',
58-
'Hezce2UWMZ3wUhVkh2LfKSs8nDzWwzs2Win7EzNN3YaR',
59-
],
60-
serviceEndpoint: 'http://localhost:8080/agency/msg',
61-
type: 'IndyAgent',
62-
},
63-
],
64-
},
65-
},
66-
label: 'alice-157ea14b-4b7c-48a5-b536-d4ed6e027b84',
67-
};
28+
import {ARIES_CONNECTION_ACK, ARIES_CONNECTION_REQUEST} from './mockdata'
6829

6930
export const dataConnectionCreate = (): IConnectionCreateData => ({
7031
id: `testConnectionId-${uuid.v4()}`,
@@ -96,6 +57,14 @@ export const createConnectionInviterRequested = async (
9657
return connection;
9758
};
9859

60+
export const createConnectionInviterFinished = async (
61+
data = dataConnectionCreate(),
62+
): Promise<Connection> => {
63+
const connection = await createConnectionInviterRequested()
64+
await connection.updateStateWithMessage(JSON.stringify(ARIES_CONNECTION_ACK));
65+
return connection;
66+
};
67+
9968
export const dataCredentialDefCreate = (): ICredentialDefCreateDataV2 => ({
10069
schemaId: 'testCredentialDefSchemaId',
10170
sourceId: 'testCredentialDefSourceId',

0 commit comments

Comments
 (0)