New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Websockets #218
Websockets #218
Conversation
Signed-off-by: Jakub Koci <jakub.koci@gmail.com>
Signed-off-by: Jakub Koci <jakub.koci@gmail.com>
Signed-off-by: Jakub Koci <jakub.koci@gmail.com>
Signed-off-by: Jakub Koci <jakub.koci@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this Jakub! I think this is a long awaited PR :)
Most comments are thoughts and don't have to be fixed right now. I think a lot those would be resolved when multiple transports are added.
However the usage of socket.io is a blocker for me, and I don't think I can be convinced to approve this before we use a generic WS library.
"@types/socket.io": "^2.1.13", | ||
"@types/socket.io-client": "^1.4.36", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be in devDependencies
@@ -38,6 +39,7 @@ export class Agent { | |||
protected messageReceiver: MessageReceiver; | |||
protected dispatcher: Dispatcher; | |||
protected messageSender: MessageSender; | |||
protected transportService: TransportService; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the transport service
if (connection) { | ||
if (transport) { | ||
this.transportService.saveTransport(connection.id, transport); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (connection) { | |
if (transport) { | |
this.transportService.saveTransport(connection.id, transport); | |
} | |
} | |
if (connection && transport) | |
this.transportService.saveTransport(connection.id, transport); | |
} |
if (transport) { | ||
outboundPackage.transport = transport; | ||
} else { | ||
outboundPackage.transport = new HttpTransport(outboundMessage.endpoint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should look at the scheme of the endpoint instead of creating a hardcoded transport. Ideally the outboundMessage.endpoint
is not set here yet. As we could then dynamically select the transport to use based on available endpoints of the the connection and available transports.
if (transport) { | ||
outboundPackage.transport = transport; | ||
} else { | ||
outboundPackage.transport = new HttpTransport(outboundMessage.endpoint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
@@ -120,4 +131,5 @@ interface MediatorConfiguration { | |||
verkey: Verkey; | |||
invitationUrl: string; | |||
alias?: string; | |||
transport?: Transport; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should save a transport with the mediator. We're moving more towards mediator coordination protocol in which case the flow probably looks something like this:
- Mediator creates invitation
- Mediatee receives invitation, sends request (probably HTTP)
- Mediatior sends response with DIDDoc containing both ws and http endpoint.
- We make a preference to use WS, but could also use HTTP. So it should be more dynamic I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. The transport here is passed mainly to say what transport should be used for this step:
- Mediatee receives invitation, sends request (probably HTTP)
I assumed that it should be possible to do it either via HTTP or WS.
Maybe, we should select the transport channel based on the service endpoint in the invitation? I see that 0. Invitation to Connect defines just one serviceEndpoint but Aries RFC 0434: Out-of-Band Protocol 1.1 shows an example with services as an array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, we should select the transport channel based on the service endpoint in the invitation?
I think for creating the connection with the mediator it should use the one from the invitation, just like we do for any other connection. After that it should use the transport(s) as defined in the received did doc
export interface Transport { | ||
type: TransportType; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be nice to add a canReply
method to this interface
public constructor(socket: Socket) { | ||
this.socket = socket; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the socket (http or ws) will be closed canReply
can be set to false.
Also when we already replied with a message on the http channel we can also set canReply
to false
public async receiveMessage(inboundPackedMessage: unknown) { | ||
return await this.messageReceiver.receiveMessage(inboundPackedMessage); | ||
public async receiveMessage(inboundPackedMessage: unknown, transport?: Transport) { | ||
return await this.messageReceiver.receiveMessage(inboundPackedMessage, transport); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be nice to add transport to the InboundMessageContext
@@ -0,0 +1,41 @@ | |||
import { Socket } from 'socket.io'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've mentioned this before, but AFAIK socket.io uses non-standard communication protocols. This means this won't work with ACA-Py as a mediator.
I have objections to merging this with socket.io instead of a general WS server. If you can make it such that socket.io can communicate with non-socket.io agents that's also fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As @TimoGlastra suggests, Javascript WebSocket works with ACA-py. I have tested this in my own code and works. https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
Thanks @TimoGlastra and @JamesKEbert for the helpful discussion and explanation of the mediation protocol in our last call. I went through the code and specs again and I understand it a little bit more. I still have some questions but also some ideas about the implementation. First of all, I read the Aries RFC 0025: DIDComm Transports and it says:
Do I understand correctly that “This behavior may be modified with additional signaling.” means Aries RFC 0092: Transports Return Route? Regarding the implementation, we should probably solve the problem with I implemented the current solution in a way to achieve some sort of synchronicity to establish a connection with a mediator. I realized that we can achieve the same with the same or similar concept like // Simplified code
const connReq = await this.connectionService.createRequest(connection.id);
await this.messageSender.sendMessage(connReq);
await returnWhenIsConnected(conn) This change will require some changes in If An edge agent connected to a mediator can set Is my understanding correct? :) |
Yep!
Yeah seems about right |
@jakubkoci can this be closed now that we have #256? |
Replaced by #250 |
First working solution with WebSockets. There is definitely still some space for improvement. Take it as minimal mergeable PR :)
Each edge agent communicates with its own mediator via WebSockets. The communication from Alice to Bob goes through Bob's mediator via HTTP. Then bob gets the message from the mediator via WebSockets and vice versa.
I basically copy-pasted
e2e.test.ts
andmediator.ts
files toe2e.ws.test.ts
respectivemediator.ws.ts
. We could have just one mediator, maybe even one e2e test file, after we add multiple inbound transporters which I would like to do as the next step.