Files
tomswallapi/internal/server/perdevice.go
T
benvin b312645387
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Add per-device routing long-tail: hosts, providers, routes, routing_rules
Storage + CRUD (migration 0006, model, id-keyed store, REST handlers) plus
compiler rendering: each section is owned by a device and projected into that
device's rendered config (hosts/providers/routes/routing_rules).
2026-07-26 00:12:19 +10:00

191 lines
4.5 KiB
Go

package server
import (
"net/http"
"github.com/go-chi/chi/v5"
"git.unkin.net/unkin/tomswallapi/internal/model"
)
// mountPerDevice wires the per-device long-tail sections: hosts, providers,
// routes, and routing-rules.
func (s *Server) mountPerDevice(r chi.Router) {
r.Route("/hosts", func(r chi.Router) {
r.Get("/", s.listHosts)
r.Post("/", s.createHost)
r.Get("/{id}", s.getHost)
r.Delete("/{id}", s.deleteHost)
})
r.Route("/providers", func(r chi.Router) {
r.Get("/", s.listProviders)
r.Post("/", s.createProvider)
r.Get("/{id}", s.getProvider)
r.Delete("/{id}", s.deleteProvider)
})
r.Route("/routes", func(r chi.Router) {
r.Get("/", s.listRoutes)
r.Post("/", s.createRoute)
r.Get("/{id}", s.getRoute)
r.Delete("/{id}", s.deleteRoute)
})
r.Route("/routing-rules", func(r chi.Router) {
r.Get("/", s.listRoutingRules)
r.Post("/", s.createRoutingRule)
r.Get("/{id}", s.getRoutingRule)
r.Delete("/{id}", s.deleteRoutingRule)
})
}
func (s *Server) listHosts(w http.ResponseWriter, r *http.Request) {
list, err := s.store.ListHosts(r.Context())
respondList(w, list, err)
}
func (s *Server) createHost(w http.ResponseWriter, r *http.Request) {
var v model.Host
if !decode(w, r, &v) {
return
}
if v.Device == "" || v.Zone == "" || v.Interface == "" {
writeError(w, http.StatusBadRequest, "device, zone, and interface are required")
return
}
id, err := s.store.CreateHost(r.Context(), v)
if err == nil {
v.ID = id
}
respondCreated(w, v, err)
}
func (s *Server) getHost(w http.ResponseWriter, r *http.Request) {
id, ok := idParam(w, r)
if !ok {
return
}
v, err := s.store.GetHost(r.Context(), id)
respondOne(w, v, err)
}
func (s *Server) deleteHost(w http.ResponseWriter, r *http.Request) {
id, ok := idParam(w, r)
if !ok {
return
}
respondDelete(w, s.store.DeleteHost(r.Context(), id))
}
func (s *Server) listProviders(w http.ResponseWriter, r *http.Request) {
list, err := s.store.ListProviders(r.Context())
respondList(w, list, err)
}
func (s *Server) createProvider(w http.ResponseWriter, r *http.Request) {
var v model.Provider
if !decode(w, r, &v) {
return
}
if v.Device == "" || v.Name == "" || v.Interface == "" {
writeError(w, http.StatusBadRequest, "device, name, and interface are required")
return
}
id, err := s.store.CreateProvider(r.Context(), v)
if err == nil {
v.ID = id
}
respondCreated(w, v, err)
}
func (s *Server) getProvider(w http.ResponseWriter, r *http.Request) {
id, ok := idParam(w, r)
if !ok {
return
}
v, err := s.store.GetProvider(r.Context(), id)
respondOne(w, v, err)
}
func (s *Server) deleteProvider(w http.ResponseWriter, r *http.Request) {
id, ok := idParam(w, r)
if !ok {
return
}
respondDelete(w, s.store.DeleteProvider(r.Context(), id))
}
func (s *Server) listRoutes(w http.ResponseWriter, r *http.Request) {
list, err := s.store.ListRoutes(r.Context())
respondList(w, list, err)
}
func (s *Server) createRoute(w http.ResponseWriter, r *http.Request) {
var v model.Route
if !decode(w, r, &v) {
return
}
if v.Device == "" || v.Dest == "" {
writeError(w, http.StatusBadRequest, "device and dest are required")
return
}
id, err := s.store.CreateRoute(r.Context(), v)
if err == nil {
v.ID = id
}
respondCreated(w, v, err)
}
func (s *Server) getRoute(w http.ResponseWriter, r *http.Request) {
id, ok := idParam(w, r)
if !ok {
return
}
v, err := s.store.GetRoute(r.Context(), id)
respondOne(w, v, err)
}
func (s *Server) deleteRoute(w http.ResponseWriter, r *http.Request) {
id, ok := idParam(w, r)
if !ok {
return
}
respondDelete(w, s.store.DeleteRoute(r.Context(), id))
}
func (s *Server) listRoutingRules(w http.ResponseWriter, r *http.Request) {
list, err := s.store.ListRoutingRules(r.Context())
respondList(w, list, err)
}
func (s *Server) createRoutingRule(w http.ResponseWriter, r *http.Request) {
var v model.RoutingRule
if !decode(w, r, &v) {
return
}
if v.Device == "" || v.Provider == "" {
writeError(w, http.StatusBadRequest, "device and provider are required")
return
}
id, err := s.store.CreateRoutingRule(r.Context(), v)
if err == nil {
v.ID = id
}
respondCreated(w, v, err)
}
func (s *Server) getRoutingRule(w http.ResponseWriter, r *http.Request) {
id, ok := idParam(w, r)
if !ok {
return
}
v, err := s.store.GetRoutingRule(r.Context(), id)
respondOne(w, v, err)
}
func (s *Server) deleteRoutingRule(w http.ResponseWriter, r *http.Request) {
id, ok := idParam(w, r)
if !ok {
return
}
respondDelete(w, s.store.DeleteRoutingRule(r.Context(), id))
}