ADR 0593 §7: the composer with its refusals leaves mesh-sdk, so mesh-sdk carries no composition rule. The catalogue functions only the node-engine's composition reaches (Resolve, Resolution's Compose, Declaration, DataItems, LeftOut, Rules and the rest, the settings, placeholder and template refusals, the rendering helpers) are copied with their tests into internal/compose/resolution; a method of a mesh-sdk shape becomes a function taking it first. The composition calls its own copies, and the captured catalogue its tests read lives here now, shared by mesh-compose's tests. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
64 lines
2.3 KiB
Go
64 lines
2.3 KiB
Go
package resolution
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
mcat "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// ZoneOn is one module's zone as one node places it: the name settled from the node's settings, the
|
|
// port its answering listen is published on there. Nothing when the module declares no zone.
|
|
func ZoneOn(m mcat.Manifest, layers []mcat.Layer, published map[int]int, node, address string) (*mcat.ZoneAt, error) {
|
|
if m.Zone == nil {
|
|
return nil, nil
|
|
}
|
|
settled, err := Settle(map[string]any{"zone": m.Zone.Name}, layers)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%s's zone on %s: %w", m.Module, node, err)
|
|
}
|
|
zone := strings.Trim(strings.ToLower(fmt.Sprint(settled["zone"])), ".")
|
|
var port int
|
|
for _, l := range m.Listens {
|
|
if l.Name == m.Zone.Listen {
|
|
port = l.Port
|
|
if at, given := published[l.Port]; given {
|
|
port = at
|
|
}
|
|
}
|
|
}
|
|
return &mcat.ZoneAt{Zone: zone, Node: node, Module: m.Module, Address: address, Port: port}, nil
|
|
}
|
|
|
|
// ZonesProblems is what the mesh refuses about its zones together: one zone declared twice, a zone
|
|
// that is the mesh's suffix or under it, a zone that is a node's public domain or under one. A module
|
|
// may not shadow names the mesh's resolver or the public DNS answers.
|
|
func ZonesProblems(zones []mcat.ZoneAt, suffix string, publicDomains []string) []string {
|
|
var problems []string
|
|
under := func(zone, domain string) bool {
|
|
domain = strings.Trim(strings.ToLower(domain), ".")
|
|
return domain != "" && (zone == domain || strings.HasSuffix(zone, "."+domain))
|
|
}
|
|
seen := map[string]mcat.ZoneAt{}
|
|
for _, z := range zones {
|
|
if other, twice := seen[z.Zone]; twice && (other.Node != z.Node || other.Module != z.Module) {
|
|
problems = append(problems, fmt.Sprintf("zone %q is declared by %s on %s and by %s on %s; one module answers a zone",
|
|
z.Zone, other.Module, other.Node, z.Module, z.Node))
|
|
}
|
|
seen[z.Zone] = z
|
|
if under(z.Zone, suffix) {
|
|
problems = append(problems, fmt.Sprintf("%s on %s declares zone %q, which is the mesh's own suffix or under it",
|
|
z.Module, z.Node, z.Zone))
|
|
}
|
|
for _, d := range publicDomains {
|
|
if under(z.Zone, d) {
|
|
problems = append(problems, fmt.Sprintf("%s on %s declares zone %q, which is the public domain %q or under it",
|
|
z.Module, z.Node, z.Zone, d))
|
|
}
|
|
}
|
|
}
|
|
sort.Strings(problems)
|
|
return problems
|
|
}
|