Documentation
¶
Overview ¶
Package interfaceschema parses, validates, and compiles Astarte interface definitions — the dynamic typed schemas (datastreams and properties) that devices and applications exchange data through.
The package mirrors upstream Astarte semantics (docs/DESIGN.md §2.6): ParseInterface performs a strict decode plus full structural validation of the Interface JSON, Compile turns a validated definition into the hot-path CompiledInterface (endpoint trie + object leaves), and CheckMinorUpgrade enforces the additive-only minor-version compatibility rule that Realm Management applies on interface updates.
Index ¶
- Constants
- Variables
- func CheckMinorUpgrade(old, next *Interface) error
- type Aggregation
- type CompiledInterface
- type CompiledMapping
- type DatabaseRetentionPolicy
- type EndpointIDResolver
- type EndpointTrie
- type Interface
- type InterfaceType
- type Mapping
- type Ownership
- type Reliability
- type Retention
- type ValueType
Constants ¶
const ( // MaxNameLength is the maximum interface name length. MaxNameLength = 128 // MaxMappings is the maximum number of mappings per interface. MaxMappings = 1024 // MaxEndpointDepth is the maximum number of endpoint levels. MaxEndpointDepth = 64 )
Structural limits, matching upstream Astarte (astarte_core).
const MaxPlaceholderValueLen = 256
MaxPlaceholderValueLen is the maximum byte length of a concrete path segment matched by a %{placeholder} (docs/DESIGN.md §2.6 hygiene rule).
Variables ¶
var ErrIncompatibleUpgrade = errors.New("incompatible interface upgrade")
ErrIncompatibleUpgrade is wrapped by every CheckMinorUpgrade rejection, so callers can classify upgrade failures with errors.Is.
var ErrInvalid = errors.New("invalid interface")
ErrInvalid is wrapped by every ParseInterface failure, so callers can classify rejection with errors.Is regardless of the specific rule violated.
Functions ¶
func CheckMinorUpgrade ¶
CheckMinorUpgrade enforces the Astarte minor-version compatibility rule exactly as Realm Management does on interface update (docs/DESIGN.md §2.6 versioning parity): next must keep the same name, major version, type, ownership, and aggregation; strictly increase the minor version; keep every existing mapping with identical attributes (description and doc may change, and placeholders may be renamed — they are not semantic); and only add mappings, never remove them.
Both arguments must be validated interfaces (from ParseInterface).
Types ¶
type Aggregation ¶
type Aggregation uint8
Aggregation states whether each mapping is sent individually (one value per publish, full endpoint path) or as one object document of last-level keys published on the common path prefix.
const ( // AggregationIndividual sends one value per endpoint publish (default). AggregationIndividual Aggregation = iota + 1 // AggregationObject sends all last-level values as a single document. AggregationObject )
Aggregation values (wire strings: "individual", "object").
func ParseAggregation ¶
func ParseAggregation(s string) (Aggregation, error)
ParseAggregation parses the wire form of an aggregation.
func (Aggregation) MarshalJSON ¶
func (a Aggregation) MarshalJSON() ([]byte, error)
MarshalJSON encodes the wire form.
func (*Aggregation) UnmarshalJSON ¶
func (a *Aggregation) UnmarshalJSON(b []byte) error
UnmarshalJSON decodes the wire form, rejecting unknown values.
type CompiledInterface ¶
type CompiledInterface struct {
// ID is the storage identifier of the interface.
ID int64
// Name is the reverse-domain interface name.
Name string
// Major and Minor are the interface version.
Major, Minor int
// Type discriminates datastream from properties.
Type InterfaceType
// Ownership states which side publishes on this interface.
Ownership Ownership
// Aggregation is individual or object.
Aggregation Aggregation
// Trie matches concrete full endpoint paths, segment-wise.
Trie *EndpointTrie
// ObjectLeaves maps, for object aggregation, each last-level name to its
// mapping; nil for individual aggregation.
ObjectLeaves map[string]*CompiledMapping
}
CompiledInterface is the hot-path form of a validated interface (docs/DESIGN.md §2.6): an endpoint trie for individual matching plus, for object aggregation, the last-level key → mapping table.
func Compile ¶
func Compile(iface *Interface, ids EndpointIDResolver) (*CompiledInterface, error)
Compile turns a validated Interface into its hot-path form. The input must come from ParseInterface (or satisfy the same invariants); endpoint or aggregation violations surface as errors, not panics. With a nil resolver every ID is zero.
type CompiledMapping ¶
type CompiledMapping struct {
// EndpointID is the storage identifier of this endpoint.
EndpointID int64
// ValueType drives both validation and BSON/JSON decoding.
ValueType ValueType
// Reliability is the MQTT QoS byte (0, 1, or 2).
Reliability byte
// Retention states what happens to undeliverable values.
Retention Retention
// Expiry is the retention expiry; 0 means never.
Expiry time.Duration
// ExplicitTimestamp states whether publishes carry their own timestamp.
ExplicitTimestamp bool
// AllowUnset permits property unset via empty payload.
AllowUnset bool
// DBRetentionTTL is the database TTL; 0 means no_ttl.
DBRetentionTTL time.Duration
}
CompiledMapping is the hot-path form of one endpoint mapping (docs/DESIGN.md §2.6). It is what the engine validates and persists against after a trie match.
type DatabaseRetentionPolicy ¶
type DatabaseRetentionPolicy uint8
DatabaseRetentionPolicy states whether stored datastream values expire from the database.
const ( // NoTTL keeps values forever (default). NoTTL DatabaseRetentionPolicy = iota // UseTTL expires values after database_retention_ttl seconds. UseTTL )
DatabaseRetentionPolicy values (wire strings: "no_ttl", "use_ttl").
func ParseDatabaseRetentionPolicy ¶
func ParseDatabaseRetentionPolicy(s string) (DatabaseRetentionPolicy, error)
ParseDatabaseRetentionPolicy parses the wire form of a database retention policy.
func (DatabaseRetentionPolicy) MarshalJSON ¶
func (p DatabaseRetentionPolicy) MarshalJSON() ([]byte, error)
MarshalJSON encodes the wire form.
func (DatabaseRetentionPolicy) String ¶
func (p DatabaseRetentionPolicy) String() string
String returns the wire form.
func (*DatabaseRetentionPolicy) UnmarshalJSON ¶
func (p *DatabaseRetentionPolicy) UnmarshalJSON(b []byte) error
UnmarshalJSON decodes the wire form, rejecting unknown values.
type EndpointIDResolver ¶
type EndpointIDResolver interface {
// ResolveInterface returns the storage ID of the interface itself.
ResolveInterface(name string, major int) (int64, error)
// ResolveEndpoint returns the storage ID of one declared endpoint
// pattern (for example "/%{sensor_id}/value").
ResolveEndpoint(endpoint string) (int64, error)
}
EndpointIDResolver supplies the storage identifiers stamped into a CompiledInterface: the interface row ID and one ID per declared endpoint. The store layer implements it against the interfaces/endpoints tables; a nil resolver compiles with all IDs zero (pure in-memory use, tests).
type EndpointTrie ¶
type EndpointTrie struct {
// contains filtered or unexported fields
}
EndpointTrie matches concrete inbound paths (for example "/4/value") against declared endpoint patterns (for example "/%{sensor_id}/value"), segment by segment. Exact-literal children take priority over the (single) parametric child; placeholder values are charset- and length-checked but not semantically interpreted. Match is O(depth) and allocation-free.
func (*EndpointTrie) Add ¶
func (t *EndpointTrie) Add(endpoint string, m *CompiledMapping) error
Add inserts one endpoint pattern with its compiled mapping. The endpoint must be syntactically valid (same rules as ParseInterface); duplicate endpoints and sibling placeholders with different names are rejected. Cross-pattern conflict checking (ambiguous literal/parametric overlap) is ParseInterface's responsibility — the trie itself resolves such overlaps deterministically, exact match first.
func (*EndpointTrie) Match ¶
func (t *EndpointTrie) Match(path string) (*CompiledMapping, bool)
Match resolves a concrete path to its compiled mapping. The path must be '/'-rooted with non-empty segments; parametric segments must additionally be ≤ 256 bytes and contain no '+' or '#'. Match never allocates.
type Interface ¶
type Interface struct {
// Name is the reverse-domain interface name (≤ 128 characters).
Name string
// Major is the major version; majors coexist as distinct interfaces.
Major int
// Minor is the minor version; bumps must be additive (CheckMinorUpgrade).
Minor int
// Type discriminates datastream from properties.
Type InterfaceType
// Ownership states which side publishes on this interface.
Ownership Ownership
// Aggregation is individual or object (defaults to individual).
Aggregation Aggregation
// Description is the optional human-readable summary.
Description string
// Doc is the optional long-form documentation.
Doc string
// Mappings are the declared endpoints (1 to 1024 entries).
Mappings []Mapping
}
Interface is a parsed and validated Astarte interface definition. Instances produced by ParseInterface are structurally valid; hand-built instances should be validated by round-tripping through ParseInterface.
func ParseInterface ¶
ParseInterface strictly decodes and validates an Astarte interface JSON document. Unknown fields, malformed values, and every structural rule violation (name syntax, versioning, endpoint syntax and uniqueness, aggregation and per-type field constraints) are rejected with an error wrapping ErrInvalid.
type InterfaceType ¶
type InterfaceType uint8
InterfaceType discriminates datastream interfaces (time-ordered values) from properties interfaces (retained key/value state).
const ( // Datastream is a stream of timestamped values. Datastream InterfaceType = iota + 1 // Properties is retained, settable/unsettable key/value state. Properties )
InterfaceType values (wire strings: "datastream", "properties").
func ParseInterfaceType ¶
func ParseInterfaceType(s string) (InterfaceType, error)
ParseInterfaceType parses the wire form of an interface type.
func (InterfaceType) MarshalJSON ¶
func (t InterfaceType) MarshalJSON() ([]byte, error)
MarshalJSON encodes the wire form.
func (*InterfaceType) UnmarshalJSON ¶
func (t *InterfaceType) UnmarshalJSON(b []byte) error
UnmarshalJSON decodes the wire form, rejecting unknown values.
type Mapping ¶
type Mapping struct {
// Endpoint is the declared path pattern, e.g. "/%{sensor_id}/value".
Endpoint string
// Type is the value type of data published on this endpoint.
Type ValueType
// Reliability is the delivery guarantee (datastream only).
Reliability Reliability
// Retention states what happens to undeliverable values (datastream only).
Retention Retention
// Expiry is the retention expiry in seconds; 0 means never (datastream only).
Expiry int64
// DatabaseRetentionPolicy states whether stored values get a TTL
// (datastream only).
DatabaseRetentionPolicy DatabaseRetentionPolicy
// DatabaseRetentionTTL is the database TTL in seconds; set if and only
// if DatabaseRetentionPolicy is UseTTL (datastream only).
DatabaseRetentionTTL int64
// AllowUnset permits unsetting the property (properties only).
AllowUnset bool
// ExplicitTimestamp states whether publishes carry their own timestamp
// (datastream only).
ExplicitTimestamp bool
// Description is the optional human-readable summary.
Description string
// Doc is the optional long-form documentation.
Doc string
}
Mapping is one parsed endpoint declaration of an Interface.
type Ownership ¶
type Ownership uint8
Ownership states which side of the platform writes an interface: the device or the server (AppEngine and triggers).
const ( // OwnershipDevice marks device-published interfaces. OwnershipDevice Ownership = iota + 1 // OwnershipServer marks server-published interfaces. OwnershipServer )
Ownership values (wire strings: "device", "server").
func ParseOwnership ¶
ParseOwnership parses the wire form of an ownership.
func (Ownership) MarshalJSON ¶
MarshalJSON encodes the wire form.
func (*Ownership) UnmarshalJSON ¶
UnmarshalJSON decodes the wire form, rejecting unknown values.
type Reliability ¶
type Reliability uint8
Reliability is the delivery guarantee of a datastream mapping. Its numeric value equals the MQTT QoS level it maps to.
const ( // ReliabilityUnreliable is at-most-once delivery (QoS 0, default). ReliabilityUnreliable Reliability = iota // ReliabilityGuaranteed is at-least-once delivery (QoS 1). ReliabilityGuaranteed // ReliabilityUnique is exactly-once delivery (QoS 2). ReliabilityUnique )
Reliability values (wire strings: "unreliable", "guaranteed", "unique").
func ParseReliability ¶
func ParseReliability(s string) (Reliability, error)
ParseReliability parses the wire form of a reliability.
func (Reliability) MarshalJSON ¶
func (r Reliability) MarshalJSON() ([]byte, error)
MarshalJSON encodes the wire form.
func (Reliability) QoS ¶
func (r Reliability) QoS() byte
QoS returns the MQTT QoS byte this reliability maps to (unreliable→0, guaranteed→1, unique→2).
func (*Reliability) UnmarshalJSON ¶
func (r *Reliability) UnmarshalJSON(b []byte) error
UnmarshalJSON decodes the wire form, rejecting unknown values.
type Retention ¶
type Retention uint8
Retention states what happens to datastream values that cannot be delivered immediately.
const ( // RetentionDiscard drops undeliverable values (default). RetentionDiscard Retention = iota // RetentionVolatile keeps undeliverable values in memory. RetentionVolatile // RetentionStored keeps undeliverable values on disk. RetentionStored )
Retention values (wire strings: "discard", "volatile", "stored").
func ParseRetention ¶
ParseRetention parses the wire form of a retention.
func (Retention) MarshalJSON ¶
MarshalJSON encodes the wire form.
func (*Retention) UnmarshalJSON ¶
UnmarshalJSON decodes the wire form, rejecting unknown values.
type ValueType ¶
type ValueType uint8
ValueType is the Astarte mapping value type: seven scalars and their seven array counterparts. It drives both payload validation and BSON/JSON decoding (docs/DESIGN.md §2.6 step 5).
const ( // Double is an IEEE 754 binary64 number. Double ValueType = iota + 1 // Integer is a signed 32-bit integer. Integer // Boolean is true or false. Boolean // LongInteger is a signed 64-bit integer. LongInteger // String is a UTF-8 string (≤ 64 KiB). String // BinaryBlob is an arbitrary byte sequence (base64 in JSON payloads). BinaryBlob // DateTime is a UTC timestamp with millisecond precision. DateTime // DoubleArray is a homogeneous array of Double. DoubleArray // IntegerArray is a homogeneous array of Integer. IntegerArray // BooleanArray is a homogeneous array of Boolean. BooleanArray // LongIntegerArray is a homogeneous array of LongInteger. LongIntegerArray // StringArray is a homogeneous array of String. StringArray // BinaryBlobArray is a homogeneous array of BinaryBlob. BinaryBlobArray // DateTimeArray is a homogeneous array of DateTime. DateTimeArray )
ValueType values. Wire strings are the lowercase names ("double", "doublearray", ...).
func ParseValueType ¶
ParseValueType parses the wire form of a value type.
func (ValueType) Elem ¶
Elem returns the scalar element type for array types and v itself for scalar types.
func (ValueType) MarshalJSON ¶
MarshalJSON encodes the wire form.
func (*ValueType) UnmarshalJSON ¶
UnmarshalJSON decodes the wire form, rejecting unknown values.