Documentation
¶
Overview ¶
Package interaction is the controller's Interaction Model client (ADR 0020, stages 2 and 3), ported from matter.js packages/protocol/src/action/client/ (ClientInteraction.ts, InputChunk.ts, subscription/) and the client half of interaction/InteractionMessenger.ts at 0ceb202d: Invoke (one command), Read with events and filters, Write, Subscribe with the registry of subscriptions and their liveness, the handler of the reports a peer pushes, and sustained subscriptions. An Interaction is bound to an exchange Provider: one session, or a peer whose sessions come and go. Invoke batching and splitting, ICD wakefulness, TCP and large messages are not ported.
The messages are encoded and decoded with im/'s client encoders and decoders, the shapes of matter.js's TLV message definitions.
Index ¶
- Constants
- Variables
- func Interval(d time.Duration) *time.Duration
- func ListChunked(cluster, attribute uint32) bool
- func Raw(n spec.Node) spec.Encodable
- type AttributeData
- type AttributeStatus
- type Config
- type EventData
- type EventStatus
- type ExchangeOptions
- type Interaction
- func (c *Interaction) Invoke(ctx context.Context, path im.ConcreteCommandPath, fields spec.Encodable, ...) (Result, error)
- func (c *Interaction) MaximumPeerResponseTime(ept time.Duration, includeSending bool) time.Duration
- func (c *Interaction) Provider() Provider
- func (c *Interaction) Read(ctx context.Context, paths ...im.ConcreteAttributePath) (*Report, error)
- func (c *Interaction) ReadWith(ctx context.Context, r ReadRequest) (*Report, error)
- func (c *Interaction) Session() *exchange.Session
- func (c *Interaction) Subscribe(ctx context.Context, req SubscribeRequest) (*Subscription, error)
- func (c *Interaction) Write(ctx context.Context, writes []WriteRequest, opts WriteOptions) (WriteStatuses, error)
- type InvokeOptions
- type Provider
- type ReadRequest
- type Report
- type Result
- type RetrySchedule
- type StatusError
- type SubscribeRequest
- type Subscription
- func (s *Subscription) Active() bool
- func (s *Subscription) Close()
- func (s *Subscription) Done() <-chan struct{}
- func (s *Subscription) ID() uint32
- func (s *Subscription) MaxEventNumber() (uint64, bool)
- func (s *Subscription) MaxInterval() time.Duration
- func (s *Subscription) Peer() exchange.PeerAddress
- type Subscriptions
- func (r *Subscriptions) Active() []*Subscription
- func (r *Subscriptions) AddPeer(s *Subscription)
- func (r *Subscriptions) BlockNewActivity(ctx context.Context) error
- func (r *Subscriptions) Close(ctx context.Context) error
- func (r *Subscriptions) CloseForPeer(addr exchange.PeerAddress)
- func (r *Subscriptions) Delete(s *Subscription)
- func (r *Subscriptions) GetPeer(addr exchange.PeerAddress, id uint32) *Subscription
- func (r *Subscriptions) HandleExchange(x *exchange.Exchange, first *exchange.Message)
- func (r *Subscriptions) IsBlocked() bool
- func (r *Subscriptions) Register(mgr *exchange.Manager)
- func (r *Subscriptions) ResetTimer()
- type SubscriptionsConfig
- type WriteOptions
- type WriteRequest
- type WriteStatus
- type WriteStatuses
Constants ¶
const ( DefaultTimedRequestTimeout = 10 * time.Second DefaultMinimumResponseTimeoutWithFailsafe = 30 * time.Second )
Timeouts of the client. Mirrors matter.js packages/protocol/src/action/client/ClientInteraction.ts:159 (DEFAULT_TIMED_REQUEST_TIMEOUT = 10 s) and :160 (DEFAULT_MINIMUM_RESPONSE_TIMEOUT_WITH_FAILSAFE = 30 s) at 0ceb202d.
const ( DefaultReadPathsSupported = 9 DefaultSubscribePathsSupported = 3 )
Path floors of the base exchange provider: the CapabilityMinima minimums a peer that reports none is assumed to support. Mirrors matter.js packages/protocol/src/protocol/ExchangeProvider.ts:85-90 at 0ceb202d.
const ( SubscriptionProcessingTime = 10 * time.Second DefaultMinIntervalFloor = time.Second SubscriptionMaxIntervalPublisherLimit = 60 * time.Minute )
Subscription defaults. Mirrors matter.js packages/protocol/src/action/client/ClientInteraction.ts:96 (SUBSCRIPTION_PROCESSING_TIME = 10 s), :149 (DEFAULT_MIN_INTERVAL_FLOOR = 1 s) and :157 (SUBSCRIPTION_MAX_INTERVAL_PUBLISHER_LIMIT = 60 min) at 0ceb202d.
const NoSubscription = ^uint32(0)
NoSubscription is the id of a subscription the peer has not granted yet — ClientSubscription.NO_SUBSCRIPTION (ClientSubscription.ts:34, :104).
Variables ¶
var ( // ErrNoSubscriptions is a Subscribe on an interaction without a // registry (Config.Subscriptions). ErrNoSubscriptions = errors.New("interaction: no subscription registry") // ErrUncommissioned is a Subscribe to a peer without a peer address — // matter.js "Subscription unavailable because peer is uncommissioned" // (ClientInteraction.ts:991-994). ErrUncommissioned = errors.New("interaction: subscription unavailable because peer is uncommissioned") )
Errors of Subscribe.
var DefaultSustainRetries = RetrySchedule{ InitialInterval: 15 * time.Second, BackoffFactor: 2, MaximumInterval: time.Hour, JitterFactor: 0.25, }
DefaultSustainRetries is the schedule a sustained subscription retries on: 15 s, doubling, at most an hour, a quarter of jitter, no timeout. Mirrors matter.js packages/protocol/src/action/client/subscription/SustainedSubscription.ts:483-499 (SustainedSubscription.DefaultRetrySchedule) at 0ceb202d.
var ErrMalformedRequest = errors.New("interaction: malformed request")
ErrMalformedRequest is a request matter.js refuses to formulate — MalformedRequestError (action/request/MalformedRequestError.ts).
var ErrNoResponse = errors.New("interaction: no response for the command")
ErrNoResponse is an InvokeResponse without an entry for the command: matter.js #invokeCommand then returns undefined (ControllerCommissioningFlow.ts:510-529).
var ErrNoSession = errors.New("interaction: no session")
ErrNoSession is a provider without a session to run the exchange on — matter.js's "No existing session available for probe" (PeerExchangeProvider.ts:118-121) and a closed dedicated session.
var ErrRequestTooLarge = errors.New("interaction: request does not fit one message")
ErrRequestTooLarge is a request that does not fit one message even without its DataVersionFilters — matter.js's MatterFlowError of InteractionMessenger.ts:1010-1014.
var ErrUnexpectedMessage = errors.New("interaction: unexpected message")
ErrUnexpectedMessage is a reply that is not the message the interaction expects — matter.js UnexpectedDataError / MatterFlowError (InteractionMessenger.ts:186-190, :924-928).
Functions ¶
func ListChunked ¶
ListChunked reports whether a list value of the attribute is chunked by default: every attribute but AccessControl ACL and Extension (Write.ts:18-21, isAclOrExtensionPath).
Types ¶
type AttributeData ¶
type AttributeData struct {
// Path is the attribute's concrete path (node, endpoint, cluster,
// attribute; no list index).
Path im.ConcreteAttributePath
// DataVersion is the cluster's data version, 0 when the report carried
// none (InputChunk.ts:309-310).
DataVersion uint32
// Value is the value as a node tree; a list reassembled from its chunks.
Value spec.Node
}
AttributeData is one attribute value of a report.
type AttributeStatus ¶
type AttributeStatus struct {
Path im.ConcreteAttributePath
Status im.StatusCode
ClusterStatus *uint8
}
AttributeStatus is one attribute status of a report.
type Config ¶
type Config struct {
// Subscriptions is the controller's subscription registry
// ([NewSubscriptions]); Subscribe needs it — matter.js takes it from
// the environment (ClientInteraction.ts:188-190, :252-257).
Subscriptions *Subscriptions
// Logger receives the diagnostics; nil discards them.
Logger *slog.Logger
// Clock paces the sustained subscriptions' retries; nil is the
// system clock.
Clock exchange.Clock
// Rand returns the retry jitter draw in [0, 1); nil is
// math/rand/v2.Float64.
Rand func() float64
}
Config configures an Interaction — what matter.js ClientInteraction takes from its context (ClientInteraction.ts:140-147).
type EventData ¶
type EventData struct {
Path im.ConcreteEventPath
Number uint64
Priority im.EventPriority
// Timestamp is the lossy convenience of InputChunk.ts:388-389: the
// epoch timestamp, else the system one, else the delta epoch one, else
// the delta system one, else 0.
Timestamp uint64
// The four timestamps as the event carried them, nil when absent.
EpochTimestamp *uint64
SystemTimestamp *uint64
DeltaEpochTimestamp *uint64
DeltaSystemTimestamp *uint64
// Value is the event's data, HasValue false when it carried none.
Value spec.Node
HasValue bool
}
EventData is one event of a report — matter.js ReadResult.EventValue as InputChunk.ts:356-413 builds it.
type EventStatus ¶
type EventStatus struct {
Path im.ConcreteEventPath
Status im.StatusCode
ClusterStatus *uint8
}
EventStatus is one event status of a report.
type ExchangeOptions ¶
type ExchangeOptions struct {
// RequireExistingSession uses the newest session and never connects.
RequireExistingSession bool
// AddressOverride sends the exchange to this address instead of the
// session's.
AddressOverride *net.UDPAddr
// ConnectionTimeout bounds the connection a peer provider waits for:
// 0 is the peer set's default, negative waits without bound (matter.js
// Forever, ClientInteraction.ts:1095).
ConnectionTimeout time.Duration
}
ExchangeOptions configures Provider.InitiateExchange — the part of matter.js NewExchangeOptions (ExchangeProvider.ts:20-63) the controller uses.
type Interaction ¶
type Interaction struct {
// contains filtered or unexported fields
}
Interaction is the client side of the Interaction Model towards one peer — matter.js ClientInteraction (ClientInteraction.ts:165-1259 at 0ceb202d) bound to an exchange Provider: a session (New) or a peer whose sessions come and go (ForPeer). It is safe for concurrent use; each call runs on its own exchange.
func Bind ¶
func Bind(p Provider, cfg Config) *Interaction
Bind returns the interaction over provider p.
func ForPeer ¶
func ForPeer(p *peer.Peer, cfg Config) *Interaction
ForPeer returns the interaction over peer p.
func New ¶
New returns the interaction over session s of mgr — matter.js DedicatedChannelExchangeProvider (ExchangeProvider.ts:122-164). A nil logger discards.
func (*Interaction) Invoke ¶
func (c *Interaction) Invoke(ctx context.Context, path im.ConcreteCommandPath, fields spec.Encodable, opts InvokeOptions) (Result, error)
Invoke invokes one command on a fresh exchange and returns the peer's answer; a status other than Success is a *StatusError. fields is the request payload (a generated request's value), nil for an empty one. Mirrors matter.js ClientInteraction.#invokeSingle (ClientInteraction.ts:434-474) with InteractionClientMessenger .sendInvokeCommand (interaction/InteractionMessenger.ts:1061-1108) at 0ceb202d:
- a timed invoke first sends a TimedRequest and waits for its Success StatusResponse (:438-440, InteractionMessenger.ts:1124-1136);
- the single command goes without a commandRef (:457-464);
- the processing time is ExpectedProcessingTime, else 30 s with the extended failsafe timeout, else the exchange's default (:466-474), for the send's final wait and the wait for the response;
- a chunked InvokeResponse is acknowledged with a StatusResponse Success after every chunk with more to come and its entries are accumulated (InteractionMessenger.ts:1082-1105);
- the first entry is the answer, as the flow's #invokeCommand reads it (ControllerCommissioningFlow.ts:506-530): a CommandStatusIB other than Success is a *StatusError.
Errors of the exchange layer pass through unchanged.
func (*Interaction) MaximumPeerResponseTime ¶
MaximumPeerResponseTime is the longest wait for the peer's answer to a message with expected processing time ept: our retransmissions, ept and the 5 s buffer, plus — with includeSending — the peer's retransmissions back to us. Mirrors matter.js ClientInteraction.maximumPeerResponseTime (ClientInteraction.ts:1249-1251), the provider's computation.
func (*Interaction) Provider ¶
func (c *Interaction) Provider() Provider
Provider is the interaction's exchange provider.
func (*Interaction) Read ¶
func (c *Interaction) Read(ctx context.Context, paths ...im.ConcreteAttributePath) (*Report, error)
Read reads attributes on a fresh exchange — Interaction.ReadWith with attribute paths only.
func (*Interaction) ReadWith ¶
func (c *Interaction) ReadWith(ctx context.Context, r ReadRequest) (*Report, error)
ReadWith reads attributes and events on a fresh exchange and returns the report, its chunks merged. Mirrors matter.js ClientInteraction.read (ClientInteraction.ts:262-298) at 0ceb202d: more paths than the provider's readPathsSupported is only logged (:263-268); the request is encoded to fit one message (InteractionMessenger.ts:994-1050); the reports are read as readDataReports does (:938-972) and each chunk goes through InputChunk (action/client/InputChunk.ts) — a list continued in the next chunk is reassembled, a malformed entry skipped. Errors of the exchange layer pass through unchanged.
func (*Interaction) Session ¶
func (c *Interaction) Session() *exchange.Session
Session is the session the interaction runs on — the provider's dedicated session, or the peer's newest one (nil when none).
func (*Interaction) Subscribe ¶
func (c *Interaction) Subscribe(ctx context.Context, req SubscribeRequest) (*Subscription, error)
Subscribe subscribes on a fresh exchange. Mirrors matter.js ClientInteraction.subscribe (ClientInteraction.ts:978-1123) at 0ceb202d:
- a request without paths is refused, more paths than the provider's subscribePathsSupported only logged (:981-989);
- the peer must have a peer address (:991-994);
- ReplaceSubscriptions closes our subscriptions with the peer first (:996-1008);
- the intervals default to 1 s and 60 min, the ceiling may not be below the floor (:1010-1021), and each is at most 65535 s (Subscribe.ts:46-60);
- the attempt (:1023-1078): the request with the intervals in seconds, encoded to fit one message (InteractionMessenger.ts:1052-1055); the priming report's chunks read and acknowledged (:1048, InteractionMessenger.ts:938-972) and handed to Updated; the SubscribeResponse; the subscription registered by (peer, id), its liveness timeout its maximum interval plus twice the maximum peer response time for a 10 s processing time (:1054-1063).
ctx bounds the establishment of a plain subscription. A sustained one (Sustain) is returned at once and establishes itself on its own until closed (:1092-1115).
func (*Interaction) Write ¶
func (c *Interaction) Write(ctx context.Context, writes []WriteRequest, opts WriteOptions) (WriteStatuses, error)
Write writes attributes on a fresh exchange. Mirrors matter.js ClientInteraction.write (ClientInteraction.ts:365-429) with Write() (action/request/Write.ts:43-185) and InteractionClientMessenger.sendWriteCommand (interaction/InteractionMessenger.ts:1110-1162) at 0ceb202d:
- a DataVersion needs a concrete endpoint, and a write needs at least one attribute (Write.ts:64-69, :105-107);
- a list value becomes the empty list (REPLACE-ALL) and one append per element with a null ListIndex, unless chunking is off or the path is AccessControl ACL or Extension (:149-171);
- a timed write first sends a TimedRequest on the same exchange and waits for its Success (:369-371; the timeout defaults to 10 s, :159);
- one WriteRequest, MoreChunkedMessages false (Write.ts:77); one that does not fit a message, or a timed one whose WriteResponse might not, is an ErrRequestTooLarge before anything is sent;
- with SuppressResponse the send expects an acknowledgement only; a message in its place is tolerated unless it is a StatusResponse with an error (IM:1138-1162, the "Matter-SDK bug" of :1156), and the result is nil (:382-384);
- otherwise the WriteResponse's statuses are the result, an empty one an empty result (:385-387).
type InvokeOptions ¶
type InvokeOptions struct {
// ExpectedProcessingTime is the peer's processing time of the command;
// 0 is the default (ClientInteraction.ts:466-474).
ExpectedProcessingTime time.Duration
// ExtendedFailSafeTimeout is useExtendedFailSafeMessageResponseTimeout:
// without an ExpectedProcessingTime the command's processing time is
// [DefaultMinimumResponseTimeoutWithFailsafe] (:466-474).
ExtendedFailSafeTimeout bool
// Timed sends a TimedRequest first (:438-440) and marks the invoke as
// timed.
Timed bool
// TimedTimeout is the TimedRequest's timeout; 0 is
// [DefaultTimedRequestTimeout] (:439).
TimedTimeout time.Duration
// SuppressResponse asks the peer for no InvokeResponse: the send
// expects an acknowledgement only and Invoke returns the zero Result.
SuppressResponse bool
}
InvokeOptions configures Interaction.Invoke — the options of matter.js Invoke.Definition the commissioning flow sets.
type Provider ¶
type Provider interface {
// InitiateExchange opens an IM exchange with the peer.
InitiateExchange(ctx context.Context, opts ExchangeOptions) (*exchange.Exchange, error)
// PeerAddress is the peer's address, false for an uncommissioned peer
// (a PASE session).
PeerAddress() (exchange.PeerAddress, bool)
// MaximumPeerResponseTime is the longest wait for the peer's answer.
MaximumPeerResponseTime(ept time.Duration, includeSending bool) time.Duration
// VerifyReachability verifies the peer answers, driving recovery; the
// base reports reachable (:114-116).
VerifyReachability(ctx context.Context) bool
// ReadPathsSupported and SubscribePathsSupported are the peer's path
// floors (:85-90).
ReadPathsSupported() int
SubscribePathsSupported() int
// Session is the dedicated session, or the newest one; nil for none.
Session() *exchange.Session
// Manager is the exchange manager the sessions live on.
Manager() *exchange.Manager
}
Provider gives an interaction its exchanges — matter.js ExchangeProvider (ExchangeProvider.ts:71-117).
func PeerProvider ¶
PeerProvider is the provider over peer p — matter.js PeerExchangeProvider (packages/protocol/src/peer/PeerExchangeProvider.ts:19-163): each exchange runs on the peer's newest session, connecting first unless RequireExistingSession is set (:73-150), reachability is the peer's (:69-71).
type ReadRequest ¶
type ReadRequest struct {
// Attributes are the attribute paths, wildcards allowed.
Attributes []im.ConcreteAttributePath
// Events are the event paths, wildcards allowed.
Events []im.ConcreteEventPath
// EventFilters are the minimum event numbers; matter.js sets eventMin
// only (Read.ts:171-176).
EventFilters []im.EventMinimumNumber
// DataVersionFilters skip clusters whose data the client holds; dropped
// or trimmed when the request would not fit one message
// (InteractionMessenger.ts:998-1050).
DataVersionFilters []im.DataVersionFilter
// NoFabricFilter reads fabric-scoped lists unfiltered; a read is
// fabric-filtered by default (fabricFilter = true, Read.ts:40).
NoFabricFilter bool
}
ReadRequest is a read — matter.js Read() (action/request/Read.ts:28-91) with numeric paths.
type Report ¶
type Report struct {
// SubscriptionID is the report's subscription id, 0 for a read's
// report: the first chunk's — matter.js hands each chunk's DataReport,
// subscriptionId included, to InputChunk (action/client/InputChunk.ts:166-169)
// and the handler reads the id off the initial report
// (ClientSubscriptionHandler.ts:77) at 0ceb202d.
SubscriptionID uint32
// Session is the session the report arrived over — the exchange's
// session matter.js takes the peer from and hands to reportStarted
// (ClientSubscriptionHandler.ts:89, :108-112).
Session *exchange.Session
Attributes []AttributeData
Statuses []AttributeStatus
Events []EventData
EventStatuses []EventStatus
}
Report is the data of a read or of one subscription report, its chunks merged.
type Result ¶
type Result struct {
// Command is the response command id; HasFields reports whether the
// answer carried a response command, Fields its fields.
Command uint32
HasFields bool
Fields spec.Node
// Status is the command's status: Success with fields, or the
// CommandStatusIB's.
Status im.StatusCode
// ClusterStatus is the cluster-specific status, nil when absent.
ClusterStatus *uint8
}
Result is the peer's answer to the command — the "cmd-response" or "cmd-status" entry of matter.js's decoded invoke result.
type RetrySchedule ¶
type RetrySchedule struct {
InitialInterval time.Duration
BackoffFactor float64
MaximumInterval time.Duration
JitterFactor float64
}
RetrySchedule configures the retries of a sustained subscription — matter.js RetrySchedule.Configuration (packages/general/src/net/RetrySchedule.ts:67-109). A zero field takes the schedule's default (an initial interval of 1 s, a backoff of 2); a zero MaximumInterval and JitterFactor mean none.
type StatusError ¶
type StatusError struct {
Status im.StatusCode
// ClusterStatus is the cluster-specific status, nil when absent.
ClusterStatus *uint8
// Path is the attribute the status is for — a write's failing path
// (matter.js PathError, action/response/WriteResult.ts:41-59) — nil for
// an interaction-level status.
Path *im.ConcreteAttributePath
}
StatusError is an interaction the peer ended with a status other than Success — a CommandStatusIB of the command (matter.js StatusResponseError.create, ControllerCommissioningFlow.ts:519-523) or a StatusResponse in place of the expected message (ReceivedStatusResponseError, InteractionMessenger.ts:201-214, :920-923).
func (*StatusError) Error ¶
func (e *StatusError) Error() string
type SubscribeRequest ¶
type SubscribeRequest struct {
// Attributes, Events, EventFilters, DataVersionFilters and
// NoFabricFilter are a read's ([ReadRequest]).
Attributes []im.ConcreteAttributePath
Events []im.ConcreteEventPath
EventFilters []im.EventMinimumNumber
DataVersionFilters []im.DataVersionFilter
NoFabricFilter bool
// ReplaceSubscriptions is keepSubscriptions false: our other
// subscriptions with the peer are closed first and the peer is told to
// drop its own (CI:996-1008). keepSubscriptions defaults to true
// (Subscribe.ts:44).
ReplaceSubscriptions bool
// MinIntervalFloor is the floor of the reporting interval; nil is
// [DefaultMinIntervalFloor] (CI:1011).
MinIntervalFloor *time.Duration
// MaxIntervalCeiling is the ceiling; nil is
// [SubscriptionMaxIntervalPublisherLimit] (CI:1012).
MaxIntervalCeiling *time.Duration
// Updated receives each report with data, its chunks merged — the
// priming report too.
Updated func(r *Report)
// KeepaliveReceived is called for an empty report (Subscribe.ts:33-37).
KeepaliveReceived func()
// Closed is called when the subscription closed (Subscribe.ts:28-31).
Closed func()
// Sustain keeps the subscription alive: when the underlying
// subscription is lost it is re-established, the peer's reachability
// verified first (ClientSubscribe.ts:14-19, SustainedSubscription.ts).
Sustain bool
// BootstrapRead, for a sustained subscription, runs before an attempt
// until it succeeds — the hook of bootstrapWithRead
// (SustainedSubscription.ts:187-204), which the node layer fills; an
// error fails the attempt.
BootstrapRead func(ctx context.Context) error
// ActiveChanged, for a sustained subscription, is called when it gains
// or loses its underlying subscription (SustainedSubscription.ts:83-95).
ActiveChanged func(active bool)
// RefreshRequest, for a sustained subscription, rewrites the request
// before every attempt but the very first and again right after a
// successful bootstrap read — matter.js refreshRequest
// (subscription/ClientSubscribe.ts:30-34; SustainedSubscription.ts:182-186,
// :200-203), which the node layer fills to send its current
// DataVersionFilters and event minimum. It rewrites the paths and
// filters; the interval bounds stay Subscribe's and the subscription
// keeps its callbacks.
RefreshRequest func(SubscribeRequest) SubscribeRequest
// MaxEventNumberChanged, for a sustained subscription, is called with
// the new highest event number once a report raised it, after Updated
// returned and before the report counts as delivered; an error is
// logged and the subscription continues. matter.js
// maxEventNumberChanged (SustainedSubscription.ts:354-364).
MaxEventNumberChanged func(number uint64) error
}
SubscribeRequest is a subscription — matter.js Subscribe (action/request/Subscribe.ts:18-63) with ClientSubscribe (subscription/ClientSubscribe.ts), numeric paths.
type Subscription ¶
type Subscription struct {
// contains filtered or unexported fields
}
Subscription is a subscription with a peer. A plain one is the Matter subscription the peer granted — matter.js PeerSubscription (PeerSubscription.ts:15-54) over ClientSubscription (ClientSubscription.ts:19-101); a sustained one keeps re-establishing its underlying subscription (SubscribeRequest.Sustain).
func (*Subscription) Active ¶
func (s *Subscription) Active() bool
Active reports whether a sustained subscription holds an established underlying subscription — SustainedSubscription.active (SustainedSubscription.ts:83-95); a plain subscription is active until closed.
func (*Subscription) Close ¶
func (s *Subscription) Close()
Close closes the subscription: its work is aborted, it leaves the registry and the request's Closed callback runs — after a sustained subscription's loop ended. The peer is told nothing (ClientRequest.ts:60-61): it learns from the InvalidSubscription its next report gets. Mirrors ClientSubscription.close (ClientSubscription.ts:60-92). It is idempotent.
func (*Subscription) Done ¶
func (s *Subscription) Done() <-chan struct{}
Done is closed once the subscription closed and its Closed callback ran.
func (*Subscription) ID ¶
func (s *Subscription) ID() uint32
ID is the subscription id; NoSubscription for a sustained subscription between underlying ones.
func (*Subscription) MaxEventNumber ¶ added in v0.7.3
func (s *Subscription) MaxEventNumber() (uint64, bool)
MaxEventNumber is the highest event number of the reports a sustained subscription delivered to its Updated callback, false before the first event; it never decreases. A plain subscription reports none. Mirrors matter.js SustainedSubscription.maxEventNumber (packages/protocol/src/action/client/subscription/SustainedSubscription.ts:105-114) at 862ad75f.
func (*Subscription) MaxInterval ¶
func (s *Subscription) MaxInterval() time.Duration
MaxInterval is the maximum interval the peer granted; for a sustained subscription the underlying one's, one hour without one (SustainedSubscription.ts:426-428).
func (*Subscription) Peer ¶
func (s *Subscription) Peer() exchange.PeerAddress
Peer is the peer's address.
type Subscriptions ¶
type Subscriptions struct {
// contains filtered or unexported fields
}
Subscriptions is the controller's subscription registry: the user-facing subscriptions, the peer subscriptions by (peer, subscription id) the inbound reports are routed by, and the liveness timer. One serves a controller (one exchange manager). It is matter.js ClientSubscriptions (packages/protocol/src/action/client/subscription/ClientSubscriptions.ts:34-278 at 0ceb202d). It is safe for concurrent use.
func NewSubscriptions ¶
func NewSubscriptions(cfg SubscriptionsConfig) *Subscriptions
NewSubscriptions returns an empty registry.
func (*Subscriptions) Active ¶
func (r *Subscriptions) Active() []*Subscription
Active returns the user-facing subscriptions (the iterator of :186-191).
func (*Subscriptions) AddPeer ¶
func (r *Subscriptions) AddPeer(s *Subscription)
AddPeer registers a peer subscription by (peer, id) and restarts the liveness timer (:132-143).
func (*Subscriptions) BlockNewActivity ¶
func (r *Subscriptions) BlockNewActivity(ctx context.Context) error
BlockNewActivity blocks new report processing, ends the reads in flight and waits for them — ClientSubscriptions.blockNewActivity (:73-95). A second call waits as well. It returns ctx's error when ctx ends first.
func (*Subscriptions) Close ¶
func (r *Subscriptions) Close(ctx context.Context) error
Close terminates every subscription: new reads are blocked and the reads in flight drained, the timer stopped, every user-facing subscription closed and waited for — ClientSubscriptions.close (:193-219). It returns ctx's error when ctx ends first.
func (*Subscriptions) CloseForPeer ¶
func (r *Subscriptions) CloseForPeer(addr exchange.PeerAddress)
CloseForPeer closes the peer subscriptions of addr, so they are re-established — after a session migrated to a new address (PeerAddressMonitor.ts:244-246), as ClientSubscriptions.closeForPeer does (:160-171).
func (*Subscriptions) Delete ¶
func (r *Subscriptions) Delete(s *Subscription)
Delete unregisters a subscription (:173-184).
func (*Subscriptions) GetPeer ¶
func (r *Subscriptions) GetPeer(addr exchange.PeerAddress, id uint32) *Subscription
GetPeer returns the peer subscription with id, nil for none (:145-150).
func (*Subscriptions) HandleExchange ¶
func (r *Subscriptions) HandleExchange(x *exchange.Exchange, first *exchange.Message)
HandleExchange handles an IM exchange a peer opened with first. Mirrors matter.js ClientSubscriptionHandler (ClientSubscriptionHandler.ts:33-145) at 0ceb202d:
- a first message other than a ReportData is not a client operation: the controller serves no Interaction Model server, so it is answered InvalidAction as InteractionServerMessenger answers an unsupported message (InteractionMessenger.ts:357-361);
- while the registry is blocked a report is answered InvalidSubscription (:33-43);
- a report without a subscription id is answered InvalidSubscription (:76-86), one for an unknown (peer, id) logged and answered InvalidSubscription (:88-104);
- otherwise the subscription is reading and ReportStarted runs (:108-112); an empty report is a keepalive — KeepaliveReceived, then the report's acknowledgement, further chunks read over (:114-128); a report with data is assembled and handed to Updated, a later chunk naming no or another subscription answered InvalidSubscription and ending it (:129-138, processReports :163-196);
- in every case the liveness deadline restarts (:139-144).
The chunks are acknowledged as readDataReports does (InteractionMessenger.ts:938-972).
func (*Subscriptions) IsBlocked ¶
func (r *Subscriptions) IsBlocked() bool
IsBlocked reports whether new report processing is blocked (:58-63).
func (*Subscriptions) Register ¶
func (r *Subscriptions) Register(mgr *exchange.Manager)
Register installs the registry's handler of the reports peers push on mgr: the first message of every IM exchange a peer opens on a secure session reaches Subscriptions.HandleExchange — matter.js ClientSubscriptionHandler (requiresSecureSession, ClientSubscriptionHandler.ts:23-31) as Peers.#configureInteractionServer installs it into the node's InteractionServer (packages/node/src/node/client/Peers.ts:546-563, packages/node/src/node/server/InteractionServer.ts:218-228).
func (*Subscriptions) ResetTimer ¶
func (r *Subscriptions) ResetTimer()
ResetTimer restarts the liveness timer for the peer subscriptions — ClientSubscriptions.resetTimer (:221-277): a subscription that is reading is skipped; one without a deadline gets now + its timeout; one past its deadline times out and closes; the timer is armed for the earliest deadline, or stopped when there is none or the registry is blocked.
type SubscriptionsConfig ¶
type SubscriptionsConfig struct {
// Clock paces the liveness timer; nil is the system clock.
Clock exchange.Clock
// Logger receives the diagnostics; nil discards them.
Logger *slog.Logger
// ReportStarted is called when a report the peer pushes starts
// arriving on one of its subscriptions, with the session it arrived
// over; a priming report does not call it, and a panic in it is
// logged and contained — matter.js ClientSubscriptions.reportStarted
// (ClientSubscriptions.ts:152-158).
ReportStarted func(s *exchange.Session)
}
SubscriptionsConfig configures NewSubscriptions.
type WriteOptions ¶
type WriteOptions struct {
// Timed sends a TimedRequest first (ClientInteraction.ts:369-371).
Timed bool
// TimedTimeout is the TimedRequest's timeout; 0 is
// [DefaultTimedRequestTimeout]. A timeout marks the write timed
// (Write.ts:74).
TimedTimeout time.Duration
// SuppressResponse asks the peer for no WriteResponse.
SuppressResponse bool
// DisableListChunking writes a list value as one AttributeDataIB; by
// default a list is written as REPLACE-ALL with the empty list and one
// append per element (chunkLists = true, Write.ts:59, :149-171).
DisableListChunking bool
}
WriteOptions configures Interaction.Write — matter.js Write.Options (Write.ts:188-199).
type WriteRequest ¶
type WriteRequest struct {
// Path names the attribute: the endpoint may be a wildcard, the cluster
// and attribute must be set.
Path im.ConcreteAttributePath
// Value is the value to write: a generated type's value, or a node tree
// through [Raw].
Value spec.Encodable
// DataVersion, when set, makes the write conditional; it needs a
// concrete endpoint (Write.ts:64-69, :128-131).
DataVersion *uint32
}
WriteRequest is one attribute to write — a Write.Attribute of matter.js (Write.ts:204-218) with numeric ids.
type WriteStatus ¶
type WriteStatus struct {
Path im.ConcreteAttributePath
Status im.StatusCode
ClusterStatus *uint8
}
WriteStatus is the peer's status for one written path — matter.js WriteResult.AttributeStatus (action/response/WriteResult.ts:34-39), the path with its ListIndex.
type WriteStatuses ¶
type WriteStatuses []WriteStatus
WriteStatuses is a write's result.
func (WriteStatuses) Err ¶
func (w WriteStatuses) Err() error
Err is nil when every path succeeded, the failing path's *StatusError when one failed, and the failing paths' errors joined when several did. Mirrors matter.js WriteResult.assertSuccess (WriteResult.ts:41-59).