Skip to content
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

feat: Add support for WebSocket transports #256

Merged
merged 13 commits into from
May 12, 2021
Merged

feat: Add support for WebSocket transports #256

merged 13 commits into from
May 12, 2021

Conversation

jakubkoci
Copy link
Contributor

@jakubkoci jakubkoci commented May 2, 2021

This is how it works now:

  • A mediator takes endpoint for invitation or DidDoc from config.
  • An edge agent takes endpoint for invitation or DidDoc from inboundConnection if it has any.
  • The edge agent gets out of band invitation via http request to mediator (http://mediator1.com/invitation). The invitation contains ws endpoint because we want to make a connection via WebSocket.
  • The edge agent takes an endpoint for outbound communication from invitation or DidDoc. For a connection with another edge agent, it takes an endpoint from indbound connection. Therefore it’s the same ws endpoint as it is contained in the mediator invitation.

To integrate ws and http servers together and support multiple transports we would need to enable following:

  • A mediator sends a different endpoint for mediation to edge agent.
  • The edge agent sets the mediation endpoint somewhere else and do not take it from inbound connection invitation or DidDoc.

Other notes:

  • I set ws endpoint directly in mediator server by editing config.endpoint to value ws://localhost:${PORT}
  • I skip the ws tests. To run them it's needed to change the mediator server to mediator-ws.ts (or integrate ws and HTTP together as I mentioned)

Related to #250

@codecov-commenter
Copy link

codecov-commenter commented May 2, 2021

Codecov Report

Merging #256 (e9a983f) into main (33c85ba) will increase coverage by 0.15%.
The diff coverage is 98.63%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #256      +/-   ##
==========================================
+ Coverage   89.47%   89.62%   +0.15%     
==========================================
  Files         195      196       +1     
  Lines        3581     3645      +64     
  Branches      393      403      +10     
==========================================
+ Hits         3204     3267      +63     
- Misses        377      378       +1     
Impacted Files Coverage Δ
...modules/connections/repository/ConnectionRecord.ts 96.22% <ø> (-0.14%) ⬇️
src/types.ts 100.00% <ø> (ø)
src/agent/MessageReceiver.ts 86.20% <80.00%> (-0.84%) ⬇️
src/agent/Agent.ts 98.57% <100.00%> (+0.04%) ⬆️
src/agent/AgentConfig.ts 95.34% <100.00%> (+0.11%) ⬆️
src/agent/Dispatcher.ts 96.96% <100.00%> (+0.19%) ⬆️
src/agent/MessageSender.ts 95.00% <100.00%> (+2.14%) ⬆️
src/agent/TransportService.ts 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 33c85ba...e9a983f. Read the comment docs.

samples/mediator-ws.ts Outdated Show resolved Hide resolved
@@ -0,0 +1,140 @@
import express from 'express'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we could get away with a bit less duplication in the http/ws mediator files

@@ -159,8 +162,8 @@ export class Agent {
return this.agentConfig.mediatorUrl
}

public async receiveMessage(inboundPackedMessage: unknown) {
return await this.messageReceiver.receiveMessage(inboundPackedMessage)
public async receiveMessage(inboundPackedMessage: unknown, transport?: Transport) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather create a single InboundMessage or InboundSession that contains both the packed message, the transport and any other context that may arise in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about creating the InboundMessageContext here and then enhanced it with other attributes inside MessageReciever?

I would rather not introduce yet another type because we already have perhaps too much (XxxMessage, XxxMessageContext, XxxPackage, ...) Then we could do the same for the outbound messages as OutboundMessageContext.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah we already have InboundMessageContext of course. Yes that sounds perfect!

Copy link
Contributor Author

@jakubkoci jakubkoci May 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like a much larger change than I anticipated. I suggest doing it in separate PR.

We would need to add wireMessage into InboundMessageContext and make message optional but then validate everywhere that it's present. Or we can figure out a different solution.

src/agent/EnvelopeService.ts Outdated Show resolved Hide resolved
src/agent/TransportService.ts Outdated Show resolved Hide resolved
src/agent/TransportService.ts Outdated Show resolved Hide resolved
src/agent/TransportService.ts Outdated Show resolved Hide resolved

private findEndpoint(connection: ConnectionRecord) {
if (connection.theirDidDoc) {
const endpoint = connection.theirDidDoc.service[0].serviceEndpoint
Copy link
Contributor

@TimoGlastra TimoGlastra May 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

didCommServices returns only the didcomm services (diddoc may include other service types) and also automatically orders the transports by priority.

We should probably also update this method to pass in supported outbound transport /schemes so we don't return the first transport scheme that may be my_custom_scheme:// while the second service is http:// which we do support

Suggested change
const endpoint = connection.theirDidDoc.service[0].serviceEndpoint
const endpoint = connection.theirDidDoc.didCommServices[0].serviceEndpoint

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this could potentially throw an error if there are no service endpoints. Dunno if we want to check that here

this.transportTable[connectionId] = transport
}

public resolveTransport(connection: ConnectionRecord): Transport {
Copy link
Contributor

@TimoGlastra TimoGlastra May 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice if we can make this more dynamic. this implementation requires to support the transport in core. Ideally adding an outbound/inbound transport class is enough

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. I think we would need to move this logic to outbound transporters and just provide some utility functions to get the endpoint from DidDoc instead of having it in the core. That would also solve your other suggestions like "update this method to pass in supported outbound transport /schemes".

src/agent/TransportService.ts Outdated Show resolved Hide resolved
@TimoGlastra TimoGlastra mentioned this pull request May 7, 2021
@TimoGlastra TimoGlastra linked an issue May 7, 2021 that may be closed by this pull request
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>
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>
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>
@jakubkoci jakubkoci marked this pull request as ready for review May 11, 2021 14:36
@jakubkoci jakubkoci requested a review from a team as a code owner May 11, 2021 14:36
Signed-off-by: Jakub Koci <jakub.koci@gmail.com>
@jakubkoci
Copy link
Contributor Author

@TimoGlastra Updated the PR according to your suggestions.

I think we can update and refactor the transport resolve mechanism when we add multi-transport. It will be more obvious how to structure the code then.

@jakubkoci
Copy link
Contributor Author

I added another two mediators to test WebSocket transports. So now, we run tests for both HTTP and websocket.

Copy link
Contributor

@TimoGlastra TimoGlastra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

This introduces some technical debt with how transports are managed that we can hopefully fix in the near future, but I think it is good to get this merged now.

@jakubkoci jakubkoci merged commit 07b479f into openwallet-foundation:main May 12, 2021
@TimoGlastra
Copy link
Contributor

The release pipeline is failing. I'll take a look at it today

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add transport into message context
3 participants