@jsonjoy.com/reactive-rpc
Version:
Reactive-RPC is a library for building reactive APIs over WebSocket, HTTP, and other RPCs.
117 lines • 4.45 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.WsFrameDecoder = void 0;
const StreamingOctetReader_1 = require("@jsonjoy.com/util/lib/buffers/StreamingOctetReader");
const constants_1 = require("./constants");
const errors_1 = require("./errors");
const frames_1 = require("./frames");
class WsFrameDecoder {
constructor() {
this.reader = new StreamingOctetReader_1.StreamingOctetReader();
}
push(uint8) {
this.reader.push(uint8);
}
readFrameHeader() {
try {
const reader = this.reader;
if (reader.size() < 2)
return undefined;
const b0 = reader.u8();
const b1 = reader.u8();
const fin = (b0 >>> 7);
const opcode = b0 & 0b1111;
const maskBit = b1 >>> 7;
let length = b1 & 0b01111111;
if (length === 126) {
if (reader.size() < 2)
return undefined;
length = (reader.u8() << 8) | reader.u8();
}
else if (length === 127) {
if (reader.size() < 8)
return undefined;
reader.skip(4);
length = reader.u32();
}
let mask;
if (maskBit) {
if (reader.size() < 4)
return undefined;
mask = [reader.u8(), reader.u8(), reader.u8(), reader.u8()];
}
if (opcode >= constants_1.WsFrameOpcode.MIN_CONTROL_OPCODE) {
switch (opcode) {
case constants_1.WsFrameOpcode.CLOSE: {
return new frames_1.WsCloseFrame(fin, opcode, length, mask, 0, '');
}
case constants_1.WsFrameOpcode.PING: {
if (length > 125)
throw new errors_1.WsFrameDecodingError();
const data = mask ? reader.bufXor(length, mask, 0) : reader.buf(length);
return new frames_1.WsPingFrame(fin, opcode, length, mask, data);
}
case constants_1.WsFrameOpcode.PONG: {
if (length > 125)
throw new errors_1.WsFrameDecodingError();
const data = mask ? reader.bufXor(length, mask, 0) : reader.buf(length);
return new frames_1.WsPongFrame(fin, opcode, length, mask, data);
}
default: {
throw new errors_1.WsFrameDecodingError();
}
}
}
return new frames_1.WsFrameHeader(fin, opcode, length, mask);
}
catch (err) {
if (err instanceof RangeError)
return undefined;
throw err;
}
}
readFrameData(frame, remaining, dst, pos) {
const reader = this.reader;
const mask = frame.mask;
const readSize = Math.min(reader.size(), remaining);
if (!mask)
reader.copy(readSize, dst, pos);
else {
const alreadyRead = frame.length - remaining;
reader.copyXor(readSize, dst, pos, mask, alreadyRead);
}
return remaining - readSize;
}
copyFrameData(frame, dst, pos) {
const reader = this.reader;
const mask = frame.mask;
const readSize = frame.length;
if (!mask)
reader.copy(readSize, dst, pos);
else
reader.copyXor(readSize, dst, pos, mask, 0);
}
readCloseFrameData(frame) {
let length = frame.length;
if (length > 125)
throw new errors_1.WsFrameDecodingError();
let code = 0;
let reason = '';
if (length > 0) {
if (length < 2)
throw new errors_1.WsFrameDecodingError();
const reader = this.reader;
const mask = frame.mask;
const octet1 = reader.u8() ^ (mask ? mask[0] : 0);
const octet2 = reader.u8() ^ (mask ? mask[1] : 0);
code = (octet1 << 8) | octet2;
length -= 2;
if (length)
reason = reader.utf8(length, mask ?? [0, 0, 0, 0], 2);
}
frame.code = code;
frame.reason = reason;
}
}
exports.WsFrameDecoder = WsFrameDecoder;
//# sourceMappingURL=WsFrameDecoder.js.map
;