| 6 | |
| 7 | let id = 0; |
| 8 | export class WsJsonRpcClient { |
| 9 | static async with<T>(url: string, callback: (client: WsJsonRpcClient) => Promise<T>): Promise<T> { |
| 10 | const client = new WsJsonRpcClient(url); |
| 11 | await client.isReady; |
| 12 | const ret = await callback(client); |
| 13 | client.destroy(); |
| 14 | return ret; |
| 15 | } |
| 16 | |
| 17 | isReady!: Promise<WsJsonRpcClient>; |
| 18 | protected _ws!: WebSocket; |
| 19 | protected isDestroyed = false; |
| 20 | |
| 21 | protected handlers: {[id: string]: any}; |
| 22 | |
| 23 | constructor(protected address: string) { |
| 24 | this.handlers = {}; |
| 25 | this.connect(); |
| 26 | } |
| 27 | |
| 28 | connect(): void { |
| 29 | try { |
| 30 | this._ws = new WebSocket(this.address); |
| 31 | |
| 32 | this.isReady = new Promise((resolve) => { |
| 33 | this._ws.on('open', () => resolve(this)); |
| 34 | }); |
| 35 | |
| 36 | this._ws.on('close', this.onSocketClose); |
| 37 | this._ws.on('message', this.onSocketMessage); |
| 38 | } catch (error) { |
| 39 | console.error(error); |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | async send<T extends ResponseSuccessType>(method: string, params?: any[]): Promise<T> { |
| 44 | await this.isReady; |
| 45 | const req: Request = {jsonrpc: '2.0', id: id++, method, params}; |
| 46 | this._ws.send(JSON.stringify(req)); |
| 47 | return new Promise<T>((resolve, reject) => { |
| 48 | this.handlers[req.id] = [resolve, reject]; |
| 49 | }); |
| 50 | } |
| 51 | |
| 52 | destroy(): void { |
| 53 | this.isDestroyed = true; |
| 54 | this._ws.close(); |
| 55 | } |
| 56 | |
| 57 | private onSocketClose = (code: number, reason: Buffer): void => { |
| 58 | if (this.isDestroyed) return; |
| 59 | |
| 60 | console.error(`disconnected from ${this.address} code: '${code}' reason: '${reason.toString()}'`); |
| 61 | setTimeout((): void => { |
| 62 | this.connect(); |
| 63 | }, 1000); |
| 64 | }; |
| 65 | |