resgate icon indicating copy to clipboard operation
resgate copied to clipboard

Client connection tracking

Open jirenius opened this issue 4 years ago • 4 comments

Issue

Services want to be able to track which clients are currently connected to any of the Resgates.

Scope

This feature should consider the following:

  1. Resgate events on client connects/disconnects
  2. Handling of Resgate restart or Resgate disconnect from NATS server
  3. Handling of service restart or service disconnect from NATS server

Notes

The tracking of client connections should only be done for WebSocket connections, and not HTTP requests. The short-lived connection created for HTTP requests would only produce unnecessary traffic of limited use.

jirenius avatar Apr 17 '20 07:04 jirenius

Solution suggestion - Connection events

Scope consideration 1

Extending the RES protocol with two new events, published by Resgate:

Connection connect event

Subject
conn.<cid>.connect

Event sent by the gateways whenever a client has disconnected. The event payload has the following parameter:

gid
Gateway ID string that is unique to each gateway.

Example payload

{
  "gid": "resgate-12345"
}

Connection disconnect event

Subject
conn.<cid>.disconnect

Event sent by the gateways whenever a client connection is disconnected. The event payload has the following parameter:

gid
Gateway ID string that is unique to each gateway.

Example payload

{
  "gid": "resgate-12345"
}

Scope consideration 2

Adding two new system events for resgate start and stop, a service could act upon them by assuming all previously established connections for that Resgate instance are to be considered disconnected:

System start event

Subject
system.start

Event sent by the gateways on start up. The event payload has the following parameter:

gid
Gateway ID string that is unique to each gateway.

System stop event

Subject
system.stop

Event sent by the gateways on shutdown. The event payload has the following parameter:

gid
Gateway ID string that is unique to each gateway.

This would not cover the case when a Resgate failed to send the system.stop event on shutdown (due to crash or lost NATS connection), and is never restarted afterwards. This would leave the services unaware of any event.

Scope consideration 3

A system request, listened to by all gateways, would allow a restarted service to get a current list of connected clients from all resgate instances.

System connections (or status?) request

Subject
system.connections

Request listened to by all gateways.
The request has no payload.

Response Each gateway respond with a json object containing its Gateway ID (gid) and a list of current connection IDs (cid), including connection tokens:

{
  "gid": "resgate-12345",
  "connections": {
    "cid-1234": { "token": null },
    "cid-2345": { "token": { "userId": 42, "role": "guest" }}
  }
}

jirenius avatar Apr 17 '20 07:04 jirenius

@jirenius why don't you add the token information on Scope consideration 1? That would make it easier for the application to identify which user is associated with the connection. Otherwise a explicit call to Scope 3 would be needed.

raphaelpereira avatar Apr 21 '20 03:04 raphaelpereira

@raphaelpereira

why don't you add the token information on Scope consideration 1

On connect, the token is always null. Resgate does not store state between reconnects, and has no concept of sessions. It is ResClient's task to rebuild state after a reconnect.

But you don't have to call "Scope3", but instead just listen for the conn.{cid}.token event, which is sent when the new connection gets its token.

On a disconnect/reconnect, this is what takes place:

  1. ResClient is (involuntarily) disconnected
    • Resgate clears all state for that connection and will send a conn.{cid}.disconnect event.
  2. ResClient reconnects to the same, or a different Resgate
    • Resgate will send a conn.{cid}.connect event. No token is available for the new connection.
  3. ResClient sends an auth request from the ResClient.setOnConnect(() => { /... here .../ }) callback. The auth request contains credentials (maybe a jwt or some other refresh token) to reauthenticate. See Resgate.io - Client Session.
  4. The service handling the auth request sets a token for the new connection with a conn.{cid}.token event.
    • Any service keeping track on connections may listen for events sent in 4)
  5. ResClient resubscribes to previously subscribed resources and resynchronizes them locally.
  6. Resgate/ResClient state is restored!

All above is done by ResClient automatically, so that the app doesn't have to bother.

jirenius avatar Apr 23 '20 06:04 jirenius

@jirenius when will this be implemented?

raphaelpereira avatar Oct 04 '20 15:10 raphaelpereira