@creditkarma/thrift-server-core
Version:
Thrift core library in TypeScript
504 lines • 15.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JSONProtocol = void 0;
const errors_1 = require("../errors");
const types_1 = require("../types");
const parseJson_1 = require("../parseJson");
const TProtocol_1 = require("./TProtocol");
class JSONProtocol extends TProtocol_1.TProtocol {
constructor(trans) {
super(trans);
this.tstack = [];
this.tpos = [];
this.rstack = [];
this.rpos = [];
this.tstack = [];
this.tpos = [];
}
writeMessageBegin(name, type, id) {
this.tstack = [];
this.tpos = [];
this.tstack.push([JSONProtocol.version, `"${name}"`, type, id]);
}
writeMessageEnd() {
const obj = this.tstack.pop();
const wobj = this.tstack.pop();
wobj.push(obj);
const wbuf = `[${wobj.join(',')}]`;
this.transport.write(Buffer.from(wbuf));
}
writeStructBegin(name) {
this.tpos.push(this.tstack.length);
this.tstack.push({});
}
writeStructEnd() {
const p = this.tpos.pop();
if (p === undefined) {
return;
}
const struct = this.tstack[p];
let str = '{';
let first = true;
for (const key of Object.keys(struct)) {
if (first) {
first = false;
}
else {
str += ',';
}
str += `${key}:${struct[key]}`;
}
str += '}';
this.tstack[p] = str;
}
writeFieldBegin(name, type, id) {
this.tpos.push(this.tstack.length);
this.tstack.push({
fieldId: `"${id}"`,
fieldType: this.getTypeName(type),
});
}
writeFieldEnd() {
const value = this.tstack.pop();
const fieldInfo = this.tstack.pop();
this.tstack[this.tstack.length - 1][fieldInfo.fieldId] = `{${fieldInfo.fieldType}:${value}}`;
this.tpos.pop();
}
writeFieldStop() { }
writeMapBegin(keyType, valType, size) {
this.tpos.push(this.tstack.length);
this.tstack.push([
this.getTypeName(keyType),
this.getTypeName(valType),
0,
]);
}
writeMapEnd() {
const p = this.tpos.pop();
if (p === undefined) {
return;
}
if (p === this.tstack.length) {
return;
}
if ((this.tstack.length - p - 1) % 2 !== 0) {
this.tstack.push('');
}
const size = (this.tstack.length - p - 1) / 2;
this.tstack[p][this.tstack[p].length - 1] = size;
let map = '}';
let first = true;
while (this.tstack.length > p + 1) {
const v = this.tstack.pop();
let k = this.tstack.pop();
if (first) {
first = false;
}
else {
map = `,${map}`;
}
if (!isNaN(k)) {
k = `"${k}"`;
}
map = `${k}:${v}${map}`;
}
map = `{${map}`;
this.tstack[p].push(map);
this.tstack[p] = `[${this.tstack[p].join(',')}]`;
}
writeListBegin(elemType, size) {
this.tpos.push(this.tstack.length);
this.tstack.push([this.getTypeName(elemType), size]);
}
writeListEnd() {
const p = this.tpos.pop();
if (p === undefined) {
return;
}
while (this.tstack.length > p + 1) {
const tmpVal = this.tstack[p + 1];
this.tstack.splice(p + 1, 1);
this.tstack[p].push(tmpVal);
}
this.tstack[p] = `[${this.tstack[p].join(',')}]`;
}
writeSetBegin(elemType, size) {
this.tpos.push(this.tstack.length);
this.tstack.push([this.getTypeName(elemType), size]);
}
writeSetEnd() {
const p = this.tpos.pop();
if (p === undefined) {
return;
}
while (this.tstack.length > p + 1) {
const tmpVal = this.tstack[p + 1];
this.tstack.splice(p + 1, 1);
this.tstack[p].push(tmpVal);
}
this.tstack[p] = `[${this.tstack[p].join(',')}]`;
}
writeBool(value) {
this.tstack.push(value ? 1 : 0);
}
writeByte(i8) {
this.tstack.push(i8);
}
writeI16(i16) {
this.tstack.push(i16);
}
writeI32(i32) {
this.tstack.push(i32);
}
writeI64(i64) {
if (typeof i64 === 'number') {
this.tstack.push(i64);
}
else if (typeof i64 === 'string') {
this.tstack.push(types_1.Int64.fromDecimalString(i64).toDecimalString());
}
else if ((0, types_1.isInt64)(i64)) {
this.tstack.push(i64.toDecimalString());
}
else {
throw new TypeError(`Expected Int64, number, or decimal string but found type ${typeof i64}`);
}
}
writeDouble(dbl) {
this.tstack.push(dbl);
}
writeString(str) {
if (str === null) {
this.tstack.push(null);
}
else {
let escapedString = '';
for (let i = 0; i < str.length; i++) {
const ch = str.charAt(i);
if (ch === '"') {
escapedString += '\\"';
}
else if (ch === '\\') {
escapedString += '\\\\';
}
else if (ch === '\b') {
escapedString += '\\b';
}
else if (ch === '\f') {
escapedString += '\\f';
}
else if (ch === '\n') {
escapedString += '\\n';
}
else if (ch === '\r') {
escapedString += '\\r';
}
else if (ch === '\t') {
escapedString += '\\t';
}
else {
escapedString += ch;
}
}
this.tstack.push(`"${escapedString}"`);
}
}
writeBinary(binary) {
let str = '';
if (typeof binary === 'string') {
str = binary;
}
else if (binary instanceof Buffer) {
const arr = binary;
for (const i of arr) {
str += String.fromCharCode(arr[i]);
}
}
else {
throw new TypeError('writeBinary only accepts String or Buffer.');
}
this.tstack.push(`"${Buffer.from(str).toString('base64')}"`);
}
readMessageBegin() {
this.rstack = [];
this.rpos = [];
const robj = (0, parseJson_1.parseJson)(this.transport.readAll());
const version = robj.shift();
if (version !== JSONProtocol.version) {
throw new Error(`Wrong thrift protocol version: ${version}`);
}
const r = {
fieldName: robj.shift(),
messageType: robj.shift(),
requestId: robj.shift(),
};
this.rstack.push(robj.shift());
return r;
}
readMessageEnd() { }
readStructBegin() {
const r = {
fieldName: '',
};
if (this.rstack[this.rstack.length - 1] instanceof Array) {
this.rstack.push(this.rstack[this.rstack.length - 1].shift());
}
return r;
}
readStructEnd() {
if (this.rstack[this.rstack.length - 2] instanceof Array) {
this.rstack.pop();
}
}
readFieldBegin() {
let fid = -1;
let ftype = types_1.TType.STOP;
for (const f in this.rstack[this.rstack.length - 1]) {
if (f === null) {
continue;
}
fid = parseInt(f, 10);
this.rpos.push(this.rstack.length);
const field = this.rstack[this.rstack.length - 1][fid];
delete this.rstack[this.rstack.length - 1][fid];
this.rstack.push(field);
break;
}
if (fid !== -1) {
for (const i in this.rstack[this.rstack.length - 1]) {
if (JSONProtocol.rType[i] === null) {
continue;
}
ftype = JSONProtocol.rType[i];
this.rstack[this.rstack.length - 1] = this.rstack[this.rstack.length - 1][i];
}
}
return {
fieldId: fid,
fieldName: '',
fieldType: ftype,
};
}
readFieldEnd() {
const pos = this.rpos.pop();
if (pos === undefined) {
return;
}
while (this.rstack.length > pos) {
this.rstack.pop();
}
}
readMapBegin() {
let map = this.rstack.pop();
let first = map.shift();
if (first instanceof Array) {
this.rstack.push(map);
map = first;
first = map.shift();
}
const r = {
keyType: JSONProtocol.rType[first],
valueType: JSONProtocol.rType[map.shift()],
size: map.shift(),
};
this.rpos.push(this.rstack.length);
this.rstack.push(map.shift());
return r;
}
readMapEnd() {
this.readFieldEnd();
}
readListBegin() {
const list = this.rstack[this.rstack.length - 1];
const r = {
elementType: JSONProtocol.rType[list.shift()],
size: list.shift(),
};
this.rpos.push(this.rstack.length);
this.rstack.push(list.shift());
return r;
}
readListEnd() {
let pos = this.rpos.pop();
if (pos === undefined) {
return;
}
pos = pos - 2;
const st = this.rstack;
st.pop();
if (st instanceof Array && st.length > pos && st[pos].length > 0) {
st.push(st[pos].shift());
}
}
readSetBegin() {
return this.readListBegin();
}
readSetEnd() {
return this.readListEnd();
}
readBool() {
const r = this.readValue();
if (r === null) {
return false;
}
else if (r === '1' || r === 1) {
return true;
}
else {
return false;
}
}
readByte() {
return this.readI32();
}
readI16() {
return this.readI32();
}
readI32() {
return parseInt(this.readValue(), 10);
}
readI64() {
return types_1.Int64.fromDecimalString(`${this.readValue()}`);
}
readDouble() {
return parseFloat(this.readValue());
}
readBinary() {
return Buffer.alloc(this.readValue(), 'base64');
}
readString() {
return this.readValue();
}
skip(type) {
switch (type) {
case types_1.TType.STOP:
return null;
case types_1.TType.BOOL:
return this.readBool();
case types_1.TType.BYTE:
return this.readByte();
case types_1.TType.I16:
return this.readI16();
case types_1.TType.I32:
return this.readI32();
case types_1.TType.I64:
return this.readI64();
case types_1.TType.DOUBLE:
return this.readDouble();
case types_1.TType.STRING:
return this.readString();
case types_1.TType.STRUCT:
this.readStructBegin();
while (true) {
const struct = this.readFieldBegin();
if (struct.fieldType === types_1.TType.STOP) {
break;
}
this.skip(struct.fieldType);
this.readFieldEnd();
}
this.readStructEnd();
return null;
case types_1.TType.MAP:
const map = this.readMapBegin();
for (let i = 0; i < map.size; i++) {
if (i > 0) {
if (this.rstack.length >
this.rpos[this.rpos.length - 1] + 1) {
this.rstack.pop();
}
}
this.skip(map.keyType);
this.skip(map.keyType);
}
this.readMapEnd();
return null;
case types_1.TType.SET:
const set = this.readSetBegin();
for (let i = 0; i < set.size; i++) {
this.skip(set.elementType);
}
this.readSetEnd();
return null;
case types_1.TType.LIST:
const list = this.readListBegin();
for (let i = 0; i < list.size; i++) {
this.skip(list.elementType);
}
this.readListEnd();
return null;
default:
throw new errors_1.TProtocolException(errors_1.TProtocolExceptionType.INVALID_DATA);
}
}
readValue() {
const f = this.rstack[this.rstack.length - 1];
if (f instanceof Array) {
if (f.length === 0) {
return undefined;
}
else {
return f.shift();
}
}
else if (f instanceof Object) {
for (const i in f) {
if (i === null) {
continue;
}
this.rstack.push(f[i]);
delete f[i];
return i;
break;
}
}
else {
this.rstack.pop();
return f;
}
}
getTypeName(type) {
switch (type) {
case types_1.TType.BOOL:
return '"tf"';
case types_1.TType.BYTE:
return '"i8"';
case types_1.TType.I16:
return '"i16"';
case types_1.TType.I32:
return '"i32"';
case types_1.TType.I64:
return '"i64"';
case types_1.TType.DOUBLE:
return '"dbl"';
case types_1.TType.STRUCT:
return '"rec"';
case types_1.TType.STRING:
return '"str"';
case types_1.TType.MAP:
return '"map"';
case types_1.TType.LIST:
return '"lst"';
case types_1.TType.SET:
return '"set"';
default:
throw new errors_1.TProtocolException(errors_1.TProtocolExceptionType.NOT_IMPLEMENTED, `Unrecognized type ${type}`);
}
}
}
exports.JSONProtocol = JSONProtocol;
JSONProtocol.version = 1;
JSONProtocol.rType = {
tf: types_1.TType.BOOL,
i8: types_1.TType.BYTE,
i16: types_1.TType.I16,
i32: types_1.TType.I32,
i64: types_1.TType.I64,
dbl: types_1.TType.DOUBLE,
rec: types_1.TType.STRUCT,
str: types_1.TType.STRING,
map: types_1.TType.MAP,
lst: types_1.TType.LIST,
set: types_1.TType.SET,
};
//# sourceMappingURL=JSONProtocol.js.map