Skip to main content

Crate affinidi_messaging_sdk

Crate affinidi_messaging_sdk 

Source
Expand description

§Affinidi Trusted Messaging SDK

The Affinidi Trusted Messaging (ATM) SDK provides a high-level interface for DIDComm v2 messaging through a mediator service. It handles message encryption, signing, routing, and transport so you can focus on building your application.

§Key Concepts

  • ATM - The main entry point. Holds configuration, profiles, and manages background tasks (e.g. message deletion).
  • profiles::ATMProfile - Represents a DID identity with an associated mediator. Each profile can independently send and receive messages.
  • Mediator - A service that stores and forwards DIDComm messages on behalf of your profile. Discovered automatically from the mediator’s DID Document.
  • protocols::Protocols - Pre-built DIDComm protocol implementations (Trust Ping, Message Pickup 3.0, Routing 2.0, etc.).
  • Transports - The SDK supports both REST (HTTPS) and WebSocket (WSS) transports. REST is used for authentication and bulk operations; WebSocket enables low-latency sending and live message streaming.

§Getting Started

§1. Initialize the TDK shared state

The SDK builds on top of affinidi-tdk-common which manages DID resolution and secrets. You need a TDKSharedState instance first:

use affinidi_tdk::common::{TDKSharedState, environments::TDKEnvironments};
use std::sync::Arc;

// Load environment configuration (DIDs, secrets, mediator endpoints)
let mut environment = TDKEnvironments::fetch_from_file(
    Some("environments.json"),
    "default",
)?;

let tdk = Arc::new(TDKSharedState::default().await);

§2. Build an ATM configuration and create the SDK instance

Use config::ATMConfig::builder() to configure the SDK, then pass it to ATM::new():

use affinidi_messaging_sdk::{ATM, config::ATMConfig};

let config = ATMConfig::builder()
    // Add custom SSL/TLS certificates if the mediator uses self-signed certs
    .with_ssl_certificates(&mut environment.ssl_certificates)
    // Optional: tune the per-profile message fetch cache
    .with_fetch_cache_limit_count(100)
    .with_fetch_cache_limit_bytes(10 * 1024 * 1024)
    .build()?;

let atm = ATM::new(config, tdk).await?;

§3. Register a profile

A profile ties a DID to a mediator. Add it to both the TDK (for secrets/DID resolution) and the ATM SDK:

use affinidi_messaging_sdk::profiles::ATMProfile;

// Get a profile from your environment configuration
let alice_tdk = environment.profiles.get("Alice").unwrap();
tdk.add_profile(alice_tdk).await;

// Convert and register with ATM (live_stream=false means no WebSocket yet)
let alice = atm
    .profile_add(
        &ATMProfile::from_tdk_profile(&atm, alice_tdk).await?,
        false,
    )
    .await?;

§4. Send a message (REST)

The simplest way to verify connectivity is a DIDComm Trust Ping:

// Send a signed trust-ping, requesting a pong response
let ping = atm
    .trust_ping()
    .send_ping(
        &alice,       // sender profile
        &target_did,  // recipient DID
        true,         // signed
        true,         // request pong response
        false,        // don't block waiting for response
    )
    .await?;

§5. Retrieve and unpack messages

After sending a message that produces a response, fetch and decrypt it:

use affinidi_messaging_sdk::messages::GetMessagesRequest;

let response = atm
    .get_messages(
        &alice,
        &GetMessagesRequest {
            message_ids: vec![msg_id],
            delete: true, // delete after retrieval
        },
    )
    .await?;

for msg in response.success {
    let (message, metadata) = atm.unpack(&msg.msg.unwrap()).await?;
    println!("Received: {:?}", message);
}

§6. Upgrade to WebSocket for live streaming

For lower latency and push-based message delivery, enable the WebSocket transport on a profile:

use std::time::Duration;

// Open a WebSocket connection to the mediator
atm.profile_enable_websocket(&alice).await?;

// Send a ping (now routed over WebSocket automatically)
let ping = atm
    .trust_ping()
    .send_ping(&alice, &target_did, true, true, false)
    .await?;

// Wait for the pong via the live stream
let pong = atm
    .message_pickup()
    .live_stream_get(
        &alice,
        &ping.message_id,
        Duration::from_secs(10),
        true, // auto-delete
    )
    .await?;

§7. Graceful shutdown

Always shut down cleanly to close WebSocket connections and stop background tasks:

atm.graceful_shutdown().await;

§Module Overview

ModuleDescription
configSDK configuration via the builder pattern (config::ATMConfig)
profilesDID profile and mediator management (profiles::ATMProfile)
messagesPack, unpack, send, list, get, fetch, and delete DIDComm messages
protocolsHigher-level DIDComm protocol implementations (Trust Ping, Message Pickup, Routing)
transportsREST and WebSocket transport layer
errorsError types (errors::ATMError)
delete_handlerBackground message deletion task
publicPublic utility functions (e.g. well-known DID resolution)

§Debug Logging

Enable SDK debug logs via the RUST_LOG environment variable:

export RUST_LOG=none,affinidi_messaging_sdk=debug

Re-exports§

pub use transport_adapter::DidCommTransport;
pub use tsp_wire::TSP_MAGIC_BYTE;
pub use tsp_wire::looks_like_tsp;

Modules§

config
delete_handler
This module contains the implementation of the delete handler.
errors
messages
profiles
Profiles modules contains the implementation of the Profile struct and its methods.
protocols
This module contains the implementation of the DIDComm protocols supported by the SDK.
public
transport_adapter
DidCommTransport — a MessageTransport over the DIDComm ATM wire.
transports
tsp_wire
Classifying a TSP frame without the tsp feature.

Structs§

ATM