express/typescript: 在服务器端,如何创建一个全局变量来存储多个套接字?

express/typescript: on the server side, how to create a global variable to store multiple sockets?

我在网页后端使用 Express + Typescript。

我已经用 socket.io:

定义了网络套接字

/src/index.ts:

const initializeExpress = (): void => {
  const app = express();

  let http = require("http").Server(app);
  let io = require("socket.io")(http, {
    cors: {}
  });
  
  const socket_ids = {};
  
  io.on("connection", function(socket: any) {
    console.log("a user connected. socket.id: ", socket.id, "socket.username: ", socket.username);    
    socket_ids[socket.username] = socket.id;
  });

  const server = http.listen(3001, function() {
    console.log("listening on *:3001");
  });


  // register middleware
  io.use((socket, next) => {
    socket.username = socket.handshake.auth.username;
    socket.organization = socket.handshake.auth.organization;
    next();
  });

  // sends each client something constantly
  setInterval(() => {
    for (const u in socket_ids){
      const my_socket = io.sockets.sockets.get(socket_ids[u]);
      my_socket.emit("knock", "knock-knock");
    }
  }, 10000);

  app.use(cors());
  app.use(express.json());
  app.use(express.urlencoded({ extended: true }));
  app.use(bodyParser.urlencoded({ extended: true }));
  app.use(bodyParser.json());
  app.use(express.static(path.join(__dirname, 'build')));
  
  app.use(addRespondToResponse);

  attachPublicRoutes(app);
};

initializeExpress();

当后端启动时,我可以确认套接字正在工作,因为我可以接收到我的代码发送到每个客户端套接字的 knock-knock 消息。

现在,在许多其他文件中,我需要根据业务逻辑在不同位置对特定客户端执行 socket.emit()。所以我需要做 my_socket = io.sockets.sockets.get(socket_ids[u]).

如何全局维护socket_ids对象和io对象/全局访问它?

您可以实现在 class 中定义的全局状态管理器(它基本上只是一个具有 get 和 set 方法的简单 javascript 对象),它可以从任何脚本导入和访问。然后将这些变量附加到该状态。

这是一个非常简单但可行的版本:

export class StateManager {

  static addToState = (key, value) => {
    if (!StateManager._singleton) {
      StateManager._singleton = new StateManager();
    }
    StateManager._singleton.addToState(key, value);
  };

  static readFromState = (key: string) => {
    if (!StateManager._singleton) {
      StateManager._singleton = new StateManager();
    }
    return StateManager._singleton.readFromState(key);
  };

  private static _singleton: StateManager;
  private _state: Record<string, any>;

  private constructor() {
    this._state = {};
  }

  private addToState = (key, value) => (this._state[key] = value);

  private readFromState = (key) => this._state[key];
}

为了便于使用,您可以将其添加到您的代码中:

import { StateManager } from './state';

// your code where socket_id and io are set

StateManager.addToState('socket_ids', socket_id);
StateManager.addToState('io', io);

// your code where you want to retrieve the values:

const socket_ids = StateManager.readFromState('socket_ids');

参见 Stackblitz 上的工作示例。