Files
mesh-host/internal/compose/resolution/zones.go
T
jschoubben d68e241724 Take the catalogue's composition rules into the node-engine
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
2026-11-02 19:15:55 +01:00

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
}