SocketCluster / socketcluster

Highly scalable realtime pub/sub and RPC framework
https://socketcluster.io
MIT License
6.15k stars 314 forks source link

Namespace in channels #592

Open alijmlzd opened 1 year ago

alijmlzd commented 1 year ago

I have different apps that all use a shared socketcluster server for PubSub.

I want to separate each app's channel names to prevent conflicts so I can have the same channel names for different apps.

I tried to prefix the channel name with the app ID on the subscribe middleware on the server - something like app1/my-channel, app2/my-channel - but not luck.

I know that I can just subscribe to app1/my-channel channel from the client but in this case, it is not suitable for me and I want to let clients just subscribe to my-channel and the server handle the namespacing based on my client app.

How can I do namespace channels to achieve this or any other solution?

Here is my code that not working:

agServer.setMiddleware(
    agServer.MIDDLEWARE_INBOUND,
    async (middlewareStream) => {
        for await (let action of middlewareStream) {
            if (action.type === action.SUBSCRIBE) {
                    action.channel = `${appId}/${action.channel}`;
                }
            }
            action.allow();
        }
    }
);
jondubois commented 1 year ago

@alijmlzd The best place to add the appId into the channel name is on the front end. You could make a wrapper around the SC socket which prepends the app ID.

Although it should be possible to do what you're trying to do on the back end using middleware, I would strongly recommend against it as it will add a lot of complexity to your app which may be an ongoing struggle in the future. Especially if you plan to scale out to multiple processes/instances at some point in the future. For example, SCC provides automatic channel sharding based on channel names but if you reuse the same channel names across different apps, your channels may not end up spreading out optimally across the cluster.

To answer your question more directly though, what is missing from your code is that while you're mapping the channel name on SUBSCRIBE you will also need to map the channel name on PUBLISH or else they won't match up.

alijmlzd commented 1 year ago

@jondubois Thank you, Yes, I currently prepending the app ID on the front end just like you mentioned, and no problem at all.

But I was curious to know how to do this on the back end for more flexibility. I actually tried to handle the channel name on PUBLISH too, but then I realized that the actual channel name that was attached to the client on the back end was still the name without app ID and not modified although I prepended it on SUBSCRIBE.

Anyway, in my case, I ended up handling the channel name using the app ID that the server provided us in the SC JWT payload, on the client right before [subscription/publish]-related methods.

jondubois commented 1 year ago

@alijmlzd good point, the front end would receive the message but not be able to match it up with the exact channel name due to missing appId.

There is an option you can pass to SC client during instantiation called channelPrefix which you could set as the appId which should solve the last part. But then you would not need to do the channel name transformation in your inbound subscribe middleware because the channelPrefix maps the channel names on both subscribe and publish in the client side. This could be a alternative if you don't want to make your own socket wrapper.

The way you've done it sounds great though.