This commit is contained in:
2022-03-17 15:55:27 +08:00
commit bd5a9fad97
92 changed files with 13861 additions and 0 deletions

1294
api/comet/grpc/comet.pb.go Normal file

File diff suppressed because it is too large Load Diff

109
api/comet/grpc/comet.proto Normal file
View File

@@ -0,0 +1,109 @@
// protoc -I=. -I=$GOPATH/src --go_out=plugins=grpc:. *.proto
syntax = "proto3";
package im.comet;
option go_package = "gitlab.33.cn/chat/im/api/comet/grpc";
message Proto {
int32 ver = 1;
int32 op = 2;
int32 seq = 3;
int32 ack = 4;
bytes body = 5;
}
enum Op {
Undefined = 0;
Auth = 1;
AuthReply = 2;
Heartbeat = 3;
HeartbeatReply = 4;
Disconnect = 5;
DisconnectReply = 6;
SendMsg = 7;
SendMsgReply = 8; //客户端回复消息已收到
ReceiveMsg = 9;
ReceiveMsgReply = 10;
ProtoReady = 11;
ProtoFinish = 12;
Raw = 13;
SyncMsgReq = 14;
SyncMsgReply = 15;
RePush = 16;
}
// Proto 中 Op 为 OpAuth 时, body 必须可以反序列化为 AuthMsg
message AuthMsg {
string appId = 1;
string token = 2;
bytes ext = 3; // 其它业务方可能需要的信息
}
// Proto 中 Op 为 SyncMsgReply 时, body 必须可以反序列化为 SyncMsg
message SyncMsg {
int64 logId = 1;
}
message Empty{}
message PushMsgReq {
repeated string keys = 1;
int32 protoOp = 2;
Proto proto = 3;
}
message PushMsgReply {
map<string,int32> index = 1;
}
message BroadcastReq{
int32 protoOp = 1;
Proto proto = 2;
}
message BroadcastReply{}
message BroadcastGroupReq {
string groupID = 1;
Proto proto = 2;
}
message BroadcastGroupReply{}
message JoinGroupsReq {
repeated string keys = 1;
repeated string gid = 2;
}
message JoinGroupsReply{}
message LeaveGroupsReq {
repeated string keys = 1;
repeated string gid = 2;
}
message LeaveGroupsReply{}
message DelGroupsReq {
repeated string gid = 1;
}
message DelGroupsReply{}
service Comet {
rpc PushMsg(PushMsgReq) returns (PushMsgReply);
rpc Broadcast(BroadcastReq) returns (BroadcastReply);
rpc BroadcastGroup(BroadcastGroupReq) returns (BroadcastGroupReply);
rpc JoinGroups(JoinGroupsReq) returns (JoinGroupsReply);
rpc LeaveGroups(LeaveGroupsReq) returns (LeaveGroupsReply);
rpc DelGroups(DelGroupsReq) returns (DelGroupsReply);
}

View File

