package handlers import ( "encoding/json" "net/http" ) const maxReportBodyBytes = 1 << 20 // 1 MiB type reportSample struct { T int64 `json:"t"` Latency *int `json:"latency"` Error *string `json:"error"` } type reportHost struct { History []reportSample `json:"history"` Name string `json:"name"` Status string `json:"status"` URL string `json:"url"` } type report struct { ClientID string `json:"clientId"` Geo json.RawMessage `json:"geo"` Hosts []reportHost `json:"hosts"` Timestamp string `json:"timestamp"` } // HandleReport returns a handler that accepts telemetry // reports from NetWatch clients. func (s *Handlers) HandleReport() http.HandlerFunc { type response struct { Status string `json:"status"` } return func(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader( w, r.Body, maxReportBodyBytes, ) var rpt report err := json.NewDecoder(r.Body).Decode(&rpt) if err != nil { s.log.Error("failed to decode report", "error", err, ) s.respondJSON(w, r, &response{Status: "error"}, http.StatusBadRequest, ) return } totalSamples := 0 for _, h := range rpt.Hosts { totalSamples += len(h.History) } s.log.Info("report received", "client_id", rpt.ClientID, "timestamp", rpt.Timestamp, "host_count", len(rpt.Hosts), "total_samples", totalSamples, "geo", string(rpt.Geo), ) bufErr := s.buf.Append(rpt) if bufErr != nil { s.log.Error("failed to buffer report", "error", bufErr, ) } s.respondJSON(w, r, &response{Status: "ok"}, http.StatusOK, ) } }