106 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
 | 
						|
const WebSocket = require("ws");
 | 
						|
const BaseServer = require("./BaseServer");
 | 
						|
 | 
						|
/** @typedef {import("../Server").WebSocketServerConfiguration} WebSocketServerConfiguration */
 | 
						|
/** @typedef {import("../Server").ClientConnection} ClientConnection */
 | 
						|
 | 
						|
module.exports = class WebsocketServer extends BaseServer {
 | 
						|
  static heartbeatInterval = 1000;
 | 
						|
 | 
						|
  /**
 | 
						|
   * @param {import("../Server")} server
 | 
						|
   */
 | 
						|
  constructor(server) {
 | 
						|
    super(server);
 | 
						|
 | 
						|
    /** @type {import("ws").ServerOptions} */
 | 
						|
    const options = {
 | 
						|
      .../** @type {WebSocketServerConfiguration} */
 | 
						|
      (this.server.options.webSocketServer).options,
 | 
						|
      clientTracking: false,
 | 
						|
    };
 | 
						|
    const isNoServerMode =
 | 
						|
      typeof options.port === "undefined" &&
 | 
						|
      typeof options.server === "undefined";
 | 
						|
 | 
						|
    if (isNoServerMode) {
 | 
						|
      options.noServer = true;
 | 
						|
    }
 | 
						|
 | 
						|
    this.implementation = new WebSocket.Server(options);
 | 
						|
 | 
						|
    /** @type {import("http").Server} */
 | 
						|
    (this.server.server).on(
 | 
						|
      "upgrade",
 | 
						|
      /**
 | 
						|
       * @param {import("http").IncomingMessage} req
 | 
						|
       * @param {import("stream").Duplex} sock
 | 
						|
       * @param {Buffer} head
 | 
						|
       */
 | 
						|
      (req, sock, head) => {
 | 
						|
        if (!this.implementation.shouldHandle(req)) {
 | 
						|
          return;
 | 
						|
        }
 | 
						|
 | 
						|
        this.implementation.handleUpgrade(req, sock, head, (connection) => {
 | 
						|
          this.implementation.emit("connection", connection, req);
 | 
						|
        });
 | 
						|
      }
 | 
						|
    );
 | 
						|
 | 
						|
    this.implementation.on(
 | 
						|
      "error",
 | 
						|
      /**
 | 
						|
       * @param {Error} err
 | 
						|
       */
 | 
						|
      (err) => {
 | 
						|
        this.server.logger.error(err.message);
 | 
						|
      }
 | 
						|
    );
 | 
						|
 | 
						|
    const interval = setInterval(() => {
 | 
						|
      this.clients.forEach(
 | 
						|
        /**
 | 
						|
         * @param {ClientConnection} client
 | 
						|
         */
 | 
						|
        (client) => {
 | 
						|
          if (client.isAlive === false) {
 | 
						|
            client.terminate();
 | 
						|
 | 
						|
            return;
 | 
						|
          }
 | 
						|
 | 
						|
          client.isAlive = false;
 | 
						|
          client.ping(() => {});
 | 
						|
        }
 | 
						|
      );
 | 
						|
    }, WebsocketServer.heartbeatInterval);
 | 
						|
 | 
						|
    this.implementation.on(
 | 
						|
      "connection",
 | 
						|
      /**
 | 
						|
       * @param {ClientConnection} client
 | 
						|
       */
 | 
						|
      (client) => {
 | 
						|
        this.clients.push(client);
 | 
						|
 | 
						|
        client.isAlive = true;
 | 
						|
 | 
						|
        client.on("pong", () => {
 | 
						|
          client.isAlive = true;
 | 
						|
        });
 | 
						|
 | 
						|
        client.on("close", () => {
 | 
						|
          this.clients.splice(this.clients.indexOf(client), 1);
 | 
						|
        });
 | 
						|
      }
 | 
						|
    );
 | 
						|
 | 
						|
    this.implementation.on("close", () => {
 | 
						|
      clearInterval(interval);
 | 
						|
    });
 | 
						|
  }
 | 
						|
};
 |