Make packet a module and import huffman

This commit is contained in:
ChillerDragon 2024-06-06 12:51:18 +08:00
parent 17047eac70
commit 4d307dc990
8 changed files with 165 additions and 116 deletions

28
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,28 @@
name: Go
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.22'
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...
- name: Format
run: diff -u <(echo -n) <(gofmt -d ./)

2
.gitignore vendored
View file

@ -1 +1,3 @@
teeworlds_client teeworlds_client
teeworlds

2
go.mod
View file

@ -1,3 +1,5 @@
module github.com/teeworlds-go/teeworlds module github.com/teeworlds-go/teeworlds
go 1.22.3 go 1.22.3
require github.com/teeworlds-go/huffman v1.0.0 // indirect

2
go.sum Normal file
View file

@ -0,0 +1,2 @@
github.com/teeworlds-go/huffman v1.0.0 h1:XSNMNAJZb+njNrPACsxcDrrLDXTGjZZt35FqLAuHi4I=
github.com/teeworlds-go/huffman v1.0.0/go.mod h1:kjaXpL6C6xL7CM+tWPNYjdEgVZB2GumKhx7rCDdXArU=

View file

@ -1,56 +0,0 @@
package main
const (
packetFlagControl = 1
packetFlagResend = 2
packetFlagCompression = 4
packetFlagConnless = 8
)
type PacketFlags struct {
connless bool
compression bool
resend bool
control bool
}
type PacketHeader struct {
flags PacketFlags
ack int
numChunks int
token [4]byte
}
func (header *PacketHeader) unpack(packet []byte) {
header.flags.unpack(packet)
header.ack = (int(packet[0]&0x3) << 8) | int(packet[1])
header.numChunks = int(packet[2])
copy(header.token[:], packet[3:7])
}
func (flags *PacketFlags) unpack(packetHeaderRaw []byte) {
flagBits := packetHeaderRaw[0] >> 2
flags.control = (flagBits & packetFlagControl) != 0
flags.resend = (flagBits & packetFlagResend) != 0
flags.compression = (flagBits & packetFlagCompression) != 0
flags.connless = (flagBits & packetFlagConnless) != 0
}
func (flags *PacketFlags) pack() []byte {
data := 0
if flags.control {
data |= packetFlagControl
}
if flags.resend {
data |= packetFlagResend
}
if flags.compression {
data |= packetFlagCompression
}
if flags.connless {
data |= packetFlagConnless
}
return []byte{byte(data)}
}

56
packet/packet.go Normal file
View file

@ -0,0 +1,56 @@
package packet
const (
packetFlagControl = 1
packetFlagResend = 2
packetFlagCompression = 4
packetFlagConnless = 8
)
type PacketFlags struct {
Connless bool
Compression bool
Resend bool
Control bool
}
type PacketHeader struct {
Flags PacketFlags
Ack int
NumChunks int
Token [4]byte
}
func (header *PacketHeader) Unpack(packet []byte) {
header.Flags.Unpack(packet)
header.Ack = (int(packet[0]&0x3) << 8) | int(packet[1])
header.NumChunks = int(packet[2])
copy(header.Token[:], packet[3:7])
}
func (flags *PacketFlags) Unpack(packetHeaderRaw []byte) {
flagBits := packetHeaderRaw[0] >> 2
flags.Control = (flagBits & packetFlagControl) != 0
flags.Resend = (flagBits & packetFlagResend) != 0
flags.Compression = (flagBits & packetFlagCompression) != 0
flags.Connless = (flagBits & packetFlagConnless) != 0
}
func (flags *PacketFlags) Pack() []byte {
data := 0
if flags.Control {
data |= packetFlagControl
}
if flags.Resend {
data |= packetFlagResend
}
if flags.Compression {
data |= packetFlagCompression
}
if flags.Connless {
data |= packetFlagConnless
}
return []byte{byte(data)}
}

View file

