Files
wild-central/internal/api/v1/handlers_domains.go
2026-07-10 20:46:22 +00:00

133 lines
3.7 KiB
Go

package v1
import (
"encoding/json"
"fmt"
"net"
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/wild-cloud/wild-central/internal/domains"
)
// DomainsListAll lists all registered domains.
func (api *API) DomainsListAll(w http.ResponseWriter, r *http.Request) {
doms, err := api.domains.List()
if err != nil {
respondError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to list domains: %v", err))
return
}
if doms == nil {
doms = []domains.Domain{}
}
respondJSON(w, http.StatusOK, map[string]any{
"domains": doms,
})
}
// DomainsGet retrieves a domain by its domain name.
func (api *API) DomainsGet(w http.ResponseWriter, r *http.Request) {
domain := mux.Vars(r)["domain"]
dom, err := api.domains.Get(domain)
if err != nil {
respondError(w, http.StatusNotFound, fmt.Sprintf("Domain not found: %v", err))
return
}
respondJSON(w, http.StatusOK, dom)
}
// DomainsRegister creates or updates a domain registration.
func (api *API) DomainsRegister(w http.ResponseWriter, r *http.Request) {
var dom domains.Domain
if err := json.NewDecoder(r.Body).Decode(&dom); err != nil {
respondError(w, http.StatusBadRequest, fmt.Sprintf("Invalid request body: %v", err))
return
}
// Validate routes
for i, r := range dom.Routes {
for _, p := range r.Paths {
if !strings.HasPrefix(p, "/") {
respondError(w, http.StatusBadRequest, fmt.Sprintf("Route %d: path prefix must start with /: %q", i, p))
return
}
}
for _, cidr := range r.IPAllow {
if _, _, err := net.ParseCIDR(cidr); err != nil {
respondError(w, http.StatusBadRequest, fmt.Sprintf("Route %d: invalid CIDR in ipAllow: %q", i, cidr))
return
}
}
}
if err := api.domains.Register(dom); err != nil {
respondError(w, http.StatusBadRequest, fmt.Sprintf("Failed to register domain: %v", err))
return
}
// Return the stored version (has defaults applied)
stored, _ := api.domains.Get(dom.DomainName)
respondJSON(w, http.StatusCreated, map[string]any{
"message": fmt.Sprintf("Domain %q registered", dom.DomainName),
"domain": stored,
})
}
// DomainsUpdate applies partial updates to a domain.
func (api *API) DomainsUpdate(w http.ResponseWriter, r *http.Request) {
domain := mux.Vars(r)["domain"]
var updates map[string]any
if err := json.NewDecoder(r.Body).Decode(&updates); err != nil {
respondError(w, http.StatusBadRequest, fmt.Sprintf("Invalid request body: %v", err))
return
}
if err := api.domains.Update(domain, updates); err != nil {
respondError(w, http.StatusNotFound, fmt.Sprintf("Failed to update domain: %v", err))
return
}
dom, _ := api.domains.Get(domain)
respondJSON(w, http.StatusOK, map[string]any{
"message": fmt.Sprintf("Domain %q updated", domain),
"domain": dom,
})
}
// DomainsDeregister removes a domain registration.
func (api *API) DomainsDeregister(w http.ResponseWriter, r *http.Request) {
domain := mux.Vars(r)["domain"]
if err := api.domains.Deregister(domain); err != nil {
respondError(w, http.StatusNotFound, fmt.Sprintf("Failed to deregister domain: %v", err))
return
}
respondMessage(w, http.StatusOK, fmt.Sprintf("Domain %q deregistered", domain))
}
// DomainsDeregisterBySource removes all domains from a source with a given backend.
func (api *API) DomainsDeregisterBySource(w http.ResponseWriter, r *http.Request) {
source := r.URL.Query().Get("source")
backend := r.URL.Query().Get("backend")
if source == "" {
respondError(w, http.StatusBadRequest, "source query parameter is required")
return
}
if err := api.domains.DeregisterBySource(source, backend); err != nil {
respondError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to deregister: %v", err))
return
}
respondMessage(w, http.StatusOK, fmt.Sprintf("Domains from %q deregistered", source))
}