初始化项目

This commit is contained in:
2026-10-19 00:11:38 +08:00
commit 9545e48e4d
150 changed files with 9559 additions and 0 deletions
@@ -0,0 +1,73 @@
/**
* 协议帧编解码基座(1.4.11)。
*
* 帧格式(小端):
* [0..3] uint32 整帧长度(含头,6 + payload)
* [4..5] uint16 序号
* [6..] bytes 载荷
*
* 该格式与 MySQL / MariaDB 的 3 字节长度头不同,是引擎无关的内部封装层:
* 各引擎协议实现(1.4.3–1.4.10)在载荷里携带自己的报文,本层只负责
* 传输分帧、粘包拆分与错误长度防御。
*/
import { ConnectionError } from '../connection/types';
/** 一帧数据。 */
export class Frame {
readonly seq: number;
readonly payload: Uint8Array;
constructor(seq: number, payload: Uint8Array) {
this.seq = seq;
this.payload = payload;
}
}
export class FrameCodec {
/** 头长度:4 字节长度 + 2 字节序号。 */
static readonly HEADER_BYTES: number = 6;
/** 单帧载荷上限:16 MB。 */
static readonly MAX_PAYLOAD_BYTES: number = 16 * 1024 * 1024;
/** 组帧。载荷超限时抛 ConnectionError。 */
static encode(seq: number, payload: Uint8Array): Uint8Array {
if (payload.length > FrameCodec.MAX_PAYLOAD_BYTES) {
throw new ConnectionError('payload too large: ' + payload.length);
}
const total: number = FrameCodec.HEADER_BYTES + payload.length;
const out: Uint8Array = new Uint8Array(total);
out[0] = total & 0xFF;
out[1] = (total >>> 8) & 0xFF;
out[2] = (total >>> 16) & 0xFF;
out[3] = (total >>> 24) & 0xFF;
out[4] = seq & 0xFF;
out[5] = (seq >>> 8) & 0xFF;
out.set(payload, FrameCodec.HEADER_BYTES);
return out;
}
/** 读取头部声明的整帧长度;不足 4 字节返回 -1。 */
static frameLength(header: Uint8Array): number {
if (header.length < 4) {
return -1;
}
return header[0] | (header[1] << 8) | (header[2] << 16) | (header[3] << 24);
}
/** 解出第一帧;数据不足返回 undefined(由调用方继续收)。 */
static decode(buffer: Uint8Array): Frame | undefined {
const total: number = FrameCodec.frameLength(buffer);
if (total < 0) {
return undefined;
}
if (total < FrameCodec.HEADER_BYTES || total > FrameCodec.HEADER_BYTES + FrameCodec.MAX_PAYLOAD_BYTES) {
throw new ConnectionError('invalid frame length: ' + total);
}
if (buffer.length < total) {
return undefined;
}
const seq: number = buffer[4] | (buffer[5] << 8);
return new Frame(seq, buffer.slice(FrameCodec.HEADER_BYTES, total));
}
}