2

My usecase of socket is not for chats, it's specifically to tell the front-end what BullMQ queue events happened, with a progress bar and telling when a job is done or failed. Currently when I'm emitting events, it's going for all users, I tried to use the socket.to(socket.id).emit({ myEvent: example }) but didn't work at all. I'm storing session on Redis.

Socket

      this.redisClient = new Redis(`${process.env.REDIS_URL}`);
      this.sessionStore = new RedisSessionStore(this.redisClient);
      this.pubClient = this.redisClient;
      this.subClient = this.pubClient.duplicate();

      this.instance.adapter(createAdapter(this.pubClient, this.subClient));
    } catch (err) {
      console.log("Error on Socket Controller: ", err.message);
    }

    this.instance.use(async (socket, next) => {
      const sessionID = socket.handshake.auth.sessionID;
      if (sessionID) {
        const session = await this.sessionStore.findSession(sessionID);
        if (session) {
          socket.sessionID = sessionID;
          socket.userID = session.userID;
          socket.username = session.username;
          return next();
        }
      }
      const username = socket.handshake.auth.username;
      if (!username) {
        return next(new Error("invalid username"));
      }
      socket.sessionID = uuidv4();
      socket.userID = uuidv4();
      socket.username = username;
      console.log(socket.sessionID, socket.userID, socket.username);
      next();
    });

    this.instance.on("connection", async (socket) => {
      // Assign socket to the class
      this.socket = this.socket == null ? socket : this.socket;

      let connectedUsersCount =
        Object.keys(this.instance.sockets.sockets).length + 1;
      let oneUserLeft = connectedUsersCount - 1;

      console.log(`New client connected`, connectedUsersCount);

      try {
        this.sessionStore.saveSession(this.socket.sessionID, {
          userID: this.socket.userID,
          username: this.socket.username,
          connected: true
        });

        // emit session details
        this.socket.emit("session", {
          sessionID: this.socket.sessionID,
          userID: this.socket.userID
        });

        // join the "userID" room
        this.socket.join(this.socket.userID);

        const users = [];
        const sessions = await this.sessionStore.findAllSessions();

        sessions.forEach((session) => {
          users.push({
            userID: session.userID,
            username: session.username,
            connected: session.connected
          });
        });
        this.socket.emit("users", users);

        // notify existing users
        this.socket.broadcast.emit("user connected", {
          userID: this.socket.userID,
          username: this.socket.username,
          connected: true,
          messages: []
        });
        integrationQueueEvents.on("progress", async (job: any) => {
          try {
            console.log("Job Progressing", job);

            const payload = {
              status: true,
              data: job.data,
              jobId: job.jobId,
              to: this.socket.userID
            };

            console.log("integration progress payload: ", payload);
            this.socket.emit("integrationProgress", payload);
          } catch (error) {
            console.log(error);
          }

          // this.socket.to(this.socket.id).emit("integrationProgress", payload);
        });

Session Store

  findSession(id) {
    return this.redisClient
      .hmget(`session:${id}`, "userID", "username", "connected")
      .then(mapSession);
  }

  saveSession(id, { userID, username, connected }) {
    this.redisClient
      .multi()
      .hset(
        `session:${id}`,
        "userID",
        userID,
        "username",
        username,
        "connected",
        connected
      )
      .expire(`session:${id}`, SESSION_TTL)
      .exec();
  }

  async findAllSessions() {
    const keys = new Set();
    let nextIndex = 0;
    do {
      const [nextIndexAsStr, results] = await this.redisClient.scan(
        nextIndex,
        "MATCH",
        "session:*",
        "COUNT",
        "100"
      );
      nextIndex = parseInt(nextIndexAsStr, 10);
      results.forEach((s) => keys.add(s));
    } while (nextIndex !== 0);
    const commands = [];
    keys.forEach((key) => {
      commands.push(["hmget", key, "userID", "username", "connected"]);
    });
    return await this.redisClient
      .multi(commands)
      .exec()
      .then((results) => {
        return results
          .map(([err, session]) => (err ? undefined : mapSession(session)))
          .filter((v) => !!v);
      });
  }

0 Answers0