WebsocketServer.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. "use strict";
  2. const WebSocket = require("ws");
  3. const BaseServer = require("./BaseServer");
  4. /** @typedef {import("../Server").WebSocketServerConfiguration} WebSocketServerConfiguration */
  5. /** @typedef {import("../Server").ClientConnection} ClientConnection */
  6. module.exports = class WebsocketServer extends BaseServer {
  7. static heartbeatInterval = 1000;
  8. /**
  9. * @param {import("../Server")} server
  10. */
  11. constructor(server) {
  12. super(server);
  13. /** @type {import("ws").ServerOptions} */
  14. const options = {
  15. .../** @type {WebSocketServerConfiguration} */
  16. (this.server.options.webSocketServer).options,
  17. clientTracking: false,
  18. };
  19. const isNoServerMode =
  20. typeof options.port === "undefined" &&
  21. typeof options.server === "undefined";
  22. if (isNoServerMode) {
  23. options.noServer = true;
  24. }
  25. this.implementation = new WebSocket.Server(options);
  26. /** @type {import("http").Server} */
  27. (this.server.server).on(
  28. "upgrade",
  29. /**
  30. * @param {import("http").IncomingMessage} req
  31. * @param {import("stream").Duplex} sock
  32. * @param {Buffer} head
  33. */
  34. (req, sock, head) => {
  35. if (!this.implementation.shouldHandle(req)) {
  36. return;
  37. }
  38. this.implementation.handleUpgrade(req, sock, head, (connection) => {
  39. this.implementation.emit("connection", connection, req);
  40. });
  41. }
  42. );
  43. this.implementation.on(
  44. "error",
  45. /**
  46. * @param {Error} err
  47. */
  48. (err) => {
  49. this.server.logger.error(err.message);
  50. }
  51. );
  52. const interval = setInterval(() => {
  53. this.clients.forEach(
  54. /**
  55. * @param {ClientConnection} client
  56. */
  57. (client) => {
  58. if (client.isAlive === false) {
  59. client.terminate();
  60. return;
  61. }
  62. client.isAlive = false;
  63. client.ping(() => {});
  64. }
  65. );
  66. }, WebsocketServer.heartbeatInterval);
  67. this.implementation.on(
  68. "connection",
  69. /**
  70. * @param {ClientConnection} client
  71. */
  72. (client) => {
  73. this.clients.push(client);
  74. client.isAlive = true;
  75. client.on("pong", () => {
  76. client.isAlive = true;
  77. });
  78. client.on("close", () => {
  79. this.clients.splice(this.clients.indexOf(client), 1);
  80. });
  81. }
  82. );
  83. this.implementation.on("close", () => {
  84. clearInterval(interval);
  85. });
  86. }
  87. };