2024-04-03 18:52:04 -06:00
|
|
|
package pnyx
|
|
|
|
|
|
|
|
import (
|
2024-04-09 17:08:46 -06:00
|
|
|
"encoding"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
2024-04-03 19:31:58 -06:00
|
|
|
)
|
|
|
|
|
2024-04-09 17:08:46 -06:00
|
|
|
type PacketType uint8
|
|
|
|
const (
|
2024-04-12 18:06:57 -06:00
|
|
|
PACKET_SERVER_COMMAND PacketType = iota
|
|
|
|
PACKET_CHANNEL_COMMAND
|
2024-04-16 15:06:53 -06:00
|
|
|
PACKET_DATA
|
|
|
|
PACKET_PEER
|
|
|
|
PACKET_PING
|
2024-04-09 17:08:46 -06:00
|
|
|
|
2024-04-12 18:06:57 -06:00
|
|
|
CHANNEL_HEADER_LEN int = 2
|
2024-04-11 21:05:50 -06:00
|
|
|
CHANNEL_COMMAND_LEN = CHANNEL_HEADER_LEN + COMMAND_LENGTH + REQ_ID_LENGTH
|
|
|
|
CHANNEL_PEER_LEN = CHANNEL_HEADER_LEN + PEER_ID_LENGTH
|
2024-04-12 18:06:57 -06:00
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
CHANNEL_COMMAND_JOIN byte = iota
|
|
|
|
CHANNEL_COMMAND_LEAVE
|
|
|
|
|
|
|
|
SERVER_COMMAND_ADD_CHANNEL byte = iota
|
2024-04-12 18:06:57 -06:00
|
|
|
SERVER_COMMAND_DEL_CHANNEL
|
2024-04-09 17:08:46 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
type Payload interface {
|
|
|
|
encoding.BinaryMarshaler
|
|
|
|
}
|
|
|
|
|
2024-04-08 11:28:52 -06:00
|
|
|
type Packet struct {
|
2024-04-09 17:08:46 -06:00
|
|
|
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]) {
|
2024-04-12 18:06:57 -06:00
|
|
|
case PACKET_SERVER_COMMAND:
|
2024-04-16 15:06:53 -06:00
|
|
|
return ParseCommandPacket(data[1:])
|
2024-04-09 17:08:46 -06:00
|
|
|
case PACKET_CHANNEL_COMMAND:
|
|
|
|
return ParseChannelCommandPacket(data[1:])
|
2024-04-16 15:06:53 -06:00
|
|
|
case PACKET_DATA:
|
|
|
|
return ParseDataPacket(data[1:])
|
|
|
|
case PACKET_PEER:
|
|
|
|
return ParsePeerPacket(data[1:])
|
|
|
|
case PACKET_PING:
|
|
|
|
return ParsePingPacket(data[1:])
|
2024-04-09 17:08:46 -06:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("Don't know how to parse packet type 0x%02x", data[0])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
type PingPacket struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
func(packet PingPacket) MarshalBinary() ([]byte, error) {
|
|
|
|
return []byte{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewPingPacket() *Packet {
|
|
|
|
return &Packet{
|
|
|
|
Type: PACKET_PING,
|
|
|
|
Payload: PingPacket{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ParsePingPacket(data []byte) (PingPacket, error) {
|
|
|
|
if len(data) != 0 {
|
|
|
|
return PingPacket{}, fmt.Errorf("Wrong number of bytes to parse PingPacket %d/0", len(data))
|
|
|
|
}
|
|
|
|
|
|
|
|
return PingPacket{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type CommandPacket struct {
|
2024-04-12 18:06:57 -06:00
|
|
|
ReqID uuid.UUID
|
|
|
|
Command byte
|
|
|
|
Data []byte
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func (packet CommandPacket) MarshalBinary() ([]byte, error) {
|
2024-04-12 18:06:57 -06:00
|
|
|
p := make([]byte, 17 + len(packet.Data))
|
|
|
|
copy(p, packet.ReqID[:])
|
|
|
|
p[16] = packet.Command
|
|
|
|
copy(p[17:], packet.Data)
|
|
|
|
|
|
|
|
return p, nil
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func NewCommandPacket(request_id uuid.UUID, command byte, data []byte) *Packet {
|
2024-04-12 18:06:57 -06:00
|
|
|
return &Packet{
|
|
|
|
Type: PACKET_SERVER_COMMAND,
|
2024-04-16 15:06:53 -06:00
|
|
|
Payload: CommandPacket{
|
2024-04-13 14:00:56 -06:00
|
|
|
ReqID: request_id,
|
2024-04-12 18:06:57 -06:00
|
|
|
Command: command,
|
|
|
|
Data: data,
|
|
|
|
},
|
2024-04-13 14:00:56 -06:00
|
|
|
}
|
2024-04-12 18:06:57 -06:00
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func ParseCommandPacket(data []byte) (CommandPacket, error) {
|
2024-04-12 18:06:57 -06:00
|
|
|
if len(data) < 17 {
|
2024-04-16 15:06:53 -06:00
|
|
|
return CommandPacket{}, fmt.Errorf("Not enough data to decode CommandPacket: %d/%d", len(data), 17)
|
2024-04-12 18:06:57 -06:00
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
return CommandPacket{
|
2024-04-12 18:06:57 -06:00
|
|
|
ReqID: uuid.UUID(data[0:16]),
|
|
|
|
Command: data[16],
|
|
|
|
Data: data[17:],
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2024-04-09 17:08:46 -06:00
|
|
|
type ChannelHeader struct {
|
2024-04-08 11:28:52 -06:00
|
|
|
Channel ChannelID
|
|
|
|
Mode ModeID
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func(packet ChannelHeader) MarshalBinary() ([]byte, error) {
|
2024-04-12 18:06:57 -06:00
|
|
|
return []byte{byte(packet.Channel), byte(packet.Mode)}, nil
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func ParseChannelHeader(data []byte) (ChannelHeader, error) {
|
2024-04-12 18:06:57 -06:00
|
|
|
if len(data) < 2 {
|
2024-04-16 15:34:53 -06:00
|
|
|
return ChannelHeader{}, fmt.Errorf("Not enough bytes to parse ChannelPacket(%d/%d)", len(data), 2)
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return ChannelHeader{
|
2024-04-12 18:06:57 -06:00
|
|
|
Channel: ChannelID(data[0]),
|
|
|
|
Mode: ModeID(data[1]),
|
2024-04-09 17:08:46 -06:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type ChannelCommandPacket struct {
|
|
|
|
ChannelHeader
|
2024-04-08 11:28:52 -06:00
|
|
|
Command byte
|
2024-04-09 17:08:46 -06:00
|
|
|
ReqID uuid.UUID
|
2024-04-08 11:28:52 -06:00
|
|
|
Data []byte
|
2024-04-06 16:38:14 -06:00
|
|
|
}
|
|
|
|
|
2024-04-12 18:06:57 -06:00
|
|
|
func NewChannelCommandPacket(request_id uuid.UUID, channel ChannelID, mode ModeID, command byte, data []byte) *Packet {
|
2024-04-09 17:08:46 -06:00
|
|
|
return &Packet{
|
|
|
|
Type: PACKET_CHANNEL_COMMAND,
|
|
|
|
Payload: ChannelCommandPacket{
|
|
|
|
ChannelHeader: ChannelHeader{
|
|
|
|
Channel: channel,
|
|
|
|
Mode: mode,
|
|
|
|
},
|
|
|
|
Command: command,
|
|
|
|
ReqID: request_id,
|
|
|
|
Data: data,
|
|
|
|
},
|
2024-04-12 18:06:57 -06:00
|
|
|
}
|
2024-04-06 16:38:14 -06:00
|
|
|
}
|
2024-04-03 18:52:04 -06:00
|
|
|
|
2024-04-09 17:08:46 -06:00
|
|
|
func(packet ChannelCommandPacket) MarshalBinary() ([]byte, error) {
|
|
|
|
header, err := packet.ChannelHeader.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-04-12 18:06:57 -06:00
|
|
|
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
|
2024-04-06 16:38:14 -06:00
|
|
|
}
|
2024-04-03 18:52:04 -06:00
|
|
|
|
2024-04-09 17:08:46 -06:00
|
|
|
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
|
2024-04-06 16:38:14 -06:00
|
|
|
}
|
|
|
|
|
2024-04-09 17:08:46 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
type PeerPacket struct {
|
2024-04-09 17:08:46 -06:00
|
|
|
ChannelHeader
|
|
|
|
Peer PeerID
|
|
|
|
Data []byte
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func NewPeerPacket(peer PeerID, channel ChannelID, mode ModeID, data []byte) *Packet {
|
2024-04-08 11:28:52 -06:00
|
|
|
return &Packet{
|
2024-04-16 15:06:53 -06:00
|
|
|
Type: PACKET_PEER,
|
|
|
|
Payload: PeerPacket{
|
2024-04-09 17:08:46 -06:00
|
|
|
ChannelHeader: ChannelHeader{
|
|
|
|
Channel: channel,
|
|
|
|
Mode: mode,
|
|
|
|
},
|
|
|
|
Peer: peer,
|
|
|
|
Data: data,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func(packet PeerPacket) MarshalBinary() ([]byte, error) {
|
2024-04-09 17:08:46 -06:00
|
|
|
header, err := packet.ChannelHeader.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:34:53 -06:00
|
|
|
data := make([]byte, CHANNEL_PEER_LEN + len(packet.Data))
|
|
|
|
copy(data, header)
|
|
|
|
copy(data[CHANNEL_HEADER_LEN:], packet.Peer[:])
|
|
|
|
copy(data[CHANNEL_PEER_LEN:], packet.Data)
|
|
|
|
return data, nil
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func ParsePeerPacket(data []byte) (PeerPacket, error) {
|
2024-04-09 17:08:46 -06:00
|
|
|
if len(data) < CHANNEL_PEER_LEN {
|
2024-04-16 15:06:53 -06:00
|
|
|
return PeerPacket{}, fmt.Errorf("Not enough bytes to parse ServerChannelPacket: %d/%d", len(data), PEER_ID_LENGTH)
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
header, err := ParseChannelHeader(data)
|
|
|
|
if err != nil {
|
2024-04-16 15:06:53 -06:00
|
|
|
return PeerPacket{}, err
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
return PeerPacket{
|
2024-04-09 17:08:46 -06:00
|
|
|
ChannelHeader: header,
|
|
|
|
Peer: PeerID(data[CHANNEL_HEADER_LEN:]),
|
2024-04-16 15:34:53 -06:00
|
|
|
Data: data[CHANNEL_HEADER_LEN + PEER_ID_LENGTH:],
|
2024-04-09 17:08:46 -06:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
type DataPacket struct {
|
2024-04-09 17:08:46 -06:00
|
|
|
ChannelHeader
|
|
|
|
Data []byte
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func NewDataPacket(channel ChannelID, mode ModeID, data []byte) *Packet {
|
2024-04-09 17:08:46 -06:00
|
|
|
return &Packet{
|
2024-04-16 15:06:53 -06:00
|
|
|
Type: PACKET_DATA,
|
|
|
|
Payload: DataPacket{
|
2024-04-09 17:08:46 -06:00
|
|
|
ChannelHeader: ChannelHeader{
|
|
|
|
Channel: channel,
|
|
|
|
Mode: mode,
|
|
|
|
},
|
|
|
|
Data: data,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func(packet DataPacket) MarshalBinary() ([]byte, error) {
|
2024-04-09 17:08:46 -06:00
|
|
|
header, err := packet.ChannelHeader.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return append(header, packet.Data...), nil
|
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
func ParseDataPacket(data []byte) (DataPacket, error) {
|
2024-04-09 17:08:46 -06:00
|
|
|
if len(data) < CHANNEL_HEADER_LEN {
|
2024-04-16 15:06:53 -06:00
|
|
|
return DataPacket{}, fmt.Errorf("Not enough data to parse DataPacket")
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
header, err := ParseChannelHeader(data)
|
|
|
|
if err != nil {
|
2024-04-16 15:06:53 -06:00
|
|
|
return DataPacket{}, nil
|
2024-04-09 17:08:46 -06:00
|
|
|
}
|
|
|
|
|
2024-04-16 15:06:53 -06:00
|
|
|
return DataPacket{
|
2024-04-09 17:08:46 -06:00
|
|
|
ChannelHeader: header,
|
|
|
|
Data: data[CHANNEL_HEADER_LEN:],
|
2024-04-08 11:28:52 -06:00
|
|
|
}, nil
|
2024-04-03 18:52:04 -06:00
|
|
|
}
|