pnyx/packet.go

267 lines
6.3 KiB
Go

package pnyx
import (
"encoding"
"fmt"
"github.com/google/uuid"
)
type PacketType uint8
const (
PACKET_SERVER_COMMAND PacketType = iota
PACKET_CHANNEL_COMMAND
PACKET_CHANNEL_DATA
PACKET_CHANNEL_PEER
CHANNEL_HEADER_LEN int = 2
CHANNEL_COMMAND_LEN = CHANNEL_HEADER_LEN + COMMAND_LENGTH + REQ_ID_LENGTH
CHANNEL_PEER_LEN = CHANNEL_HEADER_LEN + PEER_ID_LENGTH
SERVER_COMMAND_ADD_CHANNEL byte = iota
SERVER_COMMAND_DEL_CHANNEL
)
type Payload interface {
encoding.BinaryMarshaler
}
type Packet struct {
Type PacketType
Payload Payload
}
func(packet Packet) MarshalBinary() ([]byte, error) {
payload, err := packet.Payload.MarshalBinary()
if err != nil {
return nil, err
}
return append([]byte{byte(packet.Type)}, payload...), nil
}
func ParsePacket(data []byte) (Payload, error) {
if len(data) < 1 {
return nil, fmt.Errorf("Packet too short to parse - %d/1", len(data))
}
switch PacketType(data[0]) {
case PACKET_SERVER_COMMAND:
return ParseServerCommandPacket(data[1:])
case PACKET_CHANNEL_DATA:
return ParseChannelDataPacket(data[1:])
case PACKET_CHANNEL_COMMAND:
return ParseChannelCommandPacket(data[1:])
case PACKET_CHANNEL_PEER:
return ParseChannelPeerPacket(data[1:])
default:
return nil, fmt.Errorf("Don't know how to parse packet type 0x%02x", data[0])
}
}
type ServerCommandPacket struct {
ReqID uuid.UUID
Command byte
Data []byte
}
func (packet ServerCommandPacket) MarshalBinary() ([]byte, error) {
p := make([]byte, 17 + len(packet.Data))
copy(p, packet.ReqID[:])
p[16] = packet.Command
copy(p[17:], packet.Data)
return p, nil
}
func NewServerCommandPacket(command byte, data []byte) (*Packet, uuid.UUID) {
req_id := uuid.New()
return &Packet{
Type: PACKET_SERVER_COMMAND,
Payload: ServerCommandPacket{
ReqID: req_id,
Command: command,
Data: data,
},
}, req_id
}
func ParseServerCommandPacket(data []byte) (ServerCommandPacket, error) {
if len(data) < 17 {
return ServerCommandPacket{}, fmt.Errorf("Not enough data to decode ServerCommandPacket: %d/%d", len(data), 17)
}
return ServerCommandPacket{
ReqID: uuid.UUID(data[0:16]),
Command: data[16],
Data: data[17:],
}, nil
}
type ChannelHeader struct {
Channel ChannelID
Mode ModeID
}
func(packet ChannelHeader) MarshalBinary() ([]byte, error) {
return []byte{byte(packet.Channel), byte(packet.Mode)}, nil
}
func ParseChannelHeader(data []byte) (ChannelHeader, error) {
if len(data) < 2 {
return ChannelHeader{}, fmt.Errorf("Not enough bytes to parse ChannelPacket(%d/%d)", len(data), 6)
}
return ChannelHeader{
Channel: ChannelID(data[0]),
Mode: ModeID(data[1]),
}, nil
}
type ChannelCommandPacket struct {
ChannelHeader
Command byte
ReqID uuid.UUID
Data []byte
}
func NewChannelCommandPacket(request_id uuid.UUID, channel ChannelID, mode ModeID, command byte, data []byte) *Packet {
return &Packet{
Type: PACKET_CHANNEL_COMMAND,
Payload: ChannelCommandPacket{
ChannelHeader: ChannelHeader{
Channel: channel,
Mode: mode,
},
Command: command,
ReqID: request_id,
Data: data,
},
}
}
func(packet ChannelCommandPacket) MarshalBinary() ([]byte, error) {
header, err := packet.ChannelHeader.MarshalBinary()
if err != nil {
return nil, err
}
data := make([]byte, len(header) + len(packet.Data) + REQ_ID_LENGTH + COMMAND_LENGTH)
copy(data, header)
data[CHANNEL_HEADER_LEN] = packet.Command
copy(data[CHANNEL_HEADER_LEN + COMMAND_LENGTH:], packet.ReqID[:])
copy(data[CHANNEL_HEADER_LEN + COMMAND_LENGTH + REQ_ID_LENGTH:], packet.Data)
return data, nil
}
func ParseChannelCommandPacket(data []byte) (ChannelCommandPacket, error) {
if len(data) < CHANNEL_COMMAND_LEN {
return ChannelCommandPacket{}, fmt.Errorf("Not enough data to decode channel command packet %d/%d", len(data), CHANNEL_COMMAND_LEN)
}
header, err := ParseChannelHeader(data[:CHANNEL_HEADER_LEN])
if err != nil {
return ChannelCommandPacket{}, err
}
command := data[CHANNEL_HEADER_LEN]
request_id := uuid.UUID(data[CHANNEL_HEADER_LEN+COMMAND_LENGTH:])
return ChannelCommandPacket{
ChannelHeader: header,
Command: command,
ReqID: request_id,
Data: data[CHANNEL_COMMAND_LEN:],
}, nil
}
type ChannelPeerPacket struct {
ChannelHeader
Peer PeerID
Data []byte
}
func NewChannelPeerPacket(peer PeerID, channel ChannelID, mode ModeID, data []byte) *Packet {
return &Packet{
Type: PACKET_CHANNEL_PEER,
Payload: ChannelPeerPacket{
ChannelHeader: ChannelHeader{
Channel: channel,
Mode: mode,
},
Peer: peer,
Data: data,
},
}
}
func(packet ChannelPeerPacket) MarshalBinary() ([]byte, error) {
header, err := packet.ChannelHeader.MarshalBinary()
if err != nil {
return nil, err
}
data := append(header, packet.Peer[:]...)
return append(data, packet.Data...), nil
}
func ParseChannelPeerPacket(data []byte) (ChannelPeerPacket, error) {
if len(data) < CHANNEL_PEER_LEN {
return ChannelPeerPacket{}, fmt.Errorf("Not enough bytes to parse ServerChannelPacket: %d/%d", len(data), PEER_ID_LENGTH)
}
header, err := ParseChannelHeader(data)
if err != nil {
return ChannelPeerPacket{}, err
}
return ChannelPeerPacket{
ChannelHeader: header,
Peer: PeerID(data[CHANNEL_HEADER_LEN:]),
Data: data[CHANNEL_PEER_LEN:],
}, nil
}
type ChannelDataPacket struct {
ChannelHeader
Data []byte
}
func NewChannelDataPacket(channel ChannelID, mode ModeID, data []byte) *Packet {
return &Packet{
Type: PACKET_CHANNEL_DATA,
Payload: ChannelDataPacket{
ChannelHeader: ChannelHeader{
Channel: channel,
Mode: mode,
},
Data: data,
},
}
}
func(packet ChannelDataPacket) MarshalBinary() ([]byte, error) {
header, err := packet.ChannelHeader.MarshalBinary()
if err != nil {
return nil, err
}
return append(header, packet.Data...), nil
}
func ParseChannelDataPacket(data []byte) (ChannelDataPacket, error) {
if len(data) < CHANNEL_HEADER_LEN {
return ChannelDataPacket{}, fmt.Errorf("Not enough data to parse ChannelDataPacket")
}
header, err := ParseChannelHeader(data)
if err != nil {
return ChannelDataPacket{}, nil
}
return ChannelDataPacket{
ChannelHeader: header,
Data: data[CHANNEL_HEADER_LEN:],
}, nil
}