UNPKG

shardy

Version:

Framework for online games and applications on Node.js

135 lines 5.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Transport = exports.TransportState = exports.TransportType = void 0; const Block_1 = require("./Block"); const Logger_1 = require("./Logger"); const Tools_1 = require("./Tools"); const LOG_TAG = Tools_1.Tools.getTag(module); var TransportType; (function (TransportType) { TransportType["TCP"] = "tcp"; TransportType["WebSocket"] = "websocket"; })(TransportType || (exports.TransportType = TransportType = {})); var TransportState; (function (TransportState) { TransportState[TransportState["Head"] = 0] = "Head"; TransportState[TransportState["Body"] = 1] = "Body"; TransportState[TransportState["Closed"] = 2] = "Closed"; })(TransportState || (exports.TransportState = TransportState = {})); class Transport { constructor(connection, log) { this.connection = connection; this.log = log; this.onData = () => { }; this.onDisconnect = () => { }; this.state = TransportState.Head; this.head = { buffer: Buffer.alloc(Block_1.BLOCK_HEAD), offset: 0, size: Block_1.BLOCK_HEAD }; this.package = { buffer: Buffer.alloc(0), offset: 0, size: 0 }; this.connection.onData = (data) => this.processData(data); this.connection.onClose = () => this.onClose(); this.connection.onError = (error) => this.onError(error); } onError(error) { this.log.error(`[${LOG_TAG}] error: ${error.message}`, Logger_1.LoggerScope.Debug); this.close(); this.onDisconnect(); } onClose() { this.log.info(`[${LOG_TAG}] close`, Logger_1.LoggerScope.Debug); this.close(); this.onDisconnect(); } processData(buffer) { if (this.state === TransportState.Closed) { this.log.warn(`[${LOG_TAG}] received data when state closed: ${buffer}`, Logger_1.LoggerScope.Debug); return; } if (!Buffer.isBuffer(buffer)) { this.log.warn(`[${LOG_TAG}] received not buffer data: ${typeof buffer}`, Logger_1.LoggerScope.Debug); return; } const end = buffer.length; let offset = 0; while (offset < end) { if (this.state === TransportState.Head) { offset = this.readHead(buffer, offset); } if (this.state === TransportState.Body) { offset = this.readBody(buffer, offset); } } } readHead(buffer, offset) { const length = Math.min(this.head.size - this.head.offset, buffer.length - offset); let result = offset + length; buffer.copy(this.head.buffer, this.head.offset, offset, result); this.head.offset += length; if (this.head.offset >= this.head.size) { const size = this.getPackageSize(this.head.buffer); if (size < 0) { this.log.warn(`[${LOG_TAG}] invalid package size: ${size}`, Logger_1.LoggerScope.Debug); result = 0; } if (Block_1.Block.check(this.head.buffer[0])) { this.package.size = size + this.head.size; this.package.buffer = Buffer.alloc(this.package.size); this.head.buffer.copy(this.package.buffer, 0, 0, this.head.size); this.package.offset = this.head.size; this.state = TransportState.Body; } else { result = buffer.length; this.log.warn(`[${LOG_TAG}] invalid block type: ${this.head.buffer[0]}`, Logger_1.LoggerScope.Debug); } } return result; } readBody(buffer, offset) { const length = Math.min(this.package.size - this.package.offset, buffer.length - offset); const result = offset + length; buffer.copy(this.package.buffer, this.package.offset, offset, result); this.package.offset += length; if (this.package.offset === this.package.size) { const buffer = this.package.buffer; this.onData(buffer); this.reset(); } return result; } reset() { this.head = { buffer: Buffer.alloc(Block_1.BLOCK_HEAD), offset: 0, size: Block_1.BLOCK_HEAD }; this.package = { buffer: Buffer.alloc(0), offset: 0, size: 0 }; if (this.state !== TransportState.Closed) { this.state = TransportState.Head; } } getPackageSize(buffer) { let result = 0; for (let i = 1; i < Block_1.BLOCK_HEAD; i++) { if (i > 1) { result <<= 8; } result += buffer.readUInt8(i); } return result; } dispatch(data) { if (this.state !== TransportState.Closed) { this.connection.send(data); } else { this.log.warn(`[${LOG_TAG}] send data when state closed: ${data}`, Logger_1.LoggerScope.Debug); } } close() { this.state = TransportState.Closed; this.connection.close(); } destroy() { this.log.info(`[${LOG_TAG}] destroy`, Logger_1.LoggerScope.Debug); this.state = TransportState.Closed; this.connection.destroy(); } } exports.Transport = Transport; //# sourceMappingURL=Transport.js.map