Mediation
This section assumes that you have:
- Set up a valid environment for development
- Basic knowledge of the required fields in the agent config
The agent setup varies depending on your target environment, React Native or Node.js.
This tutorial assumes a Node.js environment for all agents (Alice, Bob, Meditator).
This tutorial shows how to set up a mediator, how to configure an agent to use a mediator, and how agents exchange messages with a mediator in place. Concepts are explained in isolation:
- First, it is shown how to set up a mediator.
- Second, it is demonstrated how to use a mediator.
- Third, the message exchange between agents with a mediator in place is explained.
What is a mediator, and Why should I use one?
A mediator is just a special type of agent.
"When we describe agent-to-agent communication, it is convenient to think of an interaction only in terms of Alice and Bob and their agents. We say things like: "Alice's agent sends a message to Bob's agent" -- or perhaps "Alice's edge agent sends a message to Bob's cloud agent, which forwards it to Bob's edge agent".
Such statements adopt a useful level of abstraction--one that's highly recommended for most discussions. However, they make a number of simplifications. By modeling the roles of mediators and relays in routing, we can support routes that use multiple transports, routes that are not fully known (or knowable) to the sender, routes that pass through mix networks, and other advanced and powerful concepts."Aries RFC 0046: Mediators and Relays
A practical example where the use of mediators is beneficial can be found in a mobile environment. A mobile agent, aka. your mobile wallet, receives messages from other agents. Technically, sending HTTP messages to a mobile agent is impossible because the agent does not have a public IP. As you have probably seen in previous examples, a workaround for this scenario is to use ngrok. Another option is to use a mediator. When an agent is configured to use a mediator, messages to that agent are routed through the mediator and from there to its destination. Thus, a mobile agent can use a "public" mediator to receive messages on its behalf and poll them from time to time.
This is just one example of how a mediator can be used. Further resources about mediators can be found here.
With mediators, WebSockets come in handy. In a production environment, it is recommendable to register a WsInboundTransport()
for Alice and a WsOutboundTransport()
for the mediator. These WebSocket transports allow the mediator to push messages to Alice instead of having Alice pull messages from the mediator repeatedly.
1. Mediator setup
The first part shows how to set up a mediator agent. Generally, there are two ways to do that: deploying it from scratch or using a third-party mediator. This section focuses on the former approach, setting up the mediator from scratch.
The mediator is set up on port 3001 and creates an Out-of-Band invitation that allows multiple other agents to connect to the mediator. Configuring an agent as a mediator demands utilizing the MediatorModule
. In this example, the autoAcceptMediationRequests
flag is set to true to accept mediation requests automatically.
const name = 'mediator'
const port = 3001
const agentConfig: InitConfig = {
label: `Aries Framework JavaScript ${name}`,
walletConfig: {
id: name,
key: name,
},
endpoints: [`http://localhost:${port}`],
}
const mediator = new Agent({
config: agentConfig,
dependencies: agentDependencies,
modules: {
indySdk: new IndySdkModule({ indySdk }),
mediator: new MediatorModule({
autoAcceptMediationRequests: true,
}),
connections: new ConnectionsModule({
autoAcceptConnections: true,
}),
},
})
mediator.registerOutboundTransport(new HttpOutboundTransport())
mediator.registerInboundTransport(new HttpInboundTransport({ port }))
await mediator.initialize()
const mediatorOutOfBandRecord = await mediator.oob.createInvitation({ multiUseInvitation: true })
const mediatiorInvitationUrl = mediatorOutOfBandRecord.outOfBandInvitation.toUrl({
domain: `http://localhost:${port}`,
})
console.log(mediatiorInvitationUrl)
2. Recipient (Alice) setup
The second part shows how to use a mediator. Becoming a recipient of a mediator requires using the MediationRecipientModule
. The setup is the same whether you use your own or a third-party mediator.
The easiest way to set everything up is by configuring the MediationRecipientModule
to connect to the mediator on agent startup. This can be done by constructing the module with the mediatorInvitationUrl
. You can get the mediatorInvitationUrl either from part one by running a mediator yourself or from a public mediator such as the Animo-mediator. The following snippet uses the latter approach.
The ConnectionsModule
used in this snippet serves the sole purpose of automatically accepting connections and thus simplifying setup.
const name = 'alice'
// paste your invitation url here
// or use the current invitation-url to connect to the public animo-mediator.
const mediatorInvitationUrl =
'https://mediator.dev.animo.id/invite?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4xL2ludml0YXRpb24iLCJAaWQiOiIyMDc1MDM4YS05ZGU3LTRiODItYWUxYi1jNzBmNDg4MjYzYTciLCJsYWJlbCI6IkFuaW1vIE1lZGlhdG9yIiwiYWNjZXB0IjpbImRpZGNvbW0vYWlwMSIsImRpZGNvbW0vYWlwMjtlbnY9cmZjMTkiXSwiaGFuZHNoYWtlX3Byb3RvY29scyI6WyJodHRwczovL2RpZGNvbW0ub3JnL2RpZGV4Y2hhbmdlLzEuMCIsImh0dHBzOi8vZGlkY29tbS5vcmcvY29ubmVjdGlvbnMvMS4wIl0sInNlcnZpY2VzIjpbeyJpZCI6IiNpbmxpbmUtMCIsInNlcnZpY2VFbmRwb2ludCI6Imh0dHBzOi8vbWVkaWF0b3IuZGV2LmFuaW1vLmlkIiwidHlwZSI6ImRpZC1jb21tdW5pY2F0aW9uIiwicmVjaXBpZW50S2V5cyI6WyJkaWQ6a2V5Ono2TWtvSG9RTUphdU5VUE5OV1pQcEw3RGs1SzNtQ0NDMlBpNDJGY3FwR25iampMcSJdLCJyb3V0aW5nS2V5cyI6W119LHsiaWQiOiIjaW5saW5lLTEiLCJzZXJ2aWNlRW5kcG9pbnQiOiJ3c3M6Ly9tZWRpYXRvci5kZXYuYW5pbW8uaWQiLCJ0eXBlIjoiZGlkLWNvbW11bmljYXRpb24iLCJyZWNpcGllbnRLZXlzIjpbImRpZDprZXk6ejZNa29Ib1FNSmF1TlVQTk5XWlBwTDdEazVLM21DQ0MyUGk0MkZjcXBHbmJqakxxIl0sInJvdXRpbmdLZXlzIjpbXX1dfQ'
const agentConfig: InitConfig = {
label: `Aries Framework JavaScript ${name}`,
walletConfig: {
id: name,
key: name,
},
logger: new ConsoleLogger(LogLevel.trace),
}
const alice = new Agent({
config: agentConfig,
dependencies: agentDependencies,
modules: {
mediationRecipient: new MediationRecipientModule({
mediatorInvitationUrl,
}),
indySdk: new IndySdkModule({ indySdk }),
},
})
alice.registerOutboundTransport(new HttpOutboundTransport())
alice.registerOutboundTransport(new WsOutboundTransport())
await alice.initialize()
In case you are using a third-party mediator and cannot create an invitationUrl, it is common practice for mediators to provide an endpoint from which the invitationUrl can be fetched.
3. Message exchange
This section explains the message exchange between agents when a mediator is in place. The process is illustrated using the diagram below. Parts one and two of this tutorial showed how to set up and use a mediator. If the mediatorInvitationUrl
is specified when constructing the MediationRecipientModule
(as in Part two), the mediation request and grant (1-2) between Alice and the mediator will be performed automatically when Alice's agent is started.
If Alice establishes a connection with another fictional agent, say, Bob's agent, who is not using any mediators (3-6). (Connection establishment is no different when a mediator is involved). Then, messages from Alice to Bob (7) are routed directly to Bob, while messages from Bob to Alice (8-9) are routed through the intermediary.
Useful resources
For more information about mediator refer to: