netkitty
Version:
Network tools kit
184 lines (183 loc) • 7.22 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Codec = void 0;
const NoAvailableCodecError_1 = require("../../errors/NoAvailableCodecError");
const FlexibleObject_1 = require("./lib/FlexibleObject");
const ProcessPacketPostHandlers_1 = require("./lib/ProcessPacketPostHandlers");
const RawData_1 = require("./headers/RawData");
const packetHeaders = __importStar(require("./PacketHeaders"));
class Codec {
#codecModuleConstructors = [];
#codecSchemas = [];
get HEADER_CODECS() {
return this.#codecModuleConstructors;
}
get CODEC_SCHEMAS() {
return this.#codecSchemas;
}
constructor(codecModuleConstructors = []) {
this.#codecModuleConstructors = this.loadHeaderCodecs();
if (codecModuleConstructors) {
const replaced = [];
codecModuleConstructors.forEach((codecModuleConstructor) => {
const id = codecModuleConstructor.PROTOCOL_ID;
this.#codecModuleConstructors.forEach((HEADER_CODEC, index, array) => {
if (HEADER_CODEC.PROTOCOL_ID === id) {
array[index] = codecModuleConstructor;
replaced.push(codecModuleConstructor);
}
});
});
codecModuleConstructors
.filter((codecModuleConstructor) => !replaced.includes(codecModuleConstructor))
.forEach((codecModuleConstructor) => this.#codecModuleConstructors.push(codecModuleConstructor));
}
this.#codecSchemas = this.loadCodecSchemas();
}
/**
* Load codec schemas
* @protected
*/
loadCodecSchemas() {
return this.HEADER_CODECS.map((codecModuleConstructor) => ({
id: codecModuleConstructor.PROTOCOL_ID,
name: codecModuleConstructor.PROTOCOL_NAME,
schema: codecModuleConstructor.PROTOCOL_SCHEMA
}));
}
/**
* Load header codecs
* @protected
*/
loadHeaderCodecs() {
let headerCodecs = [...Object.values(packetHeaders)];
headerCodecs = headerCodecs.filter((codec) => codec.PROTOCOL_ID !== RawData_1.RawData.PROTOCOL_ID);
//Ensure RawData codec is in the end of header codecs
headerCodecs.push(RawData_1.RawData);
return headerCodecs;
}
/**
* Internal encode headers to packet
* @param inputs
* @param errors
* @private
*/
async #encode(inputs, errors = []) {
const codecData = {
packet: Buffer.from([]),
startPos: 0,
postHandlers: []
};
const codecModules = [];
for (const input of inputs) {
const codecModuleConstructor = this.HEADER_CODECS.find((codec) => codec.PROTOCOL_ID === input.id);
if (!codecModuleConstructor)
continue;
const codecModule = codecModuleConstructor.CREATE_INSTANCE(codecData, codecModules);
codecModule.instance = new FlexibleObject_1.FlexibleObject(codecModule.validate(input.data));
await codecModule.encode();
codecModule.errors.forEach((errorInfo) => errors.push(errorInfo));
codecData.startPos = codecModule.endPos;
codecModules.push(codecModule);
}
return codecData;
}
/**
* Internal decode packet
* @param codecData
* @param codecModules
* @private
*/
async #decode(codecData, codecModules = []) {
const codecModuleConstructor = this.HEADER_CODECS.find((codecModuleConstructor) => codecModuleConstructor.MATCH(codecData, codecModules));
//This unavailable error should not be thrown, the raw data codec will always match unknown data successfully
if (!codecModuleConstructor)
throw new NoAvailableCodecError_1.NoAvailableCodecError('No available codec constructor');
const codecModule = codecModuleConstructor.CREATE_INSTANCE(codecData, codecModules);
await codecModule.decode();
codecData.startPos = codecModule.endPos;
codecModules.push(codecModule);
if (codecData.startPos >= codecData.packet.length)
return;
return this.#decode(codecData, codecModules);
}
/**
* Decode packet
* @param packet
*/
async decode(packet) {
const codecData = {
packet: packet,
startPos: 0,
postHandlers: []
};
const codecModules = [];
await this.#decode(codecData, codecModules);
const postDecodeHandlers = (0, ProcessPacketPostHandlers_1.ProcessPacketDecodePostHandlers)(codecData.postHandlers);
let postDecodeHandler = postDecodeHandlers.shift();
while (postDecodeHandler) {
await postDecodeHandler.handler();
postDecodeHandler = postDecodeHandlers.shift();
}
return codecModules.map((codecModule) => ({
id: codecModule.id,
name: codecModule.name,
nickname: codecModule.nickname,
protocol: codecModule.isProtocol,
errors: codecModule.errors,
data: codecModule.instance.getValue()
}));
}
/**
* Encode packet
* @param inputs
*/
async encode(inputs) {
const errors = [];
const codecData = await this.#encode(inputs, errors);
const postEncodeHandlers = (0, ProcessPacketPostHandlers_1.ProcessPacketEncodePostHandlers)(codecData.postHandlers);
let postEncodeHandler = postEncodeHandlers.shift();
while (postEncodeHandler) {
await postEncodeHandler.handler();
postEncodeHandler = postEncodeHandlers.shift();
}
return {
packet: codecData.packet,
errors: errors
};
}
}
exports.Codec = Codec;