Dynamic Channel Subscription/Unsubscription

Hey, I’m looking for some advice on system configuration. I’ve been looking through the docs + the GitHub issues but can’t find exactly what I’m looking for.

My current setup is using websocket-over-http. I subscribe the connection to a user_id channel and a system channel. This allows me to send individual messages, or broadcast to all users. Everything here works fine.

What I would like to do is dynamically create channels, and conditionally subscribe/unsubscribe users. The use case would be game/chat rooms, where users may join and leave of their own accord, or they may need to be kicked. Another could be timed events that are only available for a limited time and then need to be closed.

The main issue is that, outside of the initial handshake request, I am not sure how to send commands to subscribe/unsubscribe a given connection ID to a new channel via http; is it even possible?

The issue here publish to close websockets · Issue #47624 · fastly/pushpin · GitHub sort of alludes to the ability to send a type in a ws-messagepublish command, but I can’t see any examples of it being actually used, and it doesn’t show how you would send that to a specific connection ID; can you send this to a specific channel (user_id) and it will set it for the connection?

This issue discussed some other options: Closing a single connection or Publishing to multiple channels · Issue #47983 · fastly/pushpin · GitHub with the general idea being that you send the same message to each connection that is part of the room. That’s fine for small numbers, but quickly gets messy the more users there are.

Another thing I am unsure of is if channels are automatically deleted once all subscribers leave, or if there is a command to allow you to drop a channel completely?

1 Like

Hi there!

outside of the initial handshake request, I am not sure how to send commands to subscribe/unsubscribe a given connection ID to a new channel via http; is it even possible?

Whenever the client sends a message over the WebSocket connection, the server will have an opportunity to respond with more control messages. So if you have a protocol flow whereby each client indicates their interest/disinterest in things by sending messages, the server can manipulate the subscriptions accordingly.

If you want to change the subscriptions of client connections without requiring action from those clients, this is a bit trickier but still possible. You can publish a refresh action, which will cause Pushpin to make an empty WebSocket-over-HTTP request to the backend for any subscribers. The server will then have an opportunity to respond with control messages.

Note that publishes have best-effort delivery, and this includes refresh actions, so in order to guarantee clients eventually check in with the server you can also set Keep-Alive-Interval.

1 Like

Thanks very much for getting back to me!

Whenever the client sends a message over the WebSocket connection, the server will have an opportunity to respond with more control messages. So if you have a protocol flow whereby each client indicates their interest/disinterest in things by sending messages, the server can manipulate the subscriptions accordingly.

Ah that’s a really clean way of handling it. Usually any change of subscription will be due to a user action anyway. For non-user actions (e.g. being kicked) I suppose I could flag the user account and then check it on the next request they make; if kicked then send the control message.

Just as an aside, as I believe you are one of the original creators, I really love this software. It is such an elegant solution to handling real-time communication, and the inclusion of ZeroMQ is so powerful.

Finally, do you have any updates on this issue: Use Rust-based event loop instead of Qt event loop in proxy/handler · Issue #48139 · fastly/pushpin · GitHub I’ve been using Rust for a lot of projects recently and am keen to see how you’ve implemented an alternative to the Qt event loop, and also any quirks moving between the implementations.

Thank you for the kind words!

The event loop transition was finished as of the latest version (1.41.0). Just haven’t followed up on the GitHub issue. Basically, we built a callback-style event loop on top of our Waker-based reactor, exposed it via an FFI, and then wrapped it with a Qt-like API to make it easier to adapt to.

The main quirks/differences we ran into were notifications being edge-triggered vs. level-triggered, sockets being buffered or not, special treatment of timeouts of zero, and how to manage deferred method calls without a QObject-equivalent.