fix: align admin behavior and Kratos integrations
This commit is contained in:
+108
-3
@@ -2,7 +2,13 @@ package biz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
type TimedTask struct {
|
||||
@@ -28,6 +34,37 @@ type TimedTaskLog struct {
|
||||
DurationMS int64
|
||||
Status, ErrorMsg, Output string
|
||||
}
|
||||
|
||||
const (
|
||||
TaskExecutorMethod = "method"
|
||||
TaskExecutorHTTP = "http"
|
||||
TaskMethodClearDB = "ClearDB"
|
||||
TaskMethodUploads = "CleanStaleUploads"
|
||||
)
|
||||
|
||||
type TaskMethod struct {
|
||||
Name string
|
||||
Description string
|
||||
}
|
||||
|
||||
var registeredTaskMethods = []TaskMethod{
|
||||
{Name: TaskMethodClearDB, Description: "清理数据库过期日志(操作记录、JWT黑名单、定时任务日志)"},
|
||||
{Name: TaskMethodUploads, Description: "清理过期大文件上传会话"},
|
||||
}
|
||||
|
||||
func RegisteredTaskMethods() []TaskMethod {
|
||||
return append([]TaskMethod(nil), registeredTaskMethods...)
|
||||
}
|
||||
|
||||
func registeredTaskMethod(name string) bool {
|
||||
for _, method := range registeredTaskMethods {
|
||||
if method.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type TaskRepo interface {
|
||||
CreateTask(context.Context, *TimedTask) error
|
||||
UpdateTask(context.Context, *TimedTask) error
|
||||
@@ -40,7 +77,75 @@ type TaskRepo interface {
|
||||
CleanupLogs(context.Context) error
|
||||
TaskNameExists(context.Context, string, uint) (bool, error)
|
||||
}
|
||||
type TaskUsecase struct{ repo TaskRepo }
|
||||
type TaskUsecase struct{ TaskRepo }
|
||||
|
||||
func NewTaskUsecase(repo TaskRepo) *TaskUsecase { return &TaskUsecase{repo: repo} }
|
||||
func (uc *TaskUsecase) Repo() TaskRepo { return uc.repo }
|
||||
func NewTaskUsecase(repo TaskRepo) *TaskUsecase { return &TaskUsecase{TaskRepo: repo} }
|
||||
|
||||
func (uc *TaskUsecase) Validate(value *TimedTask) error {
|
||||
if value.Name == "" {
|
||||
return errors.New("任务名不能为空")
|
||||
}
|
||||
var err error
|
||||
if value.WithSeconds {
|
||||
_, err = cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor).Parse(value.Spec)
|
||||
} else {
|
||||
_, err = cron.ParseStandard(value.Spec)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("cron 表达式非法: %w", err)
|
||||
}
|
||||
switch value.ExecutorType {
|
||||
case TaskExecutorMethod:
|
||||
if !registeredTaskMethod(value.MethodName) {
|
||||
return errors.New("方法未注册")
|
||||
}
|
||||
if len(value.Params) > 0 && !json.Valid(value.Params) {
|
||||
return errors.New("params 必须是合法 JSON")
|
||||
}
|
||||
case TaskExecutorHTTP:
|
||||
parsed, parseErr := url.Parse(value.HTTPURL)
|
||||
if parseErr != nil || (parsed.Scheme != "http" && parsed.Scheme != "https") || parsed.Hostname() == "" {
|
||||
return errors.New("httpUrl 必须是合法的 http/https 地址")
|
||||
}
|
||||
if len(value.HTTPHeader) > 0 {
|
||||
headers := map[string]string{}
|
||||
if json.Unmarshal(value.HTTPHeader, &headers) != nil {
|
||||
return errors.New("httpHeader 必须是 JSON 对象")
|
||||
}
|
||||
}
|
||||
default:
|
||||
return errors.New("executorType 必须为 method 或 http")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uc *TaskUsecase) Create(ctx context.Context, value *TimedTask) error {
|
||||
if err := uc.Validate(value); err != nil {
|
||||
return err
|
||||
}
|
||||
exists, err := uc.TaskNameExists(ctx, value.Name, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return fmt.Errorf("任务名 %s 已存在", value.Name)
|
||||
}
|
||||
return uc.CreateTask(ctx, value)
|
||||
}
|
||||
|
||||
func (uc *TaskUsecase) Update(ctx context.Context, value *TimedTask) error {
|
||||
if value.ID == 0 {
|
||||
return errors.New("缺少任务 ID")
|
||||
}
|
||||
if err := uc.Validate(value); err != nil {
|
||||
return err
|
||||
}
|
||||
exists, err := uc.TaskNameExists(ctx, value.Name, value.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return fmt.Errorf("任务名 %s 已存在", value.Name)
|
||||
}
|
||||
return uc.UpdateTask(ctx, value)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user