126 lines
2.7 KiB
TypeScript
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);
|
|
}
|
|
}
|