Files
fanqie-go/internal/algos/protobuf.go
T
chenxin 6981148727 🔧 chore: 初始化番茄小说 API 项目结构
新增项目基础框架,包含核心 API 实现、算法模块、HTTP 处理器等完整功能模块
2026-08-28 15:22:22 +08:00

405 lines
9.1 KiB
Go

package algos
import (
"fmt"
)
// ProtoFieldType 协议字段类型
type ProtoFieldType int
const (
ProtoFieldTypeVARINT ProtoFieldType = 0
ProtoFieldTypeINT64 ProtoFieldType = 1
ProtoFieldTypeSTRING ProtoFieldType = 2
ProtoFieldTypeGROUPSTART ProtoFieldType = 3
ProtoFieldTypeGROUPEND ProtoFieldType = 4
ProtoFieldTypeINT32 ProtoFieldType = 5
ProtoFieldTypeERROR1 ProtoFieldType = 6
ProtoFieldTypeERROR2 ProtoFieldType = 7
)
// ProtoField 协议字段
type ProtoField struct {
Idx int
Type ProtoFieldType
Val interface{}
}
// NewProtoField 创建新的协议字段
func NewProtoField(idx int, fieldType ProtoFieldType, val interface{}) *ProtoField {
return &ProtoField{
Idx: idx,
Type: fieldType,
Val: val,
}
}
// IsAsciiStr 检查是否为ASCII字符串
func (pf *ProtoField) IsAsciiStr() bool {
if data, ok := pf.Val.([]byte); ok {
for _, b := range data {
if b < 0x20 || b > 0x7E {
return false
}
}
return true
}
return false
}
// ProtoReader 协议读取器
type ProtoReader struct {
data []byte
pos int
}
// NewProtoReader 创建新的协议读取器
func NewProtoReader(data []byte) *ProtoReader {
return &ProtoReader{
data: data,
pos: 0,
}
}
// Seek 设置位置
func (pr *ProtoReader) Seek(pos int) {
pr.pos = pos
}
// IsRemain 检查是否还有剩余数据
func (pr *ProtoReader) IsRemain(length int) bool {
return pr.pos+length <= len(pr.data)
}
// Read0 读取一个字节
func (pr *ProtoReader) Read0() byte {
if !pr.IsRemain(1) {
panic("buffer overflow")
}
ret := pr.data[pr.pos]
pr.pos++
return ret & 0xFF
}
// Read 读取指定长度的字节
func (pr *ProtoReader) Read(length int) []byte {
if !pr.IsRemain(length) {
panic("buffer overflow")
}
ret := pr.data[pr.pos : pr.pos+length]
pr.pos += length
return ret
}
// ReadInt32 读取32位整数
func (pr *ProtoReader) ReadInt32() uint32 {
bytes := pr.Read(4)
return uint32(bytes[0]) | uint32(bytes[1])<<8 | uint32(bytes[2])<<16 | uint32(bytes[3])<<24
}
// ReadInt64 读取64位整数
func (pr *ProtoReader) ReadInt64() uint64 {
bytes := pr.Read(8)
return uint64(bytes[0]) | uint64(bytes[1])<<8 | uint64(bytes[2])<<16 | uint64(bytes[3])<<24 |
uint64(bytes[4])<<32 | uint64(bytes[5])<<40 | uint64(bytes[6])<<48 | uint64(bytes[7])<<56
}
// ReadVarint 读取可变长度整数
func (pr *ProtoReader) ReadVarint() uint64 {
vint := uint64(0)
n := 0
for {
b := pr.Read0()
vint |= uint64(b&0x7F) << (7 * n)
if b < 0x80 {
break
}
n++
}
return vint
}
// ReadString 读取字符串
func (pr *ProtoReader) ReadString() []byte {
length := pr.ReadVarint()
return pr.Read(int(length))
}
// ProtoWriter 协议写入器
type ProtoWriter struct {
data []byte
}
// NewProtoWriter 创建新的协议写入器
func NewProtoWriter() *ProtoWriter {
return &ProtoWriter{
data: make([]byte, 0),
}
}
// Write0 写入一个字节
func (pw *ProtoWriter) Write0(b byte) {
pw.data = append(pw.data, b&0xFF)
}
// Write 写入字节数组
func (pw *ProtoWriter) Write(bytes []byte) {
pw.data = append(pw.data, bytes...)
}
// WriteInt32 写入32位整数
func (pw *ProtoWriter) WriteInt32(val uint32) {
bs := []byte{
byte(val & 0xFF),
byte((val >> 8) & 0xFF),
byte((val >> 16) & 0xFF),
byte((val >> 24) & 0xFF),
}
pw.Write(bs)
}
// WriteInt64 写入64位整数
func (pw *ProtoWriter) WriteInt64(val uint64) {
bs := []byte{
byte(val & 0xFF),
byte((val >> 8) & 0xFF),
byte((val >> 16) & 0xFF),
byte((val >> 24) & 0xFF),
byte((val >> 32) & 0xFF),
byte((val >> 40) & 0xFF),
byte((val >> 48) & 0xFF),
byte((val >> 56) & 0xFF),
}
pw.Write(bs)
}
// WriteVarint 写入可变长度整数
func (pw *ProtoWriter) WriteVarint(vint uint64) {
vint = vint & 0xFFFFFFFF
for vint > 0x80 {
pw.Write0(byte((vint & 0x7F) | 0x80))
vint >>= 7
}
pw.Write0(byte(vint & 0x7F))
}
// WriteString 写入字符串
func (pw *ProtoWriter) WriteString(bytes []byte) {
pw.WriteVarint(uint64(len(bytes)))
pw.Write(bytes)
}
// ToBytes 转换为字节数组
func (pw *ProtoWriter) ToBytes() []byte {
return pw.data
}
// ProtoBuf 协议缓冲区
type ProtoBuf struct {
fields []*ProtoField
}
// NewProtoBuf 创建新的协议缓冲区
func NewProtoBuf(data interface{}) *ProtoBuf {
pb := &ProtoBuf{
fields: make([]*ProtoField, 0),
}
if data != nil {
switch v := data.(type) {
case []byte:
if len(v) > 0 {
pb.parseBuf(v)
}
case map[int]interface{}:
if len(v) > 0 {
pb.parseDict(v)
}
default:
panic(fmt.Sprintf("unsupported type(%T) to protobuf", data))
}
}
return pb
}
// parseBuf 解析字节数组
func (pb *ProtoBuf) parseBuf(bytes []byte) {
reader := NewProtoReader(bytes)
for reader.IsRemain(1) {
key := reader.ReadVarint()
fieldType := ProtoFieldType(key & 0x7)
fieldIdx := int(key >> 3)
if fieldIdx == 0 {
break
}
switch fieldType {
case ProtoFieldTypeINT32:
pb.Put(NewProtoField(fieldIdx, fieldType, reader.ReadInt32()))
case ProtoFieldTypeINT64:
pb.Put(NewProtoField(fieldIdx, fieldType, reader.ReadInt64()))
case ProtoFieldTypeVARINT:
pb.Put(NewProtoField(fieldIdx, fieldType, reader.ReadVarint()))
case ProtoFieldTypeSTRING:
pb.Put(NewProtoField(fieldIdx, fieldType, reader.ReadString()))
default:
panic(fmt.Sprintf("parse protobuf error, unexpected field type: %d", fieldType))
}
}
}
// ToBuf 转换为字节数组
func (pb *ProtoBuf) ToBuf() []byte {
writer := NewProtoWriter()
for _, field := range pb.fields {
key := uint64((field.Idx << 3) | int(field.Type&7))
writer.WriteVarint(key)
switch field.Type {
case ProtoFieldTypeINT32:
writer.WriteInt32(field.Val.(uint32))
case ProtoFieldTypeINT64:
writer.WriteInt64(field.Val.(uint64))
case ProtoFieldTypeVARINT:
writer.WriteVarint(field.Val.(uint64))
case ProtoFieldTypeSTRING:
writer.WriteString(field.Val.([]byte))
default:
panic(fmt.Sprintf("encode to protobuf error, unexpected field type: %d", field.Type))
}
}
return writer.ToBytes()
}
// Get 获取字段
func (pb *ProtoBuf) Get(idx int) *ProtoField {
for _, field := range pb.fields {
if field.Idx == idx {
return field
}
}
return nil
}
// GetList 获取字段列表
func (pb *ProtoBuf) GetList(idx int) []*ProtoField {
result := make([]*ProtoField, 0)
for _, field := range pb.fields {
if field.Idx == idx {
result = append(result, field)
}
}
return result
}
// GetInt 获取整数
func (pb *ProtoBuf) GetInt(idx int) uint64 {
pf := pb.Get(idx)
if pf == nil {
return 0
}
switch pf.Type {
case ProtoFieldTypeINT32:
return uint64(pf.Val.(uint32))
case ProtoFieldTypeINT64:
return pf.Val.(uint64)
case ProtoFieldTypeVARINT:
return pf.Val.(uint64)
default:
panic(fmt.Sprintf("getInt(%d) -> %d", idx, pf.Type))
}
}
// GetBytes 获取字节数组
func (pb *ProtoBuf) GetBytes(idx int) []byte {
pf := pb.Get(idx)
if pf == nil {
return nil
}
if pf.Type == ProtoFieldTypeSTRING {
return pf.Val.([]byte)
}
panic(fmt.Sprintf("getBytes(%d) -> %d", idx, pf.Type))
}
// GetUTF8 获取UTF8字符串
func (pb *ProtoBuf) GetUTF8(idx int) string {
bs := pb.GetBytes(idx)
if bs == nil {
return ""
}
return string(bs)
}
// GetProtoBuf 获取嵌套的ProtoBuf
func (pb *ProtoBuf) GetProtoBuf(idx int) *ProtoBuf {
bs := pb.GetBytes(idx)
if bs == nil {
return nil
}
return NewProtoBuf(bs)
}
// Put 添加字段
func (pb *ProtoBuf) Put(field *ProtoField) {
pb.fields = append(pb.fields, field)
}
// PutInt32 添加32位整数
func (pb *ProtoBuf) PutInt32(idx int, val uint32) {
pb.Put(NewProtoField(idx, ProtoFieldTypeINT32, val))
}
// PutInt64 添加64位整数
func (pb *ProtoBuf) PutInt64(idx int, val uint64) {
pb.Put(NewProtoField(idx, ProtoFieldTypeINT64, val))
}
// PutVarint 添加可变长度整数
func (pb *ProtoBuf) PutVarint(idx int, val uint64) {
pb.Put(NewProtoField(idx, ProtoFieldTypeVARINT, val))
}
// PutBytes 添加字节数组
func (pb *ProtoBuf) PutBytes(idx int, data []byte) {
pb.Put(NewProtoField(idx, ProtoFieldTypeSTRING, data))
}
// PutUTF8 添加UTF8字符串
func (pb *ProtoBuf) PutUTF8(idx int, data string) {
pb.Put(NewProtoField(idx, ProtoFieldTypeSTRING, []byte(data)))
}
// PutProtoBuf 添加嵌套的ProtoBuf
func (pb *ProtoBuf) PutProtoBuf(idx int, data *ProtoBuf) {
pb.Put(NewProtoField(idx, ProtoFieldTypeSTRING, data.ToBuf()))
}
// parseDict 解析字典
func (pb *ProtoBuf) parseDict(data map[int]interface{}) {
for k, v := range data {
switch val := v.(type) {
case int:
pb.PutVarint(k, uint64(val))
case uint64:
pb.PutVarint(k, val)
case int64:
pb.PutVarint(k, uint64(val))
case string:
pb.PutUTF8(k, val)
case []byte:
pb.PutBytes(k, val)
case map[int]interface{}:
pb.PutProtoBuf(k, NewProtoBuf(val))
default:
panic(fmt.Sprintf("unsupported type(%T) to protobuf", v))
}
}
}