go-teeworlds-protocol/chunk7/chunk.go

104 lines
2.2 KiB
Go
Raw Normal View History

2024-06-20 00:26:04 +00:00
package chunk7
2024-06-07 07:38:35 +00:00
import (
"fmt"
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
)
2024-06-07 07:38:35 +00:00
const (
2024-06-17 04:24:08 +00:00
chunkFlagVital = 1
2024-06-07 07:38:35 +00:00
chunkFlagResend = 2
)
type ChunkFlags struct {
2024-06-17 04:24:08 +00:00
Vital bool
2024-06-07 07:38:35 +00:00
Resend bool
}
2024-06-19 04:13:57 +00:00
func (flags *ChunkFlags) ToInt() int {
v := 0
if flags.Resend {
v |= chunkFlagResend
}
if flags.Vital {
v |= chunkFlagVital
}
return v
}
2024-06-07 07:38:35 +00:00
type ChunkHeader struct {
Flags ChunkFlags
Size int
// sequence number
// will be acknowledged in the packet header ack
2024-06-17 04:24:08 +00:00
Seq int
2024-06-07 07:38:35 +00:00
}
type Chunk struct {
Header ChunkHeader
2024-06-17 04:24:08 +00:00
Data []byte
2024-06-07 07:38:35 +00:00
}
2024-06-19 04:13:57 +00:00
func (header *ChunkHeader) Pack() []byte {
len := 2
if header.Flags.Vital {
len = 3
}
data := make([]byte, len)
data[0] = (byte(header.Flags.ToInt()&0x03) << 6) | ((byte(header.Size) >> 6) & 0x3f)
data[1] = (byte(header.Size) & 0x3f)
if header.Flags.Vital {
data[1] |= (byte(header.Seq) >> 2) & 0xc0
data[2] = byte(header.Seq) & 0xff
}
return data
}
func (header *ChunkHeader) Unpack(u *packer.Unpacker) error {
data, err := u.GetRaw(2)
if err != nil {
return err
}
flagBits := (data[0] >> 6) & 0x03
header.Flags.Vital = (flagBits & chunkFlagVital) != 0
header.Flags.Resend = (flagBits & chunkFlagResend) != 0
header.Size = (int(data[0]&0x3F) << 6) | (int(data[1]) & 0x3F)
if header.Flags.Vital {
thirdByte, err := u.GetByte()
if err != nil {
return err
}
header.Seq = int((data[1]&0xC0)<<2) | int(thirdByte)
}
return nil
}
// TODO: give this a better name
//
// but it would be nice to have two unpack methods for all structs
//
// Unpack(u *packer.Unpacker)
// UnpackTodoFindAGoodName(data []byte)
//
// See https://github.com/teeworlds-go/go-teeworlds-protocol/issues/5
func (header *ChunkHeader) UnpackRaw(data []byte) error {
if len(data) < 2 {
return fmt.Errorf("size=%d not enough data to read chunk header", len(data))
}
2024-06-07 07:38:35 +00:00
flagBits := (data[0] >> 6) & 0x03
header.Flags.Vital = (flagBits & chunkFlagVital) != 0
header.Flags.Resend = (flagBits & chunkFlagResend) != 0
2024-06-17 04:24:08 +00:00
header.Size = (int(data[0]&0x3F) << 6) | (int(data[1]) & 0x3F)
2024-06-07 07:38:35 +00:00
if header.Flags.Vital {
if len(data) < 3 {
return fmt.Errorf("size=%d not enough data to read vital chunk header", len(data))
}
2024-06-17 04:24:08 +00:00
header.Seq = int((data[1]&0xC0)<<2) | int(data[2])
2024-06-07 07:38:35 +00:00
}
return nil
2024-06-07 07:38:35 +00:00
}