Carry a channel's capabilities on its claim and tell the router every kind, so an answer is judged by the controller's record and not the channel's word
This commit is contained in:
@@ -84,6 +84,8 @@ type Placements struct {
|
||||
// Interchangeable is each module whose definition says its instances are the same anywhere,
|
||||
// so the module's plain subject is issued to all of them in one queue.
|
||||
Interchangeable map[string]bool
|
||||
// Kinds is every kind held of a kinded bench, by whom and with what capabilities (ADR 0259 §5).
|
||||
Kinds []KindHeld
|
||||
}
|
||||
|
||||
// AnswersForTheModule says whether an instance of a module on one machine is issued the module's
|
||||
@@ -115,8 +117,18 @@ func MembershipFor(node string, d Declared, where Placements) Membership {
|
||||
}
|
||||
}
|
||||
m.State = stateIssuedFor(d, node)
|
||||
if t := SeatTrafficOf(d.Module, d.Holds, d.Uses, d.Watches); len(t.Publish)+len(t.Subscribe)+
|
||||
len(t.Answers)+len(t.Workers)+len(t.Records) > 0 {
|
||||
t := SeatTrafficOf(d.Module, d.Holds, d.Uses, d.Watches)
|
||||
for _, s := range append(append([]Seat{}, d.Uses...), d.Watches...) {
|
||||
if !s.Kinded {
|
||||
continue
|
||||
}
|
||||
for _, k := range where.Kinds {
|
||||
if k.Seat == s.Name && !kindListed(t.Kinds, k) {
|
||||
t.Kinds = append(t.Kinds, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(t.Publish)+len(t.Subscribe)+len(t.Answers)+len(t.Workers)+len(t.Records)+len(t.Kinds) > 0 {
|
||||
m.SeatTraffic = &t
|
||||
}
|
||||
if len(d.Invokes) > 0 {
|
||||
@@ -155,5 +167,34 @@ func PlacementsOf(r Records, interchangeable map[string]bool) Placements {
|
||||
for _, nodes := range p.Nodes {
|
||||
sort.Strings(nodes)
|
||||
}
|
||||
for node, declared := range r.Assigned {
|
||||
for _, d := range declared {
|
||||
for _, s := range d.Holds {
|
||||
if s.Kinded && s.Kind != "" {
|
||||
p.Kinds = append(p.Kinds, KindHeld{Seat: s.Name, Kind: s.Kind, Module: d.Module, Node: node,
|
||||
Capabilities: s.Capabilities})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(p.Kinds, func(i, j int) bool {
|
||||
a, b := p.Kinds[i], p.Kinds[j]
|
||||
if a.Seat != b.Seat {
|
||||
return a.Seat < b.Seat
|
||||
}
|
||||
if a.Kind != b.Kind {
|
||||
return a.Kind < b.Kind
|
||||
}
|
||||
return a.Node < b.Node
|
||||
})
|
||||
return p
|
||||
}
|
||||
|
||||
func kindListed(list []KindHeld, k KindHeld) bool {
|
||||
for _, x := range list {
|
||||
if x.Seat == k.Seat && x.Kind == k.Kind && x.Module == k.Module && x.Node == k.Node {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -75,6 +75,8 @@ type Seat struct {
|
||||
Proofs []string
|
||||
// Records are the holder's buckets, by their full name, each user reads under its own name.
|
||||
Records []string
|
||||
// Capabilities are what this principal's claim of a kinded bench promises (ADR 0234 §2).
|
||||
Capabilities []string
|
||||
}
|
||||
|
||||
// A Principal is one user of the bus. Its permissions are derived from what it declares and
|
||||
|
||||
@@ -47,6 +47,19 @@ type SeatTraffic struct {
|
||||
Workers []Worker `json:"workers,omitempty"`
|
||||
// Records is the direct-get subjects of the records it reads under its own name.
|
||||
Records []string `json:"records,omitempty"`
|
||||
// Kinds are the holders of every kinded bench it uses or watches, with what each promises: the one
|
||||
// account of which channel is which, and what it can carry, that the router judges an answer by. The
|
||||
// controller's, from the claims, never a channel's word (novox/hq ADR 0259 §5).
|
||||
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"`
|
||||
}
|
||||
|
||||
// KindedBenches are the seats that may be kinded (ADR 0234 §2): making another is a decision, recorded.
|
||||
|
||||
@@ -238,3 +238,35 @@ func TestASeatWithoutTheNewRulesIsComposedAsBefore(t *testing.T) {
|
||||
t.Error("an old seat's holder lost its accept")
|
||||
}
|
||||
}
|
||||
|
||||
// The router learns which channel is which, and what each promises, from the controller's membership:
|
||||
// the claims, never a channel's word (ADR 0259 §5).
|
||||
func TestTheRoutersMembershipNamesEveryKindAndItsCapabilities(t *testing.T) {
|
||||
tg := channelSeat("telegram")
|
||||
tg.Capabilities = []string{"choice", "verified-sender"}
|
||||
desk := channelSeat("desktop")
|
||||
desk.Capabilities = []string{"choice"}
|
||||
router := Declared{Module: "messenger", Holds: []Seat{operatorChannel()}, Uses: []Seat{channelSeat("")}}
|
||||
records := Records{Nodes: []string{"anchor", "laptop"}, Assigned: map[string][]Declared{
|
||||
"anchor": {router, {Module: "telegram", Holds: []Seat{tg}}},
|
||||
"laptop": {{Module: "desk-channel", Holds: []Seat{desk}}},
|
||||
}}
|
||||
where := PlacementsOf(records, nil)
|
||||
m := MembershipFor("anchor", router, where)
|
||||
if m.SeatTraffic == nil || len(m.SeatTraffic.Kinds) != 2 {
|
||||
t.Fatalf("the router is not told the kinds: %+v", m.SeatTraffic)
|
||||
}
|
||||
byKind := map[string]KindHeld{}
|
||||
for _, k := range m.SeatTraffic.Kinds {
|
||||
byKind[k.Kind] = k
|
||||
}
|
||||
if k := byKind["telegram"]; k.Module != "telegram" || k.Node != "anchor" || !namesVerb(k.Capabilities, "verified-sender") {
|
||||
t.Errorf("telegram is %+v", k)
|
||||
}
|
||||
if k := byKind["desktop"]; k.Module != "desk-channel" || namesVerb(k.Capabilities, "verified-sender") {
|
||||
t.Errorf("the desk is %+v", k)
|
||||
}
|
||||
if other := MembershipFor("anchor", Declared{Module: "mesh-delivery", Uses: []Seat{operatorChannel()}}, where); other.SeatTraffic != nil && len(other.SeatTraffic.Kinds) > 0 {
|
||||
t.Error("an asker is told the channels")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user