-
Notifications
You must be signed in to change notification settings - Fork 176
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
[Access] Draft design of new WebSockets #6508
Comments
Looks great @Guitarheroua. A few comments:
|
@peterargue What is described here is the Web Application Messaging Protocol, or simply WAMP Protocol, which has a few implementations in Go. The most popular one is NEXUS, which implements the WAMP protocol and includes the features we need. It's also actively maintained, with a new version released this year. While it seems like a good fit for our requirements, we should first discuss the pros and cons of using it. My main concern is the subscription model on the client side. To me, it adds an extra layer of complexity, and clients might not be happy with that. |
We agreed that the Nexus library offers many useful features, but it also includes a lot of unnecessary functionality that we won't use. Additionally, the WAMP protocol implemented by this library adds an extra layer of complexity, particularly on the client side, making it more challenging to handle. |
Thanks for the updates. I think we can consolidate the endpoints a bit. With grpc, we get some input validation for free. Since we don't get that with websockets, I think it makes sense to group the endpoints and add explicit argument checks, similar to the rest endpoints. e.g.
each have optional args For What does the Endpoint to What will the endpoint logic look like? Will it be similar to the existing events endpoint where it simply passes the backend subscription object to the |
I don't think we'll want this on all topics, so I don't think it's worth the complexity of adding it for only a subset. It's not harmful to have duplicate streams, and may limit some usecases. Best to use a combination of max subscriptions per connection, max responses per second, and send timeouts.
I think a client should only need the subscription ID to unsubscribe |
Looks good @Guitarheroua. |
User Story: WebSocket Subscription Management
Connection Establishment:
The client establishes a single WebSocket connection with the Access Node (AN), e.g., via
ws://localhost:8080/ws
. This connection is maintained until closed by either the AN or the client.Subscription Mechanism:
The client sends a subscription request through the WebSocket to subscribe to topics. The AN responds with either success or failure. Upon success, a unique subscription ID is generated:
The client can subscribe to multiple topics through the same connection, managing the messages received accordingly.
If needed, the client can pass initial parameters via the
arguments
field:Updates from the AN are received as follows:
Unsubscription:
To unsubscribe the client sends the following message:
List Active Subscriptions:
The client can request the list of active subscriptions:
Closing the Connection:
The client can close the connection manually, or the AN may do so. When the connection closes, all subscriptions are lost.
Access Node Implementation Requirements
WebSocketBroker Requirements
The
WebSocketBroker
is similar to the existingWebSocketController
but includes several key improvements:Connection Management:
The broker should establish the WebSocket connection during construction but avoid subscribing to topics immediately. It will handle ping/pong messages for connection tracking and error management.
Messages Responce
The response messages for the client should have the following format:
The
list_subscriptions
action`s response will be different and should have the following format:Message Handling: The broker listens for incoming client messages and processes actions like
subscribe
,unsubscribe
, andlist_subscriptions
. Supported topics include:Handler Creation:
For each new subscription, the broker creates a
SubscriptionHandler
specific to the topic. The handler formats and sends the appropriate response to the client, using the correct topic and data.Unsubscription:
The broker should allow unsubscribing by subscription ID.
List Subscriptions:
The broker should return a list of all active subscriptions for the client upon request.
Limitations
The broker should implement limits on the maximum number of subscriptions per connection, the maximum number of responses per second, and the send timeout.
Connection Handling:
The broker should manage connectivity by handling ping/pong messages and unsubscriptions. If the client fails to respond to ping/pong messages, the broker should gracefully close the connection and clean up all associated subscriptions.
A visual representation of the new REST subscription process:
New Pub/Sub API Description
1. The
router.go
A new
AddWsPubSubRoute
function will configure the route for the new subscription mechanism, using a distinct address such asv1/ws
, separate from the currentv1/subscribe_events
route. There will be one main route and one handler for the pub/sub mechanism. Different topics (akin to REST routes) will be handled by theWebSocketBroker
, which reacts to messages from the client.2. The
WebSocketBroker
The
WebSocketBroker
manages subscriptions within a single connection between the client and the node.The
conn
field represents the WebSocket connection for bidirectional communication with the client. It handles incoming messages from the client and broadcasts messages back to the client based on subscribed topics. Additionally, it manages ping/pong messages, error handling, and connectivity issues.The methods associated with the
conn
field include:readMessages
:This method runs while the connection is active. It retrieves, validates, and processes client messages. Actions handled include
subscribe
,unsubscribe
, andlist_subscriptions
. Additional actions can be added as needed.writeMessages
:This method runs while the connection is active, listening on the
broadcast
channel. It retrieves responses and sends them to the client.broadcastMessage
:This method will be called by each
SubscriptionHandler
, who will receive formatted subscription messages and write them to thebroadcast
channel.pingPongHandler
:This method periodically checks connection availability using ping/pong messages and will terminate the connection if the client becomes unresponsive.
The methods associated with the
subs
field include:subscribe
:Triggered by the
readMessages
method when theaction
issubscribe
. It takes the topic from the message’stopic
field, creates the appropriateSubscriptionHandler
for the topic using a factory functionCreateSubscription
, and adds an instance of the new handler to thesubs
map. The client receives a notification confirming the successful subscription along with the specific ID.unsubscribe
:It is triggered by the
readMessages
method when theaction
isunsubscribe
. It removes the relevant handler from thesubs
map by callingSubscriptionHandler::CloseSubscription
and notifying the client of successful unsubscription.listSubscriptions
:It is triggered by the
readMessages
method when theaction
islist_subscriptions
. It gathers all active subscriptions for the current connection, formats the response, and sends it back to the client.3. The
SubscriptionHandler
The
SubscriptionHandler
interface abstracts the actual subscriptions used by theWebSocketBroker
. ConcreteSubscriptionHandler
implementations will be created during theWebSocketBroker::subscribe
call, depending on thetopic
provided by the client. For example, the topicevents
will have anEventsSubscriptionHandler
implementation managing event subscriptions.New[Concrete]SubscriptionHandler
:Each constructor function takes a
topic
, thearguments
from the client’s message, and thebroadcastMessage
callback function. It stores these values and creates the correspondingsubscription.Subscription
on the backend. Each subscription is unique, identified by an ID fromsubscription.Subscription
and linked to an individual instance ofSubscriptionHandler
. This ensures the client can subscribe to the same topic multiple times with different parameters.messagesHandler
:Each handler includes a method that processes messages received from the backend and formats them for the client. This formatted message is passed to the Broker for further processing by calling the
broadcastMessage
callback.Close
:The method gracefully shuts down the subscription when called.
ID
:The method should return the
subscription.Subscription
ID.Topic
:The method should return the subscription topic.
CreateSubscription
:A free factory function, part of the
SubscriptionHandler
module that creates concreteSubscriptionHandler
based on thetopic
from theWebSocketBroker
and returns a new instance ofSubscriptionHandler
.WebSocketBroker and SubscriptionHandler Relationship
Receiving a Subscription Request:
subscribe
action and the topic to subscribe to.WebSocketBroker
processes this message inside thereadMessages()
method. It parses the message, and extracts thetopic
andarguments
. Then thesubscribe()
method is called.subscribe()
method, based on the topic from the subscription request, theWebSocketBroker
callsCreateSubscription
to instantiate the appropriateSubscriptionHandler
for the topic.CreateSubscription
function is a factory method responsible for returning the correctSubscriptionHandler
(e.g.,EventsSubscriptionHandler
,BlocksSubscriptionHandler
, etc.).SubscriptionHandler
is stored in thesubs
map of theWebSocketBroker
using the topic and a generated subscription ID.broadcastMessage
.Handling Subscription Data:
SubscriptionHandler
listens for updates from the backend relevant to its topic.SubscriptionHandler
calls thebroadcastMessage(data)
callback function provided by theWebSocketBroker
.broadcastMessage
method then sends this data to thebroadcast
channel, which the broker monitors.Broadcasting Data to the Client:
WebSocketBroker
listens on thebroadcast
channel using thewriteMessages()
method.writeMessages()
retrieves it from the channel and sends it to the client over the WebSocket connection.The text was updated successfully, but these errors were encountered: