UNPKG

@devgrid/netron

Version:

A powerful TypeScript library for building distributed systems with event bus, streaming capabilities, and remote object invocation. Features WebSocket-based bidirectional communication between Node.js and browser environments, service discovery, and type

109 lines 4.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NetronReadableStream = void 0; const stream_1 = require("stream"); const MAX_BUFFER_SIZE = 10_000; class NetronReadableStream extends stream_1.Readable { constructor({ peer, streamId, isLive = false, ...opts }) { super({ ...opts, objectMode: true }); this.buffer = new Map(); this.expectedIndex = 0; this.isClosed = false; this.isComplete = false; this.cleanup = () => { this.peer.logger.debug('Cleaning up stream resources', { streamId: this.id }); if (this.timeout) clearTimeout(this.timeout); this.peer.readableStreams.delete(this.id); this.buffer.clear(); }; this.handleError = (error) => { this.peer.logger.error('Stream error occurred', { streamId: this.id, error }); this.cleanup(); }; this.peer = peer; this.id = streamId; this.isLive = isLive; this.peer.logger.info('Creating readable stream', { streamId: this.id, isLive }); this.peer.readableStreams.set(this.id, this); if (!this.isLive) { this.resetTimeout(); } this.on('close', this.cleanup); this.on('error', this.handleError); } onPacket(packet) { if (this.isClosed) { this.peer.logger.warn('Received packet for closed stream', { streamId: this.id }); return; } this.resetTimeout(); if (this.buffer.size > MAX_BUFFER_SIZE) { this.peer.logger.error('Stream buffer overflow', { streamId: this.id, size: this.buffer.size }); this.destroy(new Error(`Buffer overflow: more than ${MAX_BUFFER_SIZE} packets buffered`)); return; } this.peer.logger.debug('Processing packet', { streamId: this.id, index: packet.streamIndex }); this.buffer.set(packet.streamIndex, packet.data); while (this.buffer.has(this.expectedIndex)) { const chunk = this.buffer.get(this.expectedIndex); this.buffer.delete(this.expectedIndex); this.expectedIndex++; if (!this.push(chunk)) { this.peer.logger.debug('Stream backpressure detected', { streamId: this.id }); break; } } if (packet.isLastChunk()) { this.peer.logger.info('Received last chunk', { streamId: this.id }); this.isComplete = true; this.closeStream(true); } } _read() { } resetTimeout() { if (this.isLive) return; if (this.timeout) clearTimeout(this.timeout); const timeoutDuration = this.peer.netron.options?.streamTimeout ?? 60000; this.peer.logger.debug('Resetting stream timeout', { streamId: this.id, timeoutDuration }); this.timeout = setTimeout(() => { const message = `Stream ${this.id} inactive for ${timeoutDuration}ms, closing.`; this.peer.logger.warn(message); this.destroy(new Error(message)); }, timeoutDuration); } closeStream(force = false) { if (this.isClosed) { this.peer.logger.warn('Attempt to close already closed stream', { streamId: this.id }); return; } if (this.isLive && !force) { this.peer.logger.warn('Attempt to close live stream', { streamId: this.id }); return; } this.peer.logger.info('Closing stream', { streamId: this.id, force }); this.push(null); if (this.isLive && force) { this.destroy(); } } destroy(error) { if (this.isClosed) { this.peer.logger.warn('Attempt to destroy already closed stream', { streamId: this.id }); return this; } this.peer.logger.info('Destroying stream', { streamId: this.id, error }); this.isClosed = true; super.destroy(error); this.cleanup(); return this; } static create(peer, streamId, isLive = false) { return new NetronReadableStream({ peer, streamId, isLive }); } } exports.NetronReadableStream = NetronReadableStream; //# sourceMappingURL=readable-stream.js.map