You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

websocket-client.ts 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /* eslint-disable @typescript-eslint/naming-convention */
  2. import { Client } from '@stomp/stompjs';
  3. import logger from './logger';
  4. interface QueueServiceResponse {
  5. conference: string;
  6. }
  7. export interface StateResponse extends QueueServiceResponse {
  8. randomDelayMs: number;
  9. status: string;
  10. }
  11. export interface VisitorResponse extends QueueServiceResponse {
  12. visitorsWaiting: number;
  13. }
  14. /**
  15. * Websocket client impl, used for visitors queue.
  16. * Uses STOMP for authenticating (https://stomp.github.io/).
  17. */
  18. export class WebsocketClient {
  19. private stompClient: Client | undefined;
  20. private static instance: WebsocketClient;
  21. private retriesCount = 0;
  22. private _connectCount = 0;
  23. /**
  24. * WebsocketClient getInstance.
  25. *
  26. * @static
  27. * @returns {WebsocketClient} - WebsocketClient instance.
  28. */
  29. static getInstance(): WebsocketClient {
  30. if (!this.instance) {
  31. this.instance = new WebsocketClient();
  32. }
  33. return this.instance;
  34. }
  35. /**
  36. * Connect to endpoint.
  37. *
  38. * @param {string} queueServiceURL - The service URL to use.
  39. * @param {string} endpoint - The endpoint to subscribe to.
  40. * @param {Function} callback - The callback to execute when we receive a message from the endpoint.
  41. * @param {string} token - The token, if any, to be used for authorization.
  42. * @param {Function?} connectCallback - The callback to execute when successfully connected.
  43. *
  44. * @returns {void}
  45. */
  46. connect(queueServiceURL: string, // eslint-disable-line max-params
  47. endpoint: string,
  48. callback: (response: StateResponse | VisitorResponse) => void,
  49. token: string | undefined,
  50. connectCallback?: () => void): void {
  51. this.stompClient = new Client({
  52. brokerURL: queueServiceURL,
  53. forceBinaryWSFrames: true,
  54. appendMissingNULLonIncoming: true
  55. });
  56. const errorConnecting = (error: any) => {
  57. if (this.retriesCount > 3) {
  58. this.stompClient?.deactivate();
  59. this.stompClient = undefined;
  60. return;
  61. }
  62. this.retriesCount++;
  63. logger.error(`Error connecting to ${queueServiceURL} ${JSON.stringify(error)}`);
  64. };
  65. this.stompClient.onWebSocketError = errorConnecting;
  66. this.stompClient.onStompError = frame => {
  67. errorConnecting(frame.headers.message);
  68. };
  69. if (token) {
  70. this.stompClient.connectHeaders = {
  71. Authorization: `Bearer ${token}`
  72. };
  73. }
  74. this.stompClient.onConnect = () => {
  75. if (!this.stompClient) {
  76. return;
  77. }
  78. this.retriesCount = 0;
  79. logger.info(`Connected to:${endpoint}`);
  80. this._connectCount++;
  81. connectCallback?.();
  82. this.stompClient.subscribe(endpoint, message => {
  83. try {
  84. callback(JSON.parse(message.body));
  85. } catch (e) {
  86. logger.error(`Error parsing response: ${message}`, e);
  87. }
  88. });
  89. };
  90. this.stompClient.activate();
  91. }
  92. /**
  93. * Disconnects the current stomp client instance and clears it.
  94. *
  95. * @returns {Promise}
  96. */
  97. disconnect(): Promise<any> {
  98. if (!this.stompClient) {
  99. return Promise.resolve();
  100. }
  101. const url = this.stompClient.brokerURL;
  102. return this.stompClient.deactivate().then(() => {
  103. logger.info(`disconnected from: ${url}`);
  104. this.stompClient = undefined;
  105. });
  106. }
  107. /**
  108. * Checks whether the instance is created and connected or in connecting state.
  109. *
  110. * @returns {boolean} Whether the connect method was executed.
  111. */
  112. isActive() {
  113. return this.stompClient !== undefined;
  114. }
  115. /**
  116. * Returns the number of connections.
  117. *
  118. * @returns {number} The number of connections for the life of the app.
  119. */
  120. get connectCount(): number {
  121. return this._connectCount;
  122. }
  123. }