Help us shape the future of Go! Take the 2026 Go Developer Survey

protocol

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 16, 2026 License: GPL-3.0

README

github.com/pacenote-sim/protocol

The wire protocol between a sim-racing telemetry client and its server: the version 1 data types, and the binary codec for lap traces.

import (
	"github.com/pacenote-sim/protocol/trace"
	"github.com/pacenote-sim/protocol/wire"
)

The client and the server depend on this module by version. A go.work file one directory up replaces it with a local checkout while both are worked on at the same time.

Package What it is
wire The v1 request and response types, with the JSON tags the API is defined in. Standard library only.
trace The lap-trace codec: structure of arrays, zig-zag delta, varint, zstd.

Why it is a module of its own

The capture client and the server are two programs, built in two repositories, by people who cannot see each other's code. Everything they agree on is here, and nothing else is: there is no HTTP in this module, no database, no business rule, no configuration. A type whose tags are a contract has to be readable in one sitting, and a codec that both sides depend on has to be the same code on both sides rather than the same specification implemented twice.

That is also why trace/testdata/golden exists. The client asserts that it produces those bytes; the server asserts that it reads them; neither has to trust the other's tests. Read trace/testdata/README.md before touching them.

The rule

Changing the wire format means bumping the codec version and regenerating the golden vectors — in that order, deliberately, and never to make a red test green.

For trace, the format is the byte layout: CodecVersion in trace/codec.go, a decoder kept for every version still in a database, and the vectors regenerated last. For wire, the format is the JSON tags: wire/testdata/shapes.json pins the serialised shape of every exported type, including the key order and every omitempty, so a tag cannot drift silently. Regenerate it only alongside a deliberate change to the API document.

A blob carries its codec version in its first byte, outside the compressed frame, so trace.Version can read it without decompressing anything and a server can migrate a table having read one byte of each row. That is the escape hatch the format is designed around, and it is the reason a format change is survivable at all.

Using it

blob, err := trace.Encode(lap)      // one allocation, sized exactly
...
pts, err = trace.Decode(blob, pts)  // no allocation at all, given room

Encode validates before it writes: a channel outside the range documented on wire.TracePoint, an offset that does not increase, or more than trace.MaxPoints samples is refused rather than stored and discovered later. Decode validates again on the way out, so a truncated, corrupt or hostile blob returns an error, never a panic, and never a trace that could not have been encoded in the first place.

Decode fills the destination slice in place. Pass the slice from the previous call — only its capacity matters — and a server ingesting forty laps allocates nothing per lap.

Budgets

From docs/SERVER.md, checked by BenchmarkEncode and BenchmarkDecode:

Path Budget
Encode, 300 samples < 40 µs, 1 alloc/op
Decode, 300 samples < 20 µs, 0 allocs/op, into a reused buffer
go test ./trace -run XXX -bench 'Encode|Decode' -benchmem -count=6

Checks

go build ./... && go vet ./...
go test -race -shuffle=on -count=1 ./...
go test -cover ./...
golangci-lint run ./...
gofumpt -l .
go test ./trace -run XXX -fuzz FuzzDecode    -fuzztime 30s
go test ./trace -run XXX -fuzz FuzzRoundTrip -fuzztime 30s

Dependencies: klauspost/compress for zstd, which is pure Go so the server stays CGO-free, plus testify and goleak for the tests. Nothing else, and .golangci.yml has a depguard rule that keeps it that way — wire may import the standard library and nothing more.

Licence

GNU General Public License, version 3 or later. Full text in LICENSE.

A program that imports wire or trace is covered by the GPL too, and has to be passed on under the same terms. Implementing the format from the types and trace/testdata/golden, without importing this module, does not.

Directories

Path Synopsis
Package trace is the binary codec for lap traces: the format described by decision D-1 of docs/SERVER.md, and the reason this module exists.
Package trace is the binary codec for lap traces: the format described by decision D-1 of docs/SERVER.md, and the reason this module exists.
Package wire holds the version 1 data types of the sim telemetry API, exactly as docs/API-V1.md defines them.
Package wire holds the version 1 data types of the sim telemetry API, exactly as docs/API-V1.md defines them.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL