safety

package
v0.52.0 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2026 License: MPL-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package safety provides end-to-end data protection and deterministic queuing primitives for safety-oriented DDS deployments.

E2EPublisher prepends an 18-byte protection header to every payload before writing. E2ESubscriber strips the header and validates CRC, sequence counter, and sample freshness on every received sample.

Wire format (little-endian, 18 bytes followed by original payload):

Bytes  0–1   DataID (uint16)
Bytes  2–3   SourceID (uint16)
Bytes  4–7   SequenceCounter (uint32, monotonically increasing per publisher)
Bytes  8–15  Timestamp (int64, Unix nanoseconds at time of Write)
Bytes 16–17  CRC-16/CCITT-FALSE over bytes 0–15 plus the original payload
Bytes 18+    Original payload

The CRC slot is treated as zero when computing the CRC.

Index

Constants

This section is empty.

Variables

View Source
var ErrQueueFull = errors.New("safety: queue full")

ErrQueueFull is returned by Enqueue when the DeterministicQueue has no remaining capacity.

Functions

This section is empty.

Types

type DeterministicQueue

type DeterministicQueue struct {
	// contains filtered or unexported fields
}

DeterministicQueue is a bounded FIFO that decouples application writes from the underlying publisher. It contains the publisher's panic (converting it to an error on the Errors channel) and provides non-blocking back-pressure via ErrQueueFull.

Typical use:

q := safety.NewDeterministicQueue(pub, 128).Start()
defer q.Stop()

if err := q.Enqueue(payload); err != nil {
    // handle back-pressure
}

func NewDeterministicQueue

func NewDeterministicQueue(pub dds.Publisher, depth int) *DeterministicQueue

NewDeterministicQueue creates a queue with the given channel depth that drains into pub. Call Start to begin delivery. A depth of ≤ 0 uses 64.

func (*DeterministicQueue) Enqueue

func (q *DeterministicQueue) Enqueue(payload []byte) error

Enqueue adds payload to the queue without blocking. Returns ErrQueueFull if the queue is at capacity.

func (*DeterministicQueue) Errors

func (q *DeterministicQueue) Errors() <-chan error

Errors returns a channel that receives errors from the drain goroutine, including publisher errors and panics wrapped as errors.

func (*DeterministicQueue) Start

Start launches the drain goroutine. Returns q for chaining.

func (*DeterministicQueue) Stop

func (q *DeterministicQueue) Stop()

Stop signals the drain goroutine to exit and waits for it to finish. Safe to call more than once.

type E2EConfig

type E2EConfig struct {
	// DataID identifies the logical data element (0–65535).
	DataID uint16
	// SourceID identifies the sender (0–65535).
	SourceID uint16
	// MaxAge is the maximum permitted age of a received sample, measured from
	// the timestamp written by the publisher. Zero disables freshness checking.
	MaxAge time.Duration
	// Topic is the DDS topic name; used to label safety metrics. Optional.
	Topic string
}

E2EConfig configures end-to-end protection parameters shared by a publisher and subscriber pair.

type E2EError

type E2EError struct {
	Kind    E2EErrorKind
	Counter uint32
	Message string
}

E2EError is sent over the Errors channel when a safety check fails.

func (E2EError) Error

func (e E2EError) Error() string

type E2EErrorKind

type E2EErrorKind int

E2EErrorKind categorises safety check failures reported by E2ESubscriber.

const (
	// ErrCRCMismatch means the CRC in the frame header did not match.
	ErrCRCMismatch E2EErrorKind = iota
	// ErrSequenceGap means one or more sequence numbers were skipped.
	ErrSequenceGap
	// ErrStaleSample means the sample's timestamp is older than MaxAge.
	ErrStaleSample
	// ErrHeaderTooShort means the payload is shorter than the 18-byte header.
	ErrHeaderTooShort
)

type E2EPublisher

type E2EPublisher struct {
	// contains filtered or unexported fields
}

E2EPublisher wraps a dds.Publisher and prepends an E2E protection header to every Write payload. It satisfies dds.Publisher.

func NewE2EPublisher

func NewE2EPublisher(pub dds.Publisher, cfg E2EConfig) *E2EPublisher

NewE2EPublisher wraps pub with end-to-end protection configured by cfg.

func (*E2EPublisher) Close

func (p *E2EPublisher) Close() error

Close closes the underlying publisher.

func (*E2EPublisher) Write

func (p *E2EPublisher) Write(payload []byte) error

Write prepends an E2E header to payload and writes the frame to the underlying publisher.

type E2ESubscriber

type E2ESubscriber struct {
	// contains filtered or unexported fields
}

E2ESubscriber wraps a dds.Subscriber, strips the E2E header from each received sample, and validates CRC, sequence counter, and freshness. Valid samples are forwarded to C(); failures are reported on Errors().

The background pump goroutine starts on construction and exits when Close is called or the underlying subscriber channel is closed.

E2ESubscriber implements SafetyMetricsProvider; call SafetyMetrics() to retrieve cumulative violation counters, and SafetyEvents() to receive a channel of individual SafetyEvent values (e.g., for monitor integration).

func NewE2ESubscriber

func NewE2ESubscriber(sub dds.Subscriber, cfg E2EConfig) *E2ESubscriber

NewE2ESubscriber wraps sub with E2E validation using cfg.

func (*E2ESubscriber) C

func (s *E2ESubscriber) C() <-chan dds.Sample

C returns the channel that delivers validated, header-stripped samples. It satisfies dds.Subscriber.

func (*E2ESubscriber) Close

func (s *E2ESubscriber) Close() error

Close stops the pump goroutine and closes the underlying subscriber.

func (*E2ESubscriber) Errors

func (s *E2ESubscriber) Errors() <-chan E2EError

Errors returns a channel that receives E2EError values for every safety check failure. The channel is buffered (32); overflows are silently dropped.

func (*E2ESubscriber) SafetyEvents added in v0.12.1

func (s *E2ESubscriber) SafetyEvents() <-chan SafetyEvent

SafetyEvents returns a channel that receives one SafetyEvent per violation. The channel is buffered (64); slow consumers cause events to be dropped. Intended for integration with monitor.Monitor.WatchSafety.

func (*E2ESubscriber) SafetyMetrics added in v0.12.1

func (s *E2ESubscriber) SafetyMetrics() Snapshot

SafetyMetrics returns a point-in-time snapshot of cumulative violation counters. It implements SafetyMetricsProvider.

type RateAlert added in v0.13.0

type RateAlert struct {
	// Topic is the DDS topic for which the threshold was exceeded.
	Topic string
	// Kind is the safety event category that triggered the alert.
	Kind SafetyEventKind
	// Rate is the observed violation rate (events per second) over the last window.
	Rate float64
	// Threshold is the configured maximum rate that was exceeded.
	Threshold float64
}

RateAlert is emitted by RateMonitor when a violation rate exceeds its threshold.

type RateMonitor added in v0.13.0

type RateMonitor struct {
	// contains filtered or unexported fields
}

RateMonitor polls a SafetyMetricsProvider at a fixed interval and invokes an alert callback whenever any violation rate exceeds its configured threshold. It is safe for concurrent use.

func NewRateMonitor added in v0.13.0

func NewRateMonitor(p SafetyMetricsProvider, interval time.Duration, thresholds RateThresholds, onAlert func(RateAlert)) *RateMonitor

NewRateMonitor starts a RateMonitor that polls p every interval. When a violation rate exceeds a threshold, onAlert is called synchronously from the background goroutine. Call Stop to release resources. Intervals ≤ 0 default to 5 seconds.

func (*RateMonitor) Stop added in v0.13.0

func (rm *RateMonitor) Stop()

Stop shuts down the background polling goroutine. It is safe to call once.

type RateThresholds added in v0.13.0

type RateThresholds struct {
	CRCFailureRate      float64
	SequenceGapRate     float64
	StaleSampleRate     float64
	SchemaViolationRate float64
}

RateThresholds defines the maximum tolerated violation rate (events per second) for each safety event kind. A threshold of zero disables that check.

type SafetyEvent added in v0.12.1

type SafetyEvent struct {
	// Kind classifies the violation.
	Kind SafetyEventKind
	// Topic is the DDS topic on which the violation was detected.
	Topic string
	// Counter is the sequence counter from the frame header (0 if unavailable).
	Counter uint32
	// Message is a human-readable description of the violation.
	Message string
}

SafetyEvent represents a single E2E safety violation detected by an E2ESubscriber. It is broadcast to registered safety event listeners (e.g., monitor.Monitor).

type SafetyEventKind added in v0.12.1

type SafetyEventKind int

SafetyEventKind categorises safety events emitted by E2ESubscriber.

const (
	// SafetyEventCRCFailure is emitted when a frame fails its CRC check.
	SafetyEventCRCFailure SafetyEventKind = iota
	// SafetyEventSequenceGap is emitted when one or more sequence numbers are skipped.
	SafetyEventSequenceGap
	// SafetyEventStaleSample is emitted when a sample exceeds MaxAge.
	SafetyEventStaleSample
	// SafetyEventHeaderTooShort is emitted when a payload is shorter than the E2E header.
	SafetyEventHeaderTooShort
	// SafetyEventSchemaViolation is emitted when a sample's type does not match the registered schema.
	SafetyEventSchemaViolation
)

func (SafetyEventKind) String added in v0.12.1

func (k SafetyEventKind) String() string

type SafetyMetricsProvider added in v0.12.1

type SafetyMetricsProvider interface {
	// SafetyMetrics returns a point-in-time snapshot of safety violation counters.
	SafetyMetrics() Snapshot
}

SafetyMetricsProvider is implemented by components that expose E2E violation counters.

type Snapshot added in v0.12.1

type Snapshot struct {
	Topic            string `json:"topic"`
	CRCFailures      uint64 `json:"crc_failures"`
	SequenceGaps     uint64 `json:"sequence_gaps"`
	StaleSamples     uint64 `json:"stale_samples"`
	HeaderTooShort   uint64 `json:"header_too_short"`
	SchemaViolations uint64 `json:"schema_violations"`
	ValidSamples     uint64 `json:"valid_samples"`
}

Snapshot is a point-in-time copy of violation counters for one subscriber.

Jump to

Keyboard shortcuts

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