Skip to content

Broadcast with fastify-websocket #589

@meddario

Description

@meddario

💬 Is this the correct way to broadcast with fastify-websocket?

Hi, I'm trying to broadcast to several clients (implementing a sort of "rooms" mechanism, where i can broadcast a message to the room participants), I stumbled upon this comment fastify/fastify-websocket#42 (comment) where the usage of a "pubsub" was suggested.

I did a few tries and I came up with this (which is a simplified version of what i wanted to do) https://github.com/meddario/fastify-websocket-example.
In particular, the fastify code with the pubsub is here https://github.com/meddario/fastify-websocket-example/blob/main/index.js.

Excerpt:

        let messageListener;

        connection.socket.on("message", (message) => {
          const { meta, room, participant, payload } = JSON.parse(message);
          console.log("received message", { meta, room, participant, payload });

          switch (meta) {
            case "join":
              // Activate a new message listener
              messageListener = (event, done) => {
                if (
                  event.room == room &&
                  (event.broadCast || event.participant == participant)
                ) {
                  connection.socket.send(
                    JSON.stringify({ meta: event.meta, payload: event.payload })
                  );
                }

                done();
              };

              emitter.on("room-event", messageListener);

              connection.socket.send(
                JSON.stringify({
                  meta: "room-joined",
                  room,
                  participant,
                })
              );
              break;

            case "send-message":
              // Use the emitter to broadcast the message to the room participants
              emitter.emit({
                topic: "room-event",
                meta: "send-message",
                room,
                broadCast: true,
                payload,
              });
              break;

            default:
              break;
          }
        });
  • When a client "joins" a room, I set up a messageListener, which will be called when the emitter receives a message.
  • When a client sends a message, an event is emitted on the emitter, the messageListener filters the message to the correct clients.
  • If I need to add for example a post endpoint that sends a message to a specific chat, I just need to use the emitter in the same way as when a message is received.

Example of the last point:

    instance.post("/test-message", (request, reply) => {
      reply.type("application/json").code(200);

      emitter.emit({
        topic: "room-event",
        meta: "send-message",
        room: request.body.room,
        broadCast: true,
        payload: {
          participant: request.body.participant,
          text: request.body.text,
          timestamp: new Date(),
        },
      });

      return { success: true };
    });

Can you please have a look and tell me if this is more or less the pattern you had in mind in that comment? Do you see any downsides or obvious errors in this approach?

Thank you in advance.

Your Environment

  • node version: 17+
  • fastify version: ^3.25.2
  • os: Ubuntu 20.04

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions