如何在基于事件的websocket实现中分离客户端?

时间:2019-09-01 16:54:35

标签: javascript node.js websocket ws

我正在基于节点的ws包编写自己的基于事件的websocket包装器,并且在服务器端分离客户端时遇到了麻烦。

我设置了一个测试方案,其中我的客户端向服务器发送一条消息,然后服务器将“ ping”发送回该客户端。

发生的是,我的测试场景与第一个连接的客户端完美协作,但是一旦另一个客户端连接,则从第一个客户端发出的消息将ping到另一个客户端(第二个客户端的消息将正确地ping到第二个客户端)。

感觉WebSocket在两个客户端之间以某种方式共享,但是我似乎找不到发生这种情况的地方。

//SERVER CODE
let events = {};

function WebSockServer(port) {
  //Init server
  const wss = new WebSocket.Server({
    port,
    clientTracking: true
  }, () => {
    if (events['open']) {
      events['open'].callback();
    }
  });

  wss.on('connection', ws => {

    ws.id = uuidv4();
    let sock = new WebSock(ws, wss);

    if (events['connection']) {
      events['connection'].callback(sock);
    }

    ws.on('message', json => {
      console.log('received message from ' + ws.id);
      const message = JSON.parse(json);

      //Check flags
      for (let key in message.flags) {
        if (key === 'binary' && message.flags[key].length > 0) {
          message.flags[key].forEach(binary => {
            const parsed = Buffer.from(message.data[binary], 'utf-16');
            message.data[binary] = parsed;
          });
        }
      }

      //Check if event handler exists & check if event is only to be triggered once
      if (events[message.event] && !events[message.event].once) {
        events[message.event].callback(message.data);
      }
      else if (events[message.event] && events[message.event].once) {
        events[message.event].callback(message.data);
        delete events[message.event];
      }
      else {
        return;
      }
    });

    ws.on('close', () => {
      if (events['close']) {
        console.log('client disconnected');
        events['close'].callback(ws.id);
      }

      wss.clients.delete(ws);
    });
  });

  //Create an event handler
  this.on = function on(event, callback) {
    events[event] = {callback, once: false};
    return this;
  }

  wss.on('error', err => {
    console.log('Server shut down.');
  });
}

function WebSock(ws, wss) {
  this.ws = ws;
  this.id = ws.id;

  //Create an event handler
  this.on = function on(event, callback) {
    events[event] = {callback, once: false};
    return this;
  }

  //Create an event handler for one time use
  this.once = function once(event, callback) {
    events[event] = {callback, once: true};
    return this;
  }

  //Emit message to socket
  this.emit = function emit(event, data) {
    let flags = {
      binary: []
    };

    //Check for binary data
    for (let key in data) {
      if (Buffer.isBuffer(data[key])) {
        const stringified = data[key].toJSON();
        data[key] = stringified;
        flags.binary.push(key);
      }
    }

    const payload = JSON.stringify({event, data, flags});
    this.ws.send(payload);
    return this;
  }

  //Emit message to specific socket
  this.emitTo = function emitTo(id, event, data) {
    let destination;
    let flags = {
      binary: []
    };

    //Find socket
    for (let socket of wss.clients) {
      if (socket.id === id) {
        destination = socket;
        break;
      }
    }

    //Check for binary data
    for (let key in data) {
      if (Buffer.isBuffer(data[key])) {
        const stringified = data[key].toJSON();
        data[key] = stringified;
        flags.binary.push(key);
      }
    }

    //Send message to socket
    if (destination) {
      //Check type
      if (typeof event != 'string' || typeof data != 'object') {
        throw new TypeError('event must be a string, data must be an object');
      }

      const payload = JSON.stringify({event, data, flags});
      destination.send(payload);
      return this;
    }
  }
}

module.exports = WebSockServer;
//CLIENT CODE
function webSock(url) {
  const ws = new WebSocket(url);

  let events = {};

  //Create an event handler
  this.on = function on(event, callback) {
    events[event] = {callback, once: false};
    return this;
  }

  //Create an event handler for one time use
  this.once = function once(event, callback) {
    events[event] = {callback, once: true};
    return this;
  }

  //Emit message to server
  this.emit = function emit(event, data) {
    let flags = {
      binary: []
    };

    //Check for binary data
    for (let key in data) {
      if (Buffer.isBuffer(data[key])) {
        const stringified = data[key].toJSON();
        data[key] = stringified;
        flags.binary.push(key);
      }
    }

    const payload = JSON.stringify({event, data, flags});
    ws.send(payload);
    return this;
  }

  ws.on('open', () => {
    if (events['open']) {
      events['open'].callback(ws);
    }
  });

  ws.on('close', () => {
    if (events['close']) {
      events['close'].callback();
    }
  })

  ws.on('message', json => {
    const message = JSON.parse(json);

    //Check flags
    for (let key in message.flags) {
      if (key === 'binary' && message.flags[key].length > 0) {
        message.flags[key].forEach(buffer => {
          const parsed = Buffer.from(message.data[buffer]);
          message.data[buffer] = parsed;
        });
      }
    }

    //Check if event handler exists & check if event is only to be triggered once
    if (events[message.event] && !events[message.event].once) {
      events[message.event].callback(message.data);
    }
    else if (events[message.event] && events[message.event].once) {
      events[message.event].callback(message.data);
      delete events[message.event];
    }
    else {
      return;
    }
  });
}

module.exports = webSock;

任何帮助将不胜感激,我确定我缺少明显的东西。

0 个答案:

没有答案