package server import ( "context" "net/http" "github.com/go-chi/chi/v5" "git.unkin.net/unkin/tomswallapi/internal/model" ) // mountPerDeviceL2 wires the per-device L2/misc sections: tunnels, stopped_rules, // proxy_arp, proxy_ndp, arp_rules, maclist. func (s *Server) mountPerDeviceL2(r chi.Router) { idCRUD(r, "/tunnels", s.listTunnels, s.createTunnel, s.getTunnel, s.deleteTunnel) idCRUD(r, "/stopped-rules", s.listStoppedRules, s.createStoppedRule, s.getStoppedRule, s.deleteStoppedRule) idCRUD(r, "/proxy-arp", s.listProxyARP, s.createProxyARP, s.getProxyARP, s.deleteProxyARP) idCRUD(r, "/proxy-ndp", s.listProxyNDP, s.createProxyNDP, s.getProxyNDP, s.deleteProxyNDP) idCRUD(r, "/arp-rules", s.listArpRules, s.createArpRule, s.getArpRule, s.deleteArpRule) idCRUD(r, "/maclist", s.listMaclist, s.createMaclist, s.getMaclist, s.deleteMaclist) } // idCRUD wires the four standard id-keyed handlers for a collection. func idCRUD(r chi.Router, path string, list, create, get, del http.HandlerFunc) { r.Route(path, func(r chi.Router) { r.Get("/", list) r.Post("/", create) r.Get("/{id}", get) r.Delete("/{id}", del) }) } func (s *Server) listTunnels(w http.ResponseWriter, r *http.Request) { list, err := s.store.ListTunnels(r.Context()) respondList(w, list, err) } func (s *Server) createTunnel(w http.ResponseWriter, r *http.Request) { var v model.Tunnel if !decode(w, r, &v) { return } if v.Device == "" || v.Type == "" || v.Zone == "" { writeError(w, http.StatusBadRequest, "device, type, and zone are required") return } id, err := s.store.CreateTunnel(r.Context(), v) if err == nil { v.ID = id } respondCreated(w, v, err) } func (s *Server) getTunnel(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } v, err := s.store.GetTunnel(r.Context(), id) respondOne(w, v, err) } func (s *Server) deleteTunnel(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } respondDelete(w, s.store.DeleteTunnel(r.Context(), id)) } func (s *Server) listStoppedRules(w http.ResponseWriter, r *http.Request) { list, err := s.store.ListStoppedRules(r.Context()) respondList(w, list, err) } func (s *Server) createStoppedRule(w http.ResponseWriter, r *http.Request) { var v model.StoppedRule if !decode(w, r, &v) { return } if v.Device == "" || v.Action == "" { writeError(w, http.StatusBadRequest, "device and action are required") return } id, err := s.store.CreateStoppedRule(r.Context(), v) if err == nil { v.ID = id } respondCreated(w, v, err) } func (s *Server) getStoppedRule(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } v, err := s.store.GetStoppedRule(r.Context(), id) respondOne(w, v, err) } func (s *Server) deleteStoppedRule(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } respondDelete(w, s.store.DeleteStoppedRule(r.Context(), id)) } func (s *Server) listProxyARP(w http.ResponseWriter, r *http.Request) { list, err := s.store.ListProxyARP(r.Context()) respondList(w, list, err) } func (s *Server) createProxyARP(w http.ResponseWriter, r *http.Request) { s.createProxy(w, r, s.store.CreateProxyARP) } func (s *Server) getProxyARP(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } v, err := s.store.GetProxyARP(r.Context(), id) respondOne(w, v, err) } func (s *Server) deleteProxyARP(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } respondDelete(w, s.store.DeleteProxyARP(r.Context(), id)) } func (s *Server) listProxyNDP(w http.ResponseWriter, r *http.Request) { list, err := s.store.ListProxyNDP(r.Context()) respondList(w, list, err) } func (s *Server) createProxyNDP(w http.ResponseWriter, r *http.Request) { s.createProxy(w, r, s.store.CreateProxyNDP) } func (s *Server) getProxyNDP(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } v, err := s.store.GetProxyNDP(r.Context(), id) respondOne(w, v, err) } func (s *Server) deleteProxyNDP(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } respondDelete(w, s.store.DeleteProxyNDP(r.Context(), id)) } // createProxy is shared by proxy_arp/ndp (identical shape). func (s *Server) createProxy(w http.ResponseWriter, r *http.Request, create func(context.Context, model.ProxyEntry) (int64, error)) { var v model.ProxyEntry if !decode(w, r, &v) { return } if v.Device == "" || v.Address == "" || v.External == "" { writeError(w, http.StatusBadRequest, "device, address, and external are required") return } id, err := create(r.Context(), v) if err == nil { v.ID = id } respondCreated(w, v, err) } func (s *Server) listArpRules(w http.ResponseWriter, r *http.Request) { list, err := s.store.ListArpRules(r.Context()) respondList(w, list, err) } func (s *Server) createArpRule(w http.ResponseWriter, r *http.Request) { var v model.ArpRule if !decode(w, r, &v) { return } if v.Device == "" || v.Action == "" { writeError(w, http.StatusBadRequest, "device and action are required") return } id, err := s.store.CreateArpRule(r.Context(), v) if err == nil { v.ID = id } respondCreated(w, v, err) } func (s *Server) getArpRule(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } v, err := s.store.GetArpRule(r.Context(), id) respondOne(w, v, err) } func (s *Server) deleteArpRule(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } respondDelete(w, s.store.DeleteArpRule(r.Context(), id)) } func (s *Server) listMaclist(w http.ResponseWriter, r *http.Request) { list, err := s.store.ListMaclist(r.Context()) respondList(w, list, err) } func (s *Server) createMaclist(w http.ResponseWriter, r *http.Request) { var v model.MaclistEntry if !decode(w, r, &v) { return } if v.Device == "" || v.Action == "" || v.Interface == "" { writeError(w, http.StatusBadRequest, "device, action, and interface are required") return } id, err := s.store.CreateMaclist(r.Context(), v) if err == nil { v.ID = id } respondCreated(w, v, err) } func (s *Server) getMaclist(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } v, err := s.store.GetMaclist(r.Context(), id) respondOne(w, v, err) } func (s *Server) deleteMaclist(w http.ResponseWriter, r *http.Request) { id, ok := idParam(w, r) if !ok { return } respondDelete(w, s.store.DeleteMaclist(r.Context(), id)) }