Documentation
¶
Index ¶
- Constants
- Variables
- func EncodeMailboxPayload(senderAddr, recipientAddr a2al.Address, recipientPub ed25519.PublicKey, ...) ([]byte, error)
- func EncodeSignedRecord(sr SignedRecord) ([]byte, error)
- func FindNodeResponseWireSize(resp *BodyFindNodeResp) (int, error)
- func FindValueResponseWireSize(resp *BodyFindValueResp) (int, error)
- func FormatObservedUDP(ip net.IP, port uint16) ([]byte, error)
- func IsPublicIP(ip net.IP) bool
- func MarshalAgentProfilePayload(p AgentProfilePayload) ([]byte, error)
- func MarshalSignedMessage(hdr Header, body any, priv ed25519.PrivateKey) ([]byte, error)
- func MarshalSignedMessageKeyStore(hdr Header, body any, ks acrypto.KeyStore, addr a2al.Address) ([]byte, error)
- func MarshalTopicPayload(p TopicPayload) ([]byte, error)
- func ParseObservedUDP(b []byte) (host string, port uint16, ok bool)
- func ReadMailboxFrameBody(r io.Reader) ([32]byte, []byte, error)
- func RecordCategory(recType uint8) uint8
- func RecordIsNewer(a, b SignedRecord) bool
- func TopicNodeID(topic string) a2al.NodeID
- func VerifySignedRecord(sr SignedRecord, now time.Time) error
- func WriteMailboxFrame(w io.Writer, msgID [32]byte, recordCBOR []byte) error
- type AgentProfilePayload
- type BodyDHTPush
- type BodyDHTPushACK
- type BodyFindNode
- type BodyFindNodeResp
- type BodyFindValue
- type BodyFindValueResp
- type BodyNATProbeEcho
- type BodyNATProbeReq
- type BodyPing
- type BodyPong
- type BodyStore
- type BodyStoreResp
- type DecodedMessage
- type DiscoverFilter
- type EndpointPayload
- type EndpointRecord
- type Header
- type MailboxFrame
- type MailboxMessage
- type MailboxPayload
- type NodeInfo
- type SignedRecord
- func DecodeSignedRecord(data []byte) (SignedRecord, error)
- func SignEndpointRecord(priv ed25519.PrivateKey, addr a2al.Address, ep EndpointPayload, ...) (SignedRecord, error)
- func SignEndpointRecordDelegated(opPriv ed25519.PrivateKey, delegationCBOR []byte, addr a2al.Address, ...) (SignedRecord, error)
- func SignRecord(priv ed25519.PrivateKey, addr a2al.Address, recType uint8, payload []byte, ...) (SignedRecord, error)
- func SignRecordDelegated(opPriv ed25519.PrivateKey, delegationCBOR []byte, addr a2al.Address, ...) (SignedRecord, error)
- type StoreReason
- type TopicEntry
- type TopicPayload
Constants ¶
const ( CategoryUnknown uint8 = 0 CategorySovereign uint8 = 1 // RecType 0x01–0x0F CategoryTopic uint8 = 2 // RecType 0x10–0x1F CategoryMailbox uint8 = 3 // RecType 0x80–0x8F )
DHT record categories (Phase 4 spec §2.1).
const ( RecTypeTopic uint8 = 0x10 RecTypeMailbox uint8 = 0x80 )
RecType constants beyond endpoint (Phase 4).
const ( // MaxMailboxPayloadCBOR is the spec §4.8 cap on SignedRecord.payload (MailboxPayload CBOR). MaxMailboxPayloadCBOR = 512 // DefaultMailboxTTL is the recommended mailbox record TTL in seconds (spec §4.8). DefaultMailboxTTL uint32 = 3600 )
const ( MailboxMsgConnectRequest uint8 = 0x01 MailboxMsgCandidates uint8 = 0x02 MailboxMsgText uint8 = 0x03 )
Mailbox message types (spec §4.3).
const ( MsgPing uint8 = 0x01 MsgPong uint8 = 0x02 MsgFindNode uint8 = 0x03 MsgFindNodeResp uint8 = 0x04 MsgFindValue uint8 = 0x05 MsgFindValueResp uint8 = 0x06 MsgStore uint8 = 0x07 MsgStoreResp uint8 = 0x08 MsgNATProbeReq uint8 = 0x09 // NAT probe request: ask peer to echo to our claimed address MsgNATProbeEcho uint8 = 0x0A // NAT probe echo: sent by responder directly to claimed address MsgDHTPush uint8 = 0x0B // DHT_PUSH: DHT node → subscriber daemon, delivers new record (oneShot) MsgDHTPushACK uint8 = 0x0C // DHT_PUSH_ACK: daemon → DHT node, optionally renews subscription )
Message type IDs (spec §7.4).
const ( // RecTypeEndpoint is the Phase 1 endpoint advertisement (spec §7.6). RecTypeEndpoint uint8 = 0x01 // MaxEndpointSignalURLLen caps each URL in EndpointPayload.Signal / Signals. MaxEndpointSignalURLLen = 2048 // MaxSignalURLs caps EndpointPayload.Signals entry count (multi-center signal URLs). MaxSignalURLs = 8 // MaxTurnURLs caps EndpointPayload.Turns entry count (credential-free relay hints for DHT). MaxTurnURLs = 16 // MaxTurnURLEntryLen caps each turn:// string length in Turns. MaxTurnURLEntryLen = 512 )
const ( // NATUnknown: reachability not yet determined. // Connecting peers should attempt direct v4 optimistically while // preparing an ICE fallback if a Signal URL is present. // Published when active probe has not completed or evidence is insufficient. NATUnknown uint8 = iota // NATFullCone: tested — any peer can initiate cold inbound UDP on v4. // Published address and port are stable. Direct dial should succeed. // (Covers public WAN bind, full-cone NAT, and cloud NAT with EIF.) NATFullCone // NATRestricted: tested — cold inbound v4 from arbitrary peers fails. // The NAT mapping is endpoint-independent (EIM): port is stable, so the // published address is a reliable routing anchor. Peers must use ICE or // hole-punch to connect. NATRestricted // NATPortRestricted: same capability semantics as NATRestricted. // Cold inbound v4 fails; port is stable; routing anchor is valid. // Treated identically to NATRestricted by all consumers. NATPortRestricted // NATSymmetric: tested — cold inbound v4 fails AND the NAT allocates a // different external port per destination (EIM broken). The published v4 // address is not a stable routing anchor. Peers must use ICE; port-spray // may improve punch success when the remote's outbound port is predictable. NATSymmetric )
NAT types for EndpointPayload (spec §7.6).
These are published capability hints, not strict RFC 3489/5780 NAT topology labels. Each value answers two questions a connecting peer needs to know:
- Can you accept cold inbound v4 UDP from an arbitrary peer?
- Is your published v4 address a stable routing anchor?
Consumers (Connect path, routing table) act solely on these two properties; any further distinction is not meaningful at the protocol level.
const AgentProfilePayloadMaxSize = 700
AgentProfilePayloadMaxSize is the hard pre-publish rejection threshold (bytes). The FIND_VALUE response budget is ~1050 B; SignedRecord wrapper adds ~156 B, leaving ≈894 B for payload. We cap at 700 B to keep routing nodes comfortable.
const AgentProfilePayloadWarnSize = 350
AgentProfilePayloadWarnSize is a soft advisory threshold (bytes). Payloads approaching this size may compete with routing nodes for UDP packet space.
const MagicMailboxFrame = "a2mb"
MagicMailboxFrame identifies a QUIC-stream mailbox direct-delivery frame.
const MaxTopicBriefRunes = 140
MaxTopicBriefRunes is spec §5.3 one-line description limit.
const MaxTopicPayloadCBOR = 512
MaxTopicPayloadCBOR is the spec §5.9 cap on SignedRecord.payload for RecType 0x10.
const ProtocolVersion uint8 = 1
ProtocolVersion is the wire protocol version (spec §7.3).
const RecTypeAgentProfile uint8 = 0x02
RecTypeAgentProfile is the sovereign RecType for AgentProfilePayload (0x02).
Variables ¶
var ( // ErrInvalidMessage is returned for malformed wire data or failed verification. ErrInvalidMessage = errors.New("a2al/protocol: invalid message") // ErrUnknownMsgType is returned when msg_type is not defined in Phase 1. ErrUnknownMsgType = errors.New("a2al/protocol: unknown msg_type") )
var ( // ErrInvalidRecord is returned when structure, signature, or address binding fails. ErrInvalidRecord = errors.New("a2al/protocol: invalid record") // ErrRecordExpired means now is past Timestamp+TTL (VerifySignedRecord). ErrRecordExpired = errors.New("a2al/protocol: record expired") // ErrPayloadApproachingLimit is a non-fatal advisory: payload is valid but // approaching the soft size threshold and may compete with routing nodes. ErrPayloadApproachingLimit = errors.New("a2al/protocol: payload approaching size limit") )
Functions ¶
func EncodeMailboxPayload ¶
func EncodeMailboxPayload(senderAddr, recipientAddr a2al.Address, recipientPub ed25519.PublicKey, msgType uint8, body []byte) ([]byte, error)
EncodeMailboxPayload encrypts (msgType, body) and returns canonical CBOR MailboxPayload.
func EncodeSignedRecord ¶ added in v0.2.4
func EncodeSignedRecord(sr SignedRecord) ([]byte, error)
EncodeSignedRecord CBOR-encodes a SignedRecord.
func FindNodeResponseWireSize ¶
func FindNodeResponseWireSize(resp *BodyFindNodeResp) (int, error)
FindNodeResponseWireSize returns the canonical CBOR size of a FIND_NODE_RESP body (UDP trim, spec §3.7).
func FindValueResponseWireSize ¶
func FindValueResponseWireSize(resp *BodyFindValueResp) (int, error)
FindValueResponseWireSize returns the canonical CBOR size of a FIND_VALUE_RESP body (UDP trim, spec §3.7).
func FormatObservedUDP ¶
FormatObservedUDP encodes IP:port to the same wire form as BodyPong.observed_addr. Both IPv4 (4+2 bytes = 6 total) and IPv6 (16+2 bytes = 18 total) are supported. No changes needed here for dual-stack.
func IsPublicIP ¶ added in v0.1.4
IsPublicIP reports whether ip is a routeable public WAN address — not loopback, link-local, private, multicast, unspecified, or RFC 6598 CGNAT (100.64/10). Used by both dht and host packages to validate observed / claimed addresses.
Works for both IPv4 and IPv6. For IPv6: GUA (2000::/3) passes; ULA (fc00::/7) and link-local (fe80::/10) are rejected. No changes needed here for dual-stack.
func MarshalAgentProfilePayload ¶ added in v0.2.0
func MarshalAgentProfilePayload(p AgentProfilePayload) ([]byte, error)
MarshalAgentProfilePayload canonical-encodes p and enforces the size limit. Returns ErrPayloadApproachingLimit (non-fatal) wrapped in the error when the payload is within the hard limit but above the advisory threshold.
func MarshalSignedMessage ¶
MarshalSignedMessage canonical-encodes header and body, signs, and returns the outer CBOR bytes.
func MarshalSignedMessageKeyStore ¶
func MarshalSignedMessageKeyStore(hdr Header, body any, ks acrypto.KeyStore, addr a2al.Address) ([]byte, error)
MarshalSignedMessageKeyStore signs with KeyStore (spec: same preimage as MarshalSignedMessage).
func MarshalTopicPayload ¶
func MarshalTopicPayload(p TopicPayload) ([]byte, error)
MarshalTopicPayload canonical-encodes p and enforces size / brief limits. If p.Version == 0, it is treated as 1 for encoding.
func ParseObservedUDP ¶
ParseObservedUDP decodes wire observed_addr (4+2 IPv4 or 16+2 IPv6, big-endian port). The wire format is address-family agnostic: 6 bytes = IPv4, 18 bytes = IPv6. Both IPv4 and IPv6 are fully supported; no changes needed here for dual-stack.
func ReadMailboxFrameBody ¶ added in v0.2.4
ReadMailboxFrameBody reads the body of a MailboxFrame after the 4-byte magic has been consumed. Returns (msgID, recordCBOR, error). Enforces a 64 KiB cap on recordCBOR.
func RecordCategory ¶
RecordCategory maps RecType to a storage/query policy bucket. Reserved ranges (0x20–0x7F, 0x90–0xFF) return CategoryUnknown and are stored like sovereign (key must be NodeID(Address)) for forward compatibility.
func RecordIsNewer ¶
func RecordIsNewer(a, b SignedRecord) bool
RecordIsNewer reports whether a should replace b. Priority: delegation.IssuedAt → Seq → Timestamp. A newer delegation always wins regardless of seq, enabling master key holders to revoke a stolen operational key by issuing a fresh delegation.
func TopicNodeID ¶
TopicNodeID returns SHA-256("topic:" || topicUTF8) as the DHT key for Topic rendezvous (Phase 4 / v2 §10.3). The formula is immutable on the wire.
func VerifySignedRecord ¶
func VerifySignedRecord(sr SignedRecord, now time.Time) error
VerifySignedRecord checks cryptographic integrity: signature validity, endpoint payload shape, and expiry. It does NOT enforce pubkey↔address authority (whether the signing key is allowed to publish for the given Address). Authority is a deployment policy; inject it via dht.Config.RecordAuth at the storage layer.
Types ¶
type AgentProfilePayload ¶ added in v0.2.0
type AgentProfilePayload struct {
Version uint8 `cbor:"1,keyasint"`
Name string `cbor:"2,keyasint,omitempty"`
Brief string `cbor:"3,keyasint,omitempty"`
Protocols []string `cbor:"4,keyasint,omitempty"`
Skills []string `cbor:"5,keyasint,omitempty"`
CardHash []byte `cbor:"6,keyasint,omitempty"`
Modalities []string `cbor:"8,keyasint,omitempty"`
Meta map[string]any `cbor:"9,keyasint,omitempty"`
}
AgentProfilePayload is the CBOR body of a RecType=0x02 sovereign record. All fields except Version are optional (omitempty). Integer map keys minimise wire footprint under the 700 B cap.
func ParseAgentProfilePayload ¶ added in v0.2.0
func ParseAgentProfilePayload(sr SignedRecord) (AgentProfilePayload, error)
ParseAgentProfilePayload decodes the payload from a RecType=0x02 SignedRecord.
type BodyDHTPush ¶ added in v0.2.4
type BodyDHTPush struct {
Key []byte `cbor:"1,keyasint"` // 32 bytes
Record SignedRecord `cbor:"2,keyasint"`
}
BodyDHTPush is the body of MsgDHTPush sent from a DHT node to a subscribed daemon. Key is the 32-byte DHT key; Record is the newly stored SignedRecord.
type BodyDHTPushACK ¶ added in v0.2.4
type BodyDHTPushACK struct {
Key []byte `cbor:"1,keyasint"` // 32 bytes
MsgID []byte `cbor:"2,keyasint"` // 32-byte SHA-256 of Record.Payload
OneShotSubscribe bool `cbor:"3,keyasint,omitempty"`
}
BodyDHTPushACK is the body of MsgDHTPushACK sent from daemon back to the DHT node. OneShotSubscribe=true renews the subscription for future records on the same key.
type BodyFindNode ¶
type BodyFindNode struct {
Target []byte `cbor:"1,keyasint"` // 32 NodeID
}
type BodyFindNodeResp ¶
type BodyFindValue ¶
type BodyFindValueResp ¶
type BodyFindValueResp struct {
Nodes []NodeInfo `cbor:"1,keyasint"`
Record *SignedRecord `cbor:"2,keyasint,omitempty"`
ObservedAddr []byte `cbor:"3,keyasint"`
Records []SignedRecord `cbor:"4,keyasint,omitempty"`
}
type BodyNATProbeEcho ¶ added in v0.1.4
type BodyNATProbeEcho struct {
Token []byte `cbor:"1,keyasint"` // 8-byte nonce echoed from BodyNATProbeReq
}
BodyNATProbeEcho is sent by the responder directly to the requester's claimed address. Token echoes the nonce from the corresponding BodyNATProbeReq.
type BodyNATProbeReq ¶ added in v0.1.4
type BodyNATProbeReq struct {
Token []byte `cbor:"1,keyasint"` // 8-byte random nonce
ClaimedAddr []byte `cbor:"2,keyasint"` // wire-encoded UDP address (6 or 18 bytes)
}
BodyNATProbeReq asks the receiver to send a NATProbeEcho directly to ClaimedAddr. Token (8 bytes) correlates the echo back to the requester's wait channel.
type BodyStore ¶
type BodyStore struct {
Record SignedRecord `cbor:"1,keyasint"`
Key []byte `cbor:"2,keyasint,omitempty"` // 32-byte DHT key; omit = NodeID(Address)
}
type BodyStoreResp ¶
type BodyStoreResp struct {
Stored bool `cbor:"1,keyasint"`
AlreadyHad bool `cbor:"2,keyasint,omitempty"` // true when the node already held an equal-or-newer record
Reason StoreReason `cbor:"3,keyasint,omitempty"` // non-zero only on rejection; 0 from old nodes means unknown
}
type DecodedMessage ¶
type DecodedMessage struct {
Header Header
SenderPubkey ed25519.PublicKey
SenderAddr a2al.Address
Body any
}
DecodedMessage is a verified, parsed wire message.
func VerifyAndDecode ¶
func VerifyAndDecode(raw []byte) (*DecodedMessage, error)
VerifyAndDecode parses the outer message, re-canonicalizes header/body, verifies Ed25519, checks sender_pubkey matches body.address for PING and PONG (spec §Step 3).
type DiscoverFilter ¶
type DiscoverFilter struct {
Protocols []string `json:"protocols,omitempty"`
Tags []string `json:"tags,omitempty"`
}
DiscoverFilter is optional client-side filtering (spec §5.5).
type EndpointPayload ¶
type EndpointPayload struct {
Endpoints []string `cbor:"1,keyasint"`
NatType uint8 `cbor:"2,keyasint"`
// Signal is the primary WebSocket base URL for ICE trickle signaling (no query; room is
// appended by peers). Kept for backward compatibility with nodes that only read key 3.
Signal string `cbor:"3,keyasint,omitempty"`
// Turns lists optional turn:// URLs without credentials (public relay hints).
Turns []string `cbor:"4,keyasint,omitempty"`
// Signals lists additional WebSocket base URLs for ICE signaling (multi-center).
// New nodes prefer this list; old nodes that only read Signal (key 3) still work.
// When non-empty, Signal should equal Signals[0] for maximum compatibility.
Signals []string `cbor:"5,keyasint,omitempty"`
}
EndpointPayload is the CBOR inside SignedRecord.payload for rec_type=0x01 (spec §7.6).
type EndpointRecord ¶
type EndpointRecord struct {
Address a2al.Address
Endpoints []string
NatType uint8
Signal string
Turns []string
// Signals is the multi-center signal URL list from EndpointPayload.Signals (key 5).
// When non-empty, callers should prefer this over Signal. Signal is kept for compat.
Signals []string
Timestamp uint64
Seq uint64
TTL uint32
}
EndpointRecord is the decoded logical view (spec Step 4); no signature material.
func ParseEndpointRecord ¶
func ParseEndpointRecord(sr SignedRecord) (EndpointRecord, error)
ParseEndpointRecord decodes an endpoint record after verification.
type Header ¶
type Header struct {
Version uint8 `cbor:"1,keyasint"`
Features uint16 `cbor:"2,keyasint"`
MsgType uint8 `cbor:"3,keyasint"`
TxID []byte `cbor:"4,keyasint"`
}
Header is the CBOR map in field 1 of the outer message (spec §7.3).
type MailboxFrame ¶ added in v0.2.4
type MailboxFrame struct {
MsgID [32]byte
Record SignedRecord
}
MailboxFrame is the QUIC direct-delivery frame format. Wire layout (stream):
[magic "a2mb" 4B][msg_id 32B][record_len 4B big-endian][record CBOR]
type MailboxMessage ¶
type MailboxMessage struct {
Sender a2al.Address
MsgType uint8
Body []byte
// Seq is copied from the outer SignedRecord.Seq; it is monotonically
// increasing per sender and serves as a unique record identifier.
Seq uint64
// SenderPubkey is the sender's Ed25519 identity public key, taken from
// SignedRecord.Pubkey after signature verification. It is guaranteed to
// correspond to Sender (same key that derived the AID). Callers may use
// this to encrypt a reply without an extra DHT lookup.
SenderPubkey ed25519.PublicKey
}
MailboxMessage is one decrypted mailbox entry for the application (spec §4.6).
func OpenMailboxRecord ¶
func OpenMailboxRecord(recipientPriv ed25519.PrivateKey, recipientAddr a2al.Address, sr SignedRecord) (MailboxMessage, error)
OpenMailboxRecord decrypts a verified mailbox SignedRecord for recipientAddr.
type MailboxPayload ¶
type MailboxPayload struct {
Recipient []byte `cbor:"1,keyasint"`
SenderAddr []byte `cbor:"2,keyasint"`
EphemeralPK []byte `cbor:"3,keyasint"`
Ciphertext []byte `cbor:"4,keyasint"`
Nonce []byte `cbor:"5,keyasint"`
}
MailboxPayload is the CBOR inside SignedRecord.payload for rec_type=0x80 (spec §4.1).
type NodeInfo ¶
type NodeInfo struct {
Address []byte `cbor:"1,keyasint"` // 21 bytes
NodeID []byte `cbor:"2,keyasint"` // 32 bytes
IP []byte `cbor:"3,keyasint"` // 4 or 16 bytes
Port uint16 `cbor:"4,keyasint"`
}
NodeInfo is the DHT routing contact shape (spec §7.6).
type SignedRecord ¶
type SignedRecord struct {
Address []byte `cbor:"1,keyasint"`
RecType uint8 `cbor:"2,keyasint"`
Payload []byte `cbor:"3,keyasint"`
Seq uint64 `cbor:"4,keyasint"`
Timestamp uint64 `cbor:"5,keyasint"`
TTL uint32 `cbor:"6,keyasint"`
Pubkey []byte `cbor:"7,keyasint"`
Signature []byte `cbor:"8,keyasint"`
Delegation []byte `cbor:"9,keyasint,omitempty"`
}
SignedRecord is the on-wire record container (spec §7.6). Record signing uses prefix "a2al-rec\0" over CBOR of fields 1–6 (implemented in record.go, Step 4). Field 9 (Delegation) is optional and carries a CBOR-encoded DelegationProof when the signing key (Pubkey) is an operational key publishing on behalf of a master-derived Address.
func DecodeSignedRecord ¶ added in v0.2.4
func DecodeSignedRecord(data []byte) (SignedRecord, error)
DecodeSignedRecord CBOR-decodes a SignedRecord from data.
func SignEndpointRecord ¶
func SignEndpointRecord(priv ed25519.PrivateKey, addr a2al.Address, ep EndpointPayload, seq, timestamp uint64, ttl uint32) (SignedRecord, error)
SignEndpointRecord builds a SignedRecord for a self-signed endpoint advertisement. The signing key must derive the same Address as addr (Phase 1/2 path).
func SignEndpointRecordDelegated ¶
func SignEndpointRecordDelegated(opPriv ed25519.PrivateKey, delegationCBOR []byte, addr a2al.Address, ep EndpointPayload, seq, timestamp uint64, ttl uint32) (SignedRecord, error)
SignEndpointRecordDelegated builds a SignedRecord where an operational key signs on behalf of a master-derived AID (Phase 3 delegation path). delegationCBOR is embedded verbatim in the record and will be verified by receivers via the RecordAuth policy injected into the DHT store. Callers must ensure delegationCBOR is a valid DelegationProof for addr authorized to opPriv.
func SignRecord ¶
func SignRecord(priv ed25519.PrivateKey, addr a2al.Address, recType uint8, payload []byte, seq, timestamp uint64, ttl uint32) (SignedRecord, error)
SignRecord builds a signed record for RecType sovereign custom (0x02–0x0F), topic (0x10–0x1F), or mailbox (0x80–0x8F). payload must be CBOR-encoded bytes.
func SignRecordDelegated ¶
func SignRecordDelegated(opPriv ed25519.PrivateKey, delegationCBOR []byte, addr a2al.Address, recType uint8, payload []byte, seq, timestamp uint64, ttl uint32) (SignedRecord, error)
SignRecordDelegated is SignRecord with an operational key and DelegationProof.
type StoreReason ¶ added in v0.1.8
type StoreReason uint8
StoreReason is the machine-readable cause carried in BodyStoreResp.Reason. Zero (StoreReasonOK) is the default and means no error information is present, which is also what older nodes send. New reasons must be assigned new non-zero values; existing values must never be reused for a different meaning.
const ( StoreReasonOK StoreReason = 0 // stored or already-had (see Stored/AlreadyHad) StoreReasonPolicy StoreReason = 1 // node-side policy rejected (ACL, whitelist, etc.) — stable refusal StoreReasonRecordInvalid StoreReason = 2 // record-level rejection (bad sig, key mismatch, delegation error) )
type TopicEntry ¶
type TopicEntry struct {
Address a2al.Address
Seq uint64
Timestamp uint64
TTL uint32
Version uint8
Topic string
Name string
Protocols []string
Tags []string
Brief string
Meta map[string]any
}
TopicEntry is the decoded logical view for discovery (spec §5.7), like EndpointRecord.
func FilterTopicEntries ¶
func FilterTopicEntries(in []TopicEntry, f *DiscoverFilter) []TopicEntry
FilterTopicEntries applies protocol/tag filters (AND: all filter tags must appear in entry.Tags; at least one protocol match if filter protocols non-empty).
func TopicEntryFromSignedRecord ¶
func TopicEntryFromSignedRecord(sr SignedRecord) (TopicEntry, error)
TopicEntryFromSignedRecord builds TopicEntry after caller verifies signature / expiry.
type TopicPayload ¶
type TopicPayload struct {
Version uint8 `cbor:"1,keyasint"`
Topic string `cbor:"2,keyasint"`
Name string `cbor:"3,keyasint"`
Protocols []string `cbor:"4,keyasint"`
Tags []string `cbor:"5,keyasint"`
Brief string `cbor:"6,keyasint"`
Meta map[string]any `cbor:"7,keyasint,omitempty"`
}
TopicPayload is the CBOR inside SignedRecord.payload for rec_type=0x10 (spec §5.3).
func ParseTopicRecord ¶
func ParseTopicRecord(sr SignedRecord) (TopicPayload, error)
ParseTopicRecord decodes a topic SignedRecord payload.