@ -1,4 +1,4 @@
package main package packet
import ( import (
"reflect" "reflect"
@ -10,13 +10,13 @@ import (
func TestPackFlagsUnset(t *testing.T) { func TestPackFlagsUnset(t *testing.T) {
flags := PacketFlags{ flags := PacketFlags{
connless: false, Connless: false,
compression: false, Compression: false,
resend: false, Resend: false,
control: false, Control: false,
} }
got := flags.pack() got := flags.Pack()
want := []byte{0b0000} want := []byte{0b0000}
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
@ -26,13 +26,13 @@ func TestPackFlagsUnset(t *testing.T) {
func TestPackFlagsCompressionSet(t *testing.T) { func TestPackFlagsCompressionSet(t *testing.T) {
flags := PacketFlags{ flags := PacketFlags{
connless: false, Connless: false,
compression: true, Compression: true,
resend: false, Resend: false,
control: false, Control: false,
} }
got := flags.pack() got := flags.Pack()
want := []byte{0b0100} want := []byte{0b0100}
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
@ -42,13 +42,13 @@ func TestPackFlagsCompressionSet(t *testing.T) {
func TestPackFlagsAllSet(t *testing.T) { func TestPackFlagsAllSet(t *testing.T) {
flags := PacketFlags{ flags := PacketFlags{
connless: true, Connless: true,
compression: true, Compression: true,
resend: true, Resend: true,
control: true, Control: true,
} }
got := flags.pack() got := flags.Pack()
want := []byte{0b1111} want := []byte{0b1111}
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
@ -61,13 +61,13 @@ func TestPackFlagsAllSet(t *testing.T) {
func TestUnpackFlagsAllSet(t *testing.T) { func TestUnpackFlagsAllSet(t *testing.T) {
got := PacketFlags{} got := PacketFlags{}
want := PacketFlags{ want := PacketFlags{
connless: true, Connless: true,
compression: true, Compression: true,
resend: true, Resend: true,
control: true, Control: true,
} }
got.unpack([]byte{0b00111100}) got.Unpack([]byte{0b00111100})
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want) t.Errorf("got %v, wanted %v", got, want)
@ -77,13 +77,13 @@ func TestUnpackFlagsAllSet(t *testing.T) {
func TestUnpackFlagsControlSet(t *testing.T) { func TestUnpackFlagsControlSet(t *testing.T) {
got := PacketFlags{} got := PacketFlags{}
want := PacketFlags{ want := PacketFlags{
connless: false, Connless: false,
compression: false, Compression: false,
resend: false, Resend: false,
control: true, Control: true,
} }
got.unpack([]byte{0b00000100}) got.Unpack([]byte{0b00000100})
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want) t.Errorf("got %v, wanted %v", got, want)
@ -93,13 +93,13 @@ func TestUnpackFlagsControlSet(t *testing.T) {
func TestUnpackFlagsUnset(t *testing.T) { func TestUnpackFlagsUnset(t *testing.T) {
got := PacketFlags{} got := PacketFlags{}
want := PacketFlags{ want := PacketFlags{
connless: false, Connless: false,
compression: false, Compression: false,
resend: false, Resend: false,
control: false, Control: false,
} }
got.unpack([]byte{0b00000000}) got.Unpack([]byte{0b00000000})
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want) t.Errorf("got %v, wanted %v", got, want)
@ -111,18 +111,18 @@ func TestUnpackFlagsUnset(t *testing.T) {
func TestUnpackCloseWithReason(t *testing.T) { func TestUnpackCloseWithReason(t *testing.T) {
got := PacketHeader{} got := PacketHeader{}
want := PacketHeader{ want := PacketHeader{
flags: PacketFlags{ Flags: PacketFlags{
connless: false, Connless: false,
compression: false, Compression: false,
resend: false, Resend: false,
control: true, Control: true,
}, },
ack: 10, Ack: 10,
numChunks: 0, NumChunks: 0,
token: [4]byte{0xcf, 0x2e, 0xde, 0x1d}, Token: [4]byte{0xcf, 0x2e, 0xde, 0x1d},
} }
got.unpack(slices.Concat([]byte{0x04, 0x0a, 0x00, 0xcf, 0x2e, 0xde, 0x1d, 0x04}, []byte("shutdown"), []byte{0x00})) got.Unpack(slices.Concat([]byte{0x04, 0x0a, 0x00, 0xcf, 0x2e, 0xde, 0x1d, 0x04}, []byte("shutdown"), []byte{0x00}))
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want) t.Errorf("got %v, wanted %v", got, want)
@ -132,18 +132,18 @@ func TestUnpackCloseWithReason(t *testing.T) {
func TestUnpackHeaderFlagsControlSet(t *testing.T) { func TestUnpackHeaderFlagsControlSet(t *testing.T) {
got := PacketHeader{} got := PacketHeader{}
want := PacketHeader{ want := PacketHeader{
flags: PacketFlags{ Flags: PacketFlags{
connless: false, Connless: false,
compression: false, Compression: false,
resend: false, Resend: false,
control: true, Control: true,
}, },
ack: 0, Ack: 0,
numChunks: 0, NumChunks: 0,
token: [4]byte{0xff, 0xff, 0xff, 0xff}, Token: [4]byte{0xff, 0xff, 0xff, 0xff},
} }
got.unpack([]byte{0b00000100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}) got.Unpack([]byte{0b00000100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff})
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want) t.Errorf("got %v, wanted %v", got, want)
@ -153,18 +153,18 @@ func TestUnpackHeaderFlagsControlSet(t *testing.T) {
func TestUnpackHeaderFlagsAllSet(t *testing.T) { func TestUnpackHeaderFlagsAllSet(t *testing.T) {
got := PacketHeader{} got := PacketHeader{}
want := PacketHeader{ want := PacketHeader{
flags: PacketFlags{ Flags: PacketFlags{
connless: true, Connless: true,
compression: true, Compression: true,
resend: true, Resend: true,
control: true, Control: true,
}, },
ack: 0, Ack: 0,
numChunks: 0, NumChunks: 0,
token: [4]byte{0xff, 0xff, 0xff, 0xff}, Token: [4]byte{0xff, 0xff, 0xff, 0xff},
} }
got.unpack([]byte{0b00111100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}) got.Unpack([]byte{0b00111100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff})
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want) t.Errorf("got %v, wanted %v", got, want)

View file

@ -8,6 +8,9 @@ import (
"os" "os"
"slices" "slices"
"time" "time"
"github.com/teeworlds-go/huffman"
"github.com/teeworlds-go/teeworlds/packet"
) )
const ( const (
@ -160,7 +163,10 @@ func byteSliceToString(s []byte) string {
} }
func (client *TeeworldsClient) onMessage(data []byte) { func (client *TeeworldsClient) onMessage(data []byte) {
if isCtrlMsg(data) { header := packet.PacketHeader{}
header.Unpack(data)
if header.Flags.Control {
ctrlMsg := data[7] ctrlMsg := data[7]
fmt.Printf("got ctrl msg %d\n", ctrlMsg) fmt.Printf("got ctrl msg %d\n", ctrlMsg)
if ctrlMsg == msgCtrlToken { if ctrlMsg == msgCtrlToken {
@ -181,10 +187,19 @@ func (client *TeeworldsClient) onMessage(data []byte) {
} else { } else {
fmt.Printf("unknown control message: %x\n", data) fmt.Printf("unknown control message: %x\n", data)
} }
} else if header.Flags.Compression {
payload := data[8:]
fmt.Printf("got compressed data: %v\n", payload)
huff := huffman.Huffman{}
decompressed, err := huff.Decompress(payload)
if err != nil {
fmt.Printf("huffman error: %v\n", err)
return
}
fmt.Printf("got decompressed: %v\n", decompressed)
} else if isMapChange(data) { } else if isMapChange(data) {
fmt.Println("got map change") fmt.Println("got map change")
client.sendReady() client.sendReady()
} else if isConReady(data) { } else if isConReady(data) {
fmt.Println("got ready") fmt.Println("got ready")
client.sendStartInfo() client.sendStartInfo()