shardy
Version:
Framework for online games and applications on Node.js
135 lines • 5.31 kB
JavaScript
"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