[Django]-Private messaging using sockjs-tornado

3👍

My answer makes the assumption that all clients in the current solution connect to a SockJS server with a channel name that is used for broadcasts of the chat messages (or something close to this scenario). I further assume that the round-trip when a user sends a message from the client is:

[Sender (Client)] ------- Message (POST) --> [App Server] --- Message --> [Database]
                                                  |
                                               Message
                                                  v
[Receiver(s) (Client)] <-- Message (WS) -- [SockJS Server]

There are multiple solutions to this problem. I will only outline the one I think is simplest and most robust here:

  • Let every user subscribe to a per-user (private) channel in addition to the broadcast-channel in the chat. If you implement this solution, the only additional change is to make the app server aware of private messages which must be sendt only to the receiver’s private channel.

Another, slightly more complex, and inelegant solution would be to create ad hoc channels for each private pair when needed. However, how would you get User B to subscribe to the (newly created) private channel when User A wants to chat with User B? One way would be to broadcast a request for User B to connect to that channel, but that would tell all the other clients (at the code level) about this private chat that will take place; and if any of those clients are compromised, that information can be misused for, for example, eavesdropping or crashing the private party.

Additional Advice

I would also like to mention that since I wrote my sockjs – example of implementing rooms answer, I have changed my own architecture to (still) use SockJS in the front-end, but with RabbitMQ using the Web-STOMP plugin on the back-end. That way,

  1. the client still uses sockjs-client with stomp-websocket in the browser,
  2. all of the back-end code to handle front-end multiplexing could be removed,
  3. the (RabbitMQ-based) back-end is fast and really robust,
  4. the client POSTs a message to the back-end app server, which in turn
    1. persists the message in the database, and
    2. acts as a client of the RabbitMQ server and either (1) broadcasts the message to all connected users, or if the message is private (2) sends the message to a single recipient over the recipient’s own private channel, as sketched out in the above suggested solution.

The whole new solution is placed behind HAProxy which terminates HTTPS and SSL/TLS-encrypted WebSocket connections.

1👍

Although sockjs-tornado does not implement such a thing like channels, nor rooms, there is example multiplex how one could implement that. Also look at sockjs – example of implementing rooms. Solution is based on structured msg – within message you additional info is sent – channel name.

Leave a comment