optimize websocket init data
This commit is contained in:
		
							parent
							
								
									f8636d20c2
								
							
						
					
					
						commit
						ffd7831efc
					
				| @ -130,8 +130,9 @@ class BitcoinRoutes { | |||||||
| 
 | 
 | ||||||
|   private getInitData(req: Request, res: Response) { |   private getInitData(req: Request, res: Response) { | ||||||
|     try { |     try { | ||||||
|       const result = websocketHandler.getInitData(); |       const result = websocketHandler.getSerializedInitData(); | ||||||
|       res.json(result); |       res.set('Content-Type', 'application/json'); | ||||||
|  |       res.send(result); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       res.status(500).send(e instanceof Error ? e.message : e); |       res.status(500).send(e instanceof Error ? e.message : e); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -30,6 +30,9 @@ class WebsocketHandler { | |||||||
|   private numConnected = 0; |   private numConnected = 0; | ||||||
|   private numDisconnected = 0; |   private numDisconnected = 0; | ||||||
| 
 | 
 | ||||||
|  |   private initData: { [key: string]: string } = {}; | ||||||
|  |   private serializedInitData: string = '{}'; | ||||||
|  | 
 | ||||||
|   constructor() { } |   constructor() { } | ||||||
| 
 | 
 | ||||||
|   setWebsocketServer(wss: WebSocket.Server) { |   setWebsocketServer(wss: WebSocket.Server) { | ||||||
| @ -38,6 +41,41 @@ class WebsocketHandler { | |||||||
| 
 | 
 | ||||||
|   setExtraInitProperties(property: string, value: any) { |   setExtraInitProperties(property: string, value: any) { | ||||||
|     this.extraInitProperties[property] = value; |     this.extraInitProperties[property] = value; | ||||||
|  |     this.setInitDataFields(this.extraInitProperties); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private setInitDataFields(data: { [property: string]: any }): void { | ||||||
|  |     for (const property of Object.keys(data)) { | ||||||
|  |       if (data[property] != null) { | ||||||
|  |         this.initData[property] = JSON.stringify(data[property]); | ||||||
|  |       } else { | ||||||
|  |         delete this.initData[property]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     this.serializedInitData = '{' | ||||||
|  |       + Object.keys(this.initData).map(key => `"${key}": ${this.initData[key]}`).join(', ') | ||||||
|  |       + '}'; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private updateInitData(): void { | ||||||
|  |     const _blocks = blocks.getBlocks().slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT); | ||||||
|  |     const da = difficultyAdjustment.getDifficultyAdjustment(); | ||||||
|  |     this.setInitDataFields({ | ||||||
|  |       'mempoolInfo': memPool.getMempoolInfo(), | ||||||
|  |       'vBytesPerSecond': memPool.getVBytesPerSecond(), | ||||||
|  |       'blocks': _blocks, | ||||||
|  |       'conversions': priceUpdater.getLatestPrices(), | ||||||
|  |       'mempool-blocks': mempoolBlocks.getMempoolBlocks(), | ||||||
|  |       'transactions': memPool.getLatestTransactions(), | ||||||
|  |       'backendInfo': backendInfo.getBackendInfo(), | ||||||
|  |       'loadingIndicators': loadingIndicators.getLoadingIndicators(), | ||||||
|  |       'da': da?.previousTime ? da : undefined, | ||||||
|  |       'fees': feeApi.getRecommendedFee(), | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public getSerializedInitData(): string { | ||||||
|  |     return this.serializedInitData; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   setupConnectionHandling() { |   setupConnectionHandling() { | ||||||
| @ -157,11 +195,13 @@ class WebsocketHandler { | |||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           if (parsedMessage.action === 'init') { |           if (parsedMessage.action === 'init') { | ||||||
|             const _blocks = blocks.getBlocks().slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT); |             if (!this.initData['blocks']?.length || !this.initData['da']) { | ||||||
|             if (!_blocks) { |               this.updateInitData(); | ||||||
|  |             } | ||||||
|  |             if (!this.initData['blocks']?.length) { | ||||||
|               return; |               return; | ||||||
|             } |             } | ||||||
|             client.send(JSON.stringify(this.getInitData(_blocks))); |             client.send(this.serializedInitData); | ||||||
|           } |           } | ||||||
| 
 | 
 | ||||||
|           if (parsedMessage.action === 'ping') { |           if (parsedMessage.action === 'ping') { | ||||||
| @ -210,6 +250,8 @@ class WebsocketHandler { | |||||||
|       throw new Error('WebSocket.Server is not set'); |       throw new Error('WebSocket.Server is not set'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     this.setInitDataFields({ 'loadingIndicators': indicators }); | ||||||
|  | 
 | ||||||
|     const response = JSON.stringify({ loadingIndicators: indicators }); |     const response = JSON.stringify({ loadingIndicators: indicators }); | ||||||
|     this.wss.clients.forEach((client) => { |     this.wss.clients.forEach((client) => { | ||||||
|       if (client.readyState !== WebSocket.OPEN) { |       if (client.readyState !== WebSocket.OPEN) { | ||||||
| @ -224,6 +266,8 @@ class WebsocketHandler { | |||||||
|       throw new Error('WebSocket.Server is not set'); |       throw new Error('WebSocket.Server is not set'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     this.setInitDataFields({ 'conversions': conversionRates }); | ||||||
|  | 
 | ||||||
|     const response = JSON.stringify({ conversions: conversionRates }); |     const response = JSON.stringify({ conversions: conversionRates }); | ||||||
|     this.wss.clients.forEach((client) => { |     this.wss.clients.forEach((client) => { | ||||||
|       if (client.readyState !== WebSocket.OPEN) { |       if (client.readyState !== WebSocket.OPEN) { | ||||||
| @ -233,26 +277,6 @@ class WebsocketHandler { | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getInitData(_blocks?: BlockExtended[]) { |  | ||||||
|     if (!_blocks) { |  | ||||||
|       _blocks = blocks.getBlocks().slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT); |  | ||||||
|     } |  | ||||||
|     const da = difficultyAdjustment.getDifficultyAdjustment(); |  | ||||||
|     return { |  | ||||||
|       'mempoolInfo': memPool.getMempoolInfo(), |  | ||||||
|       'vBytesPerSecond': memPool.getVBytesPerSecond(), |  | ||||||
|       'blocks': _blocks, |  | ||||||
|       'conversions': priceUpdater.getLatestPrices(), |  | ||||||
|       'mempool-blocks': mempoolBlocks.getMempoolBlocks(), |  | ||||||
|       'transactions': memPool.getLatestTransactions(), |  | ||||||
|       'backendInfo': backendInfo.getBackendInfo(), |  | ||||||
|       'loadingIndicators': loadingIndicators.getLoadingIndicators(), |  | ||||||
|       'da': da?.previousTime ? da : undefined, |  | ||||||
|       'fees': feeApi.getRecommendedFee(), |  | ||||||
|       ...this.extraInitProperties |  | ||||||
|     }; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   handleNewStatistic(stats: OptimizedStatistic) { |   handleNewStatistic(stats: OptimizedStatistic) { | ||||||
|     if (!this.wss) { |     if (!this.wss) { | ||||||
|       throw new Error('WebSocket.Server is not set'); |       throw new Error('WebSocket.Server is not set'); | ||||||
| @ -310,8 +334,11 @@ class WebsocketHandler { | |||||||
|     } |     } | ||||||
|     const recommendedFees = feeApi.getRecommendedFee(); |     const recommendedFees = feeApi.getRecommendedFee(); | ||||||
| 
 | 
 | ||||||
|  |     // update init data
 | ||||||
|  |     this.updateInitData(); | ||||||
|  | 
 | ||||||
|     // cache serialized objects to avoid stringify-ing the same thing for every client
 |     // cache serialized objects to avoid stringify-ing the same thing for every client
 | ||||||
|     const responseCache = {}; |     const responseCache = { ...this.initData }; | ||||||
|     function getCachedResponse(key: string,  data): string { |     function getCachedResponse(key: string,  data): string { | ||||||
|       if (!responseCache[key]) { |       if (!responseCache[key]) { | ||||||
|         responseCache[key] = JSON.stringify(data); |         responseCache[key] = JSON.stringify(data); | ||||||
| @ -342,6 +369,8 @@ class WebsocketHandler { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     const latestTransactions = newTransactions.slice(0, 6).map((tx) => Common.stripTransaction(tx)); | ||||||
|  | 
 | ||||||
|     this.wss.clients.forEach(async (client) => { |     this.wss.clients.forEach(async (client) => { | ||||||
|       if (client.readyState !== WebSocket.OPEN) { |       if (client.readyState !== WebSocket.OPEN) { | ||||||
|         return; |         return; | ||||||
| @ -352,7 +381,7 @@ class WebsocketHandler { | |||||||
|       if (client['want-stats']) { |       if (client['want-stats']) { | ||||||
|         response['mempoolInfo'] = getCachedResponse('mempoolInfo', mempoolInfo); |         response['mempoolInfo'] = getCachedResponse('mempoolInfo', mempoolInfo); | ||||||
|         response['vBytesPerSecond'] = getCachedResponse('vBytesPerSecond', vBytesPerSecond); |         response['vBytesPerSecond'] = getCachedResponse('vBytesPerSecond', vBytesPerSecond); | ||||||
|         response['transactions'] = getCachedResponse('transactions', newTransactions.slice(0, 6).map((tx) => Common.stripTransaction(tx))); |         response['transactions'] = getCachedResponse('transactions', latestTransactions); | ||||||
|         if (da?.previousTime) { |         if (da?.previousTime) { | ||||||
|           response['da'] = getCachedResponse('da', da); |           response['da'] = getCachedResponse('da', da); | ||||||
|         } |         } | ||||||
| @ -587,14 +616,19 @@ class WebsocketHandler { | |||||||
|     const da = difficultyAdjustment.getDifficultyAdjustment(); |     const da = difficultyAdjustment.getDifficultyAdjustment(); | ||||||
|     const fees = feeApi.getRecommendedFee(); |     const fees = feeApi.getRecommendedFee(); | ||||||
| 
 | 
 | ||||||
|     const responseCache = {}; |     // update init data
 | ||||||
|     function getCachedResponse(key,  data) { |     this.updateInitData(); | ||||||
|  | 
 | ||||||
|  |     const responseCache = { ...this.initData }; | ||||||
|  |     function getCachedResponse(key, data): string { | ||||||
|       if (!responseCache[key]) { |       if (!responseCache[key]) { | ||||||
|         responseCache[key] = JSON.stringify(data); |         responseCache[key] = JSON.stringify(data); | ||||||
|       } |       } | ||||||
|       return responseCache[key]; |       return responseCache[key]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     const mempoolInfo = memPool.getMempoolInfo(); | ||||||
|  | 
 | ||||||
|     this.wss.clients.forEach((client) => { |     this.wss.clients.forEach((client) => { | ||||||
|       if (client.readyState !== WebSocket.OPEN) { |       if (client.readyState !== WebSocket.OPEN) { | ||||||
|         return; |         return; | ||||||
| @ -606,7 +640,7 @@ class WebsocketHandler { | |||||||
| 
 | 
 | ||||||
|       const response = {}; |       const response = {}; | ||||||
|       response['block'] = getCachedResponse('block', block); |       response['block'] = getCachedResponse('block', block); | ||||||
|       response['mempoolInfo'] = getCachedResponse('mempoolInfo', memPool.getMempoolInfo(),); |       response['mempoolInfo'] = getCachedResponse('mempoolInfo', mempoolInfo); | ||||||
|       response['da'] = getCachedResponse('da', da?.previousTime ? da : undefined); |       response['da'] = getCachedResponse('da', da?.previousTime ? da : undefined); | ||||||
|       response['fees'] = getCachedResponse('fees', fees); |       response['fees'] = getCachedResponse('fees', fees); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user