package controllers import ( "net/http" "time" "gitea.tbdevent.eu/TBD/reforger_crawler_main/metrics" "gitea.tbdevent.eu/TBD/reforger_crawler_main/models" "github.com/gin-gonic/gin" ) const ( maxTelemetryBody = 1 << 20 maxTelemetryMetrics = 1000 maxTelemetryEvents = 200 ) // SubmitTelemetry receives metrics, events and a heartbeat from a service // (indexer, scraper, ...). See models.TelemetryBatch for the payload. func SubmitTelemetry(c *gin.Context) { c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxTelemetryBody) var batch models.TelemetryBatch if err := c.ShouldBindJSON(&batch); err != nil { c.JSON(400, gin.H{"error": "Invalid JSON"}) return } if !metrics.ValidName(batch.Service) || batch.Service == metrics.MainService { c.JSON(400, gin.H{"error": "service must match ^[a-z_][a-z0-9_]{0,63}$ and not be \"main\""}) return } if batch.Instance == "" || len(batch.Instance) > 128 { c.JSON(400, gin.H{"error": "instance is required (max 128 characters)"}) return } if len(batch.Metrics) > maxTelemetryMetrics || len(batch.Events) > maxTelemetryEvents { c.JSON(413, gin.H{"error": "too many metrics or events in one batch"}) return } now := time.Now() if err := metrics.Heartbeat(&batch, c.ClientIP(), now); err != nil { c.JSON(500, gin.H{"error": "failed to store heartbeat"}) return } result := metrics.Ingest(batch.Service, batch.Instance, batch.Metrics, now) if err := metrics.RecordEvents(batch.Service, batch.Instance, batch.Events, now); err != nil { c.JSON(500, gin.H{"error": "failed to store events"}) return } c.JSON(200, result) }