feat: change project structure
This commit is contained in:
188
hsp/packet.go
Normal file
188
hsp/packet.go
Normal file
@ -0,0 +1,188 @@
|
||||
package hsp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
const (
|
||||
Magic uint32 = 0xDEADBEEF
|
||||
)
|
||||
|
||||
const (
|
||||
PacketVersion int = 1
|
||||
)
|
||||
|
||||
type RawPacket struct {
|
||||
Magic uint32
|
||||
Version uint8
|
||||
Flags uint8
|
||||
HeaderSize uint16
|
||||
PayloadSize uint32
|
||||
Header []byte
|
||||
Payload []byte
|
||||
}
|
||||
|
||||
type Packet struct {
|
||||
Version int
|
||||
Flags int
|
||||
Headers map[string]string
|
||||
Payload []byte
|
||||
}
|
||||
|
||||
type PacketDuplex struct {
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func BuildPacket(headers map[string]string, payload []byte) *Packet {
|
||||
return &Packet{
|
||||
Version: PacketVersion,
|
||||
Flags: 0, // TODO:
|
||||
Headers: headers,
|
||||
Payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
func ParseHeaders(rawHeaders []byte, headers *map[string]string) error {
|
||||
i := 0
|
||||
for i < len(rawHeaders) {
|
||||
if rawHeaders[i] == '\n' {
|
||||
break
|
||||
}
|
||||
var key string
|
||||
for rawHeaders[i] != ':' {
|
||||
if rawHeaders[i] != ' ' {
|
||||
key += string(rawHeaders[i])
|
||||
}
|
||||
i++
|
||||
}
|
||||
i++
|
||||
var value string
|
||||
for rawHeaders[i] != '\n' {
|
||||
if rawHeaders[i] != ' ' {
|
||||
value += string(rawHeaders[i])
|
||||
}
|
||||
i++
|
||||
}
|
||||
i++
|
||||
(*headers)[key] = value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SerializeHeaders(headers *map[string]string) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
for k, v := range(*headers) {
|
||||
fmt.Fprintf(buf, "%s:%s\n", k, v)
|
||||
}
|
||||
fmt.Fprintf(buf, "\n")
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func NewPacketDuplex(conn net.Conn) *PacketDuplex {
|
||||
return &PacketDuplex{
|
||||
conn,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *PacketDuplex) ReadPacket() (*Packet, error) {
|
||||
rpkt := &RawPacket{}
|
||||
|
||||
err := binary.Read(r.conn, binary.BigEndian, &rpkt.Magic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rpkt.Magic != Magic {
|
||||
return nil, errors.New("Magic bytes are invalid")
|
||||
}
|
||||
|
||||
err = binary.Read(r.conn, binary.BigEndian, &rpkt.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = binary.Read(r.conn, binary.BigEndian, &rpkt.Flags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = binary.Read(r.conn, binary.BigEndian, &rpkt.HeaderSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = binary.Read(r.conn, binary.BigEndian, &rpkt.PayloadSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpkt.Header = make([]byte, rpkt.HeaderSize)
|
||||
if _, err := io.ReadFull(r.conn, rpkt.Header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpkt.Payload = make([]byte, rpkt.PayloadSize)
|
||||
if _, err := io.ReadFull(r.conn, rpkt.Payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pkt := &Packet{
|
||||
Version: int(rpkt.Version),
|
||||
Flags: int(rpkt.Flags),
|
||||
Headers: make(map[string]string),
|
||||
Payload: rpkt.Payload,
|
||||
}
|
||||
|
||||
ParseHeaders(rpkt.Header, &pkt.Headers)
|
||||
|
||||
return pkt, nil
|
||||
}
|
||||
|
||||
func (r *PacketDuplex) WritePacket(packet *Packet) (int, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
if err := binary.Write(buf, binary.BigEndian, Magic); err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("Failed to write magic into packet: %s", err.Error()))
|
||||
}
|
||||
|
||||
if err := binary.Write(buf, binary.BigEndian, uint8(packet.Version)); err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("Failed to write version into packet: %s", err.Error()))
|
||||
}
|
||||
|
||||
if err := binary.Write(buf, binary.BigEndian, uint8(packet.Flags)); err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("Failed to write flags into packet: %s", err.Error()))
|
||||
}
|
||||
|
||||
rawHeaders := SerializeHeaders(&packet.Headers)
|
||||
headerSize := len(rawHeaders)
|
||||
payloadSize := len(packet.Payload)
|
||||
|
||||
if err := binary.Write(buf, binary.BigEndian, uint16(headerSize)); err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("Failed to write header size into packet: %s", err.Error()))
|
||||
}
|
||||
|
||||
if err := binary.Write(buf, binary.BigEndian, uint32(payloadSize)); err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("Failed to write payload size into packet: %s", err.Error()))
|
||||
}
|
||||
|
||||
if _, err := buf.Write(rawHeaders[:headerSize]); err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("Failed to write raw headers: %s", err.Error()))
|
||||
}
|
||||
|
||||
if _, err := buf.Write(packet.Payload[:payloadSize]); err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("Failed to write payload: %s", err.Error()))
|
||||
}
|
||||
|
||||
n, err := r.conn.Write(buf.Bytes())
|
||||
if err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("Failed to send packet over connection: %s", err.Error()))
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user