Files
bl/common/serialize/Serialize.go
昔念 720294ad27 refactor(blazing): 重构项目并优化数据结构
- 更新 LoginUserInfo 结构体,将 uint64 类型改为 uint32
- 调整 ServerInfo 结构体,将 IP 字段从 []byte 改为 string
- 移除未使用的 ArraySerialize 结构体
- 更新 ByteArray 类,修改相关方法名
- 删除未使用的 serialize 相关代码
- 优化模块导入,移除冗余依赖
2025-06-22 12:05:07 +08:00

381 lines
9.6 KiB
Go
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.

package serialize
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tnnmigga/enum"
)
// DefaultPacketSerializer 默认序列化实现,使用大端序写入数据
func DefaultPacketSerializer[T any]() PacketSerializer[T] {
return func(data T) ([]byte, error) {
var buf bytes.Buffer
if err := binary.Write(&buf, binary.BigEndian, data); err != nil {
return nil, errors.New("binary.Write failed: " + err.Error())
}
// 使用大端序写入数据
// 1. 使用reflect获取结构体类型
// typ := reflect.TypeOf(data)
// fmt.Println("结构体类型名称:", typ.Name())
// fmt.Println("字段数量:", typ.NumField())
// for i := 0; i < typ.NumField(); i++ {
// field := typ.Field(i)
// fmt.Printf("字段名: %s, 类型: %s",
// field.Name, field.Type)
// fmt.Println("字段值:", reflect.ValueOf(data).Field(i).Interface())
// // writedata := reflect.ValueOf(data).Field(i).Interface()
// fmt.Println(field.Type.Kind())
// // serializebase[T](field, &buf, writedata)
// }
return buf.Bytes(), nil
}
}
// DefaultPacketDeserializer 默认反序列化实现,使用大端序读取数据
func DefaultPacketDeserializer[T any]() PacketDeserializer[T] {
return func(data []byte) (T, error) {
var result T
reader := bytes.NewReader(data)
// 使用大端序读取数据
if err := binary.Read(reader, binary.BigEndian, &result); err != nil {
var zero T
return zero, err
}
return result, nil
}
}
// NewDefaultPacketHandler 创建默认的数据包处理句柄
func NewDefaultPacketHandler[T any]() *PacketHandler[T] {
return &PacketHandler[T]{
Serialize: DefaultPacketSerializer[T](),
Deserialize: DefaultPacketDeserializer[T](),
}
}
type SerializeMode int
var lengthtype = enum.New[struct {
LENGTH_FIRST SerializeMode
FIXED_LENGTH SerializeMode
}]()
// PacketSerializer 定义序列化函数类型,将数据转换为字节切片
type PacketSerializer[T any] func(data T) ([]byte, error)
// PacketDeserializer 定义反序列化函数类型,将字节切片转换为数据
type PacketDeserializer[T any] func(data []byte) (T, error)
// PacketHandler 封装序列化和反序列化处理函数
type PacketHandler[T any] struct {
Serialize PacketSerializer[T] // 序列化函数
Deserialize PacketDeserializer[T] // 反序列化函数
}
// 定长序列化器
type FixedVarSerializer struct {
byteOrder binary.ByteOrder
}
// 新建序列化器
func NewFixedVarSerializer(order binary.ByteOrder) *FixedVarSerializer {
if order == nil {
order = binary.BigEndian
}
return &FixedVarSerializer{byteOrder: order}
}
// 序列化任意结构体
func (s *FixedVarSerializer) Serialize(obj interface{}) ([]byte, error) {
var buf bytes.Buffer
err := s.serializeValue(reflect.ValueOf(obj), &buf)
if err != nil {
return nil, fmt.Errorf("序列化失败: %w", err)
}
return buf.Bytes(), nil
}
// 递归序列化值
func (s *FixedVarSerializer) serializeValue(val reflect.Value, buf *bytes.Buffer) error {
kind := val.Kind()
switch kind {
case reflect.Struct:
return s.serializeStruct(val, buf)
case reflect.Slice, reflect.Array:
return s.serializeSlice(val, buf)
default:
if err := binary.Write(buf, s.byteOrder, val.Interface()); err != nil {
return nil
}
return nil
}
}
// 序列化结构体
func (s *FixedVarSerializer) serializeStruct(val reflect.Value, buf *bytes.Buffer) error {
typ := val.Type()
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
fieldVal := val.Field(i)
if !field.IsExported() {
continue
}
// 解析标签格式mode,params 如 fixed:16 或 varlen
tag := field.Tag.Get("serialize")
if tag == "" {
// 未指定标签:按原生类型序列化
err := s.serializeValue(fieldVal, buf)
if err != nil {
return err
}
continue
}
// 解析模式和参数
mode, params, err := parseTag(tag)
if err != nil {
return err
}
// 根据模式序列化
switch mode {
case lengthtype.FIXED_LENGTH:
err = s.serializeFixedField(fieldVal, params, buf)
case lengthtype.LENGTH_FIRST:
err = s.serializeVarWithLenField(fieldVal, params, buf)
default:
return fmt.Errorf("无效的序列化模式: %s", tag)
}
if err != nil {
return err
}
}
return nil
}
// 解析标签格式fixed:N 或 varlen 或 varlen:N
func parseTag(tag string) (SerializeMode, string, error) {
parts := splitTag(tag)
if len(parts) == 0 {
return 0, "", fmt.Errorf("空标签")
}
modeStr := parts[0]
params := ""
if len(parts) > 1 {
params = parts[1]
}
switch modeStr {
case "fixed":
if params == "" {
return 0, "", fmt.Errorf("fixed模式需指定长度")
}
return lengthtype.FIXED_LENGTH, params, nil
case "varlen":
// varlen模式可指定长度字段字节数如varlen:2表示用2字节存长度
if params == "" {
params = "4" // 默认用4字节存长度
}
return lengthtype.LENGTH_FIRST, params, nil
default:
return 0, "", fmt.Errorf("未知模式: %s", modeStr)
}
}
// 定长模式序列化字段
func (s *FixedVarSerializer) serializeFixedField(val reflect.Value, lengthStr string, buf *bytes.Buffer) error {
length, err := strconv.Atoi(lengthStr)
if err != nil {
return fmt.Errorf("无效的定长参数: %s", lengthStr)
}
return s.serializeFixedLengthValue(val, length, buf)
}
// 不定长+长度模式序列化字段
func (s *FixedVarSerializer) serializeVarWithLenField(val reflect.Value, lenBytesStr string, buf *bytes.Buffer) error {
lenBytes, err := strconv.Atoi(lenBytesStr)
if err != nil {
return fmt.Errorf("无效的长度字节数: %s", lenBytesStr)
}
if lenBytes < 1 || lenBytes > 8 {
return fmt.Errorf("长度字节数需在1-8之间")
}
// 先序列化内容到临时缓冲区
var contentBuf bytes.Buffer
err = s.serializeValue(val, &contentBuf)
if err != nil {
return err
}
content := contentBuf.Bytes()
// 写入长度(用指定字节数)
lenBuf := make([]byte, lenBytes)
switch lenBytesStr {
case "4":
s.byteOrder.PutUint32(lenBuf, uint32(len(content)))
case "2":
s.byteOrder.PutUint16(lenBuf, uint16(len(content)))
}
//s.byteOrder.PutUint32(lenBuf, uint32(len(content)))
buf.Write(lenBuf[:lenBytes])
// 写入内容
buf.Write(content)
return nil
}
// 序列化定长值
func (s *FixedVarSerializer) serializeFixedLengthValue(val reflect.Value, length int, buf *bytes.Buffer) error {
kind := val.Kind()
if kind == reflect.String {
str := val.String()
if len(str) > length {
str = str[:length]
}
buf.WriteString(str)
buf.Write(make([]byte, length-len(str)))
return nil
}
var tmpBuf bytes.Buffer
fmt.Println(val)
err := s.serializeValue(val, &tmpBuf)
if err != nil {
return err
}
tmpData := tmpBuf.Bytes()
if len(tmpData) > length {
buf.Write(tmpData[:length])
} else {
buf.Write(tmpData)
buf.Write(make([]byte, length-len(tmpData)))
}
return nil
}
// 序列化slice
func (s *FixedVarSerializer) serializeSlice(val reflect.Value, buf *bytes.Buffer) error {
tempslice := gconv.SliceAny(val)
fmt.Println(val)
//binary.Write(buf, s.byteOrder, val.Bytes())
for i := 0; i < len(tempslice); i++ {
err := s.serializeValue(val.Index(i), buf)
if err != nil {
return err
}
}
// for i := 0; i < len(tempslice); i++ {
// kind := val.Type().Elem().Field(i)
// tag := kind.Tag.Get("serialize")
// // 检查元素是否有标签
// if tag != "" {
// // 元素有标签:按定长模式处理
// mode, params, err := parseTag(tag)
// if err != nil {
// return err
// }
// if mode == lengthtype.FIXED_LENGTH {
// // 定长slice解析maxItems和itemLen
// parts := splitTag(params)
// if len(parts) != 2 {
// return fmt.Errorf("定长slice标签需格式为 fixed:N,M")
// }
// maxItems, _ := strconv.Atoi(parts[0])
// itemLen, _ := strconv.Atoi(parts[1])
// return s.serializeFixedSlice(val, maxItems, itemLen, buf)
// }
// }
// 无标签或不定长模式按原生slice处理先写长度再写元素
// count := val.Len()
// binary.Write(buf, s.byteOrder, int32(len(tempslice)))
// for i := 0; i < count; i++ {
// err := s.serializeValue(val.Index(i), buf)
// if err != nil {
// return err
// }
// }
return nil
//}
return nil
}
// 序列化定长slice
func (s *FixedVarSerializer) serializeFixedSlice(val reflect.Value, maxItems, itemLen int, buf *bytes.Buffer) error {
count := val.Len()
if count > maxItems {
count = maxItems
}
buf.WriteByte(byte(count))
for i := 0; i < maxItems; i++ {
if i < count {
item := val.Index(i)
tmpBuf := &bytes.Buffer{}
err := s.serializeValue(item, tmpBuf)
if err != nil {
return err
}
tmpData := tmpBuf.Bytes()
if len(tmpData) > itemLen {
buf.Write(tmpData[:itemLen])
} else {
buf.Write(tmpData)
buf.Write(make([]byte, itemLen-len(tmpData)))
}
} else {
buf.Write(make([]byte, itemLen))
}
}
return nil
}
// 辅助函数:分割标签参数
func splitTag(tag string) []string {
if tag == "" {
return nil
}
return strings.Split(tag, ":")
}
// 示例结构体(混合模式)
type Address struct {
City string `serialize:"fixed:20"` // 定长模式20字节
Country string `serialize:"varlen"` // 不定长模式先写4字节长度再写内容
}
type Person struct {
Name string `serialize:"fixed:16"` // 定长姓名
Age uint8 // 原生类型
Address Address // 嵌套结构体
Hobbies []string `serialize:"fixed:5,20"` // 定长slice5个元素每个20字节
Friends []Person `serialize:"varlen"` // 不定长slice先写长度再写内容
Metadata []float64 `serialize:"varlen:2"` // 不定长slice用2字节存长度
}