You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.1 KiB
Go
147 lines
3.1 KiB
Go
2 years ago
|
package message
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"errors"
|
||
|
)
|
||
|
|
||
|
var _ Codec = (*NNetCodec)(nil)
|
||
|
|
||
|
const (
|
||
|
msgRouteCompressMask = 0x01 // 0000 0001 last bit
|
||
|
msgTypeMask = 0x07 // 0000 0111 1-3 bit (需要>>)
|
||
|
msgRouteLengthMask = 0xFF // 1111 1111 last 8 bit
|
||
|
msgHeadLength = 0x02 // 0000 0010 2 bit
|
||
|
)
|
||
|
|
||
|
// Errors that could be occurred in message codec
|
||
|
var (
|
||
|
ErrWrongMessageType = errors.New("wrong message type")
|
||
|
ErrInvalidMessage = errors.New("invalid message")
|
||
|
ErrRouteInfoNotFound = errors.New("route info not found in dictionary")
|
||
|
ErrWrongMessage = errors.New("wrong message")
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
routes = make(map[string]uint16) // route map to code
|
||
|
codes = make(map[uint16]string) // code map to route
|
||
|
)
|
||
|
|
||
|
type NNetCodec struct{}
|
||
|
|
||
|
func (n *NNetCodec) routable(t Type) bool {
|
||
|
return t == Request || t == Notify || t == Push
|
||
|
}
|
||
|
|
||
|
func (n *NNetCodec) invalidType(t Type) bool {
|
||
|
return t < Request || t > Push
|
||
|
}
|
||
|
|
||
|
func (n *NNetCodec) Encode(v interface{}) ([]byte, error) {
|
||
|
m, ok := v.(*Message)
|
||
|
if !ok {
|
||
|
return nil, ErrWrongMessageType
|
||
|
}
|
||
|
if n.invalidType(m.Type) {
|
||
|
return nil, ErrWrongMessageType
|
||
|
}
|
||
|
buf := make([]byte, 0)
|
||
|
flag := byte(m.Type << 1) // 编译器提示,此处 byte 转换不能删
|
||
|
|
||
|
code, compressed := routes[m.Route]
|
||
|
if compressed {
|
||
|
flag |= msgRouteCompressMask
|
||
|
}
|
||
|
buf = append(buf, flag)
|
||
|
|
||
|
if m.Type == Request || m.Type == Response {
|
||
|
n := m.ID
|
||
|
// variant length encode
|
||
|
for {
|
||
|
b := byte(n % 128)
|
||
|
n >>= 7
|
||
|
if n != 0 {
|
||
|
buf = append(buf, b+128)
|
||
|
} else {
|
||
|
buf = append(buf, b)
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if n.routable(m.Type) {
|
||
|
if compressed {
|
||
|
buf = append(buf, byte((code>>8)&0xFF))
|
||
|
buf = append(buf, byte(code&0xFF))
|
||
|
} else {
|
||
|
buf = append(buf, byte(len(m.Route)))
|
||
|
buf = append(buf, []byte(m.Route)...)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
buf = append(buf, m.Data...)
|
||
|
return buf, nil
|
||
|
}
|
||
|
|
||
|
func (n *NNetCodec) Decode(data []byte) (interface{}, error) {
|
||
|
if len(data) < msgHeadLength {
|
||
|
return nil, ErrInvalidMessage
|
||
|
}
|
||
|
m := New()
|
||
|
flag := data[0]
|
||
|
offset := 1
|
||
|
m.Type = Type((flag >> 1) & msgTypeMask) // 编译器提示,此处Type转换不能删
|
||
|
|
||
|
if n.invalidType(m.Type) {
|
||
|
return nil, ErrWrongMessageType
|
||
|
}
|
||
|
|
||
|
if m.Type == Request || m.Type == Response {
|
||
|
id := uint64(0)
|
||
|
// little end byte order
|
||
|
// WARNING: must can be stored in 64 bits integer
|
||
|
// variant length encode
|
||
|
for i := offset; i < len(data); i++ {
|
||
|
b := data[i]
|
||
|
id += uint64(b&0x7F) << uint64(7*(i-offset))
|
||
|
if b < 128 {
|
||
|
offset = i + 1
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
m.ID = id
|
||
|
}
|
||
|
|
||
|
if offset >= len(data) {
|
||
|
return nil, ErrWrongMessage
|
||
|
}
|
||
|
|
||
|
if n.routable(m.Type) {
|
||
|
if flag&msgRouteCompressMask == 1 {
|
||
|
m.compressed = true
|
||
|
code := binary.BigEndian.Uint16(data[offset:(offset + 2)])
|
||
|
route, ok := codes[code]
|
||
|
if !ok {
|
||
|
return nil, ErrRouteInfoNotFound
|
||
|
}
|
||
|
m.Route = route
|
||
|
offset += 2
|
||
|
} else {
|
||
|
m.compressed = false
|
||
|
rl := data[offset]
|
||
|
offset++
|
||
|
if offset+int(rl) > len(data) {
|
||
|
return nil, ErrWrongMessage
|
||
|
}
|
||
|
m.Route = string(data[offset:(offset + int(rl))])
|
||
|
offset += int(rl)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if offset > len(data) {
|
||
|
return nil, ErrWrongMessage
|
||
|
}
|
||
|
m.Data = data[offset:]
|
||
|
return m, nil
|
||
|
}
|