#![cfg(all(feature = "webvh", feature = "didcomm"))]
use std::sync::Arc;
use std::time::Duration;
use affinidi_messaging_didcomm::Message;
use affinidi_messaging_didcomm_service::{
DIDCommHandler, DIDCommResponse, DIDCommService, DIDCommServiceConfig, DIDCommServiceError,
HandlerContext, Router, TRUST_PING_TYPE, handler_fn, ignore_handler, trust_ping_handler,
};
use affinidi_tdk::common::config::TDKConfig;
use affinidi_tdk::secrets_resolver::secrets::Secret;
use tokio_util::sync::CancellationToken;
use tracing::warn;
use vti_common::telemetry::SharedTelemetrySink;
use crate::didcomm_bridge::DIDCommBridge;
use crate::messaging::handshake::{
HandshakeError, HandshakeOptions, ResolvedMediator, mediator_handshake,
};
use crate::messaging::live_prover::{DIDCommServiceProver, StaticListenerConfigBuilder};
pub struct TransientHandshakeContext {
pub vta_did: String,
pub secrets: Vec<Secret>,
pub tdk_config: Option<TDKConfig>,
}
pub async fn run_transient_handshake(
ctx: TransientHandshakeContext,
resolver: &affinidi_did_resolver_cache_sdk::DIDCacheClient,
telemetry: &SharedTelemetrySink,
mediator_did: &str,
opts: HandshakeOptions,
) -> Result<ResolvedMediator, HandshakeError> {
let bridge = Arc::new(DIDCommBridge::new(mediator_did));
let handler = match build_transient_handler(Arc::clone(&bridge)) {
Ok(h) => h,
Err(e) => {
return Err(HandshakeError::Failed {
stage: crate::messaging::handshake::HandshakeStage::Connect,
cause: format!("transient handler build failed: {e}"),
});
}
};
let shutdown = CancellationToken::new();
let service_config = DIDCommServiceConfig { listeners: vec![] };
let service = match DIDCommService::start(service_config, handler, shutdown.clone()).await {
Ok(s) => s,
Err(e) => {
return Err(HandshakeError::Failed {
stage: crate::messaging::handshake::HandshakeStage::Connect,
cause: format!("transient DIDCommService::start failed: {e}"),
});
}
};
bridge.set_service(service.clone());
let config_builder = Arc::new(StaticListenerConfigBuilder::new(
&ctx.vta_did,
ctx.secrets,
ctx.tdk_config,
));
let prover = DIDCommServiceProver::new(service.clone(), Arc::clone(&bridge), config_builder);
let result = mediator_handshake(
resolver,
&prover,
telemetry,
mediator_did,
&ctx.vta_did,
opts,
)
.await;
shutdown.cancel();
tokio::time::sleep(Duration::from_millis(50)).await;
result
}
fn build_transient_handler(
bridge: Arc<DIDCommBridge>,
) -> Result<TransientBridgeHandler, DIDCommServiceError> {
let router = Router::new()
.route(TRUST_PING_TYPE, handler_fn(trust_ping_handler))?
.fallback(handler_fn(ignore_handler));
Ok(TransientBridgeHandler {
inner: router,
bridge,
})
}
struct TransientBridgeHandler {
inner: Router,
bridge: Arc<DIDCommBridge>,
}
#[async_trait::async_trait]
impl DIDCommHandler for TransientBridgeHandler {
async fn handle(
&self,
ctx: HandlerContext,
message: Message,
meta: affinidi_messaging_didcomm::UnpackMetadata,
) -> Result<Option<DIDCommResponse>, DIDCommServiceError> {
if self.bridge.try_complete(&message) {
return Ok(None);
}
if message.thid.is_some() {
warn!(
msg_type = %message.typ,
"transient-handshake: unmatched response (stale or unrelated)"
);
}
self.inner.handle(ctx, message, meta).await
}
}
#[cfg(test)]
mod tests {
use crate::messaging::handshake::HandshakeStage;
#[test]
fn transient_handshake_module_compiles() {
let _stage = HandshakeStage::Resolve;
}
}