protohackers/cmd/speeddaemon/message.go

109 lines
2.4 KiB
Go

package main
import (
"bytes"
"encoding/binary"
"fmt"
"time"
)
const (
errorHeader byte = 0x10
plateHeader byte = 0x20
ticketHeader byte = 0x21
wantHeartbeatHeader byte = 0x40
heartbeatHeader byte = 0x41
amCameraHeader byte = 0x80
amDispatcherHeader byte = 0x81
)
func encodeErrorMessage(msg string) []byte {
b := bytes.NewBuffer([]byte{errorHeader})
b.WriteByte(byte(len(msg)))
b.Write([]byte(msg))
return b.Bytes()
}
type plateMessage struct {
plate string
timestamp time.Time
}
func decodePlateMessage(data []byte) (*plateMessage, error) {
if data[0] != plateHeader {
return nil, fmt.Errorf("attempted to decode plate message with header %0x", data[0])
}
pl := int(data[1])
plate := string(data[2 : 2+pl])
ts32 := binary.BigEndian.Uint32(data[2+pl:])
return &plateMessage{
plate: plate,
timestamp: time.Unix(int64(ts32), 0),
}, nil
}
type ticketMessage struct {
plate string
road uint16
mileOne uint16
timestampOne uint32
mileTwo uint16
timestampTwo uint32
speed uint16
}
func encodeTicketMessage(data []byte) (*ticketMessage, error) {
panic("unimplemented")
}
type wantHeartbeatMessage uint32
func decodeWantHeartbeatMessage(data []byte) (*wantHeartbeatMessage, error) {
if data[0] != wantHeartbeatHeader {
return nil, fmt.Errorf("attempted to decode wantHearbeatMessage with header %0x", data[0])
}
d := wantHeartbeatMessage(binary.BigEndian.Uint32(data[1:]))
return &d, nil
}
func encodeHeartbeat() []byte {
return []byte{heartbeatHeader}
}
type amCameraMessage struct {
road, mile, limit uint16
}
func decodeAmCameraMessage(data []byte) (*amCameraMessage, error) {
if data[0] != amCameraHeader {
return nil, fmt.Errorf("attempted to decode amCameraMessage with header %0x", data[0])
}
return &amCameraMessage{
road: binary.BigEndian.Uint16(data[1:3]),
mile: binary.BigEndian.Uint16(data[3:5]),
limit: binary.BigEndian.Uint16(data[5:]),
}, nil
}
type amDispatcherMessage struct {
numroads byte
roads []uint16
}
func decodeAmDispatcherMessage(data []byte) (*amDispatcherMessage, error) {
if data[0] != amDispatcherHeader {
return nil, fmt.Errorf("attempted to decode amDispatcherMessage with header %0x", data[0])
}
var roads []uint16
for i, j := 0, 2; i < int(data[1]); i++ {
roads = append(roads, binary.BigEndian.Uint16(data[j:j+2]))
j += 2
}
return &amDispatcherMessage{
data[1],
roads,
}, nil
}