Files
dbmgr-hmos/engine/src/main/ets/protocol/FrameCodec.ets
T
2026-10-19 00:11:38 +08:00

74 lines
2.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 协议帧编解码基座(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));
}
}