init: 自 zomaintain/backend/zonat 平移独立成库; module path 改为 git.zeroonesoft.cn/golib/zonat; 内部 import 同步重写
This commit is contained in:
+149
@@ -0,0 +1,149 @@
|
||||
// frame.go 帧协议,wire format 与 zonat 桥接帧完全一致
|
||||
// (ver(1) + cmd(1) + length(2, LE) + sid(4, LE) + data)。
|
||||
// 本文件取自 zonat client/internal/frame 的本地修复副本,仅裁掉未用方法。
|
||||
package agent
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
const FrameVersion byte = 1
|
||||
|
||||
// 帧头部
|
||||
const (
|
||||
sizeOfVer = 1
|
||||
sizeOfCmd = 1
|
||||
sizeOfLength = 2
|
||||
sizeOfSid = 4
|
||||
headerSize = sizeOfVer + sizeOfCmd + sizeOfSid + sizeOfLength
|
||||
)
|
||||
|
||||
const (
|
||||
frameBufSize = 0x10000
|
||||
)
|
||||
|
||||
type Frame struct {
|
||||
ver byte
|
||||
cmd byte
|
||||
sid uint32
|
||||
data []byte
|
||||
}
|
||||
|
||||
func NewFrame(version byte, cmd byte, sid uint32) Frame {
|
||||
return Frame{ver: version, cmd: cmd, sid: sid}
|
||||
}
|
||||
|
||||
// ReadFrame 读取一帧。头部与数据均用 ReadFull,防止单次 Read 短读导致解析错乱,
|
||||
// 也不会把后续帧的数据读进缓冲丢弃。
|
||||
func ReadFrame(conn net.Conn) (Frame, error) {
|
||||
f := NewFrame(0, 0, 0)
|
||||
hdr := RawHeader{}
|
||||
if _, err := io.ReadFull(conn, hdr[:]); err != nil {
|
||||
return f, err
|
||||
}
|
||||
|
||||
f.ver = hdr.Version()
|
||||
f.cmd = hdr.Cmd()
|
||||
f.sid = hdr.StreamID()
|
||||
|
||||
length := int(hdr.Length())
|
||||
if length == 0 {
|
||||
return f, nil
|
||||
}
|
||||
data := make([]byte, length)
|
||||
if _, err := io.ReadFull(conn, data); err != nil {
|
||||
return f, err
|
||||
}
|
||||
f.data = data
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func WriteFrame(conn net.Conn, frame Frame) error {
|
||||
hdr := RawHeader{}
|
||||
hdr[0] = frame.ver
|
||||
hdr[1] = frame.cmd
|
||||
binary.LittleEndian.PutUint16(hdr[2:], uint16(len(frame.data)))
|
||||
binary.LittleEndian.PutUint32(hdr[4:], frame.sid)
|
||||
|
||||
buf := hdr.Bytes()
|
||||
buf = append(buf, frame.data...)
|
||||
_, err := conn.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *Frame) Version() byte {
|
||||
return f.ver
|
||||
}
|
||||
|
||||
func (f *Frame) Cmd() byte {
|
||||
return f.cmd
|
||||
}
|
||||
|
||||
func (f *Frame) Length() uint16 {
|
||||
return uint16(len(f.data))
|
||||
}
|
||||
|
||||
func (f *Frame) Data() []byte {
|
||||
return f.data
|
||||
}
|
||||
|
||||
func (f *Frame) StreamID() uint32 {
|
||||
return f.sid
|
||||
}
|
||||
|
||||
func (f *Frame) SetData(data []byte) error {
|
||||
if len(data) > frameBufSize-1 {
|
||||
return fmt.Errorf("超出最大长度:%d", frameBufSize-1)
|
||||
}
|
||||
f.data = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Frame) Marshal(v any) error {
|
||||
buf, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return f.SetData(buf)
|
||||
}
|
||||
|
||||
func (f *Frame) Unmarshal(v any) error {
|
||||
if len(f.data) == 0 {
|
||||
return errors.New("没有数据")
|
||||
}
|
||||
return json.Unmarshal(f.data, v)
|
||||
}
|
||||
|
||||
func (f *Frame) String() string {
|
||||
return fmt.Sprintf("Version:%d Cmd:%d StreamID:%d Length:%d",
|
||||
f.Version(), f.Cmd(), f.StreamID(), f.Length())
|
||||
}
|
||||
|
||||
type RawHeader [headerSize]byte
|
||||
|
||||
func (h RawHeader) Version() byte {
|
||||
return h[0]
|
||||
}
|
||||
|
||||
func (h RawHeader) Cmd() byte {
|
||||
return h[1]
|
||||
}
|
||||
|
||||
func (h RawHeader) Length() uint16 {
|
||||
return binary.LittleEndian.Uint16(h[2:])
|
||||
}
|
||||
|
||||
func (h RawHeader) StreamID() uint32 {
|
||||
return binary.LittleEndian.Uint32(h[4:])
|
||||
}
|
||||
|
||||
func (h RawHeader) Bytes() []byte {
|
||||
buf := make([]byte, headerSize)
|
||||
copy(buf, h[:])
|
||||
return buf
|
||||
}
|
||||
Reference in New Issue
Block a user