@qsocket/protocol
Version:
QSocket Protocol: A versatile protocol for transmitting messages of any type in buffer format, designed exclusively for the QSocket ecosystem. Enables efficient, high-speed data transfer between processes and across client-server connections.
328 lines (324 loc) • 11.6 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to2, from2, except, desc) => {
if (from2 && typeof from2 === "object" || typeof from2 === "function") {
for (let key of __getOwnPropNames(from2))
if (!__hasOwnProp.call(to2, key) && key !== except)
__defProp(to2, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
}
return to2;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
EQSocketProtocolContentType: () => EQSocketProtocolContentType,
EQSocketProtocolMessageType: () => EQSocketProtocolMessageType,
QSocketProtocolDecodeError: () => QSocketProtocolDecodeError,
QSocketProtocolEncodeError: () => QSocketProtocolEncodeError,
from: () => from,
to: () => to
});
module.exports = __toCommonJS(src_exports);
// src/bin/protocol.enums.ts
var EQSocketProtocolMessageType = /* @__PURE__ */ ((EQSocketProtocolMessageType2) => {
EQSocketProtocolMessageType2[EQSocketProtocolMessageType2["DATA"] = 0] = "DATA";
EQSocketProtocolMessageType2[EQSocketProtocolMessageType2["CONTROL"] = 1] = "CONTROL";
EQSocketProtocolMessageType2[EQSocketProtocolMessageType2["ACK"] = 2] = "ACK";
return EQSocketProtocolMessageType2;
})(EQSocketProtocolMessageType || {});
var EQSocketProtocolContentType = /* @__PURE__ */ ((EQSocketProtocolContentType2) => {
EQSocketProtocolContentType2[EQSocketProtocolContentType2["UNDEFINED"] = 0] = "UNDEFINED";
EQSocketProtocolContentType2[EQSocketProtocolContentType2["NULL"] = 1] = "NULL";
EQSocketProtocolContentType2[EQSocketProtocolContentType2["BOOLEAN"] = 2] = "BOOLEAN";
EQSocketProtocolContentType2[EQSocketProtocolContentType2["NUMBER"] = 3] = "NUMBER";
EQSocketProtocolContentType2[EQSocketProtocolContentType2["STRING"] = 4] = "STRING";
EQSocketProtocolContentType2[EQSocketProtocolContentType2["JSON"] = 5] = "JSON";
EQSocketProtocolContentType2[EQSocketProtocolContentType2["BUFFER"] = 6] = "BUFFER";
return EQSocketProtocolContentType2;
})(EQSocketProtocolContentType || {});
// src/bin/protocol.errors.ts
var QSocketProtocolEncodeError = class extends Error {
/**
* Creates an instance of QSocketProtocolEncodeError.
*
* @param message - A descriptive error message.
* @param originalError - (Optional) The original error that caused this encoding error, if any.
*/
constructor(message, originalError) {
super(message);
this.originalError = originalError;
this.name = "QSocketProtocolEncodeError";
if (originalError) {
this.stack += `
Caused by: ${originalError.stack}`;
}
}
};
var QSocketProtocolDecodeError = class extends Error {
/**
* Creates an instance of QSocketProtocolDecodeError.
*
* @param message - A descriptive error message.
* @param originalError - (Optional) The original error that caused this decoding error, if any.
*/
constructor(message, originalError) {
super(message);
this.originalError = originalError;
this.name = "QSocketProtocolDecodeError";
if (originalError) {
this.stack += `
Caused by: ${originalError.stack}`;
}
}
};
// src/bin/protocol.ts
var encodeString = (() => {
if (typeof TextEncoder !== "undefined") {
const encoder = new TextEncoder();
return (str) => encoder.encode(str);
}
if (typeof Buffer !== "undefined") {
return (str) => {
const buffer = Buffer.from(str, "utf8");
const copy = new Uint8Array(buffer.length);
copy.set(buffer);
return copy;
};
}
return (str) => {
const maxLength = str.length * 4;
const result = new Uint8Array(maxLength);
let offset = 0;
for (let i = 0; i < str.length; i++) {
let charCode = str.charCodeAt(i);
if (charCode < 128) {
result[offset++] = charCode;
} else if (charCode < 2048) {
result[offset++] = 192 | charCode >> 6;
result[offset++] = 128 | charCode & 63;
} else if (charCode < 55296 || charCode >= 57344) {
result[offset++] = 224 | charCode >> 12;
result[offset++] = 128 | charCode >> 6 & 63;
result[offset++] = 128 | charCode & 63;
} else {
if (++i >= str.length) throw new Error("Invalid surrogate pair in string");
charCode = 65536 + ((charCode & 1023) << 10 | str.charCodeAt(i) & 1023);
result[offset++] = 240 | charCode >> 18;
result[offset++] = 128 | charCode >> 12 & 63;
result[offset++] = 128 | charCode >> 6 & 63;
result[offset++] = 128 | charCode & 63;
}
}
const resultBuffer = result.slice(0, offset);
return resultBuffer;
};
})();
var decodeString = (() => {
if (typeof TextDecoder !== "undefined") {
const decoder = new TextDecoder("utf-8");
return (bytes) => decoder.decode(bytes);
}
if (typeof Buffer !== "undefined") {
return (bytes) => Buffer.from(bytes).toString("utf8");
}
return (bytes) => {
let result = "";
let i = 0;
while (i < bytes.length) {
const byte1 = bytes[i++];
if (byte1 < 128) {
result += String.fromCharCode(byte1);
} else if (byte1 < 224) {
const byte2 = bytes[i++];
if ((byte2 & 192) !== 128) throw new Error("Invalid UTF-8 sequence");
result += String.fromCharCode((byte1 & 31) << 6 | byte2 & 63);
} else if (byte1 < 240) {
const byte2 = bytes[i++];
const byte3 = bytes[i++];
if ((byte2 & 192) !== 128 || (byte3 & 192) !== 128) throw new Error("Invalid UTF-8 sequence");
result += String.fromCharCode((byte1 & 15) << 12 | (byte2 & 63) << 6 | byte3 & 63);
} else {
const byte2 = bytes[i++];
const byte3 = bytes[i++];
const byte4 = bytes[i++];
if ((byte2 & 192) !== 128 || (byte3 & 192) !== 128 || (byte4 & 192) !== 128) throw new Error("Invalid UTF-8 sequence");
const codePoint = (byte1 & 7) << 18 | (byte2 & 63) << 12 | (byte3 & 63) << 6 | byte4 & 63;
const highSurrogate = 55296 + (codePoint - 65536 >> 10);
const lowSurrogate = 56320 + (codePoint - 65536 & 1023);
result += String.fromCharCode(highSurrogate, lowSurrogate);
}
}
return result;
};
})();
function writeUInt32BE(buffer, offset, value) {
buffer[offset] = value >>> 24 & 255;
buffer[offset + 1] = value >>> 16 & 255;
buffer[offset + 2] = value >>> 8 & 255;
buffer[offset + 3] = value & 255;
}
function readUInt32BE(buffer, offset) {
return (buffer[offset] << 24 | buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3]) >>> 0;
}
var staticDataViewBuffer = new Uint8Array(8);
var staticDataView = new DataView(staticDataViewBuffer.buffer);
function writeDoubleBE(buffer, offset, value) {
staticDataView.setFloat64(0, value, false);
buffer.set(staticDataViewBuffer, offset);
}
function readDoubleBE(buffer, offset) {
staticDataViewBuffer.set(buffer.subarray(offset, offset + 8));
return staticDataView.getFloat64(0, false);
}
function to(message) {
try {
let totalLength = 0;
const chunkBinaries = new Array(message.length);
let chunk;
let meta;
let data;
for (let i = 0; i < message.length; i++) {
chunk = message[i];
meta = encodeString(JSON.stringify(chunk.meta));
data = encodePayload(chunk);
totalLength += 1 + 4 + meta.length + 4 + data.length;
chunkBinaries[i] = {
encoding: chunk.payload["Content-Type"],
meta,
data
};
}
const messageBinary = new Uint8Array(totalLength);
let offset = 0;
let chunkBinary;
for (let i = 0; i < chunkBinaries.length; i++) {
chunkBinary = chunkBinaries[i];
messageBinary[offset] = chunkBinary.encoding;
offset += 1;
writeUInt32BE(messageBinary, offset, chunkBinary.meta.length);
offset += 4;
messageBinary.set(chunkBinary.meta, offset);
offset += chunkBinary.meta.length;
writeUInt32BE(messageBinary, offset, chunkBinary.data.length);
offset += 4;
messageBinary.set(chunkBinary.data, offset);
offset += chunkBinary.data.length;
}
return messageBinary;
} catch (error) {
throw new QSocketProtocolEncodeError(error.message);
}
}
function encodePayload(chunk) {
const { data } = chunk.payload;
const contentType = chunk.payload["Content-Type"];
switch (contentType) {
case 0 /* UNDEFINED */:
case 1 /* NULL */:
return new Uint8Array(0);
// No data for undefined or null
case 2 /* BOOLEAN */:
return new Uint8Array([data ? 1 : 0]);
// 1 byte representing boolean value
case 3 /* NUMBER */:
const numberBuffer = new Uint8Array(8);
writeDoubleBE(numberBuffer, 0, data);
return numberBuffer;
case 4 /* STRING */:
return encodeString(data);
// Encode the string
case 5 /* JSON */:
return encodeString(JSON.stringify(data));
// Encode the JSON string
case 6 /* BUFFER */:
if (data instanceof Uint8Array) {
return data;
} else if (data instanceof Buffer) {
return new Uint8Array(data);
} else {
throw new Error("Invalid data type for BUFFER content type");
}
default:
throw new Error("Unknown content type");
}
}
function from(buffer) {
try {
const message = [];
let offset = 0;
while (offset < buffer.length) {
const contentType = buffer[offset];
offset += 1;
const metaLength = readUInt32BE(buffer, offset);
offset += 4;
const metaString = decodeString(buffer.slice(offset, offset + metaLength));
let meta;
try {
meta = JSON.parse(metaString);
} catch (error) {
console.log("Failed to parse metadata");
throw error;
}
offset += metaLength;
const dataLength = readUInt32BE(buffer, offset);
offset += 4;
const data = decodePayloadData(buffer, contentType, offset, dataLength);
offset += dataLength;
message.push({
meta,
payload: {
data,
"Content-Type": contentType
}
});
}
return message;
} catch (error) {
throw new QSocketProtocolDecodeError(error.message);
}
}
function decodePayloadData(buffer, contentType, offset, length) {
switch (contentType) {
case 0 /* UNDEFINED */:
return void 0;
// No data for undefined
case 1 /* NULL */:
return null;
// No data for null
case 2 /* BOOLEAN */:
return buffer[offset] !== 0;
// Decode boolean value
case 3 /* NUMBER */:
return readDoubleBE(buffer, offset);
// Decode 64-bit float
case 4 /* STRING */:
return decodeString(buffer.slice(offset, offset + length));
// Decode string
case 5 /* JSON */:
return JSON.parse(decodeString(buffer.slice(offset, offset + length)));
// Decode JSON string
case 6 /* BUFFER */:
return buffer.slice(offset, offset + length);
// Return a slice of the buffer
default:
throw new Error("Unknown content type");
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
EQSocketProtocolContentType,
EQSocketProtocolMessageType,
QSocketProtocolDecodeError,
QSocketProtocolEncodeError,
from,
to
});
//# sourceMappingURL=index.cjs.map