spark-server/internal/transport/tcp/protocol/payload.go
2026-09-16 19:08:06 +08:00

147 lines
3.4 KiB
Go

package protocol
import (
"spark-server/internal/pkg/errs"
"google.golang.org/protobuf/encoding/protowire"
)
type AuthRequest struct {
Token string
DeviceID uint64
AppVersion string
Language string
}
type AuthResponse struct {
UserID int64
DeviceID uint64
}
type ErrorBody struct {
Code int32
Message string
}
func EncodeAuthRequest(a AuthRequest) []byte {
out := appendStringField(nil, 1, a.Token)
out = appendVarintField(out, 2, a.DeviceID)
out = appendStringField(out, 3, a.AppVersion)
out = appendStringField(out, 4, a.Language)
return out
}
func DecodeAuthRequest(body []byte) (AuthRequest, error) {
var req AuthRequest
for len(body) > 0 {
num, typ, tagLen := protowire.ConsumeTag(body)
if tagLen < 0 {
return AuthRequest{}, errs.ErrInvalidFrame
}
body = body[tagLen:]
val, n, err := consumeField(typ, body)
if err != nil {
return AuthRequest{}, err
}
body = body[n:]
assignAuth(&req, num, typ, val)
}
return req, nil
}
func assignAuth(req *AuthRequest, num protowire.Number, typ protowire.Type, val []byte) {
switch {
case num == 1 && typ == protowire.BytesType:
req.Token = string(val)
case num == 2 && typ == protowire.VarintType:
v, _ := protowire.ConsumeVarint(val)
req.DeviceID = v
case num == 3 && typ == protowire.BytesType:
req.AppVersion = string(val)
case num == 4 && typ == protowire.BytesType:
req.Language = string(val)
}
}
func EncodeAuthResponse(a AuthResponse) []byte {
out := appendVarintField(nil, 1, uint64(a.UserID))
return appendVarintField(out, 2, a.DeviceID)
}
func EncodeError(e ErrorBody) []byte {
out := appendVarintField(nil, 1, uint64(e.Code))
return appendStringField(out, 2, e.Message)
}
// DecodeError reads a protobuf-wire error payload.
func DecodeError(body []byte) (ErrorBody, error) {
var out ErrorBody
for len(body) > 0 {
num, typ, tagLen := protowire.ConsumeTag(body)
if tagLen < 0 {
return ErrorBody{}, errs.ErrInvalidFrame
}
body = body[tagLen:]
val, n, err := consumeField(typ, body)
if err != nil {
return ErrorBody{}, err
}
body = body[n:]
if num == 1 && typ == protowire.VarintType {
v, _ := protowire.ConsumeVarint(val)
out.Code = int32(v)
}
if num == 2 && typ == protowire.BytesType {
out.Message = string(val)
}
}
return out, nil
}
func EncodeMsgID(id int64) []byte {
return appendVarintField(nil, 1, uint64(id))
}
func EncodeKick(reason string) []byte {
return appendStringField(nil, 1, reason)
}
func appendStringField(out []byte, field protowire.Number, s string) []byte {
if s == "" {
return out
}
out = protowire.AppendVarint(out, protowire.EncodeTag(field, protowire.BytesType))
return protowire.AppendString(out, s)
}
func appendVarintField(out []byte, field protowire.Number, v uint64) []byte {
if v == 0 {
return out
}
out = protowire.AppendVarint(out, protowire.EncodeTag(field, protowire.VarintType))
return protowire.AppendVarint(out, v)
}
func consumeField(typ protowire.Type, body []byte) ([]byte, int, error) {
switch typ {
case protowire.VarintType:
v, n := protowire.ConsumeVarint(body)
if n < 0 {
return nil, 0, errs.ErrInvalidFrame
}
return protowire.AppendVarint(nil, v), n, nil
case protowire.BytesType:
v, n := protowire.ConsumeBytes(body)
if n < 0 {
return nil, 0, errs.ErrInvalidFrame
}
return append([]byte(nil), v...), n, nil
default:
n := protowire.ConsumeFieldValue(1, typ, body)
if n < 0 {
return nil, 0, errs.ErrInvalidFrame
}
return nil, n, nil
}
}