2025-06-02 17:41:15 +02:00

126 lines
2.7 KiB
TypeScript

import { JSON_BytesToken } from "../utils/json_byte_repr.ts";
// TODO: make this an iterator
export class JSON_Chunker {
private jsons: Array<string> = [];
private chunks: Array<Uint8Array> = [];
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);
}
}