UNPKG

@litert/redis

Version:

A redis protocol implement for Node.js.

253 lines 9.66 kB
"use strict"; /** * Copyright 2025 Angus.Fenying <fenying@litert.org> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Decoder = void 0; const C = require("./Common"); const E = require("./Errors"); const Constants = require("./Constants"); const node_events_1 = require("node:events"); var PROTO_DELIMITER = Constants.PROTO_DELIMITER; var EDecodeStatus; (function (EDecodeStatus) { /** * Reading nothing. */ EDecodeStatus[EDecodeStatus["IDLE"] = 0] = "IDLE"; /** * Reading the length of a byte-string. */ EDecodeStatus[EDecodeStatus["READING_STRING_LENGTH"] = 1] = "READING_STRING_LENGTH"; /** * Reading the content of a byte-string. */ EDecodeStatus[EDecodeStatus["READING_STRING"] = 2] = "READING_STRING"; /** * Reading the content of a message. */ EDecodeStatus[EDecodeStatus["READING_MESSAGE"] = 3] = "READING_MESSAGE"; /** * Reading the content of a failure. */ EDecodeStatus[EDecodeStatus["READING_FAILURE"] = 4] = "READING_FAILURE"; /** * Reading the value of an integer. */ EDecodeStatus[EDecodeStatus["READING_INTEGER"] = 5] = "READING_INTEGER"; /** * Reading the length of a list. */ EDecodeStatus[EDecodeStatus["READING_LIST_LENGTH"] = 6] = "READING_LIST_LENGTH"; /** * Reading the elements of a list. */ EDecodeStatus[EDecodeStatus["READING_LIST"] = 7] = "READING_LIST"; })(EDecodeStatus || (EDecodeStatus = {})); class DecodeContext { /** * The status of decoder context. */ status; data; value; type; pos; constructor(status = EDecodeStatus.IDLE, pos = 0) { this.data = {}; this.status = status; this.pos = pos; } } class Decoder extends node_events_1.EventEmitter { _buf; _ctx; _contextStack; _cursor; constructor() { super(); this.reset(); } reset() { this._ctx = new DecodeContext(); this._contextStack = []; this._buf = Buffer.allocUnsafe(0); this._cursor = 0; return this; } update(data) { this._buf = Buffer.concat([this._buf, data]); while (this._buf.length) { let end; switch (this._ctx.status) { case EDecodeStatus.READING_LIST: case EDecodeStatus.IDLE: switch (this._buf[this._cursor]) { case 36: // $ this._push(EDecodeStatus.READING_STRING_LENGTH); break; case 42: // * this._push(EDecodeStatus.READING_LIST_LENGTH); break; case 43: // + this._push(EDecodeStatus.READING_MESSAGE); break; case 45: // - this._push(EDecodeStatus.READING_FAILURE); break; case 58: // : this._push(EDecodeStatus.READING_INTEGER); break; default: this.emit('error', new E.E_PROTOCOL_ERROR({ 'message': 'Unrecognizable format of stream.' })); return this; } break; case EDecodeStatus.READING_MESSAGE: this._ctx.type = C.EDataType.MESSAGE; end = this._buf.indexOf(PROTO_DELIMITER, this._cursor); if (end > -1) { this._ctx.value = this._buf.subarray(this._ctx.pos, end); this._pop(end + 2); } else { // this._cursor = this._buf.length - 2; return this; } break; case EDecodeStatus.READING_FAILURE: this._ctx.type = C.EDataType.FAILURE; end = this._buf.indexOf(PROTO_DELIMITER, this._cursor); if (end > -1) { this._ctx.value = this._buf.subarray(this._ctx.pos, end); this._pop(end + 2); } else { // this._cursor = this._buf.length - 2; return this; } break; case EDecodeStatus.READING_INTEGER: this._ctx.type = C.EDataType.INTEGER; end = this._buf.indexOf(PROTO_DELIMITER, this._cursor); if (end > -1) { this._ctx.value = parseInt(this._buf.subarray(this._ctx.pos, end).toString()); this._pop(end + 2); } else { // this._cursor = this._buf.length - 2; return this; } break; case EDecodeStatus.READING_LIST_LENGTH: end = this._buf.indexOf(PROTO_DELIMITER, this._cursor); if (end > -1) { this._ctx.data.length = parseInt(this._buf.subarray(this._ctx.pos, end).toString()); if (this._ctx.data.length === -1) { this._ctx.type = C.EDataType.NULL; this._ctx.value = null; this._pop(end + 2); } else { this._ctx.type = C.EDataType.LIST; this._ctx.value = []; if (this._ctx.data.length === 0) { this._pop(end + 2); } else { this._cut(end + 2); this._ctx.pos = this._cursor; this._ctx.status = EDecodeStatus.READING_LIST; } } } else { // this._cursor = this._buf.length - 2; return this; } break; case EDecodeStatus.READING_STRING_LENGTH: this._ctx.type = C.EDataType.STRING; end = this._buf.indexOf(PROTO_DELIMITER, this._cursor); if (end > -1) { this._ctx.data.length = parseInt(this._buf.subarray(this._ctx.pos, end).toString()); if (this._ctx.data.length === -1) { this._ctx.type = C.EDataType.NULL; this._ctx.value = null; this._pop(end + 2); } else { this._cut(end + 2); this._ctx.pos = this._cursor; this._ctx.status = EDecodeStatus.READING_STRING; } } else { // this._cursor = this._buf.length - 2; return this; } break; case EDecodeStatus.READING_STRING: if (this._buf.length >= this._ctx.data.length + 2) { this._ctx.value = this._buf.subarray(this._ctx.pos, this._ctx.pos + this._ctx.data.length); this._pop(this._ctx.data.length + 2); } else { // this._cursor = this._buf.length - 2; return this; } break; } } return this; } _push(newStatus) { this._contextStack.push(this._ctx); this._ctx = new DecodeContext(newStatus); this._cursor++; this._ctx.pos = this._cursor; } _pop(end) { const context = this._ctx; this._ctx = this._contextStack.pop(); if (this._ctx.status === EDecodeStatus.READING_LIST) { this._ctx.value.push([ context.type, context.value ]); if (this._ctx.data.length === this._ctx.value.length) { this._pop(0); } } else { this.emit('data', context.type, context.value); } if (end) { this._cut(end); } } /** * Trim the buffer before the specific position. */ _cut(end) { this._buf = this._buf.subarray(end); this._cursor = 0; } } exports.Decoder = Decoder; exports.default = Decoder; //# sourceMappingURL=Decoder.js.map