import { JSON_BytesToken } from "../utils/json_byte_repr.ts"; // TODO: make this an iterator export class JSON_Chunker { private jsons: Array = []; private chunks: Array = []; private totalBytes = 0; private _openBrackets = 0; private _openArray = 0; private decoder = new TextDecoder("utf-8"); private debug = true; private get delimiterToken() { return this.openArray + this.openBrackets } private get openBrackets() { return this._openBrackets; } private set openBrackets(value) { this._openBrackets = value; if (this._openBrackets < 0) { this._openBrackets = 0; } } private get openArray() { return this._openArray; } private set openArray(value) { this._openArray = value; if (this._openArray < 0) { this._openArray = 0; } } public get messageReady() { return (this.jsons.length !== 0); } public get message() { const msg = this.jsons.shift(); return msg; } public pushChunk(chunk: Uint8Array) { const chunkLen = chunk.length; let lastByteRead = 0; for (let i = 0; i < chunkLen; i++) { const byte = chunk[i]; switch (byte) { case JSON_BytesToken.OPEN_ARR: this.openArray = this.openArray + 1; break; case JSON_BytesToken.CLOSE_ARR: this.openArray = this.openArray - 1; break; case JSON_BytesToken.OPEN_BRACKET: this.openBrackets = this.openBrackets + 1; break; case JSON_BytesToken.CLOSE_BRACKET: this.openBrackets = this.openBrackets - 1; break; default: continue; } // If we are in this situation, then we have a JSON if (this.delimiterToken === 0) { const _chunk = chunk.slice(lastByteRead, i + 1); // console.log(this.decoder.decode(_chunk)); this.insertChunk(_chunk); this.flush(); lastByteRead = i + 1; } } // Otherwise insert the remaining chunk this.insertChunk( chunk.slice(lastByteRead), ); } private insertChunk(chunk: Uint8Array) { this.totalBytes += chunk.length; this.chunks.push(chunk); } private flush() { let remainingBytes = this.totalBytes; let writtenBytes = 0; const msg = new Uint8Array(this.totalBytes); for (let chunk of this.chunks) { const validBytes = Math.min( remainingBytes, chunk.length, ); chunk = chunk.slice(0, validBytes); msg.set(chunk, writtenBytes); writtenBytes += validBytes; remainingBytes -= validBytes; } this.totalBytes = 0; this.chunks = [] const message = this.decoder.decode(msg); this.jsons.push(message); } }