mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-06 07:36:37 +08:00
框架化
This commit is contained in:
@@ -17,7 +17,6 @@ limitations under the License.
|
||||
package task
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -81,44 +80,17 @@ func DispatchTask(c *gin.Context) {
|
||||
}
|
||||
|
||||
var payloadBytes []byte
|
||||
if req.TaskType == task.TaskTypeSendEmail {
|
||||
if strings.TrimSpace(req.Payload) == "" {
|
||||
c.JSON(http.StatusBadRequest, util.Err("任务参数 Payload 不能为空"))
|
||||
return
|
||||
}
|
||||
|
||||
var mailPayload struct {
|
||||
To string `json:"to"`
|
||||
Subject string `json:"subject"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(req.Payload), &mailPayload); err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err("无效的 JSON 格式: "+err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
mailPayload.To = strings.TrimSpace(mailPayload.To)
|
||||
mailPayload.Subject = strings.TrimSpace(mailPayload.Subject)
|
||||
mailPayload.Body = strings.TrimSpace(mailPayload.Body)
|
||||
|
||||
if mailPayload.To == "" || mailPayload.Subject == "" || mailPayload.Body == "" {
|
||||
c.JSON(http.StatusBadRequest, util.Err("收件人地址 (to)、邮件主题 (subject) 和邮件内容 (body) 不能为空"))
|
||||
return
|
||||
}
|
||||
|
||||
var err error
|
||||
payloadBytes, err = json.Marshal(mailPayload)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err("构造邮件任务载荷失败"))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if req.Payload != "" {
|
||||
payloadBytes = []byte(req.Payload)
|
||||
}
|
||||
if strings.TrimSpace(req.Payload) != "" {
|
||||
payloadBytes = []byte(req.Payload)
|
||||
}
|
||||
|
||||
taskID, err := task.DispatchTask(c.Request.Context(), req.TaskType, payloadBytes, "manual")
|
||||
validated, err := task.ValidateAndNormalizePayload(meta.AsynqTask, payloadBytes)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, util.Err(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
taskID, err := task.DispatchTask(c.Request.Context(), req.TaskType, validated, "manual")
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, util.Err(fmt.Sprintf("%s: %v", TaskDispatchFailed, err)))
|
||||
return
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/linux-do/credit/internal/model"
|
||||
"github.com/linux-do/credit/internal/task"
|
||||
@@ -38,6 +39,29 @@ type SendEmailPayload struct {
|
||||
// SendEmailHandler 发送验证码邮件的异步任务处理器
|
||||
type SendEmailHandler struct{}
|
||||
|
||||
// ValidatePayload 实现 task.PayloadValidator 接口
|
||||
// 校验并标准化邮件发送参数,框架在 Admin 下发时自动调用
|
||||
func (h *SendEmailHandler) ValidatePayload(payload []byte) ([]byte, error) {
|
||||
if len(payload) == 0 {
|
||||
return nil, errors.New("任务参数不能为空")
|
||||
}
|
||||
|
||||
var req SendEmailPayload
|
||||
if err := json.Unmarshal(payload, &req); err != nil {
|
||||
return nil, fmt.Errorf("无效的 JSON 格式: %w", err)
|
||||
}
|
||||
|
||||
req.To = strings.TrimSpace(req.To)
|
||||
req.Subject = strings.TrimSpace(req.Subject)
|
||||
req.Body = strings.TrimSpace(req.Body)
|
||||
|
||||
if req.To == "" || req.Subject == "" || req.Body == "" {
|
||||
return nil, errors.New("to、subject、body 不能为空")
|
||||
}
|
||||
|
||||
return json.Marshal(req)
|
||||
}
|
||||
|
||||
// Execute 执行邮件异步发送逻辑
|
||||
func (h *SendEmailHandler) Execute(ctx context.Context, payload []byte) (*task.TaskResult, error) {
|
||||
var req SendEmailPayload
|
||||
|
||||
@@ -46,6 +46,20 @@ func getHandler(asynqTaskType string) (TaskHandler, bool) {
|
||||
return h, ok
|
||||
}
|
||||
|
||||
// ValidateAndNormalizePayload 校验并标准化任务参数。
|
||||
// 如果 Handler 实现了 PayloadValidator,调用其 ValidatePayload 方法;
|
||||
// 否则直接返回原始 payload。
|
||||
func ValidateAndNormalizePayload(asynqTaskType string, payload []byte) ([]byte, error) {
|
||||
handler, ok := getHandler(asynqTaskType)
|
||||
if !ok {
|
||||
return payload, nil
|
||||
}
|
||||
if validator, ok := handler.(PayloadValidator); ok {
|
||||
return validator.ValidatePayload(payload)
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
// contextKey 用于 context 存取 taskID
|
||||
type contextKey string
|
||||
|
||||
|
||||
@@ -24,6 +24,13 @@ type TaskResult struct {
|
||||
Detail string // 可选的详细结果 JSON
|
||||
}
|
||||
|
||||
// PayloadValidator 可选接口,带参数的任务 Handler 应实现此接口。
|
||||
// 框架在 Admin 下发时自动调用,完成参数校验和标准化(如 Trim 空白)。
|
||||
// 无参数的任务无需实现,框架会直接透传 payload。
|
||||
type PayloadValidator interface {
|
||||
ValidatePayload(payload []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
// TaskHandler 异步任务处理器接口
|
||||
// 所有异步任务必须实现此接口,框架将自动管理任务执行记录的创建、状态流转和日志写入。
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user