@@ -0,0 +1,281 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package grpc
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// CometClient is the client API for Comet service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type CometClient interface {
PushMsg(ctx context.Context, in *PushMsgReq, opts ...grpc.CallOption) (*PushMsgReply, error)
Broadcast(ctx context.Context, in *BroadcastReq, opts ...grpc.CallOption) (*BroadcastReply, error)
BroadcastGroup(ctx context.Context, in *BroadcastGroupReq, opts ...grpc.CallOption) (*BroadcastGroupReply, error)
JoinGroups(ctx context.Context, in *JoinGroupsReq, opts ...grpc.CallOption) (*JoinGroupsReply, error)
LeaveGroups(ctx context.Context, in *LeaveGroupsReq, opts ...grpc.CallOption) (*LeaveGroupsReply, error)
DelGroups(ctx context.Context, in *DelGroupsReq, opts ...grpc.CallOption) (*DelGroupsReply, error)
}
type cometClient struct {
cc grpc.ClientConnInterface
}
func NewCometClient(cc grpc.ClientConnInterface) CometClient {
return &cometClient{cc}
}
func (c *cometClient) PushMsg(ctx context.Context, in *PushMsgReq, opts ...grpc.CallOption) (*PushMsgReply, error) {
out := new(PushMsgReply)
err := c.cc.Invoke(ctx, "/im.comet.Comet/PushMsg", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *cometClient) Broadcast(ctx context.Context, in *BroadcastReq, opts ...grpc.CallOption) (*BroadcastReply, error) {
out := new(BroadcastReply)
err := c.cc.Invoke(ctx, "/im.comet.Comet/Broadcast", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *cometClient) BroadcastGroup(ctx context.Context, in *BroadcastGroupReq, opts ...grpc.CallOption) (*BroadcastGroupReply, error) {
out := new(BroadcastGroupReply)
err := c.cc.Invoke(ctx, "/im.comet.Comet/BroadcastGroup", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *cometClient) JoinGroups(ctx context.Context, in *JoinGroupsReq, opts ...grpc.CallOption) (*JoinGroupsReply, error) {
out := new(JoinGroupsReply)
err := c.cc.Invoke(ctx, "/im.comet.Comet/JoinGroups", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *cometClient) LeaveGroups(ctx context.Context, in *LeaveGroupsReq, opts ...grpc.CallOption) (*LeaveGroupsReply, error) {
out := new(LeaveGroupsReply)
err := c.cc.Invoke(ctx, "/im.comet.Comet/LeaveGroups", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *cometClient) DelGroups(ctx context.Context, in *DelGroupsReq, opts ...grpc.CallOption) (*DelGroupsReply, error) {
out := new(DelGroupsReply)
err := c.cc.Invoke(ctx, "/im.comet.Comet/DelGroups", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// CometServer is the server API for Comet service.
// All implementations must embed UnimplementedCometServer
// for forward compatibility
type CometServer interface {
PushMsg(context.Context, *PushMsgReq) (*PushMsgReply, error)
Broadcast(context.Context, *BroadcastReq) (*BroadcastReply, error)
BroadcastGroup(context.Context, *BroadcastGroupReq) (*BroadcastGroupReply, error)
JoinGroups(context.Context, *JoinGroupsReq) (*JoinGroupsReply, error)
LeaveGroups(context.Context, *LeaveGroupsReq) (*LeaveGroupsReply, error)
DelGroups(context.Context, *DelGroupsReq) (*DelGroupsReply, error)
mustEmbedUnimplementedCometServer()
}
// UnimplementedCometServer must be embedded to have forward compatible implementations.
type UnimplementedCometServer struct {
}
func (UnimplementedCometServer) PushMsg(context.Context, *PushMsgReq) (*PushMsgReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method PushMsg not implemented")
}
func (UnimplementedCometServer) Broadcast(context.Context, *BroadcastReq) (*BroadcastReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method Broadcast not implemented")
}
func (UnimplementedCometServer) BroadcastGroup(context.Context, *BroadcastGroupReq) (*BroadcastGroupReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method BroadcastGroup not implemented")
}
func (UnimplementedCometServer) JoinGroups(context.Context, *JoinGroupsReq) (*JoinGroupsReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method JoinGroups not implemented")
}
func (UnimplementedCometServer) LeaveGroups(context.Context, *LeaveGroupsReq) (*LeaveGroupsReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method LeaveGroups not implemented")
}
func (UnimplementedCometServer) DelGroups(context.Context, *DelGroupsReq) (*DelGroupsReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method DelGroups not implemented")
}
func (UnimplementedCometServer) mustEmbedUnimplementedCometServer() {}
// UnsafeCometServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to CometServer will
// result in compilation errors.
type UnsafeCometServer interface {
mustEmbedUnimplementedCometServer()
}
func RegisterCometServer(s grpc.ServiceRegistrar, srv CometServer) {
s.RegisterService(&Comet_ServiceDesc, srv)
}
func _Comet_PushMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PushMsgReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CometServer).PushMsg(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/im.comet.Comet/PushMsg",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CometServer).PushMsg(ctx, req.(*PushMsgReq))
}
return interceptor(ctx, in, info, handler)
}
func _Comet_Broadcast_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BroadcastReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CometServer).Broadcast(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/im.comet.Comet/Broadcast",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CometServer).Broadcast(ctx, req.(*BroadcastReq))
}
return interceptor(ctx, in, info, handler)
}
func _Comet_BroadcastGroup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(BroadcastGroupReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CometServer).BroadcastGroup(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/im.comet.Comet/BroadcastGroup",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CometServer).BroadcastGroup(ctx, req.(*BroadcastGroupReq))
}
return interceptor(ctx, in, info, handler)
}
func _Comet_JoinGroups_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(JoinGroupsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CometServer).JoinGroups(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/im.comet.Comet/JoinGroups",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CometServer).JoinGroups(ctx, req.(*JoinGroupsReq))
}
return interceptor(ctx, in, info, handler)
}
func _Comet_LeaveGroups_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(LeaveGroupsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CometServer).LeaveGroups(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/im.comet.Comet/LeaveGroups",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CometServer).LeaveGroups(ctx, req.(*LeaveGroupsReq))
}
return interceptor(ctx, in, info, handler)
}
func _Comet_DelGroups_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DelGroupsReq)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(CometServer).DelGroups(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/im.comet.Comet/DelGroups",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(CometServer).DelGroups(ctx, req.(*DelGroupsReq))
}
return interceptor(ctx, in, info, handler)
}
// Comet_ServiceDesc is the grpc.ServiceDesc for Comet service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Comet_ServiceDesc = grpc.ServiceDesc{
ServiceName: "im.comet.Comet",
HandlerType: (*CometServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "PushMsg",
Handler: _Comet_PushMsg_Handler,
},
{
MethodName: "Broadcast",
Handler: _Comet_Broadcast_Handler,
},
{
MethodName: "BroadcastGroup",
Handler: _Comet_BroadcastGroup_Handler,
},
{
MethodName: "JoinGroups",
Handler: _Comet_JoinGroups_Handler,
},
{
MethodName: "LeaveGroups",
Handler: _Comet_LeaveGroups_Handler,
},
{
MethodName: "DelGroups",
Handler: _Comet_DelGroups_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "comet.proto",
}

