133 lines
2.8 KiB
JavaScript
133 lines
2.8 KiB
JavaScript
import { decodeVarint } from "./varintUtils";
|
|
|
|
export class BufferReader {
|
|
constructor(buffer) {
|
|
this.buffer = buffer;
|
|
this.offset = 0;
|
|
}
|
|
|
|
readVarInt() {
|
|
const result = decodeVarint(this.buffer, this.offset);
|
|
this.offset += result.length;
|
|
|
|
return result.value;
|
|
}
|
|
|
|
readBuffer(length) {
|
|
this.checkByte(length);
|
|
const result = this.buffer.slice(this.offset, this.offset + length);
|
|
this.offset += length;
|
|
|
|
return result;
|
|
}
|
|
|
|
// gRPC has some additional header - remove it
|
|
trySkipGrpcHeader() {
|
|
const backupOffset = this.offset;
|
|
|
|
if (this.buffer[this.offset] === 0 && this.leftBytes() >= 5) {
|
|
this.offset++;
|
|
const length = this.buffer.readInt32BE(this.offset);
|
|
this.offset += 4;
|
|
|
|
if (length > this.leftBytes()) {
|
|
// Something is wrong, revert
|
|
this.offset = backupOffset;
|
|
}
|
|
}
|
|
}
|
|
|
|
leftBytes() {
|
|
return this.buffer.length - this.offset;
|
|
}
|
|
|
|
checkByte(length) {
|
|
const bytesAvailable = this.leftBytes();
|
|
if (length > bytesAvailable) {
|
|
throw new Error(
|
|
"Not enough bytes left. Requested: " +
|
|
length +
|
|
" left: " +
|
|
bytesAvailable
|
|
);
|
|
}
|
|
}
|
|
|
|
checkpoint() {
|
|
this.savedOffset = this.offset;
|
|
}
|
|
|
|
resetToCheckpoint() {
|
|
this.offset = this.savedOffset;
|
|
}
|
|
}
|
|
|
|
export const TYPES = {
|
|
VARINT: 0,
|
|
FIXED64: 1,
|
|
LENDELIM: 2,
|
|
FIXED32: 5
|
|
};
|
|
|
|
export function decodeProto(buffer) {
|
|
const reader = new BufferReader(buffer);
|
|
const parts = [];
|
|
|
|
reader.trySkipGrpcHeader();
|
|
|
|
try {
|
|
while (reader.leftBytes() > 0) {
|
|
reader.checkpoint();
|
|
|
|
const byteRange = [reader.offset];
|
|
const indexType = parseInt(reader.readVarInt().toString());
|
|
const type = indexType & 0b111;
|
|
const index = indexType >> 3;
|
|
|
|
let value;
|
|
if (type === TYPES.VARINT) {
|
|
value = reader.readVarInt().toString();
|
|
} else if (type === TYPES.LENDELIM) {
|
|
const length = parseInt(reader.readVarInt().toString());
|
|
value = reader.readBuffer(length);
|
|
} else if (type === TYPES.FIXED32) {
|
|
value = reader.readBuffer(4);
|
|
} else if (type === TYPES.FIXED64) {
|
|
value = reader.readBuffer(8);
|
|
} else {
|
|
throw new Error("Unknown type: " + type);
|
|
}
|
|
byteRange.push(reader.offset);
|
|
|
|
parts.push({
|
|
byteRange,
|
|
index,
|
|
type,
|
|
value
|
|
});
|
|
}
|
|
} catch (err) {
|
|
reader.resetToCheckpoint();
|
|
}
|
|
|
|
return {
|
|
parts,
|
|
leftOver: reader.readBuffer(reader.leftBytes())
|
|
};
|
|
}
|
|
|
|
export function typeToString(type, subType) {
|
|
switch (type) {
|
|
case TYPES.VARINT:
|
|
return "varint";
|
|
case TYPES.LENDELIM:
|
|
return subType || "len_delim";
|
|
case TYPES.FIXED32:
|
|
return "fixed32";
|
|
case TYPES.FIXED64:
|
|
return "fixed64";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|