import { BinaryReader, MessageType, RepeatType, ScalarType, WireType } from '@protobuf-ts/runtime'; import type { PartialFieldInfo } from '@protobuf-ts/runtime'; // 值包装类 export class ValueWrapper { public _value: T; public _fieldId: number; public _opt: boolean; public _callback?: Function; constructor(field: number, value: T, opt: boolean, callback?: Function) { this._value = value; this._fieldId = field; this._opt = opt; this._callback = callback; } public get value(): T { return this._value; } public set value(newValue: T) { this._value = newValue; } public getTypeName(): string { return this.constructor.name; } public getFieldId() { return this._fieldId; } public getField(key: string): PartialFieldInfo { return autoTypeToField(key, this); } } export class DoubleWrapper extends ValueWrapper { getTypeName() { return "DoubleWrapper"; } } export class FloatWrapper extends ValueWrapper { getTypeName() { return "FloatWrapper"; } } export class StringWrapper extends ValueWrapper { getTypeName() { return "StringWrapper"; } } export class UInt32Wrapper extends ValueWrapper { getTypeName() { return "UInt32Wrapper"; } } export class Int32Wrapper extends ValueWrapper { getTypeName() { return "Int32Wrapper"; } } export class Int64Wrapper extends ValueWrapper { getTypeName() { return "Int64Wrapper"; } } export class UInt64Wrapper extends ValueWrapper { getTypeName() { return "UInt64Wrapper"; } } export class ArrayWrapper extends ValueWrapper { getTypeName() { return "ArrayWrapper"; } } export class BoolWrapper extends ValueWrapper { getTypeName() { return "BoolWrapper"; } } export class BytesWrapper extends ValueWrapper { getTypeName() { return "BytesWrapper"; } } export class Fixed64Wrapper extends ValueWrapper { getTypeName() { return "Fixed64Wrapper"; } } export class Fixed32Wrapper extends ValueWrapper { getTypeName() { return "Fixed32Wrapper"; } } export class SFixed32Wrapper extends ValueWrapper { getTypeName() { return "SFixed32Wrapper"; } } export class SFixed64Wrapper extends ValueWrapper { getTypeName() { return "SFixed64Wrapper"; } } export class SInt32Wrapper extends ValueWrapper { getTypeName() { return "SInt32Wrapper"; } } export class SInt64Wrapper extends ValueWrapper { getTypeName() { return "SInt64Wrapper"; } } export class UnknownWrapper extends ValueWrapper { getTypeName() { return "UnknownWrapper"; } } // 类型提取工具 export type ExtractType = T extends ArrayWrapper ? V[] : T extends ValueWrapper ? U : T extends ProtoBufBase ? ExtractSchema : T; export type ExtractSchema = Omit<{ [K in keyof T]: T[K] extends ProtoBufBase ? ExtractSchema : ExtractType; }, keyof ProtoBufBase>; const NameDataKeys = { UInt32Wrapper: "UInt32Wrapper", Int32Wrapper: "Int32Wrapper", Int64Wrapper: "Int64Wrapper", UInt64Wrapper: "UInt64Wrapper", StringWrapper: "StringWrapper", ArrayWrapper: "ArrayWrapper", BoolWrapper: "BoolWrapper", BytesWrapper: "BytesWrapper", DoubleWrapper: "DoubleWrapper", FloatWrapper: "FloatWrapper", Fixed64Wrapper: "Fixed64Wrapper", Fixed32Wrapper: "Fixed32Wrapper", SFixed32Wrapper: "SFixed32Wrapper", SFixed64Wrapper: "SFixed64Wrapper", SInt32Wrapper: "SInt32Wrapper", SInt64Wrapper: "SInt64Wrapper", UnknownWrapper: "UnknownWrapper", } // 类型映射工具 const typeMap = { [NameDataKeys.UInt32Wrapper]: UInt32Wrapper, [NameDataKeys.Int32Wrapper]: Int32Wrapper, [NameDataKeys.Int64Wrapper]: Int64Wrapper, [NameDataKeys.UInt64Wrapper]: UInt64Wrapper, [NameDataKeys.StringWrapper]: StringWrapper, [NameDataKeys.ArrayWrapper]: ArrayWrapper, [NameDataKeys.BoolWrapper]: BoolWrapper, [NameDataKeys.BytesWrapper]: BytesWrapper, [NameDataKeys.DoubleWrapper]: DoubleWrapper, [NameDataKeys.FloatWrapper]: FloatWrapper, [NameDataKeys.Fixed64Wrapper]: Fixed64Wrapper, [NameDataKeys.Fixed32Wrapper]: Fixed32Wrapper, [NameDataKeys.SFixed32Wrapper]: SFixed32Wrapper, [NameDataKeys.SFixed64Wrapper]: SFixed64Wrapper, [NameDataKeys.SInt32Wrapper]: SInt32Wrapper, [NameDataKeys.SInt64Wrapper]: SInt64Wrapper, [NameDataKeys.UnknownWrapper]: UnknownWrapper, }; const scalarMap: { [key: string]: ScalarType } = { [NameDataKeys.UInt32Wrapper]: ScalarType.UINT32, [NameDataKeys.Int32Wrapper]: ScalarType.INT32, [NameDataKeys.Int64Wrapper]: ScalarType.INT64, [NameDataKeys.UInt64Wrapper]: ScalarType.UINT64, [NameDataKeys.StringWrapper]: ScalarType.STRING, [NameDataKeys.BytesWrapper]: ScalarType.BYTES, [NameDataKeys.BoolWrapper]: ScalarType.BOOL, [NameDataKeys.DoubleWrapper]: ScalarType.DOUBLE, [NameDataKeys.FloatWrapper]: ScalarType.FLOAT, [NameDataKeys.Fixed64Wrapper]: ScalarType.FIXED64, [NameDataKeys.Fixed32Wrapper]: ScalarType.FIXED32, [NameDataKeys.SFixed32Wrapper]: ScalarType.SFIXED32, [NameDataKeys.SFixed64Wrapper]: ScalarType.SFIXED64, [NameDataKeys.SInt32Wrapper]: ScalarType.SINT32, [NameDataKeys.SInt64Wrapper]: ScalarType.SINT64, [NameDataKeys.UnknownWrapper]: ScalarType.BYTES, }; export function autoTypeToClass(typeName: string) { return typeMap[typeName] || UnknownWrapper; } function autoTypeToScalar(typeName: string) { return scalarMap[typeName] || ScalarType.BYTES; } // 默认值创建构造类 export function PBArray(field: number = 0, data: T, opt: boolean = false, value: T[] = []) { return new ArrayWrapper(field, value, opt, () => data) as unknown as Omit[]; } export function PBDouble(field: number = 0, opt: boolean = false, value = 0) { return new DoubleWrapper(field, value, opt) as unknown as number; } export function PBFloat(field: number = 0, opt: boolean = false, value = 0) { return new FloatWrapper(field, value, opt) as unknown as number; } export function PBString(field: number = 0, opt: boolean = false, value = "") { return new StringWrapper(field, value, opt) as unknown as string; } export function PBUint32(field: number = 0, opt: boolean = false, value = 0) { return new UInt32Wrapper(field, value, opt) as unknown as number; } export function PBInt32(field: number = 0, opt: boolean = false, value = 0) { return new Int32Wrapper(field, value, opt) as unknown as number; } export function PBInt64(field: number = 0, opt: boolean = false, value = BigInt(0)) { return new Int64Wrapper(field, value, opt) as unknown as bigint; } export function PBUint64(field: number = 0, opt: boolean = false, value = BigInt(0)) { return new UInt64Wrapper(field, value, opt) as unknown as bigint; } export function PBBool(field: number = 0, opt: boolean = false, value = false) { return new BoolWrapper(field, value, opt) as unknown as boolean; } export function PBBytes(field: number = 0, opt: boolean = false, value = new Uint8Array()) { return new BytesWrapper(field, value, opt) as unknown as Uint8Array; } export function PBFixed64(field: number = 0, opt: boolean = false, value = BigInt(0)) { return new Fixed64Wrapper(field, value, opt) as unknown as bigint; } export function PBFixed32(field: number = 0, opt: boolean = false, value = 0) { return new Fixed32Wrapper(field, value, opt) as unknown as number; } export function PBSFixed32(field: number = 0, opt: boolean = false, value = 0) { return new SFixed32Wrapper(field, value, opt) as unknown as number; } export function PBSFixed64(field: number = 0, opt: boolean = false, value = BigInt(0)) { return new SFixed64Wrapper(field, value, opt) as unknown as bigint; } export function PBSInt32(field: number = 0, opt: boolean = false, value = 0) { return new SInt32Wrapper(field, value, opt) as unknown as number; } export function PBSInt64(field: number = 0, opt: boolean = false, value = BigInt(0)) { return new SInt64Wrapper(field, value, opt) as unknown as bigint; } export function autoTypeToField(key: string, dataValue: ValueWrapper): PartialFieldInfo { const typeName = dataValue.getTypeName(); const no = dataValue.getFieldId(); const opt = dataValue._opt; if (typeName === NameDataKeys.ArrayWrapper) { const item = dataValue._callback?.(); if (item instanceof ProtoBufBase) { return { no, name: key, kind: 'message', T: () => new MessageType(key, item.generateFields()), opt: opt || false, repeat: RepeatType.PACKED, } as PartialFieldInfo; } if (item instanceof ValueWrapper) { const itemType = item.getTypeName(); return { no, name: key, kind: 'scalar', T: autoTypeToScalar(itemType), opt: opt || false, repeat: itemType === NameDataKeys.StringWrapper || itemType === NameDataKeys.BytesWrapper ? RepeatType.UNPACKED : RepeatType.PACKED, } as PartialFieldInfo; } throw new Error("ArrayWrapper item type error"); } return { no, name: key, kind: 'scalar', T: autoTypeToScalar(typeName), opt: opt || false, repeat: RepeatType.NO, } as PartialFieldInfo; } // Protobuf标记类 export class ProtoBufBase { public _fieldId: number = 0; //默认标记类 public generateFields(): PartialFieldInfo[] { const fields: PartialFieldInfo[] = []; for (const innerKey of Object.keys(this)) { const key = '_' + innerKey; const value = this[key as keyof this]; if (value instanceof ValueWrapper) { fields.push(value.getField(innerKey)); } if (value instanceof ProtoBufBase) { fields.push({ no: value._fieldId, name: innerKey, kind: 'message', T: () => new MessageType(key, value.generateFields()), repeat: RepeatType.NO, opt: false, }); } } return fields; } public assignFields(fields: { [key: string]: unknown }) { for (const innerKey of Object.keys(this)) { const key = '_' + innerKey; let value = this[key as keyof this]; if (value instanceof ValueWrapper) { const fieldValue = fields[innerKey]; if (fieldValue !== undefined) { value.value = fieldValue; } } else if (value instanceof ProtoBufBase) { const fieldValue = fields[innerKey]; if (fieldValue !== undefined) { value.assignFields(fieldValue as { [key: string]: unknown }); } } else { const fieldValue = fields[innerKey]; if (fieldValue !== undefined) { this[key as keyof this] = fieldValue as typeof value; } } } } public toObject(): Omit { const obj: { [key: string]: unknown } = {}; for (const innerKey of Object.keys(this)) { const key = '_' + innerKey; const value = this[key as keyof this]; if (value) { if (value instanceof ValueWrapper) { obj[innerKey] = value.value; } if (value instanceof ProtoBufBase) { obj[innerKey] = value.toObject(); } } } return obj as Omit; } public encode(): Uint8Array { return new MessageType("message", this.generateFields()).toBinary(this.toObject()); } public decode(data: Uint8Array) { const pbData = new MessageType("message", this.generateFields()).fromBinary(data); this.assignFields(pbData as { [key: string]: unknown }); return this; } public then(callback: (data: this) => void) { callback(this); } } export function proxyClassProtobuf(protobuf: T): T { return new Proxy(protobuf, { set(target, prop, value) { const targetValue = target[prop as keyof T]; if (targetValue instanceof ValueWrapper) { // 是否引用决定 // const WrapperClass = autoTypeToClass(targetValue.getTypeName()); // target[prop as keyof T] = new WrapperClass(targetValue._fieldId, value, targetValue._opt) as typeof targetValue; (target[prop as keyof T] as ValueWrapper).value = value; return true; } target[prop as keyof T] = value; return true; }, get(target, prop) { if (typeof prop === "string" && prop.startsWith("_")) { const key = prop.slice(1); if (target[key as keyof T]) { return target[key as keyof T]; } } const targetValue = target[prop as keyof T]; if (targetValue instanceof ValueWrapper) { return targetValue.value; } return targetValue; } }) as T; } // 代理创建工具 export function ProtoBuf(field: number, valueClass: new () => T): T; export function ProtoBuf(valueClass: new () => T): T; export function ProtoBuf(data: number | (new () => T), valueClass?: new () => T): T { const dataClass = proxyClassProtobuf(valueClass ? new valueClass() : new (data as new () => T)()); dataClass._fieldId = typeof data === "number" ? data : 0; return dataClass; } export function ProtoBufEx>(valueClass: new () => T, value?: U): T { const dataClass = proxyClassProtobuf(new valueClass()); if (value) { dataClass.assignFields(value); } return dataClass; } export function ProtoBufQuick(pb: T, data: U): ProtoBufBase { let protobuf = class extends ProtoBufBase { }; const instance = ProtoBuf(protobuf); Object.assign(instance, pb); instance.assignFields(data); return instance; } export function ProtoBufIn(field: number, data: T): T; export function ProtoBufIn(data: T): T; export function ProtoBufIn(data: number | T, value?: T): T { if (typeof data === "number") { let dataclass = new class extends ProtoBufBase { constructor() { super(); Object.assign(this, value); } } as ProtoBufBase; dataclass._fieldId = data; return proxyClassProtobuf(dataclass) as T; } return proxyClassProtobuf(new class extends ProtoBufBase { constructor() { super(); Object.assign(this, data); } } as ProtoBufBase) as T; } export function UnWrap(data: T) { return (data as ValueWrapper).value as T; } export function decodeProtoBuf(typeName: string, message: any, fieldNo: number, wireType: WireType, data: Uint8Array, encodeBytes?: (data: Uint8Array) => T) { let value; const reader = new BinaryReader(data); switch (wireType) { case WireType.Varint: value = reader.uint64(); value = value.hi > 0 ? value.toBigInt() : Number(value.lo); break; case WireType.Bit64: value = reader.fixed64(); break; case WireType.LengthDelimited: let data = reader.bytes(); try { value = ProtoBufDecode(data); } catch (error) { try { value = new TextDecoder().decode(data); if (value.indexOf('�') !== -1) { throw new Error('Invalid UTF-8 sequence in input'); } } catch (error) { if (encodeBytes) { value = encodeBytes(data); } else { value = data; } } } break; case WireType.StartGroup: case WireType.EndGroup: // Groups are deprecated and not supported break; case WireType.Bit32: value = reader.fixed32(); break; default: throw new Error(`Unknown wire type: ${wireType}`); } if (message[fieldNo]) { if (message[fieldNo] instanceof Array) { message[fieldNo].push(value); } else { message[fieldNo] = [message[fieldNo], value]; } } else { message[fieldNo] = value; } } export function ProtoBufDecode(data: Uint8Array, encodeBytes?: (data: Uint8Array) => T) { const messageType = new MessageType("message", []); const decodedMessage = messageType.fromBinary(data, { readUnknownField: (typeName, message, fieldNo, wireType, data) => decodeProtoBuf(typeName, message, fieldNo, wireType, data, encodeBytes), }); return decodedMessage; } export class ChainProto extends ProtoBufBase { push(data: T) { Object.assign(this, data); return this; } }