Files
brianmcgee e3a7790e57
buildbot/nix-eval Build done.
PR Size Review Check / pr-size-review-gate (pull_request) Successful in 24s
sizelint / sizelint (pull_request) Successful in 2m12s
buildbot/nix-build Build done.
gitea-mq Already up to date with target branch
fix breaks in gofumpt and golangci-lint from updating nixpkgs
2026-07-07 16:32:14 +01:00

75 lines
2.0 KiB
Go

package config
import (
"fmt"
"log/slog"
dmnet "git.clan.lol/clan/data-mesher/pkg/net"
)
// HTTP represents the configuration for an HTTP server, including port and interfaces.
type HTTP struct {
Port uint16 `mapstructure:"port"`
Interfaces []string `mapstructure:"interfaces"`
// generated after looking at the interfaces
ListenAddresses []string `mapstructure:"-"`
// Resolver is used to resolve interface names to IP addresses. If nil, uses the default system resolver.
Resolver dmnet.InterfaceResolver `mapstructure:"-"`
}
// Validate checks the HTTP configuration to ensure required fields are set and derives the listen addresses.
// Returns an error if the configuration is invalid.
func (h *HTTP) Validate() error {
defer func() {
slog.Debug(
"http config",
"listen_addresses", h.ListenAddresses,
"port", h.Port,
"interfaces", h.Interfaces,
)
}()
if h.Port == 0 {
return fmt.Errorf("%w: http port must be between 1 and 65535", ErrInvalidConfig)
}
if len(h.Interfaces) == 0 {
return fmt.Errorf("%w: at least one http interface is required", ErrInvalidConfig)
}
// determine network resolver
resolver := h.Resolver
if resolver == nil {
// if no resolver is specified we fall back to the system resolver
resolver = dmnet.DefaultResolver{}
}
// bind to all addresses found for the interfaces
for _, iface := range h.Interfaces {
addrs, err := resolver.InterfaceAddresses(iface)
if err != nil {
return fmt.Errorf("%w: failed to resolve ip addresses for interface %q: %w", ErrInvalidConfig, iface, err)
}
for _, addr := range addrs {
// we don't want multicast or link-local addresses
if addr.IP.IsMulticast() || addr.IP.IsLinkLocalMulticast() || addr.IP.IsLinkLocalUnicast() {
continue
}
h.ListenAddresses = append(h.ListenAddresses, dmnet.ConnectString(addr.IP, h.Port))
}
}
if len(h.ListenAddresses) == 0 {
return fmt.Errorf(
"%w: failed to resolve any ip addresses for interfaces %q",
ErrInvalidConfig, h.Interfaces,
)
}
return nil
}