Files
geo/server/internal/tenant/transport/monitoring_callback_handler.go
T
root 6066f43a7d Add monitoring service and database schema
- Implement monitoring service with heartbeat, lease tasks, resume tasks, and task result handling.
- Create monitoring time utilities for business date calculations.
- Add unit tests for date window resolution and business day handling.
- Define database schema for monitoring-related tables including quotas, daily reports, and task management.
- Establish migration scripts for creating and dropping monitoring tables.
2026-04-12 09:56:18 +08:00

163 lines
4.3 KiB
Go

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
}