|
|
|
@@ -0,0 +1,181 @@
|
|
|
|
|
// Package seatfiles is the indexer's one reading of the seat definitions a revision carries (novox/hq ADR 0633 §1, §6;
|
|
|
|
|
// ADR 0635, ADR 0636 §4): a manifest is judged against the seats of the revision it belongs to, never against the list
|
|
|
|
|
// the judge was built with. A definition is the contracts module's `seats/<seat>/seat.json` (design 26 *A seat's
|
|
|
|
|
// definition*), with the parts it includes from `parts/<part>.json`. This reader takes of it only what a manifest is
|
|
|
|
|
// judged by (the seat's scope, what it delivers, its verbs and events) and reads the rest leniently: the format's one
|
|
|
|
|
// strict reader (mesh-sdk seatdef) is not in the mesh-sdk the judge is built with, and the indexer of the revision keeps
|
|
|
|
|
// the definitions whole.
|
|
|
|
|
//
|
|
|
|
|
// It is the indexer's own package, a module of its own so that the checker's rules can require it (the lead's ruling on
|
|
|
|
|
// milestone 47/B0, ADR 0634 §1: shared code lives with its owner): the indexer's judge and the checker's seat list read
|
|
|
|
|
// definitions here and nowhere else. Milestone G's domain SDK reading replaces it.
|
|
|
|
|
package seatfiles
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Definition is the part of one seat's definition a manifest is judged by.
|
|
|
|
|
type Definition struct {
|
|
|
|
|
Format int `json:"format"`
|
|
|
|
|
Seat string `json:"seat"`
|
|
|
|
|
Scope string `json:"scope"`
|
|
|
|
|
Decision string `json:"decision"`
|
|
|
|
|
HolderDeclares bool `json:"holder-declares"`
|
|
|
|
|
Delivers string `json:"delivers"`
|
|
|
|
|
Replicated bool `json:"replicated"`
|
|
|
|
|
PulledByKind bool `json:"pulled-by-kind"`
|
|
|
|
|
Yields bool `json:"yields"`
|
|
|
|
|
HeldByTheEngine bool `json:"held-by-the-engine"`
|
|
|
|
|
Includes []string `json:"includes"`
|
|
|
|
|
Verbs []DefVerb `json:"verbs"`
|
|
|
|
|
Accepts []DefName `json:"accepts"`
|
|
|
|
|
Events []DefName `json:"events"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefVerb is a verb of a definition.
|
|
|
|
|
type DefVerb struct {
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
Description string `json:"description"`
|
|
|
|
|
Optional bool `json:"optional"`
|
|
|
|
|
Replaces []string `json:"replaces"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefName is an accepted message or an event of a definition.
|
|
|
|
|
type DefName struct {
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Part is a part a definition includes: verbs and events written once for the seats that share them.
|
|
|
|
|
type Part struct {
|
|
|
|
|
Part string `json:"part"`
|
|
|
|
|
Verbs []DefVerb `json:"verbs"`
|
|
|
|
|
Events []DefName `json:"events"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ParseDefinition reads one definition; a file that is not one names a seat and a scope.
|
|
|
|
|
func ParseDefinition(raw []byte) (Definition, error) {
|
|
|
|
|
var d Definition
|
|
|
|
|
if err := json.Unmarshal(raw, &d); err != nil {
|
|
|
|
|
return Definition{}, fmt.Errorf("a seat definition is not JSON: %w", err)
|
|
|
|
|
}
|
|
|
|
|
if d.Seat == "" || (d.Scope != catalogue.ScopeMesh && d.Scope != catalogue.ScopeNode) {
|
|
|
|
|
return Definition{}, fmt.Errorf("a seat definition names its seat and its scope (mesh or node), not %q and %q", d.Seat, d.Scope)
|
|
|
|
|
}
|
|
|
|
|
return d, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ParsePart reads one part.
|
|
|
|
|
func ParsePart(raw []byte) (Part, error) {
|
|
|
|
|
var p Part
|
|
|
|
|
if err := json.Unmarshal(raw, &p); err != nil {
|
|
|
|
|
return Part{}, fmt.Errorf("a part of a seat definition is not JSON: %w", err)
|
|
|
|
|
}
|
|
|
|
|
return p, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Resolve is the definition with the verbs and events of the parts it includes put first, as the indexer keeps it.
|
|
|
|
|
func (d Definition) Resolve(parts map[string]Part) (Definition, error) {
|
|
|
|
|
out := d
|
|
|
|
|
out.Includes, out.Verbs, out.Events = nil, nil, nil
|
|
|
|
|
for _, name := range d.Includes {
|
|
|
|
|
p, ok := parts[name]
|
|
|
|
|
if !ok {
|
|
|
|
|
return Definition{}, fmt.Errorf("the seat %s includes the part %q, which is not given", d.Seat, name)
|
|
|
|
|
}
|
|
|
|
|
out.Verbs = append(out.Verbs, p.Verbs...)
|
|
|
|
|
out.Events = append(out.Events, p.Events...)
|
|
|
|
|
}
|
|
|
|
|
out.Verbs = append(out.Verbs, d.Verbs...)
|
|
|
|
|
out.Events = append(out.Events, d.Events...)
|
|
|
|
|
return out, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Seats are the seats of resolved definitions, in the catalogue's types; a seat its holder declares itself is left out.
|
|
|
|
|
// A definition still naming parts it includes is refused: resolve it first.
|
|
|
|
|
func Seats(defs []Definition) ([]catalogue.Seat, error) {
|
|
|
|
|
var out []catalogue.Seat
|
|
|
|
|
for _, d := range defs {
|
|
|
|
|
if d.HolderDeclares {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if len(d.Includes) > 0 {
|
|
|
|
|
return nil, fmt.Errorf("the seat %s names parts it includes: resolve it first", d.Seat)
|
|
|
|
|
}
|
|
|
|
|
s := catalogue.Seat{Name: d.Seat, Scope: d.Scope, Delivers: d.Delivers, Replicated: d.Replicated,
|
|
|
|
|
PulledByKind: d.PulledByKind, Yields: d.Yields, HeldByTheEngine: d.HeldByTheEngine, Decision: d.Decision}
|
|
|
|
|
for _, a := range d.Accepts {
|
|
|
|
|
s.Accepts = append(s.Accepts, a.Name)
|
|
|
|
|
}
|
|
|
|
|
for _, e := range d.Events {
|
|
|
|
|
s.Emits = append(s.Emits, e.Name)
|
|
|
|
|
}
|
|
|
|
|
for _, v := range d.Verbs {
|
|
|
|
|
s.Serves = append(s.Serves, catalogue.Verb{Name: v.Name, Description: v.Description, Optional: v.Optional, Replaces: v.Replaces})
|
|
|
|
|
}
|
|
|
|
|
out = append(out, s)
|
|
|
|
|
}
|
|
|
|
|
return out, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SeatsOfFiles are the seats of resolved definitions given as files, as a request carries them.
|
|
|
|
|
func SeatsOfFiles(raws [][]byte) ([]catalogue.Seat, error) {
|
|
|
|
|
defs := make([]Definition, 0, len(raws))
|
|
|
|
|
for _, raw := range raws {
|
|
|
|
|
d, err := ParseDefinition(raw)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
defs = append(defs, d)
|
|
|
|
|
}
|
|
|
|
|
return Seats(defs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ResolveRaw is the definition raw resolved with the parts it includes, each read by part, every field it carries kept as
|
|
|
|
|
// written: the verbs and events of its parts put first, then its own, and no includes. It reads raw and every part as
|
|
|
|
|
// ParseDefinition and ParsePart do, and answers the definition read with it. It is how a request's `seats` carry a
|
|
|
|
|
// definition whole (ADR 0636 §4).
|
|
|
|
|
func ResolveRaw(raw []byte, part func(name string) ([]byte, error)) (Definition, json.RawMessage, error) {
|
|
|
|
|
d, err := ParseDefinition(raw)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Definition{}, nil, err
|
|
|
|
|
}
|
|
|
|
|
var whole map[string]json.RawMessage
|
|
|
|
|
if err := json.Unmarshal(raw, &whole); err != nil {
|
|
|
|
|
return Definition{}, nil, err
|
|
|
|
|
}
|
|
|
|
|
type listed struct{ Verbs, Events []json.RawMessage }
|
|
|
|
|
var verbs, events []json.RawMessage
|
|
|
|
|
for _, name := range d.Includes {
|
|
|
|
|
praw, err := part(name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Definition{}, nil, fmt.Errorf("the seat %s includes the part %q: %w", d.Seat, name, err)
|
|
|
|
|
}
|
|
|
|
|
var l listed
|
|
|
|
|
if _, err := ParsePart(praw); err != nil {
|
|
|
|
|
return Definition{}, nil, fmt.Errorf("the part %q of the seat %s: %w", name, d.Seat, err)
|
|
|
|
|
}
|
|
|
|
|
_ = json.Unmarshal(praw, &l)
|
|
|
|
|
verbs, events = append(verbs, l.Verbs...), append(events, l.Events...)
|
|
|
|
|
}
|
|
|
|
|
var own listed
|
|
|
|
|
_ = json.Unmarshal(raw, &own)
|
|
|
|
|
verbs, events = append(verbs, own.Verbs...), append(events, own.Events...)
|
|
|
|
|
delete(whole, "includes")
|
|
|
|
|
for k, list := range map[string][]json.RawMessage{"verbs": verbs, "events": events} {
|
|
|
|
|
if len(list) == 0 {
|
|
|
|
|
delete(whole, k)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
b, err := json.Marshal(list)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return Definition{}, nil, err
|
|
|
|
|
}
|
|
|
|
|
whole[k] = b
|
|
|
|
|
}
|
|
|
|
|
out, err := json.Marshal(whole)
|
|
|
|
|
return d, out, err
|
|
|
|
|
}
|