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_JOIN_CHANNEL byte = iota SERVER_COMMAND_LEAVE_CHANNEL SERVER_COMMAND_ADD_CHANNEL 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(request_id uuid.UUID, command byte, data []byte) *Packet { return &Packet{ Type: PACKET_SERVER_COMMAND, Payload: ServerCommandPacket{ ReqID: request_id, Command: command, Data: data, }, } } 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 }