mesh/repo-check head c61212eba77c merged into trunk c6e669f71e8e — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript)…
mesh/merge-gate head c61212eba77c merged into trunk c6e669f71e8e — pass: group feat/r4d composed: every machine composes with the change as it did without …
mesh/delivery delivered
mesh/delivery-group group feat/r4d merged: every member is merged
mesh/check failed: unit: ..test: node:internal/modules/esm/resolve:241 | c61212eba77c on 5652312f09d2 | unit 1629 run, 0 kept, 3 skipped | integration…
166 lines
6.5 KiB
Go
166 lines
6.5 KiB
Go
// Package membership is what the mesh issues an assignment to serve and to reach (novox/hq ADR 0160), as a
|
|
// process reads it from the bus: the Membership shape, the one subject it is published on, the stream that
|
|
// holds it, and the bus address helpers a reader needs. The controller composes it and the route proxy reads
|
|
// it; both use this one definition, so there is no second copy to drift (novox/hq issue 1633).
|
|
package membership
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
// AssignmentsStream holds every assignment's membership, the newest per subject.
|
|
const AssignmentsStream = "ASSIGNMENTS"
|
|
|
|
// Subject is the one address a runtime derives for itself: where its own membership is published, from
|
|
// the two names its credential carries. Everything else is in the membership.
|
|
func Subject(node, module string) string {
|
|
return "mesh.assignment." + node + "." + module
|
|
}
|
|
|
|
// DirectGetSubject is the subject-addressed direct get of a membership from its stream: the one request an
|
|
// account may make of the stream.
|
|
func DirectGetSubject(node, module string) string {
|
|
return "$JS.API.DIRECT.GET." + AssignmentsStream + "." + Subject(node, module)
|
|
}
|
|
|
|
// Membership is one assignment's subjects: what this instance of a module on this machine serves,
|
|
// and what it may reach.
|
|
type Membership struct {
|
|
Node string `json:"node"`
|
|
Module string `json:"module"`
|
|
// Serves is every address a tool of this instance answers on. `{tool}` stands for the tool's
|
|
// own name. An address with a queue is shared with the module's other instances.
|
|
Serves []Served `json:"serves"`
|
|
// Seats is every verb of a seat this instance holds, at the subject the seat's callers use.
|
|
Seats []SeatServed `json:"seats,omitempty"`
|
|
// Emits is where an event of this module lands; `{event}` stands for the event's name.
|
|
Emits string `json:"emits"`
|
|
// Reaches is each tool this module may call, `<module>.<tool>`, to the subjects that reach it.
|
|
Reaches map[string][]string `json:"reaches,omitempty"`
|
|
// Tools is where this instance answers what it serves.
|
|
Tools string `json:"tools"`
|
|
// Receives is what this assignment is given for each requirement it receives, by requirement (novox/hq
|
|
// ADR 0167): kept as JSON because the catalogue owns the shape of a contribution.
|
|
Receives map[string]json.RawMessage `json:"receives,omitempty"`
|
|
// Mesh is every machine's address on the private network (novox/hq ADR 0167).
|
|
Mesh []string `json:"mesh,omitempty"`
|
|
// State is every bucket this module's code may reach, and whether it may write it (novox/hq ADR 0201).
|
|
State []StateIssued `json:"state,omitempty"`
|
|
// Logs is every log this module's code may reach (novox/hq ADR 0297).
|
|
Logs []LogIssued `json:"logs,omitempty"`
|
|
// SeatTraffic is what this module's code may submit, say, hear, take, ask, answer and read on seats
|
|
// that name their caller or their kind (novox/hq ADR 0259 §3).
|
|
SeatTraffic *SeatTraffic `json:"seat-traffic,omitempty"`
|
|
// Streams are this module's own streams, Hears the module streams it hears (novox/hq ADR 0363).
|
|
Streams []StreamIssued `json:"streams,omitempty"`
|
|
Hears []HeardIssued `json:"hears,omitempty"`
|
|
// Waits are the event families a session may wait on through the mesh MCP server (novox/hq ADR 0367 §2).
|
|
Waits []WaitIssued `json:"waits,omitempty"`
|
|
}
|
|
|
|
// Served is one address a tool is answered on.
|
|
type Served struct {
|
|
Subject string `json:"subject"`
|
|
Queue string `json:"queue,omitempty"`
|
|
}
|
|
|
|
// SeatServed is one verb of a held seat, where its callers ask.
|
|
type SeatServed struct {
|
|
Seat string `json:"seat"`
|
|
Verb string `json:"verb"`
|
|
Subject string `json:"subject"`
|
|
}
|
|
|
|
// StateIssued is one bucket an assignment may reach, by the name its module uses for it (novox/hq ADR 0201).
|
|
// Key, when set, is the one key it may reach (novox/hq ADR 0260): this machine's.
|
|
type StateIssued struct {
|
|
Name string `json:"name"`
|
|
Bucket string `json:"bucket"`
|
|
Writes bool `json:"writes,omitempty"`
|
|
Key string `json:"key,omitempty"`
|
|
}
|
|
|
|
// LogIssued is one log an assignment may reach, by the name its module uses for it (novox/hq ADR 0297).
|
|
type LogIssued struct {
|
|
Name string `json:"name"`
|
|
Stream string `json:"stream"`
|
|
Subject string `json:"subject"`
|
|
Writes bool `json:"writes"`
|
|
}
|
|
|
|
// Worker is one durable consumer a holder pulls a seat's work from.
|
|
type Worker struct {
|
|
Stream string
|
|
Consumer string
|
|
Filter string
|
|
}
|
|
|
|
// SeatTraffic is one module's seat traffic beyond tools. Publish and Subscribe are subject patterns, in the
|
|
// server's wildcards.
|
|
type SeatTraffic struct {
|
|
Publish []string `json:"publish,omitempty"`
|
|
Subscribe []string `json:"subscribe,omitempty"`
|
|
Answers []string `json:"answers,omitempty"`
|
|
Workers []Worker `json:"workers,omitempty"`
|
|
Records []string `json:"records,omitempty"`
|
|
Kinds []KindHeld `json:"kinds,omitempty"`
|
|
}
|
|
|
|
// KindHeld is one kind of a kinded bench and who holds it.
|
|
type KindHeld struct {
|
|
Seat string `json:"seat"`
|
|
Kind string `json:"kind"`
|
|
Module string `json:"module"`
|
|
Node string `json:"node"`
|
|
Capabilities []string `json:"capabilities,omitempty"`
|
|
}
|
|
|
|
// StreamIssued is one of a module's own streams as its membership names it (ADR 0363 §2).
|
|
type StreamIssued struct {
|
|
Stream string `json:"stream"`
|
|
Events []string `json:"events"`
|
|
Subject string `json:"subject"`
|
|
}
|
|
|
|
// HeardIssued is one module stream an assignment hears (ADR 0363 §8).
|
|
type HeardIssued struct {
|
|
Stream string `json:"stream"`
|
|
Consumer string `json:"consumer"`
|
|
}
|
|
|
|
// WaitIssued is one family as a membership issues it: the name a session asks for, and its subject.
|
|
type WaitIssued struct {
|
|
Event string `json:"event"`
|
|
Subject string `json:"subject"`
|
|
}
|
|
|
|
// CredentialIn reads the credential out of a bus address, `[scheme://]user:password@host:port`, splitting on
|
|
// the last at-sign so a password containing one stays whole, and returns the address without it.
|
|
func CredentialIn(address string) (user, password, bare string) {
|
|
at := strings.LastIndex(address, "@")
|
|
if at < 0 {
|
|
return "", "", address
|
|
}
|
|
scheme := ""
|
|
rest := address[:at]
|
|
if i := strings.Index(rest, "://"); i >= 0 {
|
|
scheme, rest = rest[:i+3], rest[i+3:]
|
|
}
|
|
user, password, _ = strings.Cut(rest, ":")
|
|
return user, password, scheme + address[at+1:]
|
|
}
|
|
|
|
// BareAddress is a bus address with any credential stripped, for something that only needs to know
|
|
// whether a server is answering there.
|
|
func BareAddress(address string) string {
|
|
_, _, bare := CredentialIn(address)
|
|
if bare == "" {
|
|
return address
|
|
}
|
|
if strings.Contains(bare, "://") {
|
|
return bare
|
|
}
|
|
return "nats://" + bare
|
|
}
|