147 lines
3.4 KiB
Go
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
|
|
}
|
|
}
|