package transport import ( "errors" "io" "strconv" "github.com/gin-gonic/gin" "github.com/geo-platform/tenant-api/internal/bootstrap" "github.com/geo-platform/tenant-api/internal/shared/response" "github.com/geo-platform/tenant-api/internal/tenant/app" ) type MonitoringCallbackHandler struct { svc *app.MonitoringCallbackService } func NewMonitoringCallbackHandler(a *bootstrap.App) *MonitoringCallbackHandler { return &MonitoringCallbackHandler{ svc: app.NewMonitoringCallbackService(a.DB, a.MonitoringDB, a.RabbitMQ, a.LLM, a.Logger), } } func (h *MonitoringCallbackHandler) Heartbeat(c *gin.Context) { installationID, installationToken, ok := parseMonitoringInstallationHeaders(c) if !ok { return } var req app.MonitoringHeartbeatRequest if err := bindOptionalJSON(c, &req); err != nil { response.Error(c, response.ErrBadRequest(40041, "invalid_params", err.Error())) return } data, svcErr := h.svc.Heartbeat(c.Request.Context(), installationID, installationToken, req) if svcErr != nil { response.Error(c, svcErr) return } response.Success(c, data) } func (h *MonitoringCallbackHandler) LeaseTasks(c *gin.Context) { installationID, installationToken, ok := parseMonitoringInstallationHeaders(c) if !ok { return } var req app.MonitoringLeaseTasksRequest if err := bindOptionalJSON(c, &req); err != nil { response.Error(c, response.ErrBadRequest(40041, "invalid_params", err.Error())) return } data, svcErr := h.svc.LeaseTasks(c.Request.Context(), installationID, installationToken, req) if svcErr != nil { response.Error(c, svcErr) return } response.Success(c, data) } func (h *MonitoringCallbackHandler) ResumeTasks(c *gin.Context) { installationID, installationToken, ok := parseMonitoringInstallationHeaders(c) if !ok { return } var req app.MonitoringResumeTasksRequest if err := bindOptionalJSON(c, &req); err != nil { response.Error(c, response.ErrBadRequest(40041, "invalid_params", err.Error())) return } data, svcErr := h.svc.ResumeTasks(c.Request.Context(), installationID, installationToken, req) if svcErr != nil { response.Error(c, svcErr) return } response.Success(c, data) } func (h *MonitoringCallbackHandler) TaskResult(c *gin.Context) { taskID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { response.Error(c, response.ErrBadRequest(40041, "invalid_task_id", "task id must be a number")) return } installationID, installationToken, ok := parseMonitoringInstallationHeaders(c) if !ok { return } var req app.MonitoringTaskResultRequest if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, response.ErrBadRequest(40041, "invalid_params", err.Error())) return } data, svcErr := h.svc.HandleTaskResult(c.Request.Context(), installationID, installationToken, taskID, req) if svcErr != nil { response.Error(c, svcErr) return } response.Success(c, data) } func (h *MonitoringCallbackHandler) SkipTask(c *gin.Context) { taskID, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { response.Error(c, response.ErrBadRequest(40041, "invalid_task_id", "task id must be a number")) return } installationID, installationToken, ok := parseMonitoringInstallationHeaders(c) if !ok { return } var req app.MonitoringSkipTaskRequest if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, response.ErrBadRequest(40041, "invalid_params", err.Error())) return } data, svcErr := h.svc.SkipTask(c.Request.Context(), installationID, installationToken, taskID, req) if svcErr != nil { response.Error(c, svcErr) return } response.Success(c, data) } func parseMonitoringInstallationHeaders(c *gin.Context) (int64, string, bool) { installationID, err := strconv.ParseInt(c.GetHeader("X-Geo-Installation-Id"), 10, 64) if err != nil { response.Error(c, response.ErrUnauthorized(40141, "invalid_installation_id", "installation id header is invalid")) return 0, "", false } installationToken := c.GetHeader("X-Geo-Installation-Token") if installationToken == "" { response.Error(c, response.ErrUnauthorized(40141, "missing_installation_token", "installation token header is required")) return 0, "", false } return installationID, installationToken, true } func bindOptionalJSON(c *gin.Context, target interface{}) error { err := c.ShouldBindJSON(target) if err == nil { return nil } if errors.Is(err, io.EOF) { return nil } return err }