6
api/comet/grpc/create.sh Normal file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
protoc -I. -I$GOPATH/src \
--go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
*.proto

304
api/comet/grpc/protocol.go Normal file
View File

@@ -0,0 +1,304 @@
package grpc
import (
"errors"
"github.com/Terry-Mao/goim/pkg/bufio"
"github.com/Terry-Mao/goim/pkg/bytes"
"github.com/Terry-Mao/goim/pkg/encoding/binary"
"github.com/Terry-Mao/goim/pkg/websocket"
gws "github.com/gorilla/websocket"
)
const (
// MaxBodySize max proto body size
MaxBodySize = int32(1 << 14)
)
const (
// size
_packSize = 4
_headerSize = 2
_verSize = 2
_opSize = 4
_seqSize = 4
_ackSize = 4
_heartSize = 4
_rawHeaderSize = _packSize + _headerSize + _verSize + _opSize + _seqSize + _ackSize
_maxPackSize = MaxBodySize + int32(_rawHeaderSize)
// offset
_packOffset = 0
_headerOffset = _packOffset + _packSize
_verOffset = _headerOffset + _headerSize
_opOffset = _verOffset + _verSize
_seqOffset = _opOffset + _opSize
_ackOffset = _seqOffset + _seqSize
_heartOffset = _ackOffset + _ackSize
)
var (
// ErrProtoPackLen proto packet len error
ErrProtoPackLen = errors.New("default server codec pack length error")
// ErrProtoHeaderLen proto header len error
ErrProtoHeaderLen = errors.New("default server codec header length error")
)
var (
// ProtoReady proto ready
ProtoReady = &Proto{Op: int32(Op_ProtoReady)}
// ProtoFinish proto finish
ProtoFinish = &Proto{Op: int32(Op_ProtoFinish)}
)
// WriteTo write a proto to bytes writer.
func (p *Proto) WriteTo(b *bytes.Writer) {
var (
packLen = _rawHeaderSize + int32(len(p.Body))
buf = b.Peek(_rawHeaderSize)
)
binary.BigEndian.PutInt32(buf[_packOffset:], packLen)
binary.BigEndian.PutInt16(buf[_headerOffset:], int16(_rawHeaderSize))
binary.BigEndian.PutInt16(buf[_verOffset:], int16(p.Ver))
binary.BigEndian.PutInt32(buf[_opOffset:], p.Op)
binary.BigEndian.PutInt32(buf[_seqOffset:], p.Seq)
binary.BigEndian.PutInt32(buf[_ackOffset:], p.Ack)
if p.Body != nil {
b.Write(p.Body)
}
}
// ReadTCP read a proto from TCP reader.
func (p *Proto) ReadTCP(rr *bufio.Reader) (err error) {
var (
bodyLen int
headerLen int16
packLen int32
buf []byte
)
if buf, err = rr.Pop(_rawHeaderSize); err != nil {
return
}
packLen = binary.BigEndian.Int32(buf[_packOffset:_headerOffset])
headerLen = binary.BigEndian.Int16(buf[_headerOffset:_verOffset])
p.Ver = int32(binary.BigEndian.Int16(buf[_verOffset:_opOffset]))
p.Op = binary.BigEndian.Int32(buf[_opOffset:_seqOffset])
p.Seq = binary.BigEndian.Int32(buf[_seqOffset:_ackOffset])
p.Ack = binary.BigEndian.Int32(buf[_ackOffset:])
if packLen > _maxPackSize {
return ErrProtoPackLen
}
if headerLen != _rawHeaderSize {
return ErrProtoHeaderLen
}
if bodyLen = int(packLen - int32(headerLen)); bodyLen > 0 {
p.Body, err = rr.Pop(bodyLen)
} else {
p.Body = nil
}
return
}
// WriteTCP write a proto to TCP writer.
func (p *Proto) WriteTCP(wr *bufio.Writer) (err error) {
var (
buf []byte
packLen int32
)
if p.Op == int32(Op_Raw) {
// write without buffer, job concact proto into raw buffer
_, err = wr.WriteRaw(p.Body)
return
}
packLen = _rawHeaderSize + int32(len(p.Body))
if buf, err = wr.Peek(_rawHeaderSize); err != nil {
return
}
binary.BigEndian.PutInt32(buf[_packOffset:], packLen)
binary.BigEndian.PutInt16(buf[_headerOffset:], int16(_rawHeaderSize))
binary.BigEndian.PutInt16(buf[_verOffset:], int16(p.Ver))
binary.BigEndian.PutInt32(buf[_opOffset:], p.Op)
binary.BigEndian.PutInt32(buf[_seqOffset:], p.Seq)
binary.BigEndian.PutInt32(buf[_ackOffset:], p.Ack)
if p.Body != nil {
_, err = wr.Write(p.Body)
}
return
}
// WriteTCPHeart write TCP heartbeat with room online.
func (p *Proto) WriteTCPHeart(wr *bufio.Writer, online int32) (err error) {
var (
buf []byte
packLen int
)
packLen = _rawHeaderSize + _heartSize
if buf, err = wr.Peek(packLen); err != nil {
return
}
// header
binary.BigEndian.PutInt32(buf[_packOffset:], int32(packLen))
binary.BigEndian.PutInt16(buf[_headerOffset:], int16(_rawHeaderSize))
binary.BigEndian.PutInt16(buf[_verOffset:], int16(p.Ver))
binary.BigEndian.PutInt32(buf[_opOffset:], p.Op)
binary.BigEndian.PutInt32(buf[_seqOffset:], p.Seq)
binary.BigEndian.PutInt32(buf[_ackOffset:], p.Ack)
// body
binary.BigEndian.PutInt32(buf[_heartOffset:], online)
return
}
// ReadWebsocket read a proto from websocket connection.
func (p *Proto) ReadWebsocket(ws *websocket.Conn) (err error) {
var (
bodyLen int
headerLen int16
packLen int32
buf []byte
)
if _, buf, err = ws.ReadMessage(); err != nil {
return
}
if len(buf) < _rawHeaderSize {
return ErrProtoPackLen
}
packLen = binary.BigEndian.Int32(buf[_packOffset:_headerOffset])
headerLen = binary.BigEndian.Int16(buf[_headerOffset:_verOffset])
p.Ver = int32(binary.BigEndian.Int16(buf[_verOffset:_opOffset]))
p.Op = binary.BigEndian.Int32(buf[_opOffset:_seqOffset])
p.Seq = binary.BigEndian.Int32(buf[_seqOffset:_ackOffset])
p.Ack = binary.BigEndian.Int32(buf[_ackOffset:])
if packLen < 0 || packLen > _maxPackSize {
return ErrProtoPackLen
}
if headerLen != _rawHeaderSize {
return ErrProtoHeaderLen
}
if bodyLen = int(packLen - int32(headerLen)); bodyLen > 0 {
p.Body = buf[headerLen:packLen]
} else {
p.Body = nil
}
return
}
// WriteWebsocket write a proto to websocket connection.
func (p *Proto) WriteWebsocket(ws *websocket.Conn) (err error) {
var (
buf []byte
packLen int
)
packLen = _rawHeaderSize + len(p.Body)
if err = ws.WriteHeader(websocket.BinaryMessage, packLen); err != nil {
return
}
if buf, err = ws.Peek(_rawHeaderSize); err != nil {
return
}
binary.BigEndian.PutInt32(buf[_packOffset:], int32(packLen))
binary.BigEndian.PutInt16(buf[_headerOffset:], int16(_rawHeaderSize))
binary.BigEndian.PutInt16(buf[_verOffset:], int16(p.Ver))
binary.BigEndian.PutInt32(buf[_opOffset:], p.Op)
binary.BigEndian.PutInt32(buf[_seqOffset:], p.Seq)
binary.BigEndian.PutInt32(buf[_ackOffset:], p.Ack)
if p.Body != nil {
err = ws.WriteBody(p.Body)
}
return
}
// WriteWebsocketHeart write websocket heartbeat with room online.
func (p *Proto) WriteWebsocketHeart(wr *websocket.Conn, online int32) (err error) {
var (
buf []byte
packLen int
)
packLen = _rawHeaderSize + _heartSize
// websocket header
if err = wr.WriteHeader(websocket.BinaryMessage, packLen); err != nil {
return
}
if buf, err = wr.Peek(packLen); err != nil {
return
}
// proto header
binary.BigEndian.PutInt32(buf[_packOffset:], int32(packLen))
binary.BigEndian.PutInt16(buf[_headerOffset:], int16(_rawHeaderSize))
binary.BigEndian.PutInt16(buf[_verOffset:], int16(p.Ver))
binary.BigEndian.PutInt32(buf[_opOffset:], p.Op)
binary.BigEndian.PutInt32(buf[_seqOffset:], p.Seq)
binary.BigEndian.PutInt32(buf[_ackOffset:], p.Ack)
// proto body
binary.BigEndian.PutInt32(buf[_heartOffset:], online)
return
}
// WriteWebsocket write a proto to websocket connection.
func (p *Proto) WriteWebsocket2(ws *gws.Conn) (err error) {
var (
buf []byte
packLen int32
)
wc, err := ws.NextWriter(websocket.BinaryMessage)
if err != nil {
return err
}
wr := bufio.NewWriter(wc)
packLen = _rawHeaderSize + int32(len(p.Body))
if buf, err = wr.Peek(_rawHeaderSize); err != nil {
return
}
binary.BigEndian.PutInt32(buf[_packOffset:], packLen)
binary.BigEndian.PutInt16(buf[_headerOffset:], int16(_rawHeaderSize))
binary.BigEndian.PutInt16(buf[_verOffset:], int16(p.Ver))
binary.BigEndian.PutInt32(buf[_opOffset:], p.Op)
binary.BigEndian.PutInt32(buf[_seqOffset:], p.Seq)
binary.BigEndian.PutInt32(buf[_ackOffset:], p.Ack)
if p.Body != nil {
_, err = wr.Write(p.Body)
}
if err != nil {
return
}
err = wr.Flush()
if err != nil {
return
}
return wc.Close()
}
// ReadWebsocket read a proto from websocket connection.
func (p *Proto) ReadWebsocket2(ws *gws.Conn) (err error) {
var (
bodyLen int
headerLen int16
packLen int32
buf []byte
)
if _, buf, err = ws.ReadMessage(); err != nil {
return
}
if len(buf) < _rawHeaderSize {
return ErrProtoPackLen
}
packLen = binary.BigEndian.Int32(buf[_packOffset:_headerOffset])
headerLen = binary.BigEndian.Int16(buf[_headerOffset:_verOffset])
p.Ver = int32(binary.BigEndian.Int16(buf[_verOffset:_opOffset]))
p.Op = binary.BigEndian.Int32(buf[_opOffset:_seqOffset])
p.Seq = binary.BigEndian.Int32(buf[_seqOffset:_ackOffset])
p.Ack = binary.BigEndian.Int32(buf[_ackOffset:])
if packLen > _maxPackSize {
return ErrProtoPackLen
}
if headerLen != _rawHeaderSize {
return ErrProtoHeaderLen
}
if bodyLen = int(packLen - int32(headerLen)); bodyLen > 0 {
p.Body = buf[headerLen:packLen]
} else {
p.Body = nil
}
return
}