tradestation-api-ts
Version:
A comprehensive TypeScript wrapper for TradeStation WebAPI v3
103 lines (102 loc) • 3.77 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.StreamManager = void 0;
const events_1 = require("events");
class StreamManager {
constructor(httpClient, config) {
this.httpClient = httpClient;
this.streams = new Map();
this.streamCount = 0;
this.maxStreams = config.maxConcurrentStreams || 10;
}
async createStream(endpoint, params = {}, options = {}) {
if (this.streamCount >= this.maxStreams) {
throw new Error(`Maximum number of concurrent streams (${this.maxStreams}) reached`);
}
const streamId = `${endpoint}:${JSON.stringify(params)}`;
if (this.streams.has(streamId)) {
return this.streams.get(streamId);
}
const emitter = new events_1.EventEmitter();
this.streams.set(streamId, emitter);
this.streamCount++;
try {
const stream = await this.httpClient.createStream(endpoint, {
...options,
params
});
let buffer = '';
stream.on('data', (chunk) => {
try {
// Add the chunk to our buffer
buffer += chunk.toString();
// Split the buffer into lines
const lines = buffer.split('\n');
// Process all complete lines
for (let i = 0; i < lines.length - 1; i++) {
const line = lines[i].trim();
if (line) {
try {
const data = JSON.parse(line);
emitter.emit('data', data);
}
catch (parseError) {
console.debug('Failed to parse line:', line);
}
}
}
// Keep the last incomplete line in the buffer
buffer = lines[lines.length - 1];
}
catch (error) {
emitter.emit('error', new Error('Failed to process stream data'));
}
});
stream.on('error', (error) => {
emitter.emit('error', error);
this.closeStream(streamId);
});
stream.on('end', () => {
// Process any remaining data in the buffer
if (buffer.trim()) {
try {
const data = JSON.parse(buffer.trim());
emitter.emit('data', data);
}
catch (parseError) {
console.debug('Failed to parse remaining buffer:', buffer);
}
}
emitter.emit('end');
this.closeStream(streamId);
});
emitter.on('close', () => {
stream.destroy?.();
this.closeStream(streamId);
});
return emitter;
}
catch (error) {
this.closeStream(streamId);
throw error;
}
}
closeStream(streamId) {
const emitter = this.streams.get(streamId);
if (emitter) {
emitter.removeAllListeners();
this.streams.delete(streamId);
this.streamCount--;
}
}
closeAllStreams() {
Array.from(this.streams.entries()).forEach(([streamId, emitter]) => {
emitter.emit('close');
this.closeStream(streamId);
});
}
getActiveStreams() {
return Array.from(this.streams.keys());
}
}
exports.StreamManager = StreamManager;