// host_bandwidth.go — REST API for /api/hosts/{id}/bandwidth. // // Host-wide upload/download caps (KB/s). Applied to every restic // invocation as --limit-upload / --limit-download. Pass null / // omit a field to clear that cap. package http import ( "encoding/json" "errors" stdhttp "net/http" "github.com/go-chi/chi/v5" "gitea.dcglab.co.uk/steve/restic-manager/internal/store" ) type hostBandwidthRequest struct { BandwidthUpKBps *int `json:"bandwidth_up_kbps"` BandwidthDownKBps *int `json:"bandwidth_down_kbps"` } type hostBandwidthView struct { BandwidthUpKBps *int `json:"bandwidth_up_kbps"` BandwidthDownKBps *int `json:"bandwidth_down_kbps"` } func (s *Server) handleUpdateHostBandwidth(w stdhttp.ResponseWriter, r *stdhttp.Request) { if !s.authedUser(r) { writeJSONError(w, stdhttp.StatusUnauthorized, "unauthorised", "") return } hostID := chi.URLParam(r, "id") if _, err := s.deps.Store.GetHost(r.Context(), hostID); err != nil { if errors.Is(err, store.ErrNotFound) { writeJSONError(w, stdhttp.StatusNotFound, "host_not_found", "") return } writeJSONError(w, stdhttp.StatusInternalServerError, "internal", "") return } var req hostBandwidthRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSONError(w, stdhttp.StatusBadRequest, "invalid_json", err.Error()) return } if req.BandwidthUpKBps != nil && *req.BandwidthUpKBps < 0 { writeJSONError(w, stdhttp.StatusBadRequest, "invalid_value", "bandwidth_up_kbps must be non-negative") return } if req.BandwidthDownKBps != nil && *req.BandwidthDownKBps < 0 { writeJSONError(w, stdhttp.StatusBadRequest, "invalid_value", "bandwidth_down_kbps must be non-negative") return } if err := s.deps.Store.SetHostBandwidth(r.Context(), hostID, req.BandwidthUpKBps, req.BandwidthDownKBps); err != nil { writeJSONError(w, stdhttp.StatusInternalServerError, "internal", err.Error()) return } // Fan out to the agent if connected. Errors are non-fatal — the // next reconnect's onAgentHello will resync. if s.deps.Hub != nil && s.deps.Hub.Connected(hostID) { _ = s.pushBandwidthToAgent(r.Context(), hostID, req.BandwidthUpKBps, req.BandwidthDownKBps) } writeJSON(w, stdhttp.StatusOK, hostBandwidthView(req)) }