UNPKG

tardis-machine

Version:

Locally runnable server with built-in data caching, providing both tick-level historical and consolidated real-time cryptocurrency market data via HTTP and WebSocket APIs

76 lines (60 loc) 2.59 kB
import qs from 'querystring' import { combine, compute, replayNormalized } from 'tardis-dev' import { HttpRequest, WebSocket } from 'uWebSockets.js' import { debug } from '../debug' import { constructDataTypeFilter, getComputables, getNormalizers, ReplayNormalizedRequestOptions, wait } from '../helpers' export async function replayNormalizedWS(ws: any, req: HttpRequest) { let messages: AsyncIterableIterator<any> | undefined try { const startTimestamp = new Date().getTime() const parsedQuery = qs.decode(req.getQuery()) const optionsString = parsedQuery['options'] as string const replayNormalizedOptions = JSON.parse(optionsString) as ReplayNormalizedRequestOptions debug('WebSocket /ws-replay-normalized started, options: %o', replayNormalizedOptions) const options = Array.isArray(replayNormalizedOptions) ? replayNormalizedOptions : [replayNormalizedOptions] const messagesIterables = options.map((option) => { // let's map from provided options to options and normalizers that needs to be added for dataTypes provided in options const messages = replayNormalized(option, ...getNormalizers(option.dataTypes)) // separately check if any computables are needed for given dataTypes const computables = getComputables(option.dataTypes) if (computables.length > 0) { return compute(messages, ...computables) } return messages }) const filterByDataType = constructDataTypeFilter(options) messages = messagesIterables.length === 1 ? messagesIterables[0] : combine(...messagesIterables) for await (const message of messages) { if (!filterByDataType(message)) { continue } const success = ws.send(JSON.stringify(message)) // handle backpressure in case of slow clients if (!success) { while (ws.getBufferedAmount() > 0) { await wait(1) } } } while (ws.getBufferedAmount() > 0) { await wait(100) } ws.end(1000, 'WS replay-normalized finished') const endTimestamp = new Date().getTime() debug( 'WebSocket /ws-replay-normalized finished, options: %o, time: %d seconds', replayNormalizedOptions, (endTimestamp - startTimestamp) / 1000 ) } catch (e: any) { // this will underlying open WS connections if (messages !== undefined) { messages!.return!() } if (!ws.closed) { ws.end(1011, e.toString()) } debug('WebSocket /ws-replay-normalized error: %o', e) console.error('WebSocket /ws-replay-normalized error:', e) } }