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;