nodejs / help

:sparkles: Need help with Node.js? File an Issue here. :rocket:
1.45k stars 278 forks source link

static variable(array) in class resets value to emty array on macOS and linux (Ubuntu) #4208

Closed xoji closed 2 months ago

xoji commented 1 year ago

I have web sockets in my project. when connecting a client, I generate an id for uniqueness and save it in a static class variable, but when I use the getClient method, it returns an empty array. This is exactly what happens on the Mac. I tested it on two different macs. But in Windows it works fine. my code:

export class WSServer {
  private static _wsClients: WSClients[] = [];
  private static _messageSubscribe = new Subject<WebsocketMessage>();

  static messageSubscribe(
    callback: (value: WebsocketMessage) => void
  ): Subscription {
    return this._messageSubscribe.subscribe({
      next: callback,
      error: (e) => {
        console.log(e);
      },
    });
  }

  static getClient(id: string | number) {
    return this._wsClients.find((client) => {
      if (client.id === id) {
        return client;
      }
    });
  }

  static init(server: Websocket.Server<Websocket.WebSocket>): void {
    server.addListener("connection", async (client, request) => {
      const routeDetails = routeSort(request.url);

      if (!routeDetails.valid) {
        client.close();
        return;
      }
      const secureResult = socketSecurity(routeDetails.param);
      if (!secureResult.valid) {
        client.close();
        return;
      }
      let session: Sessions | null;
      if (secureResult.hasSession) {
        session = await Sessions.findOne({
          where: { sessionId: secureResult.data?.session_id },
        });
        if (!session) {
          client.close();
          return;
        }
        await session.update({ online: true, last_sign: new Date().getTime() });
      } else {
        session = await Sessions.create({
          platform: secureResult.data?.session!.platform!,
          brand: secureResult.data!.session!.brand!,
          web: secureResult.data!.session!.web!,
          mobile: secureResult.data!.session!.mobile!,
          last_sign: new Date().getTime(),
          online: true,
        });
      }
      this._wsClients.push({
        id: session.socket_id,
        ws: client,
        session_id: session.sessionId,
      });
      const options = new LocalOptions();
      client.send(
        JSON.stringify({
          type: "connection",
          data: {
            session_id: session.sessionId,
            socket_id: session.socket_id,
            prod_mode: options.prodMode,
          },
        })
      );
      client.on("close", () => {
        this._wsClients = this._wsClients.filter((val) => {
          return val.id != session?.socket_id;
        });
        session?.update({ online: false, last_sign: new Date().getTime() });
      });
      client.on("error", () => {
        this._wsClients = this._wsClients.filter((val) => {
          return val.id != session?.socket_id;
        });
        session?.update({ online: false, last_sign: new Date().getTime() });
      });
      client.on("message", (value) => {
        try {
          this._messageSubscribe.next(JSON.parse(value.toString()));
        } catch (e) {
          console.log(e);
        }
      });
      console.log("client connected!");
    });
    LocalOptions.subscribe("prodMode", (val) => {
      for (const c of this._wsClients) {
        const data: any = {
          type: "changedProdMode",
          data: {
            prod: val,
          },
        };
        c.ws.send(JSON.stringify(data));
      }
    });
  }

  static send<T = WebsocketMessage>(clientId: number | string, message: T) {
    const client = this._wsClients.find((item) => {
      return item.id == clientId;
    });
    if (client) {
      client.ws.send(JSON.stringify(message));
    }
  }
}

I tried to create a variable outside the class and record the clients there but the result is the same. Launched and tested in windows everything works fine but the same code and the same libraries but does not work on macOS. I tried on a poppy with an intel processor and with an apple processor. The result is the same.

prettydiff commented 1 year ago

Could you edit your post so that your code is wrapped in a code block:

```javascript my code here ```

Also, I do not use classes so I cannot help you navigate any problems with OOP code decoration. Here is how I have solved for this in TypeScript with just functions and an object for storing sockets:

My websocket implementation is at:

My TypeScript definition for the websocket code is at:

I define a websocket as (my personal implementation):

preveen-stack commented 12 months ago

cc @nodejs/platform-macos

xoji commented 12 months ago

I noticed that the problem is due to cluster. when I save a client using cluster, the reference to the client object is lost. Even native (created websocket server) shows number of clients 0

github-actions[bot] commented 3 months ago

It seems there has been no activity on this issue for a while, and it is being closed in 30 days. If you believe this issue should remain open, please leave a comment. If you need further assistance or have questions, you can also search for similar issues on Stack Overflow. Make sure to look at the README file for the most updated links.

github-actions[bot] commented 2 months ago

It seems there has been no activity on this issue for a while, and it is being closed. If you believe this issue should remain open, please leave a comment. If you need further assistance or have questions, you can also search for similar issues on Stack Overflow. Make sure to look at the README file for the most updated links.