github.com/christoph-karpowicz/db_mediator@v0.0.0-20210207102849-61a28a1071d8/web/src/ws/ws.tsx (about)

     1  import Application from '../app/app';
     2  import WSRequest from './request';
     3  import { sleep } from '../utils/async';
     4  
     5  class WS {
     6      private static readonly TIMEOUT_AFTER: number = 2500;
     7      private static _instance: WS;
     8      private _connString: string;
     9      private _socket: WebSocket;
    10      private _isConnected: boolean;
    11  
    12      private constructor(connString: string) {
    13          this._connString = connString;
    14      }
    15  
    16      set isConnected(isConnected: boolean) {
    17          this._isConnected = isConnected;
    18      }
    19  
    20      get isConnected(): boolean {
    21          return this._isConnected;
    22      }
    23      
    24      get socket(): WebSocket {
    25          return this._socket;
    26      }
    27  
    28      public static async getSocket(): Promise<WS> {
    29          if (!WS._instance || !WS._instance.isConnected) {
    30              WS._instance = new WS("ws://127.0.0.1:8000/ws/");
    31              await WS._instance.init().catch(err => {
    32                  console.log(err);
    33              });
    34          }
    35          return WS._instance;
    36      }
    37      
    38      public async init(): Promise<void> {
    39          console.log('Websocket init.')
    40          await this.createSocket();
    41          await this.setOnOpen();
    42          this.setOnClose();
    43          this.setOnError();
    44          this.setOnMessage();
    45      }
    46  
    47      private createSocket(): Promise<any> {
    48          return new Promise<boolean>((resolve, reject) => {
    49              try {
    50                  this._socket = new WebSocket(this._connString);
    51                  resolve(true);
    52              } catch(err) {
    53                  reject(`Invalid URL "${this._connString}". Failed to create a web socket.`);
    54              }
    55          });
    56      }
    57  
    58      private setOnOpen(): Promise<boolean> {
    59          return new Promise<boolean>(resolve => {
    60              this._socket.onopen = () => {
    61                  console.log("Successfully Connected");
    62                  this.isConnected = true;
    63                  resolve(true)
    64              };
    65          });
    66      }
    67  
    68      private setOnClose() {
    69          this._socket.onclose = event => {
    70              console.log("Socket Closed Connection: ", event);
    71              this.isConnected = false;
    72          };
    73      }
    74  
    75      private setOnError() {
    76          this._socket.onerror = error => {
    77              console.log("Socket Error: ", error);
    78              this.isConnected = false;
    79          };
    80      }
    81  
    82      private setOnMessage() {
    83          this._socket.onmessage = function (event) {
    84              try {
    85                  const response = JSON.parse(event.data);
    86                  Application.wsRequestPool.respond(response);
    87              } catch(e) {
    88                  console.error(e);
    89              }
    90          }
    91      }
    92      
    93      public emitAndAwaitResponse(req: WSRequest): Promise<object> {
    94          req.setExpectResponse(true);
    95          
    96          return new Promise<object>((resolve, reject) => {
    97              const timeStart = new Date().getTime();
    98              
    99              const emitted: boolean = this.emit(req);
   100              if (!emitted) {
   101                  reject({ msg: "Websocket is closed." });
   102                  return;
   103              }
   104  
   105              const awaitResponse = (initial?: boolean) => {
   106                  const sleepFor = initial ? 1 : 1000;
   107                  
   108                  sleep(sleepFor).then(() => {
   109                      const currentTime = new Date().getTime();
   110                      const timeDiff = currentTime - timeStart;
   111                      if (timeDiff > WS.TIMEOUT_AFTER) {
   112                          reject({ msg: `Request with ID: ${req.getId()} timed out.` });
   113                          return;
   114                      }
   115      
   116                      if (Application.wsRequestPool.hasResponse(req.getId())) {
   117                          resolve(Application.wsRequestPool.poll(req.getId()));
   118                          return;
   119                      }
   120  
   121                      awaitResponse();
   122                  });
   123              }
   124  
   125              awaitResponse(true);
   126          });
   127      }
   128  
   129      public emit(req: WSRequest): boolean {
   130          if (!this.isConnected) {
   131              return false;
   132          }
   133          
   134          this._socket.send(req.json);
   135          Application.wsRequestPool.append(req);
   136          return true;
   137      }
   138  
   139  }
   140  
   141  export default WS;