After establishing a DIDComm connection with a peer, one of many supported interactions is the ability to exchange text messages back and forth along the E2EE channel. The Edge Agent supports Aries Basic Message Protocol (RFC 0095) to accomplish this.
The MessagingModule contains the methods to receive, send and manage these messages. It is accessed via the agent's fields: agent.connections.messaging.
Subscribe to Inbound Messages
As described in the section, subscription to new incoming Basic Messages is supported via the subscribeToAgentEvents API. The subscriber will be invoked once for each new message, and will include the inbound message data, such as the content, the receivedTime and the ID of the Connection who sent it.
class MessageSubscriber : AgentEventSubscriber {
func inboundBasicMessage(basicMessage: BasicMessage.Inbound) {
// the following will be invoked whenever a new basic message is received.
print("new message: \(basicMessage)")
}
func connectionExchangeStateChanged(connectionExchange: ConnectionExchange) {}
func credentialExchangeStateChanged(credentialExchange: CredentialExchange) {}
func proofExchangeStateChanged(proofExchange: ProofExchange) {}
func messageProcessed(messageId: String) {}
}
let customSubscriber = MessageSubscriber()
let subscriberId = agent.subscribeToAgentEvents(subscriber: customSubscriber)
val subscriber = object : AgentEventSubscriber {
override fun inboundBasicMessage(basicMessage: BasicMessage.Inbound) {
// the following will be invoked whenever a new basic message is received.
println("new message: $basicMessage")
}
}
val subscriberId = agent.subscribeToAgentEvents(subscriber)
See for more subscription management details.
Send Messages
To send a basic message to a connection, the sendBasicMessage API can simply be used. On success, the outbound basic message that was sent to the peer will be returned.
let agent: SudoDIEdgeAgent
let connectionId: String // the identifier of the [Connection] to message
do {
let sentMessage = try await agent.connections.messaging.sendBasicMessage(
connectionId: connectionId,
content: "hello world"
)
} catch {
// handle error
}
val agent: SudoDIEdgeAgent
val connectionId: String // the identifier of the [Connection] to message
try {
val sentMessage = agent.connections.messaging.sendBasicMessage(
connectionId = connectionId,
content = "hello world"
)
} catch (e: MessagingModule.SendBasicMessageException) {
// handle error
}
Query Messages
The SDK features one API for listing basic messages in a variety of ways: listBasicMessages. The API is designed to support common peer to peer messaging use cases.
The method takes a ListBasicMessagesOptions object as input as a way to configure pagination, sorting and filtering. It has the following fields within it:
filters - A ListBasicMessagesFilter object with configurations for how results should be filtered
filters.connectionId - if provided, the resulting list of messages will only contain messages from the given connection
filters.limitMessagesPerConnection - if provided, the resulting list of messages will limit the number of messages from a single connection. Useful for "conversation list views": "list recent messages, limited to 1 per connection".
paging - A common Paging object, configuring the limit of items to fetch, and the current cursor position (if any)
sorting - A ListBasicMessagesSorting object specifying how the results should be sorted (pre filtering and paging). Currently chronological sorting (ascending and descending) is supported
The value returned is a PageResult<BasicMessage>, which contains a list of items and a string cursor, nextToken, if there is more items to fetch. This nextToken can be passed into the paging item when performing the next listBasicMessages operation to fetch the next page of items from where the cursor was up to.
List All Recent Messages
let agent: SudoDIEdgeAgent
let pageSize: UInt = 10
do {
let page1 = try await agent.connections.messaging.listBasicMessages(
options: .init(
paging: .init(limit: pageSize)
)
)
let pageItems1 = page1.items
// fetch next page if nextToken is not nil
let page2 = try await agent.connections.messaging.listBasicMessages(
options: .init(
paging: .init(limit: pageSize, nextToken: page1.nextToken)
)
)
let pageItems2 = page2.items
// continue..
} catch {
// handle error
}
val agent: SudoDIEdgeAgent
val pageSize = 10u
try {
val page1 = agent.connections.messaging.listBasicMessages(
options = ListBasicMessagesOptions(
paging = Paging(pageSize)
)
)
val pageItems1 = page1.items
// fetch next page if nextToken is not null
val page2 = agent.connections.messaging.listBasicMessages(
options = ListBasicMessagesOptions(
paging = Paging(pageSize, page1.nextToken)
)
)
val pageItems2 = page2.items
// continue..
} catch (e: MessagingModule.ListBasicMessagesException) {
// handle error
}
List Oldest Messages
let agent: SudoDIEdgeAgent
let pageSize: UInt = 10
do {
let page = try await agent.connections.messaging.listBasicMessages(
options: .init(
paging: .init(limit: pageSize),
sorting: .chronological(direction: .ascending)
)
)
let pageItems = page.items
} catch {
// handle error
}
val agent: SudoDIEdgeAgent
val pageSize = 10u
try {
val page = agent.connections.messaging.listBasicMessages(
options = ListBasicMessagesOptions(
paging = Paging(pageSize),
sorting = ListBasicMessagesSorting.Chronological(SortDirection.ASCENDING)
)
)
val pageItems = page.items
} catch (e: MessagingModule.ListBasicMessagesException) {
// handle error
}
List Recent Messages with a Connection
let agent: SudoDIEdgeAgent
let connectionId: String
let pageSize: UInt = 10
do {
let page = try await agent.connections.messaging.listBasicMessages(
options: .init(
filters: .init(connectionId: connectionId),
paging: .init(limit: pageSize)
)
)
let pageItems = page.items
} catch {
// handle error
}
val agent: SudoDIEdgeAgent
val connectionId: String
val pageSize = 10u
try {
val page = agent.connections.messaging.listBasicMessages(
options = ListBasicMessagesOptions(
filters = ListBasicMessagesFilter(connectionId = connectionId),
paging = Paging(pageSize),
)
)
val pageItems = page.items
} catch (e: MessagingModule.ListBasicMessagesException) {
// handle error
}
List Most Recent Connection Conversations
To support use cases like a "recent conversations" list view, the list API may be used like so:
let agent: SudoDIEdgeAgent
let pageSize: UInt = 10
do {
let page = try await agent.connections.messaging.listBasicMessages(
options: .init(
filters: .init(limitMessagesPerConnection: 1),
paging: .init(limit: pageSize)
)
)
let pageItems = page.items
} catch {
// handle error
}
val agent: SudoDIEdgeAgent
val pageSize = 10u
try {
val page = agent.connections.messaging.listBasicMessages(
options = ListBasicMessagesOptions(
filters = ListBasicMessagesFilter(limitMessagesPerConnection = 1u),
paging = Paging(pageSize),
)
)
val pageItems = page.items
} catch (e: MessagingModule.ListBasicMessagesException) {
// handle error
}
Delete Messages
Delete All Messages with a Connection
All basic messages to/from a connection can be deleted from storage with the deleteBasicMessagesForConnection API.
let agent: SudoDIEdgeAgent
let connectionId: String
do {
try await agent.connections.messaging.deleteBasicMessagesForConnection(
connectionId: connectionId
)
} catch {
// handle error
}
Some Edge Agent SDK consumers may wish to handle Basic Message storage themselves, for instance, to add their own indexes and data schema. Or even to just avoid message storage all together. If that is the case, the SDKs managed storage of Basic Messages can be opt out of with the AgentConfiguration's messagingConfiguration.storeBasicMessages field. By default this is true, setting the configuration field to false will disable storage of Basic Messages.
See Agent Management for details on managing the agent's configuration.
With storage disabled, Basic Messages will still be processed and will still invoke the subscription (see Subscribe to Inbound Messages), but nothing will be put into the agent's database. Meaning the above APIs (list, delete) will have limited functionality.