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
68 lines • 3.06 kB
JavaScript
import { once } from 'node:events';
import { replay } from 'tardis-dev';
import { debug } from "../debug.js";
export const replayHttp = async (req, res) => {
try {
const startTimestamp = new Date().getTime();
const requestUrl = new URL(req.url, 'http://localhost');
const optionsString = requestUrl.searchParams.get('options') ?? undefined;
const replayOptions = JSON.parse(optionsString);
debug('GET /replay request started, options: %o', replayOptions);
const streamedMessagesCount = await writeMessagesToResponse(res, replayOptions);
const endTimestamp = new Date().getTime();
debug('GET /replay request finished, options: %o, time: %d seconds, total messages count:%d', replayOptions, (endTimestamp - startTimestamp) / 1000, streamedMessagesCount);
}
catch (e) {
const errorInfo = {
responseText: e.responseText,
message: e.message,
url: e.url
};
debug('GET /replay request error: %o', e);
console.error('GET /replay request error:', e);
if (!res.finished) {
res.statusCode = e.status || 500;
res.end(JSON.stringify(errorInfo));
}
}
};
async function writeMessagesToResponse(res, replayOptions) {
const responsePrefixBuffer = Buffer.from('{"localTimestamp":"');
const responseMiddleBuffer = Buffer.from('","message":');
const responseSuffixBuffer = Buffer.from('}\n');
const newLineBuffer = Buffer.from('\n');
const BATCH_SIZE = 32;
// not 100% sure that's necessary since we're returning ndjson in fact, not json
res.setHeader('Content-Type', 'application/x-json-stream');
let buffers = [];
let totalMessagesCount = 0;
const messages = replay({ ...replayOptions, skipDecoding: true });
for await (let messageWithTimestamp of messages) {
totalMessagesCount++;
if (messageWithTimestamp === undefined) {
// if received message is undefined (disconnect)
// return it as new line
buffers.push(newLineBuffer);
}
else {
// instead of writing each message directly to response,
// let's batch them and send in BATCH_SIZE batches (each message is 5 buffers: prefix etc)
// also instead of converting messages to string or parsing them let's manually stich together desired json response using buffers which is faster
buffers.push(responsePrefixBuffer, messageWithTimestamp.localTimestamp, responseMiddleBuffer, messageWithTimestamp.message, responseSuffixBuffer);
if (buffers.length >= BATCH_SIZE * 5) {
const ok = res.write(Buffer.concat(buffers));
buffers = [];
if (!ok) {
await once(res, 'drain');
}
}
}
}
if (buffers.length > 0) {
res.write(Buffer.concat(buffers));
buffers = [];
}
res.end('');
return totalMessagesCount;
}
//# sourceMappingURL=replay.js.map