dashboard and status API list a port's domains apart from its hostnames (closes #245)
check / check (push) Successful in 1m18s

A port entry in the state saves the apex domains that resolve to its
address with its hostnames. The dashboard's Ports table now has a
Domains column next to Hostnames, and a port entry in /api/v1/status
has a `domains` list, with `hostnames` no longer holding a domain. A
name is taken as a domain when it has a domain entry, as the dashboard
and API already tell a domain's own records from a hostname's. Both
read the split from one function, buildPorts. The state file is
unchanged; README says its port `hostnames` include domains.

Model: opus-5-5
This commit is contained in:
2026-10-02 08:18:21 +00:00
parent 008ec5d13a
commit bd9e3e27b9
7 changed files with 155 additions and 28 deletions
+26 -9
View File
@@ -32,8 +32,11 @@ type statusHostnameInfo struct {
}
// statusPortInfo holds status information for a monitored port.
// Domains and Hostnames list the apex domains and the hostnames that
// resolve to its address.
type statusPortInfo struct {
Open bool `json:"open"`
Domains []string `json:"domains"`
Hostnames []string `json:"hostnames"`
LastChecked time.Time `json:"lastChecked"`
}
@@ -99,7 +102,6 @@ func buildStatusResponse(
LastUpdated: snap.LastUpdated,
Domains: make(map[string]*statusDomainInfo),
Hostnames: make(map[string]*statusHostnameInfo),
Ports: make(map[string]*statusPortInfo),
Certificates: make(map[string]*statusCertificateInfo),
}
@@ -107,7 +109,7 @@ func buildStatusResponse(
buildDomains(snap, domainRecords, resp)
buildHostnames(hostnames, resp)
buildPorts(snap, resp)
resp.Ports = buildPorts(snap)
buildCertificates(snap, resp)
buildCounts(resp)
@@ -195,21 +197,36 @@ func nameserverInfo(
return info
}
func buildPorts(
snap state.Snapshot,
resp *statusResponse,
) {
// buildPorts returns the port entries saved in snap. A port entry
// saves apex domains with its hostnames; they are told apart as in
// splitHostnames, by a domain entry in snap.Domains.
func buildPorts(snap state.Snapshot) map[string]*statusPortInfo {
ports := make(map[string]*statusPortInfo, len(snap.Ports))
for key, ps := range snap.Ports {
hostnames := make([]string, len(ps.Hostnames))
copy(hostnames, ps.Hostnames)
domains := []string{}
hostnames := []string{}
for _, name := range ps.Hostnames {
if _, isDomain := snap.Domains[name]; isDomain {
domains = append(domains, name)
} else {
hostnames = append(hostnames, name)
}
}
sort.Strings(domains)
sort.Strings(hostnames)
resp.Ports[key] = &statusPortInfo{
ports[key] = &statusPortInfo{
Open: ps.Open,
Domains: domains,
Hostnames: hostnames,
LastChecked: ps.LastChecked,
}
}
return ports
}
func buildCertificates(