rsocket-rxjs
Version:
RSocket Protocol Client Implementation
211 lines (210 loc) • 8.41 kB
JavaScript
import { getUint64 } from '../../utlities/conversions';
import { Payload } from './payload';
export var FrameType;
(function (FrameType) {
FrameType[FrameType["SETUP"] = 1] = "SETUP";
FrameType[FrameType["LEASE"] = 2] = "LEASE";
FrameType[FrameType["KEEPALIVE"] = 3] = "KEEPALIVE";
FrameType[FrameType["REQUEST_RESPONSE"] = 4] = "REQUEST_RESPONSE";
FrameType[FrameType["REQUEST_FNF"] = 5] = "REQUEST_FNF";
FrameType[FrameType["REQUEST_STREAM"] = 6] = "REQUEST_STREAM";
FrameType[FrameType["REQUEST_CHANNEL"] = 7] = "REQUEST_CHANNEL";
FrameType[FrameType["REQUEST_N"] = 8] = "REQUEST_N";
FrameType[FrameType["CANCEL"] = 9] = "CANCEL";
FrameType[FrameType["PAYLOAD"] = 10] = "PAYLOAD";
FrameType[FrameType["ERROR"] = 11] = "ERROR";
FrameType[FrameType["METADATA_PUSH"] = 12] = "METADATA_PUSH";
FrameType[FrameType["RESUME"] = 13] = "RESUME";
FrameType[FrameType["RESUME_OK"] = 14] = "RESUME_OK";
FrameType[FrameType["EXT"] = 63] = "EXT";
})(FrameType || (FrameType = {}));
export var ErrorCode;
(function (ErrorCode) {
ErrorCode[ErrorCode["RESERVED"] = 0] = "RESERVED";
ErrorCode[ErrorCode["INVALID_SETUP"] = 1] = "INVALID_SETUP";
ErrorCode[ErrorCode["UNSUPPORTED_SETUP"] = 2] = "UNSUPPORTED_SETUP";
ErrorCode[ErrorCode["REJECTED_SETUP"] = 3] = "REJECTED_SETUP";
ErrorCode[ErrorCode["REJECTED_RESUME"] = 4] = "REJECTED_RESUME";
ErrorCode[ErrorCode["CONNECTION_ERROR"] = 257] = "CONNECTION_ERROR";
ErrorCode[ErrorCode["CONNECTION_CLOSE"] = 258] = "CONNECTION_CLOSE";
ErrorCode[ErrorCode["APPLICATION_ERROR"] = 513] = "APPLICATION_ERROR";
ErrorCode[ErrorCode["REJECTED"] = 514] = "REJECTED";
ErrorCode[ErrorCode["CANCELED"] = 515] = "CANCELED";
ErrorCode[ErrorCode["INVALID"] = 516] = "INVALID";
ErrorCode[ErrorCode["RESERVED_EXT"] = 4294967295] = "RESERVED_EXT";
})(ErrorCode || (ErrorCode = {}));
/**
* Flyweight around a buffer that gives access to frame type etc...
*/
export class Frame {
/**
*
* @param buffer Containing frame data
*/
constructor(buffer) {
this.buffer = buffer;
this.view = new DataView(buffer.buffer);
}
streamId() {
return this.view.getUint32(0);
}
type() {
return this.view.getUint16(4) >> 10;
}
metadataPresent() {
return ((this.view.getUint16(4) >> 8) & 1) == 1;
}
resumeEnable() {
return ((this.view.getUint16(4)) & 7) == 1;
}
willHonorLease() {
return ((this.view.getUint16(4) >> 6) & 1) == 1;
}
majorVersion() {
return this.view.getUint16(6);
}
minorVersion() {
return this.view.getUint16(8);
}
timeBetweenKeeaplive() {
return this.view.getUint32(10);
}
maxLifetime() {
return this.view.getUint32(14);
}
/**
* Only meaningful if resume enabled!
*/
tokenLength() {
return this.view.getUint16(18);
}
/**
* Only meaningful if resume enabled!
*/
resumeIdentificationToken() {
return new Uint8Array(this.buffer.buffer, 20, this.tokenLength());
}
getResumeEnableOffset() {
if (this.resumeEnable()) {
return 20 + this.tokenLength();
}
else {
return 18;
}
}
metadataMimeLength() {
return this.view.getUint8(this.getResumeEnableOffset());
}
metadataMimeType() {
const start = this.getResumeEnableOffset() + 1;
return new Uint8Array(this.buffer.buffer, start, this.metadataMimeLength());
}
dataMimeLength() {
return this.view.getUint8(this.getResumeEnableOffset() + 1 + this.metadataMimeLength());
}
dataMimeType() {
const start = this.getResumeEnableOffset() + 1 + this.metadataMimeLength() + 1;
return new Uint8Array(this.buffer.buffer, start, this.dataMimeLength());
}
errorCode() {
return this.view.getInt32(6);
}
timeToLive() {
return this.view.getUint32(6);
}
numberOfRequest() {
return this.view.getUint32(10);
}
respondWithKeepalive() {
return (((this.view.getUint16(4)) >> 7) & 1) == 1;
}
lastReceivedPosition() {
return getUint64(this.view, 6);
}
fragmentFollows() {
return (((this.view.getUint16(4)) >> 7) & 1) == 1;
}
initialRequests() {
return this.view.getUint32(6);
}
isStreamComplete() {
return (((this.view.getUint16(4)) >> 6) & 1) == 1;
}
requests() {
return this.initialRequests();
}
isNext() {
return (((this.view.getUint16(4)) >> 5) & 1) == 1;
}
metadataPushData() {
return new Uint8Array(this.buffer.buffer, 6);
}
canBeIgnored() {
return ((this.view.getUint8(4) >> 6) & 1) == 1;
}
extendedType() {
return this.view.getUint32(6);
}
metadataLength(offset) {
if (this.metadataPresent() == false) {
return 0;
}
else {
return (this.view.getUint8(offset + 2) | (this.view.getUint8(offset + 1) << 8) | (this.view.getUint8(offset) << 16));
}
}
payload() {
switch (this.type()) {
case FrameType.SETUP:
const offset = this.getResumeEnableOffset() + 1 + this.metadataMimeLength() + 1 + this.dataMimeLength();
if (this.metadataPresent()) {
return new Payload(new Uint8Array(this.buffer.buffer, offset + 3 + this.metadataLength(offset)), new Uint8Array(this.buffer.buffer, offset + 3, this.metadataLength(offset)));
}
else {
return new Payload(new Uint8Array(this.buffer.buffer, offset));
}
case FrameType.ERROR:
return new Payload(new Uint8Array(this.buffer.buffer, 10));
case FrameType.LEASE:
if (this.metadataPresent()) {
return new Payload(new Uint8Array(this.buffer.buffer, 14 + 3 + this.metadataLength(14)), new Uint8Array(this.buffer.buffer, 14 + 3, this.metadataLength(3)));
}
else {
return new Payload(new Uint8Array(this.buffer.buffer, 14));
}
case FrameType.KEEPALIVE:
return new Payload(new Uint8Array(this.buffer.buffer, 14));
case FrameType.REQUEST_RESPONSE:
case FrameType.REQUEST_FNF:
case FrameType.PAYLOAD:
if (this.metadataPresent()) {
return new Payload(new Uint8Array(this.buffer.buffer, 6 + 3 + this.metadataLength(6)), new Uint8Array(this.buffer.buffer, 6 + 3, this.metadataLength(6)));
}
else {
return new Payload(new Uint8Array(this.buffer.buffer, 6));
}
case FrameType.REQUEST_STREAM:
case FrameType.REQUEST_CHANNEL:
if (this.metadataPresent()) {
return new Payload(new Uint8Array(this.buffer.buffer, 10 + 3 + this.metadataLength(10)), new Uint8Array(this.buffer.buffer, 10 + 3, this.metadataLength(10)));
}
else {
return new Payload(new Uint8Array(this.buffer.buffer, 10));
}
case FrameType.REQUEST_N:
throw new Error('Frame Type REQUEST_N does not have payload attached!');
case FrameType.CANCEL:
throw new Error('Frame Type CANCEL does not have payload attached!');
case FrameType.METADATA_PUSH:
throw new Error('Frame Type METADATA_PUSH has no payload attached. Get using metadataPushData()');
case FrameType.EXT:
// TODO : As I never used this feature I don't understand it... Probably needs work
if (this.metadataPresent()) {
return new Payload(new Uint8Array(this.buffer.buffer, 10 + 3 + this.metadataLength(10)), new Uint8Array(this.buffer.buffer, 10 + 3, this.metadataLength(10)));
}
else {
return new Payload(new Uint8Array(this.buffer.buffer, 10));
}
}
}
}