The controller's healer H1 answers a send that went unreported by asking the machine first: a report lost on its way (issue 264) needs no second send. The node-engine now hears mesh.node.<self>.ask.report on core NATS and enqueues a reconcile whose account is said whether or not it is news; a delivery waiting meanwhile is applied and reported instead. The answer is an ordinary report on its own subject, so the node publishes nothing new and answers nobody's inbox. The genesis lock grants the controller the healer-acted seat event, which it now composes; the genesis test in mesh-controller holds the two equal.
83 lines
3.3 KiB
Go
83 lines
3.3 KiB
Go
package link
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// What a host hears, as the host's own words for it.
|
|
//
|
|
// The outbound half is behind `Bus` (bus.go); this is the other half — dialling, and the
|
|
// declarations that arrive. The run loop reads its own words for a declaration rather than the
|
|
// client library's delivery type, so nothing past this file knows what carried it.
|
|
//
|
|
// **The host still imports nothing of the mesh's own** (novox/hq ADR 0005). This is its own
|
|
// interface over its own libraries, and it agrees with the controller only because a conformance
|
|
// fixture holds both to one envelope.
|
|
|
|
// Link is this node's live connection to its mesh: what it hears, and what it says.
|
|
//
|
|
// One interface rather than two, because dialling once is what keeps both halves of a node on the
|
|
// same connection.
|
|
type Link interface {
|
|
// Bus is what this node says: what it applied, and that it is here.
|
|
Bus
|
|
|
|
// Declarations is what the mesh tells this node to be.
|
|
Declarations() <-chan Declaration
|
|
|
|
// Lost says the link ended, and why.
|
|
//
|
|
// **Read rather than discovered.** A node that finds out by noticing silence is a node that
|
|
// believed it was in the mesh for as long as the silence lasted, which is the one state ADR
|
|
// 0004 says must never look like being connected.
|
|
Lost() <-chan error
|
|
|
|
// Close lets go of whatever was dialled.
|
|
Close()
|
|
}
|
|
|
|
// Asked is a link that hears the mesh asking this node to say again what it last applied (novox/hq
|
|
// to-be 45 §6, the `report` verb). Optional: a link without it is never asked, and the mesh then sends
|
|
// the current declaration again instead.
|
|
type Asked interface {
|
|
AskedToReport() <-chan struct{}
|
|
}
|
|
|
|
// Declaration is one thing the mesh told this node to be.
|
|
//
|
|
// **Handled, once — after the report is published.** A node that dies between applying and
|
|
// reporting leaves the declaration with the mesh and applies it again on return, which is safe
|
|
// because applying is reconciliation: it converges rather than repeating.
|
|
//
|
|
// There is one way of being done rather than two. A declaration set aside because a newer arrived
|
|
// with it is settled exactly as an applied one is, and the difference between them is a fact the
|
|
// *report* carries — a second method here would be a distinction the bus does not make.
|
|
type Declaration interface {
|
|
// Body is the signed declaration as it arrived, bytes unchanged: a node verifies what it
|
|
// received rather than what it re-encoded.
|
|
Body() []byte
|
|
|
|
// Handled settles it. Called after the report for it has been published, either way.
|
|
Handled() error
|
|
}
|
|
|
|
// Open opens this node's link to its mesh.
|
|
//
|
|
// Named Open rather than Dial because Dial is this package's raw TLS dial, which the enrolment path
|
|
// uses to see a certificate before it trusts anything.
|
|
//
|
|
// **The mesh has one bus** (novox/hq ADR 0131): the one the broker seat delivers. A membership
|
|
// still records which transport it was minted for, so a host can say what it is dialling, and a
|
|
// membership recorded for anything else is a membership this host cannot use.
|
|
func Open(ctx context.Context, m Membership, timeout time.Duration) (Link, error) {
|
|
if m.Transport != OnNATS {
|
|
return nil, fmt.Errorf("this membership is for %q, and the mesh's bus is %s", m.Transport, OnNATS)
|
|
}
|
|
return dialNats(ctx, m, timeout)
|
|
}
|
|
|
|
// OnNATS is the bus a membership names: the mesh's own, and the only one.
|
|
const OnNATS = "nats"
|