The mesh runs on the seat's bus alone (novox/hq ADR 0131, design 28 task 5.5). The host's old dialling and enrolment paths are deleted with the switch that chose between them; a membership or a token naming another bus is refused before anything is sent, rather than dialled on a transport that no longer exists.
76 lines
3.0 KiB
Go
76 lines
3.0 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()
|
|
}
|
|
|
|
// 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"
|