Files
bun.sh/test/cli/inspect/socket-framer.ts
Alistair Smith 4117af6e46 feat(vscode-extension) error reporting, qol (#15261)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Ashcon Partovi <ashcon@partovi.net>
Co-authored-by: Electroid <Electroid@users.noreply.github.com>
Co-authored-by: Meghan Denny <meghan@bun.sh>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2024-11-22 02:55:21 -08:00

80 lines
2.5 KiB
TypeScript

interface Socket<T = any> {
data: T;
write(data: string | Buffer): void;
}
const enum FramerState {
WaitingForLength,
WaitingForMessage,
}
let socketFramerMessageLengthBuffer: Buffer;
export class SocketFramer {
private state: FramerState = FramerState.WaitingForLength;
private pendingLength: number = 0;
private sizeBuffer: Buffer = Buffer.alloc(0);
private sizeBufferIndex: number = 0;
private bufferedData: Buffer = Buffer.alloc(0);
constructor(private onMessage: (message: string) => void) {
if (!socketFramerMessageLengthBuffer) {
socketFramerMessageLengthBuffer = Buffer.alloc(4);
}
this.reset();
}
reset(): void {
this.state = FramerState.WaitingForLength;
this.bufferedData = Buffer.alloc(0);
this.sizeBufferIndex = 0;
this.sizeBuffer = Buffer.alloc(4);
}
send(socket: Socket, data: string): void {
socketFramerMessageLengthBuffer.writeUInt32BE(data.length, 0);
socket.write(socketFramerMessageLengthBuffer);
socket.write(data);
}
onData(socket: Socket, data: Buffer): void {
this.bufferedData = this.bufferedData.length > 0 ? Buffer.concat([this.bufferedData, data]) : data;
let messagesToDeliver: string[] = [];
while (this.bufferedData.length > 0) {
if (this.state === FramerState.WaitingForLength) {
if (this.sizeBufferIndex + this.bufferedData.length < 4) {
const remainingBytes = Math.min(4 - this.sizeBufferIndex, this.bufferedData.length);
this.bufferedData.copy(this.sizeBuffer, this.sizeBufferIndex, 0, remainingBytes);
this.sizeBufferIndex += remainingBytes;
this.bufferedData = this.bufferedData.slice(remainingBytes);
break;
}
const remainingBytes = 4 - this.sizeBufferIndex;
this.bufferedData.copy(this.sizeBuffer, this.sizeBufferIndex, 0, remainingBytes);
this.pendingLength = this.sizeBuffer.readUInt32BE(0);
this.state = FramerState.WaitingForMessage;
this.sizeBufferIndex = 0;
this.bufferedData = this.bufferedData.slice(remainingBytes);
}
if (this.bufferedData.length < this.pendingLength) {
break;
}
const message = this.bufferedData.toString("utf-8", 0, this.pendingLength);
this.bufferedData = this.bufferedData.slice(this.pendingLength);
this.state = FramerState.WaitingForLength;
this.pendingLength = 0;
this.sizeBufferIndex = 0;
messagesToDeliver.push(message);
}
for (const message of messagesToDeliver) {
this.onMessage(message);
}
}
}