MatthewWid / better-sse

⬆ Dead simple, dependency-less, spec-compliant server-sent events implementation for Node, written in TypeScript.
MIT License
444 stars 14 forks source link

create new named channels #66

Closed marekdziem closed 1 month ago

marekdziem commented 1 month ago

I'd like to understand how to create named channels from a unique event identifiers.

so a given channel can be dynamically created and named as the unique event name string = myEventName

how to do this? in examples you have:

const ticker = createChannel(); but how to get something like:

const eval(myEventName) = createChannel()

so I can add new sessions to the named channel based on myEventName in the path?

then broadcast to just those registered to channel myEventName?

thanks!

MatthewWid commented 1 month ago

There is no idiomatic way to do this with the library, but I have seen some users implement a basic pubsub class to achieve this. Something like the following:

import {Session, Channel, createChannel} from "better-sse";

class PubSub {
        private events = new Map<string, Channel>();

        subscribe(session: Session, event: string): void {
                if (!this.events.has(event)) {
                        const newChannel = createChannel();

                        this.events.set(event, newChannel);

                        // Clean up channel if no more subscribers
                        newChannel.on("session-deregistered", () => {
                                if (newChannel.sessionCount === 0) {
                                        this.events.delete(event);
                                }
                        });
                }

                const channel = this.events.get(event) as Channel;

                channel.register(session);
        }

        unsubscribe(session: Session, event: string): void {
                const channel = this.events.get(event);

                if (channel) {
                        channel.deregister(session);
                }
        }

        publish(data: unknown, event: string): void {
                const channel = this.events.get(event);

                if (channel) {
                        channel.broadcast(data, event);
                }
        }
}

export {PubSub};

Essentially we create a map from an event name to a channel, and then when we subscribe a session to a given event name we register it to the corresponding channel, creating the channel if it doesn't exist already.

Channels are very lightweight and cheap to create, so this solution is still quite performant.

An example of using it would be:

const pubsub = new PubSub();

setInterval(() => {
        pubsub.publish("Hello there!", "ping");
}, 1000);

app.get("/sse", async (req, res) => {
        const session = await createSession(req, res);

        pubsub.subscribe(session, "ping");
});
marekdziem commented 1 month ago

wow Many thanksd12 amazing Matthew Wid! :)

MatthewWid commented 1 month ago

No problem 🙂