feat(delivery): switch AWX delivery to callbacks

This commit is contained in:
mac
2026-07-27 15:19:18 +08:00
parent 97f0de16bc
commit e0ee36cadb
9 changed files with 594 additions and 104 deletions
+35 -19
View File
@@ -19,42 +19,54 @@ func NewDeliveryHandler(s *service.DeliveryService) *DeliveryHandler {
return &DeliveryHandler{service: s}
}
type ExecutionHandler struct {
type DeliveryCallbackHandler struct {
service *service.DeliveryService
token string
}
func NewExecutionHandler(s *service.DeliveryService, token string) *ExecutionHandler {
return &ExecutionHandler{service: s, token: strings.TrimSpace(token)}
func NewDeliveryCallbackHandler(s *service.DeliveryService, token string) *DeliveryCallbackHandler {
return &DeliveryCallbackHandler{service: s, token: strings.TrimSpace(token)}
}
type executionPayload struct {
TaskID string `json:"task_id" binding:"required"`
PayloadHash string `json:"payload_hash" binding:"required"`
IdempotencyKey string `json:"idempotency_key" binding:"required"`
}
func (h *ExecutionHandler) Create(c *gin.Context) {
provided := strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer ")
func (h *DeliveryCallbackHandler) authorize(c *gin.Context) bool {
provided := strings.TrimSpace(strings.TrimPrefix(c.GetHeader("Authorization"), "Bearer "))
if h.token == "" || subtle.ConstantTimeCompare([]byte(provided), []byte(h.token)) != 1 {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid service credential"})
return false
}
return true
}
func (h *DeliveryCallbackHandler) StageEvent(c *gin.Context) {
if !h.authorize(c) {
return
}
var req executionPayload
var req service.DeliveryStageEventInput
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
job, replay, err := h.service.CreateExecution(c.Request.Context(), req.TaskID, req.PayloadHash, req.IdempotencyKey)
if err != nil {
if err := h.service.HandleStageEvent(c.Request.Context(), c.Param("id"), req); err != nil {
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
return
}
status := http.StatusCreated
if replay {
status = http.StatusOK
c.JSON(http.StatusAccepted, gin.H{"ok": true})
}
func (h *DeliveryCallbackHandler) AWXJobEvent(c *gin.Context) {
if !h.authorize(c) {
return
}
c.JSON(status, gin.H{"execution": job, "idempotent_replay": replay})
var req service.AWXJobNotificationInput
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid AWX webhook JSON: " + err.Error()})
return
}
if err := h.service.HandleAWXJobNotification(c.Request.Context(), req); err != nil {
c.JSON(http.StatusConflict, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusAccepted, gin.H{"ok": true})
}
// CreateMySQL 提交 MySQL 交付请求
@@ -114,7 +126,11 @@ func (h *DeliveryHandler) List(c *gin.Context) {
if raw := c.Query("business_line_id"); raw != "" {
businessLineID, _ = strconv.ParseUint(raw, 10, 64)
}
items, err := h.service.ListTasks(c.Request.Context(), claims.UserID, claims.IsAdmin, businessLineID)
items, err := h.service.ListTasks(c.Request.Context(), claims.UserID, claims.IsAdmin, service.DeliveryTaskListFilter{
BusinessLineID: businessLineID,
Component: c.Query("component"),
ActiveOnly: strings.EqualFold(c.Query("active"), "true"),
})
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
+1 -1
View File
@@ -96,7 +96,7 @@ func (h *TaskLogHandler) Get(c *gin.Context) {
}
func (h *TaskLogHandler) listAWXTasks(c *gin.Context, userID uint64, isAdmin bool, businessLineID uint64) ([]taskLogSummary, error) {
tasks, err := h.delivery.ListTasks(c.Request.Context(), userID, isAdmin, businessLineID)
tasks, err := h.delivery.ListTasks(c.Request.Context(), userID, isAdmin, service.DeliveryTaskListFilter{BusinessLineID: businessLineID})
if err != nil {
return nil, err
}