Files
StarPilot/mapd_repo/cereal/subscriber.go
T
firestar5683 ab81464bd1 Maps
Add navigation and map matching providers with the vendored map service sources.

Co-authored-by: Daniel Koepping <elkoled@gmail.com>
Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
2026-10-14 19:56:17 -05:00

88 lines
2.0 KiB
Go

package cereal
import (
"capnproto.org/go/capnp/v3"
"github.com/pfeiferj/gomsgq"
"pfeifer.dev/mapd/cereal/log"
"pfeifer.dev/mapd/settings"
)
type Reader[T any] func(log.Event) (T, error)
type Subscriber[T any] struct {
Sub gomsgq.MsgqSubscriber
reader Reader[T]
readBytes func() []byte
maxBytes int
}
type DecodedEvent[T any] struct {
Value T
Valid bool
LogMonoTime uint64
}
func (s *Subscriber[T]) ReadEvent() (result DecodedEvent[T], success bool) {
// Generated union accessors panic on a different Event variant. An IPC
// message with the wrong discriminant is a decode failure, not a process
// crash.
defer func() {
if recover() != nil {
result = DecodedEvent[T]{}
success = false
}
}()
read := s.readBytes
if read == nil {
read = s.Sub.Read
}
data := read()
if len(data) == 0 || (s.maxBytes > 0 && len(data) > s.maxBytes) {
return result, false
}
msg, err := capnp.Unmarshal(data)
if err != nil {
return result, false
}
// Bound traversal even for malformed pointer graphs. The limit scales with
// the service's message size so large modelV2 events remain readable.
msg.ResetReadLimit(uint64(len(data)) * 16)
event, err := log.ReadRootEvent(msg)
if err != nil {
return result, false
}
result.Value, err = s.reader(event)
if err != nil {
return result, false
}
result.Valid = event.Valid()
result.LogMonoTime = event.LogMonoTime()
return result, true
}
// Read retains the established value-only API for car, model, and CLI users.
func (s *Subscriber[T]) Read() (obj T, success bool) {
event, success := s.ReadEvent()
return event.Value, success
}
func NewSubscriber[T any](name string, reader Reader[T], conflate bool, shadow bool) (subscriber Subscriber[T]) {
msgq := gomsgq.Msgq{}
err := msgq.Init(name, settings.GetSegmentSize(name))
if err != nil {
panic(err)
}
sub := gomsgq.MsgqSubscriber{}
sub.Conflate = conflate
sub.Shadow = shadow
sub.Init(msgq)
subscriber.Sub = sub
subscriber.reader = reader
subscriber.maxBytes = int(settings.GetSegmentSize(name))
return subscriber
}