浏览代码

refactor(server): 调整定时任务执行时间并优化端口验证逻辑

- 将定时任务执行时间从每分钟调整为每小时的第0分钟
- 在 TCP、UDP 和 Web 转发 API 中,将端口验证逻辑改为自定义验证函数
- 新增 isPortStringValid 验证器,用于检查字符串是否为有效的端口号
- 更新相应的错误提示信息
fusu 1 周之前
父节点
当前提交
776e9633c5
共有 5 个文件被更改,包括 36 次插入7 次删除
  1. 1 1
      api/v1/tcpForwarding.go
  2. 1 1
      api/v1/udpForwarding.go
  3. 1 1
      api/v1/webForwarding.go
  4. 4 4
      internal/server/task.go
  5. 29 0
      pkg/validation/validation.go

+ 1 - 1
api/v1/tcpForwarding.go

@@ -5,7 +5,7 @@ package v1
 type TcpForwardingDataRequest struct {
 	Id                int      `form:"id" json:"id"`
 	CdnWebId          int      `form:"cdnWebId" json:"cdnWebId"`
-	Port              string   `form:"port" json:"port" validate:"required,numeric,min=1,max=65535"`
+	Port              string   `form:"port" json:"port" validate:"required,isPortStringValid"`
 	BackendList       []string `form:"backendList" json:"backendList" validate:"required,dive,hostport"`
 	Comment           string   `form:"comment" json:"comment" validate:"max=50"`
 	Proxy             bool     `form:"proxy" json:"proxy" default:"false"`

+ 1 - 1
api/v1/udpForwarding.go

@@ -3,7 +3,7 @@ package v1
 type UdpForwardingDataRequest struct {
 	Id                int    `form:"id" json:"id"`
 	CdnWebId          int    `form:"cdnWebId" json:"cdnWebId"`
-	Port              string   `form:"port" json:"port" validate:"required,numeric,min=1,max=65535"`
+	Port              string   `form:"port" json:"port" validate:"required,isPortStringValid"`
 	BackendList       []string `form:"backendList" json:"backendList" validate:"required,dive,hostport"`
 	Comment           string   `form:"comment" json:"comment" validate:"max=50"`
 	Proxy             bool     `form:"proxy" json:"proxy" default:"false"`

+ 1 - 1
api/v1/webForwarding.go

@@ -4,7 +4,7 @@ package v1
 type WebForwardingDataRequest struct {
 	Id                 int    `form:"id" json:"id"`
 	CdnWebId          int    `form:"cdnWebId" json:"cdnWebId"`
-	Port               string    `form:"port" json:"port" validate:"required,numeric,min=1,max=65535"`
+	Port               string    `form:"port" json:"port" validate:"required,isPortStringValid"`
 	Domain             string `form:"domain" json:"domain" validate:"omitempty,idn_fqdn|ip"`
 	BackendList        []BackendList `form:"backendList" json:"backendList" validate:"required,dive"`
 	IsHttps            int    `form:"isHttps" json:"isHttps" default:"0"`

+ 4 - 4
internal/server/task.go

@@ -76,7 +76,7 @@ func (t *TaskServer) Start(ctx context.Context) error {
 
 
 
-	_, err := t.scheduler.Cron("* * * * *").Do(func() {
+	_, err := t.scheduler.Cron("0 * * * *").Do(func() {
 		err := t.wafTask.SynchronizationTime(ctx)
 		if err != nil {
 			t.log.Error("同步到期时间失败", zap.Error(err))
@@ -86,7 +86,7 @@ func (t *TaskServer) Start(ctx context.Context) error {
 		t.log.Error("同步到期时间注册任务失败", zap.Error(err))
 	}
 
-	_, err = t.scheduler.Cron("* * * * *").Do(func() {
+	_, err = t.scheduler.Cron("0 * * * *").Do(func() {
 		err := t.wafTask.StopPlan(ctx)
 		if err != nil {
 			t.log.Error("停止套餐失败", zap.Error(err))
@@ -97,7 +97,7 @@ func (t *TaskServer) Start(ctx context.Context) error {
 	}
 
 
-	_, err = t.scheduler.Cron("* * * * *").Do(func() {
+	_, err = t.scheduler.Cron("0 * * * *").Do(func() {
 		err := t.wafTask.RecoverRecentPlan(ctx)
 		if err != nil {
 			t.log.Error("续费失败", zap.Error(err))
@@ -108,7 +108,7 @@ func (t *TaskServer) Start(ctx context.Context) error {
 	}
 
 
-	_, err = t.scheduler.Cron("* * * * *").Do(func() {
+	_, err = t.scheduler.Cron("0 * * * *").Do(func() {
 		err := t.wafTask.CleanUpStaleRecords(ctx)
 		if err != nil {
 			t.log.Error("续费失败", zap.Error(err))

+ 29 - 0
pkg/validation/validation.go

@@ -128,6 +128,7 @@ func registerCustomValidations(v *validator.Validate) {
 	// 注册 hostport 校验器
 	v.RegisterValidation("hostport", validateHostPort)
 	v.RegisterValidation("idn_fqdn",isIdnFqdn)
+	v.RegisterValidation("isPortStringValid", isPortStringValid)
 
 	// 为 hostport 校验器注册中文翻译
 	v.RegisterTranslation("hostport", trans, func(ut ut.Translator) error {
@@ -143,6 +144,13 @@ func registerCustomValidations(v *validator.Validate) {
 		t, _ := ut.T("idn_fqdn", fe.Field())
 		return t
 	})
+
+	v.RegisterTranslation("isPortStringValid", trans, func(ut ut.Translator) error {
+		return ut.Add("isPortStringValid", "{0} 必须是有效的端口号", true)
+	}, func(ut ut.Translator, fe validator.FieldError) string {
+		t, _ := ut.T("isPortStringValid", fe.Field())
+		return t
+	})
 }
 
 // validateHostPort 是一个自定义校验函数,用于检查字符串是否为有效的 "host:port"。
@@ -227,4 +235,25 @@ func isIdnFqdn(fl validator.FieldLevel) bool {
 
 	// 如果没有错误,说明它在格式上是一个有效的 FQDN。
 	return err == nil
+}
+
+func isPortStringValid(fl validator.FieldLevel) bool {
+	// 1. 获取字段的字符串值
+	portStr := fl.Field().String()
+
+	// 2. 将字符串转换为整数
+	// 注意:Atoi 已经确保了字符串是纯数字,所以 'numeric' 标签其实有点冗余,但保留它有助于提前过滤和提供更清晰的错误。
+	portNum, err := strconv.Atoi(portStr)
+	if err != nil {
+		// 如果无法转换为整数(例如,包含非数字字符),则验证失败。
+		// 理论上 'numeric' 标签会先捕捉到这个错误。
+		return false
+	}
+
+	// 3. 检查数值范围
+	if portNum >= 1 && portNum <= 65535 {
+		return true // 在有效范围内,验证通过
+	}
+
+	return false // 不在有效范围内,验证失败
 }