UNPKG

@creditkarma/thrift-server-core

Version:
504 lines 15.2 kB
"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