mirror of https://github.com/ehang-io/nps
236 lines
5.6 KiB
Go
236 lines
5.6 KiB
Go
package common
|
||
|
||
import (
|
||
"bytes"
|
||
"encoding/binary"
|
||
"encoding/json"
|
||
"errors"
|
||
"io"
|
||
"strings"
|
||
)
|
||
|
||
type NetPackager interface {
|
||
Pack(writer io.Writer) (err error)
|
||
UnPack(reader io.Reader) (err error)
|
||
}
|
||
|
||
type BasePackager struct {
|
||
Length uint16
|
||
Content []byte
|
||
}
|
||
|
||
func (Self *BasePackager) NewPac(contents ...interface{}) (err error) {
|
||
Self.clean()
|
||
for _, content := range contents {
|
||
switch content.(type) {
|
||
case nil:
|
||
Self.Content = Self.Content[:0]
|
||
case []byte:
|
||
err = Self.appendByte(content.([]byte))
|
||
case string:
|
||
err = Self.appendByte([]byte(content.(string)))
|
||
if err != nil {
|
||
return
|
||
}
|
||
err = Self.appendByte([]byte(CONN_DATA_SEQ))
|
||
default:
|
||
err = Self.marshal(content)
|
||
}
|
||
}
|
||
Self.setLength()
|
||
return
|
||
}
|
||
|
||
func (Self *BasePackager) appendByte(data []byte) (err error) {
|
||
m := len(Self.Content)
|
||
n := m + len(data)
|
||
if n <= cap(Self.Content) {
|
||
Self.Content = Self.Content[0:n] // grow the length for copy
|
||
copy(Self.Content[m:n], data)
|
||
return nil
|
||
} else {
|
||
return errors.New("pack content too large")
|
||
}
|
||
}
|
||
|
||
//似乎这里涉及到父类作用域问题,当子类调用父类的方法时,其struct仅仅为父类的
|
||
func (Self *BasePackager) Pack(writer io.Writer) (err error) {
|
||
err = binary.Write(writer, binary.LittleEndian, Self.Length)
|
||
if err != nil {
|
||
return
|
||
}
|
||
err = binary.Write(writer, binary.LittleEndian, Self.Content)
|
||
return
|
||
}
|
||
|
||
//Unpack 会导致传入的数字类型转化成float64!!
|
||
//主要原因是json unmarshal并未传入正确的数据类型
|
||
func (Self *BasePackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||
Self.clean()
|
||
n += 2 // uint16
|
||
err = binary.Read(reader, binary.LittleEndian, &Self.Length)
|
||
if err != nil {
|
||
return
|
||
}
|
||
if int(Self.Length) > cap(Self.Content) {
|
||
err = errors.New("unpack err, content length too large")
|
||
}
|
||
Self.Content = Self.Content[:int(Self.Length)]
|
||
//n, err := io.ReadFull(reader, Self.Content)
|
||
//if n != int(Self.Length) {
|
||
// err = io.ErrUnexpectedEOF
|
||
//}
|
||
err = binary.Read(reader, binary.LittleEndian, Self.Content)
|
||
n += Self.Length
|
||
return
|
||
}
|
||
|
||
func (Self *BasePackager) marshal(content interface{}) (err error) {
|
||
tmp, err := json.Marshal(content)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
err = Self.appendByte(tmp)
|
||
return
|
||
}
|
||
|
||
func (Self *BasePackager) Unmarshal(content interface{}) (err error) {
|
||
err = json.Unmarshal(Self.Content, content)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return
|
||
}
|
||
|
||
func (Self *BasePackager) setLength() {
|
||
Self.Length = uint16(len(Self.Content))
|
||
return
|
||
}
|
||
|
||
func (Self *BasePackager) clean() {
|
||
Self.Length = 0
|
||
Self.Content = Self.Content[:0] // reset length
|
||
}
|
||
|
||
func (Self *BasePackager) Split() (strList []string) {
|
||
n := bytes.IndexByte(Self.Content, 0)
|
||
strList = strings.Split(string(Self.Content[:n]), CONN_DATA_SEQ)
|
||
strList = strList[0 : len(strList)-1]
|
||
return
|
||
}
|
||
|
||
type ConnPackager struct { // Todo
|
||
ConnType uint8
|
||
BasePackager
|
||
}
|
||
|
||
func (Self *ConnPackager) NewPac(connType uint8, content ...interface{}) (err error) {
|
||
Self.ConnType = connType
|
||
err = Self.BasePackager.NewPac(content...)
|
||
return
|
||
}
|
||
|
||
func (Self *ConnPackager) Pack(writer io.Writer) (err error) {
|
||
err = binary.Write(writer, binary.LittleEndian, Self.ConnType)
|
||
if err != nil {
|
||
return
|
||
}
|
||
err = Self.BasePackager.Pack(writer)
|
||
return
|
||
}
|
||
|
||
func (Self *ConnPackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||
err = binary.Read(reader, binary.LittleEndian, &Self.ConnType)
|
||
if err != nil && err != io.EOF {
|
||
return
|
||
}
|
||
n, err = Self.BasePackager.UnPack(reader)
|
||
n += 2
|
||
return
|
||
}
|
||
|
||
type MuxPackager struct {
|
||
Flag uint8
|
||
Id int32
|
||
Window uint32
|
||
ReadLength uint32
|
||
BasePackager
|
||
}
|
||
|
||
func (Self *MuxPackager) NewPac(flag uint8, id int32, content ...interface{}) (err error) {
|
||
Self.Flag = flag
|
||
Self.Id = id
|
||
switch flag {
|
||
case MUX_PING_FLAG, MUX_PING_RETURN, MUX_NEW_MSG, MUX_NEW_MSG_PART:
|
||
Self.Content = WindowBuff.Get()
|
||
err = Self.BasePackager.NewPac(content...)
|
||
//logs.Warn(Self.Length, string(Self.Content))
|
||
case MUX_MSG_SEND_OK:
|
||
// MUX_MSG_SEND_OK contains two data
|
||
switch content[0].(type) {
|
||
case int:
|
||
Self.Window = uint32(content[0].(int))
|
||
case uint32:
|
||
Self.Window = content[0].(uint32)
|
||
}
|
||
switch content[1].(type) {
|
||
case int:
|
||
Self.ReadLength = uint32(content[1].(int))
|
||
case uint32:
|
||
Self.ReadLength = content[1].(uint32)
|
||
}
|
||
}
|
||
return
|
||
}
|
||
|
||
func (Self *MuxPackager) Pack(writer io.Writer) (err error) {
|
||
err = binary.Write(writer, binary.LittleEndian, Self.Flag)
|
||
if err != nil {
|
||
return
|
||
}
|
||
err = binary.Write(writer, binary.LittleEndian, Self.Id)
|
||
if err != nil {
|
||
return
|
||
}
|
||
switch Self.Flag {
|
||
case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN:
|
||
err = Self.BasePackager.Pack(writer)
|
||
WindowBuff.Put(Self.Content)
|
||
case MUX_MSG_SEND_OK:
|
||
err = binary.Write(writer, binary.LittleEndian, Self.Window)
|
||
if err != nil {
|
||
return
|
||
}
|
||
err = binary.Write(writer, binary.LittleEndian, Self.ReadLength)
|
||
}
|
||
return
|
||
}
|
||
|
||
func (Self *MuxPackager) UnPack(reader io.Reader) (n uint16, err error) {
|
||
err = binary.Read(reader, binary.LittleEndian, &Self.Flag)
|
||
if err != nil {
|
||
return
|
||
}
|
||
err = binary.Read(reader, binary.LittleEndian, &Self.Id)
|
||
if err != nil {
|
||
return
|
||
}
|
||
switch Self.Flag {
|
||
case MUX_NEW_MSG, MUX_NEW_MSG_PART, MUX_PING_FLAG, MUX_PING_RETURN:
|
||
Self.Content = WindowBuff.Get() // need get a window buf from pool
|
||
Self.BasePackager.clean() // also clean the content
|
||
n, err = Self.BasePackager.UnPack(reader)
|
||
//logs.Warn("unpack", Self.Length, string(Self.Content))
|
||
case MUX_MSG_SEND_OK:
|
||
err = binary.Read(reader, binary.LittleEndian, &Self.Window)
|
||
if err != nil {
|
||
return
|
||
}
|
||
n += 4 // uint32
|
||
err = binary.Read(reader, binary.LittleEndian, &Self.ReadLength)
|
||
n += 4 // uint32
|
||
}
|
||
n += 5 //uint8 int32
|
||
return
|
||
}
|