init
This commit is contained in:
304
api/comet/grpc/protocol.go
Normal file
304
api/comet/grpc/protocol.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user