155 lines
3.1 KiB
Go
155 lines
3.1 KiB
Go
|
package cli
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/binary"
|
||
|
"io"
|
||
|
"math"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
PacketTypeCompleter byte = 0x01
|
||
|
PacketTypeCommand = 0x02
|
||
|
PacketTypeHandshake = 0x03
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
FlagPortion = 0x00
|
||
|
FlagComplete = 0x01
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
Frame struct {
|
||
|
Feature []byte
|
||
|
Type byte `json:"type"`
|
||
|
Flag byte `json:"flag"`
|
||
|
Seq uint16 `json:"seq"`
|
||
|
Data []byte `json:"data"`
|
||
|
Error string `json:"error"`
|
||
|
Timestamp int64 `json:"timestamp"`
|
||
|
}
|
||
|
)
|
||
|
|
||
|
func readFrame(r io.Reader) (frame *Frame, err error) {
|
||
|
var (
|
||
|
n int
|
||
|
dataLength uint16
|
||
|
errorLength uint16
|
||
|
errBuf []byte
|
||
|
)
|
||
|
frame = &Frame{Feature: make([]byte, 3)}
|
||
|
if _, err = io.ReadFull(r, frame.Feature); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if !bytes.Equal(frame.Feature, Feature) {
|
||
|
err = io.ErrUnexpectedEOF
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Read(r, binary.LittleEndian, &frame.Type); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Read(r, binary.LittleEndian, &frame.Flag); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Read(r, binary.LittleEndian, &frame.Seq); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Read(r, binary.LittleEndian, &frame.Timestamp); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Read(r, binary.LittleEndian, &dataLength); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Read(r, binary.LittleEndian, &errorLength); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if dataLength > 0 {
|
||
|
frame.Data = make([]byte, dataLength)
|
||
|
if n, err = io.ReadFull(r, frame.Data); err == nil {
|
||
|
if n < int(dataLength) {
|
||
|
err = io.ErrShortBuffer
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if errorLength > 0 {
|
||
|
errBuf = make([]byte, errorLength)
|
||
|
if n, err = io.ReadFull(r, errBuf); err == nil {
|
||
|
if n < int(dataLength) {
|
||
|
err = io.ErrShortBuffer
|
||
|
} else {
|
||
|
frame.Error = string(errBuf)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func writeFrame(w io.Writer, frame *Frame) (err error) {
|
||
|
var (
|
||
|
n int
|
||
|
dl int
|
||
|
dataLength uint16
|
||
|
errorLength uint16
|
||
|
errBuf []byte
|
||
|
)
|
||
|
if _, err = w.Write(Feature); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if frame.Data != nil {
|
||
|
dl = len(frame.Data)
|
||
|
if dl > math.MaxUint16 {
|
||
|
return io.ErrNoProgress
|
||
|
}
|
||
|
dataLength = uint16(dl)
|
||
|
}
|
||
|
if frame.Error != "" {
|
||
|
errBuf = []byte(frame.Error)
|
||
|
errorLength = uint16(len(errBuf))
|
||
|
}
|
||
|
if err = binary.Write(w, binary.LittleEndian, frame.Type); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Write(w, binary.LittleEndian, frame.Flag); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Write(w, binary.LittleEndian, frame.Seq); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Write(w, binary.LittleEndian, frame.Timestamp); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Write(w, binary.LittleEndian, dataLength); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if err = binary.Write(w, binary.LittleEndian, errorLength); err != nil {
|
||
|
return
|
||
|
}
|
||
|
if dataLength > 0 {
|
||
|
if n, err = w.Write(frame.Data); err == nil {
|
||
|
if n < int(dataLength) {
|
||
|
err = io.ErrShortWrite
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if errorLength > 0 {
|
||
|
if n, err = w.Write(errBuf); err == nil {
|
||
|
if n < int(errorLength) {
|
||
|
err = io.ErrShortWrite
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func newFrame(t, f byte, seq uint16, data []byte) *Frame {
|
||
|
return &Frame{
|
||
|
Feature: Feature,
|
||
|
Type: t,
|
||
|
Flag: f,
|
||
|
Seq: seq,
|
||
|
Data: data,
|
||
|
Timestamp: time.Now().Unix(),
|
||
|
}
|
||
|
}
|