Procházet zdrojové kódy

feat(limit): 新增全局限流功能并重构相关代码

- 新增 GlobalLimitRequest、TcpLimitRequest、UdpLimitRequest 和 WebLimitRequest 结构体
- 重构 TcpLimitService、UdpLimitService 和 WebLimitService 接口和实现
- 新增 GetGlobalLimitConfig、GetTcpLimitConfig、GetUdpLimitConfig 和 GetWebLimitConfig 方法
- 优化了配置获取和处理逻辑,提高了代码复用性和可维护性
fusu před 2 měsíci
rodič
revize
bfffb31e0f

+ 6 - 0
api/v1/gateWayGroup.go

@@ -0,0 +1,6 @@
+package v1
+
+type AddGateWayGroupRequest struct {
+	Name    string `json:"name" form:"name" binding:"required"`
+	Comment string `json:"comment" form:"comment"`
+}

+ 29 - 0
api/v1/globalLimit.go

@@ -0,0 +1,29 @@
+package v1
+
+type GlobalLimitRequest struct {
+	Uid     int    `json:"uid" form:"uid" binding:"required"`
+	HostId  int    `json:"host_id" form:"host_id" binding:"required"`
+	Comment string `json:"comment" form:"comment" binding:"required"`
+	Domain  string `json:"domain" form:"domain"`
+}
+type GlobalLimitSendRequest struct {
+	Tag           string `json:"tag" form:"tag" binding:"required"`
+	Bps           string `form:"bps" json:"bps" default:"0"`
+	MaxBytesMonth string `form:"max_bytes_month" json:"max_bytes_month" default:"0"`
+	ExpiredAt     string `form:"expired_at" json:"expired_at omitempty"`
+	Comment       string `form:"comment" json:"comment"`
+}
+
+type GlobalLimitRequireResponse struct {
+	ExpiredAt       string
+	GlobalLimitName string
+	Bps             string
+	MaxBytesMonth   string
+}
+
+type GeneralLimitRequireRequest struct {
+	Uid    int    `json:"uid" form:"uid" binding:"required"`
+	HostId int    `json:"host_id" form:"host_id" binding:"required"`
+	Tag    string `json:"tag" form:"tag" binding:"required"`
+	RuleId int    `json:"rule_id" form:"rule_id" binding:"required"`
+}

+ 5 - 0
api/v1/host.go

@@ -22,3 +22,8 @@ type GameShieldHostBackendConfigResponse struct {
 	MaxBandwidthCount   int64
 	OnlineDevicesCount  int64
 }
+
+type GlobalLimitConfigResponse struct {
+	MaxBytesMonth string `default:"0"`
+	Bps           string `default:"0"`
+}

+ 12 - 7
api/v1/tcpLimit.go

@@ -1,16 +1,21 @@
 package v1
 
 type TcpLimitRequest struct {
+	ConnCount    int    `json:"conn_count" form:"conn_count" default:"0"`
+	ConnDuration string `json:"conn_duration" form:"conn_duration"  default:"0s"`
+	MaxConnCount int    `json:"max_conn_count" form:"max_conn_count" default:"0"`
+}
+
+type TcpLimitDeleteRequest struct {
+	WafTcpLimitId int `json:"waf_tcp_limit_id" form:"waf_tcp_limit_id"`
+}
+
+type TcpLimitSendRequest struct {
 	WafTcpLimitId int    `json:"waf_tcp_limit_id" form:"waf_tcp_limit_id"`
 	Tag           string `json:"tag" form:"tag" binding:"required"`
-	Uid           int    `json:"uid" form:"uid" binding:"required"`
 	ConnCount     int    `json:"conn_count" form:"conn_count" default:"0"`
 	ConnDuration  string `json:"conn_duration" form:"conn_duration"  default:"0s"`
 	MaxConnCount  int    `json:"max_conn_count" form:"max_conn_count" default:"0"`
-	Bps           string `form:"bps" json:"bps" default:"0"`
-	MaxBytesMonth int    `form:"max_bytes_month" json:"max_bytes_month" default:"0"`
-}
-
-type TcpLimitDeleteRequest struct {
-	WafTcpLimitId int `json:"waf_tcp_limit_id" form:"waf_tcp_limit_id"`
+	RuleId        int    `json:"waf_common_limit_id" form:"waf_common_limit_id"`
+	Comment       string `form:"comment" json:"comment"`
 }

+ 10 - 5
api/v1/udpLimit.go

@@ -1,16 +1,21 @@
 package v1
 
 type UdpLimitRequest struct {
-	WafUdpLimitId     int    `json:"waf_udp_limit_id" form:"waf_udp_limit_id"`
-	Tag               string `json:"tag" form:"tag" binding:"required"`
-	Uid               int    `json:"uid" form:"uid" binding:"required"`
 	QosPacketCount    int    `form:"qos_packet_count" json:"qos_packet_count"`
 	QosPacketDuration string `form:"qos_packet_duration" json:"qos_packet_duration" default:"0s"`
 	MaxConnCount      int    `form:"max_conn_count" json:"max_conn_count"`
-	Bps               string `form:"bps" json:"bps" default:"0"`
-	MaxBytesMonth     int    `form:"max_bytes_month" json:"max_bytes_month" default:"0"`
 }
 
 type UdpLimitDeleteRequest struct {
 	WafUdpLimitId int `json:"waf_udp_limit_id" form:"waf_udp_limit_id"`
 }
+
+type UdpLimitSendRequest struct {
+	WafUdpLimitId     int    `json:"waf_udp_limit_id" form:"waf_udp_limit_id"`
+	Tag               string `json:"tag" form:"tag" binding:"required"`
+	QosPacketCount    int    `form:"qos_packet_count" json:"qos_packet_count" default:"0"`
+	QosPacketDuration string `form:"qos_packet_duration" json:"qos_packet_duration" default:"0s"`
+	MaxConnCount      int    `form:"max_conn_count" json:"max_conn_count" default:"0"`
+	RuleId            int    `json:"waf_common_limit_id" form:"waf_common_limit_id"`
+	Comment           string `form:"comment" json:"comment"`
+}

+ 11 - 7
api/v1/webLimit.go

@@ -1,15 +1,19 @@
 package v1
 
 type WebLimitRequest struct {
-	WafWebLimitId int    `json:"waf_web_limit_id" form:"waf_web_limit_id"`
-	Tag           string `json:"tag" form:"tag" binding:"required"`
-	Uid           int    `json:"uid" form:"uid" binding:"required"`
-	QpsCount      int    `json:"qps_count" form:"qps_count" default:"0"`
-	QpsDuration   string `json:"qps_duration" form:"qps_duration"  default:"0s"`
-	Bps           string `form:"bps" json:"bps" default:"0"`
-	MaxBytesMonth int    `form:"max_bytes_month" json:"max_bytes_month" default:"0"`
+	QpsCount    int    `json:"qps_count" form:"qps_count" default:"0"`
+	QpsDuration string `json:"qps_duration" form:"qps_duration"  default:"0s"`
 }
 
 type WebLimitDeleteRequest struct {
 	WafWebLimitId int `json:"waf_web_limit_id" form:"waf_web_limit_id"`
 }
+
+type WebLimitSendRequest struct {
+	WafWebLimitId int    `json:"waf_web_limit_id" form:"waf_web_limit_id"`
+	Tag           string `json:"tag" form:"tag" binding:"required"`
+	QpsCount      int    `json:"qps_count" form:"qps_count" default:"0"`
+	QpsDuration   string `json:"qps_duration" form:"qps_duration"  default:"0s"`
+	RuleId        int    `json:"waf_common_limit_id" form:"waf_common_limit_id"`
+	Comment       string `form:"comment" json:"comment"`
+}

+ 6 - 0
cmd/server/wire/wire.go

@@ -38,6 +38,8 @@ var repositorySet = wire.NewSet(
 	repository.NewGameShieldBackendRepository,
 	repository.NewGameShieldSdkIpRepository,
 	repository.NewHostRepository,
+	repository.NewGlobalLimitRepository,
+	repository.NewGatewayGroupRepository,
 )
 
 var serviceSet = wire.NewSet(
@@ -60,6 +62,8 @@ var serviceSet = wire.NewSet(
 	service.NewGameShieldBackendService,
 	service.NewGameShieldSdkIpService,
 	service.NewHostService,
+	service.NewGlobalLimitService,
+	service.NewGatewayGroupService,
 )
 
 var handlerSet = wire.NewSet(
@@ -77,6 +81,8 @@ var handlerSet = wire.NewSet(
 	handler.NewGameShieldBackendHandler,
 	handler.NewGameShieldSdkIpHandler,
 	handler.NewHostHandler,
+	handler.NewGlobalLimitHandler,
+	handler.NewGatewayGroupHandler,
 )
 
 var jobSet = wire.NewSet(

+ 12 - 7
cmd/server/wire/wire_gen.go

@@ -60,7 +60,7 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 	webForwardingService := service.NewWebForwardingService(serviceService, requiredService, webForwardingRepository, crawlerService, parserService)
 	webForwardingHandler := handler.NewWebForwardingHandler(handlerHandler, webForwardingService)
 	webLimitRepository := repository.NewWebLimitRepository(repositoryRepository)
-	webLimitService := service.NewWebLimitService(serviceService, webLimitRepository, requiredService, parserService, crawlerService)
+	webLimitService := service.NewWebLimitService(serviceService, webLimitRepository, requiredService, parserService, crawlerService, hostService)
 	webLimitHandler := handler.NewWebLimitHandler(handlerHandler, webLimitService)
 	tcpforwardingRepository := repository.NewTcpforwardingRepository(repositoryRepository)
 	tcpforwardingService := service.NewTcpforwardingService(serviceService, tcpforwardingRepository, parserService, requiredService, crawlerService)
@@ -69,12 +69,17 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 	udpForWardingService := service.NewUdpForWardingService(serviceService, udpForWardingRepository, requiredService, parserService, crawlerService)
 	udpForWardingHandler := handler.NewUdpForWardingHandler(handlerHandler, udpForWardingService)
 	tcpLimitRepository := repository.NewTcpLimitRepository(repositoryRepository)
-	tcpLimitService := service.NewTcpLimitService(serviceService, tcpLimitRepository, requiredService, parserService, crawlerService)
+	tcpLimitService := service.NewTcpLimitService(serviceService, tcpLimitRepository, requiredService, parserService, crawlerService, hostService)
 	tcpLimitHandler := handler.NewTcpLimitHandler(handlerHandler, tcpLimitService)
 	udpLimitRepository := repository.NewUdpLimitRepository(repositoryRepository)
-	udpLimitService := service.NewUdpLimitService(serviceService, udpLimitRepository, requiredService, crawlerService, parserService)
+	udpLimitService := service.NewUdpLimitService(serviceService, udpLimitRepository, requiredService, crawlerService, parserService, hostService)
 	udpLimitHandler := handler.NewUdpLimitHandler(handlerHandler, udpLimitService)
-	httpServer := server.NewHTTPServer(logger, viperViper, jwtJWT, limiterLimiter, handlerFunc, userHandler, gameShieldHandler, gameShieldBackendHandler, webForwardingHandler, webLimitHandler, tcpforwardingHandler, udpForWardingHandler, tcpLimitHandler, udpLimitHandler)
+	globalLimitRepository := repository.NewGlobalLimitRepository(repositoryRepository)
+	gatewayGroupRepository := repository.NewGatewayGroupRepository(repositoryRepository)
+	gatewayGroupService := service.NewGatewayGroupService(serviceService, gatewayGroupRepository, requiredService, parserService)
+	globalLimitService := service.NewGlobalLimitService(serviceService, globalLimitRepository, duedateService, crawlerService, viperViper, requiredService, parserService, hostService, tcpLimitService, udpLimitService, webLimitService, gatewayGroupService)
+	globalLimitHandler := handler.NewGlobalLimitHandler(handlerHandler, globalLimitService)
+	httpServer := server.NewHTTPServer(logger, viperViper, jwtJWT, limiterLimiter, handlerFunc, userHandler, gameShieldHandler, gameShieldBackendHandler, webForwardingHandler, webLimitHandler, tcpforwardingHandler, udpForWardingHandler, tcpLimitHandler, udpLimitHandler, globalLimitHandler)
 	jobJob := job.NewJob(transaction, logger, sidSid)
 	userJob := job.NewUserJob(jobJob, userRepository)
 	jobServer := server.NewJobServer(logger, userJob)
@@ -85,11 +90,11 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 
 // wire.go:
 
-var repositorySet = wire.NewSet(repository.NewDB, repository.NewRepository, repository.NewTransaction, repository.NewUserRepository, repository.NewGameShieldRepository, repository.NewGameShieldPublicIpRepository, repository.NewWebForwardingRepository, repository.NewTcpforwardingRepository, repository.NewUdpForWardingRepository, repository.NewGameShieldUserIpRepository, repository.NewWebLimitRepository, repository.NewTcpLimitRepository, repository.NewUdpLimitRepository, repository.NewGameShieldBackendRepository, repository.NewGameShieldSdkIpRepository, repository.NewHostRepository)
+var repositorySet = wire.NewSet(repository.NewDB, repository.NewRepository, repository.NewTransaction, repository.NewUserRepository, repository.NewGameShieldRepository, repository.NewGameShieldPublicIpRepository, repository.NewWebForwardingRepository, repository.NewTcpforwardingRepository, repository.NewUdpForWardingRepository, repository.NewGameShieldUserIpRepository, repository.NewWebLimitRepository, repository.NewTcpLimitRepository, repository.NewUdpLimitRepository, repository.NewGameShieldBackendRepository, repository.NewGameShieldSdkIpRepository, repository.NewHostRepository, repository.NewGlobalLimitRepository, repository.NewGatewayGroupRepository)
 
-var serviceSet = wire.NewSet(service.NewService, service.NewUserService, service.NewGameShieldService, service.NewCrawlerService, service.NewGameShieldPublicIpService, service.NewDuedateService, service.NewFormatterService, service.NewParserService, service.NewRequiredService, service.NewWebForwardingService, service.NewTcpforwardingService, service.NewUdpForWardingService, service.NewGameShieldUserIpService, service.NewWebLimitService, service.NewTcpLimitService, service.NewUdpLimitService, service.NewGameShieldBackendService, service.NewGameShieldSdkIpService, service.NewHostService)
+var serviceSet = wire.NewSet(service.NewService, service.NewUserService, service.NewGameShieldService, service.NewCrawlerService, service.NewGameShieldPublicIpService, service.NewDuedateService, service.NewFormatterService, service.NewParserService, service.NewRequiredService, service.NewWebForwardingService, service.NewTcpforwardingService, service.NewUdpForWardingService, service.NewGameShieldUserIpService, service.NewWebLimitService, service.NewTcpLimitService, service.NewUdpLimitService, service.NewGameShieldBackendService, service.NewGameShieldSdkIpService, service.NewHostService, service.NewGlobalLimitService, service.NewGatewayGroupService)
 
-var handlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler, handler.NewGameShieldHandler, handler.NewGameShieldPublicIpHandler, handler.NewWebForwardingHandler, handler.NewTcpforwardingHandler, handler.NewUdpForWardingHandler, handler.NewGameShieldUserIpHandler, handler.NewWebLimitHandler, handler.NewTcpLimitHandler, handler.NewUdpLimitHandler, handler.NewGameShieldBackendHandler, handler.NewGameShieldSdkIpHandler, handler.NewHostHandler)
+var handlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler, handler.NewGameShieldHandler, handler.NewGameShieldPublicIpHandler, handler.NewWebForwardingHandler, handler.NewTcpforwardingHandler, handler.NewUdpForWardingHandler, handler.NewGameShieldUserIpHandler, handler.NewWebLimitHandler, handler.NewTcpLimitHandler, handler.NewUdpLimitHandler, handler.NewGameShieldBackendHandler, handler.NewGameShieldSdkIpHandler, handler.NewHostHandler, handler.NewGlobalLimitHandler, handler.NewGatewayGroupHandler)
 
 var jobSet = wire.NewSet(job.NewJob, job.NewUserJob)
 

+ 2 - 2
config/local.yml

@@ -47,8 +47,8 @@ log:
 crawler:
   username: "admin"
   password: "mr7c6r61jIRLGhcnT5j9"
-  Url: "http://api.hongxingdun.net:8700/"
-  keyUrl: "http://api.hongxingdun.net:13350/sdk/key?app_name="
+  Url: "http://115.238.186.121:8700/"
+  keyUrl: "http://115.238.186.121:13350/sdk/key?app_name="
 
 # 令牌桶限流配置
 limiter:

+ 25 - 0
internal/handler/gatewaygroup.go

@@ -0,0 +1,25 @@
+package handler
+
+import (
+	"github.com/gin-gonic/gin"
+	"github.com/go-nunu/nunu-layout-advanced/internal/service"
+)
+
+type GatewayGroupHandler struct {
+	*Handler
+	gatewayGroupService service.GatewayGroupService
+}
+
+func NewGatewayGroupHandler(
+	handler *Handler,
+	gatewayGroupService service.GatewayGroupService,
+) *GatewayGroupHandler {
+	return &GatewayGroupHandler{
+		Handler:             handler,
+		gatewayGroupService: gatewayGroupService,
+	}
+}
+
+func (h *GatewayGroupHandler) GetGatewayGroup(ctx *gin.Context) {
+
+}

+ 69 - 0
internal/handler/globallimit.go

@@ -0,0 +1,69 @@
+package handler
+
+import (
+	"github.com/gin-gonic/gin"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+	"github.com/go-nunu/nunu-layout-advanced/internal/service"
+	"net/http"
+)
+
+type GlobalLimitHandler struct {
+	*Handler
+	globalLimitService service.GlobalLimitService
+}
+
+func NewGlobalLimitHandler(
+	handler *Handler,
+	globalLimitService service.GlobalLimitService,
+) *GlobalLimitHandler {
+	return &GlobalLimitHandler{
+		Handler:            handler,
+		globalLimitService: globalLimitService,
+	}
+}
+
+//func (h *GlobalLimitHandler) GetGlobalLimit(ctx *gin.Context) {
+//
+//}
+
+func (h *GlobalLimitHandler) AddGlobalLimit(ctx *gin.Context) {
+	req := new(v1.GlobalLimitRequest)
+	if err := ctx.ShouldBind(req); err != nil {
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
+		return
+	}
+	err := h.globalLimitService.AddGlobalLimit(ctx, *req)
+	if err != nil {
+		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
+		return
+	}
+	v1.HandleSuccess(ctx, nil)
+}
+
+func (h *GlobalLimitHandler) EditGlobalLimit(ctx *gin.Context) {
+	req := new(v1.GlobalLimitRequest)
+	if err := ctx.ShouldBind(req); err != nil {
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
+		return
+	}
+	err := h.globalLimitService.EditGlobalLimit(ctx, *req)
+	if err != nil {
+		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
+		return
+	}
+	v1.HandleSuccess(ctx, nil)
+}
+
+func (h *GlobalLimitHandler) DeleteGlobalLimit(ctx *gin.Context) {
+	req := new(v1.GlobalLimitRequest)
+	if err := ctx.ShouldBind(req); err != nil {
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
+		return
+	}
+	err := h.globalLimitService.DeleteGlobalLimit(ctx, *req)
+	if err != nil {
+		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
+		return
+	}
+	v1.HandleSuccess(ctx, nil)
+}

+ 4 - 4
internal/handler/tcplimit.go

@@ -28,7 +28,7 @@ func (h *TcpLimitHandler) GetTcpLimit(ctx *gin.Context) {
 }
 
 func (h *TcpLimitHandler) AddTcpLimit(ctx *gin.Context) {
-	req := new(v1.TcpLimitRequest)
+	req := new(v1.GeneralLimitRequireRequest)
 
 	if err := ctx.ShouldBind(req); err != nil {
 		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
@@ -45,19 +45,19 @@ func (h *TcpLimitHandler) AddTcpLimit(ctx *gin.Context) {
 }
 
 func (h *TcpLimitHandler) EditTcpLimit(ctx *gin.Context) {
-	req := new(v1.TcpLimitRequest)
+	req := new(v1.TcpLimitSendRequest)
 
 	if err := ctx.ShouldBind(req); err != nil {
 		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.tcpLimitService.UpdateTcpLimit(ctx, req)
+	err := h.tcpLimitService.UpdateTcpLimit(ctx, req)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 
 }
 

+ 4 - 4
internal/handler/udplimit.go

@@ -28,7 +28,7 @@ func (h *UdpLimitHandler) GetUdpLimit(ctx *gin.Context) {
 }
 
 func (h *UdpLimitHandler) AddUdpLimit(ctx *gin.Context) {
-	req := new(v1.UdpLimitRequest)
+	req := new(v1.GeneralLimitRequireRequest)
 
 	if err := ctx.ShouldBind(req); err != nil {
 		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
@@ -45,19 +45,19 @@ func (h *UdpLimitHandler) AddUdpLimit(ctx *gin.Context) {
 }
 
 func (h *UdpLimitHandler) EditUdpLimit(ctx *gin.Context) {
-	req := new(v1.UdpLimitRequest)
+	req := new(v1.UdpLimitSendRequest)
 
 	if err := ctx.ShouldBind(req); err != nil {
 		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.udpLimitService.UpdateUdpLimit(ctx, req)
+	err := h.udpLimitService.UpdateUdpLimit(ctx, req)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 }
 
 func (h *UdpLimitHandler) DeleteUdpLimit(ctx *gin.Context) {

+ 4 - 4
internal/handler/weblimit.go

@@ -28,7 +28,7 @@ func (h *WebLimitHandler) GetWebLimit(ctx *gin.Context) {
 }
 
 func (h *WebLimitHandler) AddWebLimit(ctx *gin.Context) {
-	req := new(v1.WebLimitRequest)
+	req := new(v1.GeneralLimitRequireRequest)
 
 	if err := ctx.ShouldBind(req); err != nil {
 		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
@@ -45,19 +45,19 @@ func (h *WebLimitHandler) AddWebLimit(ctx *gin.Context) {
 }
 
 func (h *WebLimitHandler) EditWebLimit(ctx *gin.Context) {
-	req := new(v1.WebLimitRequest)
+	req := new(v1.WebLimitSendRequest)
 
 	if err := ctx.ShouldBind(req); err != nil {
 		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.webLimitService.UpdateWebLimit(ctx, req)
+	err := h.webLimitService.UpdateWebLimit(ctx, req)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 }
 
 func (h *WebLimitHandler) DeleteWebLimit(ctx *gin.Context) {

+ 11 - 0
internal/model/gatewaygroup.go

@@ -0,0 +1,11 @@
+package model
+
+import "gorm.io/gorm"
+
+type GatewayGroup struct {
+	gorm.Model
+}
+
+func (m *GatewayGroup) TableName() string {
+	return "gateway_group"
+}

+ 21 - 0
internal/model/globallimit.go

@@ -0,0 +1,21 @@
+package model
+
+import "time"
+
+type GlobalLimit struct {
+	Id              int `gorm:"primary"`
+	HostId          int
+	RuleId          int
+	TcpLimitRuleId  int
+	UdpLimitRuleId  int
+	WebLimitRuleId  int
+	GatewayGroupId  int
+	GlobalLimitName string
+	Comment         string
+	createdAt       time.Time
+	updatedAt       time.Time
+}
+
+func (m *GlobalLimit) TableName() string {
+	return "shd_waf"
+}

+ 28 - 0
internal/repository/gatewaygroup.go

@@ -0,0 +1,28 @@
+package repository
+
+import (
+	"context"
+	"github.com/go-nunu/nunu-layout-advanced/internal/model"
+)
+
+type GatewayGroupRepository interface {
+	GetGatewayGroup(ctx context.Context, id int64) (*model.GatewayGroup, error)
+}
+
+func NewGatewayGroupRepository(
+	repository *Repository,
+) GatewayGroupRepository {
+	return &gatewayGroupRepository{
+		Repository: repository,
+	}
+}
+
+type gatewayGroupRepository struct {
+	*Repository
+}
+
+func (r *gatewayGroupRepository) GetGatewayGroup(ctx context.Context, id int64) (*model.GatewayGroup, error) {
+	var gatewayGroup model.GatewayGroup
+
+	return &gatewayGroup, nil
+}

+ 64 - 0
internal/repository/globallimit.go

@@ -0,0 +1,64 @@
+package repository
+
+import (
+	"context"
+	"github.com/go-nunu/nunu-layout-advanced/internal/model"
+)
+
+type GlobalLimitRepository interface {
+	GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error)
+	AddGlobalLimit(ctx context.Context, req *model.GlobalLimit) error
+	UpdateGlobalLimitByHostId(ctx context.Context, req *model.GlobalLimit) error
+	DeleteGlobalLimitByHostId(ctx context.Context, hostId int64) error
+	IsGlobalLimitExistByHostId(ctx context.Context, hostId int64) (bool, error)
+}
+
+func NewGlobalLimitRepository(
+	repository *Repository,
+) GlobalLimitRepository {
+	return &globalLimitRepository{
+		Repository: repository,
+	}
+}
+
+type globalLimitRepository struct {
+	*Repository
+}
+
+func (r *globalLimitRepository) GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error) {
+	var globalLimit model.GlobalLimit
+
+	return &globalLimit, nil
+}
+
+func (r *globalLimitRepository) AddGlobalLimit(ctx context.Context, req *model.GlobalLimit) error {
+	if err := r.DB(ctx).Create(&req).Error; err != nil {
+		return err
+	}
+	return nil
+}
+
+func (r *globalLimitRepository) UpdateGlobalLimitByHostId(ctx context.Context, req *model.GlobalLimit) error {
+	if err := r.DB(ctx).Where("host_id = ?", req.HostId).Updates(&req).Error; err != nil {
+		return err
+	}
+	return nil
+}
+
+func (r *globalLimitRepository) DeleteGlobalLimitByHostId(ctx context.Context, hostId int64) error {
+	if err := r.DB(ctx).Where("host_id = ?", hostId).Delete(&model.GlobalLimit{}).Error; err != nil {
+		return err
+	}
+	return nil
+}
+
+func (r *globalLimitRepository) IsGlobalLimitExistByHostId(ctx context.Context, hostId int64) (bool, error) {
+	var count int64
+	err := r.DB(ctx).Model(&model.GlobalLimit{}).Where("host_id = ?", hostId).Count(&count).Error
+
+	if err != nil {
+		return false, err
+	}
+
+	return count > 0, nil
+}

+ 4 - 0
internal/server/http.go

@@ -30,6 +30,7 @@ func NewHTTPServer(
 	udpForwardingHandler *handler.UdpForWardingHandler,
 	tcpLimitHandler *handler.TcpLimitHandler,
 	udpLimitHandler *handler.UdpLimitHandler,
+	globalLimitHandler *handler.GlobalLimitHandler,
 
 ) *http.Server {
 	gin.SetMode(gin.DebugMode)
@@ -112,6 +113,9 @@ func NewHTTPServer(
 			noAuthRouter.POST("/gameShieldBackend/edit", ipAllowlistMiddleware, gameShieldBackendHandler.EditGameShieldBackend)
 			noAuthRouter.POST("/gameShieldBackend/delete", ipAllowlistMiddleware, gameShieldBackendHandler.DeleteGameShieldBackend)
 			noAuthRouter.POST("/gameShieldBackend/replacementSourceMachineIp", ipAllowlistMiddleware, gameShieldBackendHandler.ReplacementSourceMachineIp)
+			noAuthRouter.POST("/globalLimit/add", ipAllowlistMiddleware, globalLimitHandler.AddGlobalLimit)
+			noAuthRouter.POST("/globalLimit/edit", ipAllowlistMiddleware, globalLimitHandler.EditGlobalLimit)
+			noAuthRouter.POST("/globalLimit/delete", ipAllowlistMiddleware, globalLimitHandler.DeleteGlobalLimit)
 		}
 		// Non-strict permission routing group
 		noStrictAuthRouter := v1.Group("/").Use(middleware.NoStrictAuth(jwt, logger))

+ 69 - 0
internal/service/gatewaygroup.go

@@ -0,0 +1,69 @@
+package service
+
+import (
+	"context"
+	"fmt"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+	"github.com/go-nunu/nunu-layout-advanced/internal/model"
+	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+	"github.com/spf13/cast"
+)
+
+type GatewayGroupService interface {
+	GetGatewayGroup(ctx context.Context, id int64) (*model.GatewayGroup, error)
+	AddGatewayGroup(ctx context.Context, req v1.AddGateWayGroupRequest) (int, error)
+}
+
+func NewGatewayGroupService
+	service *Service,
+	gatewayGroupRepository repository.GatewayGroupRepository,
+    gatewayGroupRepository repository.GatewayGroupRepository,
+	required RequiredService,
+	parser ParserService,
+) GatewayGroupService {
+		Service:                service,
+		Service:        service,
+		required:               required,
+		parser:                 parser,
+		parser: parser,
+	}
+}
+
+type gatewayGroupService struct {
+	*Service
+	required               RequiredService
+	parser                 ParserService
+	parser ParserService
+}
+
+func (s *gatewayGroupService) GetGatewayGroup(ctx context.Context, id int64) (*model.GatewayGroup, error) {
+	return s.gatewayGroupRepository.GetGatewayGroup(ctx, id)
+}
+
+func (s *gatewayGroupService) AddGatewayGroup(ctx context.Context, req v1.AddGateWayGroupRequest) (int, error) {
+		"name":    req.Name,
+		"name": req.Name,
+		"comment": req.Comment,
+	}
+	respBody, err := s.required.SendForm(ctx, "admin/info/waf_gateway_group/new", "admin/new/waf_gateway_group", formData)
+	if err != nil {
+		return 0, err
+	}
+	gateWayGroupIdBase, err := s.parser.GetRuleIdByColumnName(ctx, respBody, req.Name)
+	if err != nil {
+		return 0, err
+	}
+	if gateWayGroupIdBase == "" {
+		res, err := s.parser.ParseAlert(string(respBody))
+		if err != nil {
+			return 0, err
+		}
+		return 0, fmt.Errorf(res)
+	}
+	gateWayGroupId, err := cast.ToIntE(gateWayGroupIdBase)
+		return 0, err
+		return 0,  err
+	}
+	return gateWayGroupId, nil
+r
+}

+ 187 - 0
internal/service/globallimit.go

@@ -0,0 +1,187 @@
+package service
+
+import (
+	"context"
+	"fmt"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+	"github.com/go-nunu/nunu-layout-advanced/internal/model"
+	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+	"github.com/spf13/cast"
+	"github.com/spf13/viper"
+	"strconv"
+)
+
+type GlobalLimitService interface {
+	GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error)
+	AddGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error
+	EditGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error
+	DeleteGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error
+}
+
+func NewGlobalLimitService(
+	service *Service,
+	globalLimitRepository repository.GlobalLimitRepository,
+	duedate DuedateService,
+	crawler CrawlerService,
+	conf *viper.Viper,
+	required RequiredService,
+	parser ParserService,
+	host HostService,
+	tcpLimit TcpLimitService,
+	udpLimit UdpLimitService,
+	webLimit WebLimitService,
+	gateWayGroup GatewayGroupService,
+) GlobalLimitService {
+	return &globalLimitService{
+		Service:               service,
+		globalLimitRepository: globalLimitRepository,
+		duedate:               duedate,
+		crawler:               crawler,
+		Url:                   conf.GetString("crawler.Url"),
+		required:              required,
+		parser:                parser,
+		host:                  host,
+		tcpLimit:              tcpLimit,
+		udpLimit:              udpLimit,
+		webLimit:              webLimit,
+		gateWayGroup:          gateWayGroup,
+	}
+}
+
+type globalLimitService struct {
+	*Service
+	globalLimitRepository repository.GlobalLimitRepository
+	duedate               DuedateService
+	crawler               CrawlerService
+	Url                   string
+	required              RequiredService
+	parser                ParserService
+	host                  HostService
+	tcpLimit              TcpLimitService
+	udpLimit              UdpLimitService
+	webLimit              WebLimitService
+	gateWayGroup          GatewayGroupService
+}
+
+func (s *globalLimitService) GlobalLimitRequire(ctx context.Context, req v1.GlobalLimitRequest) (res v1.GlobalLimitRequireResponse, err error) {
+	isExist, err := s.globalLimitRepository.IsGlobalLimitExistByHostId(ctx, int64(req.HostId))
+	if err != nil {
+		return v1.GlobalLimitRequireResponse{}, err
+	}
+	if isExist {
+		return v1.GlobalLimitRequireResponse{}, fmt.Errorf("配置限制已存在")
+	}
+	res.ExpiredAt, err = s.duedate.NextDueDate(ctx, req.Uid, req.HostId)
+	if err != nil {
+		return v1.GlobalLimitRequireResponse{}, err
+	}
+	configCount, err := s.host.GetGlobalLimitConfig(ctx, req.HostId)
+	if err != nil {
+		return v1.GlobalLimitRequireResponse{}, fmt.Errorf("获取配置限制失败: %w", err)
+	}
+	res.Bps = configCount.Bps
+	res.MaxBytesMonth = configCount.MaxBytesMonth
+	res.GlobalLimitName = strconv.Itoa(req.Uid) + "_" + strconv.Itoa(req.HostId) + "_" + req.Domain
+	return res, nil
+}
+
+func (s *globalLimitService) GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error) {
+	return s.globalLimitRepository.GetGlobalLimit(ctx, id)
+}
+
+func (s *globalLimitService) AddGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
+	require, err := s.GlobalLimitRequire(ctx, req)
+	if err != nil {
+		return err
+	}
+	formData := map[string]interface{}{
+		"tag":             require.GlobalLimitName,
+		"bps":             require.Bps,
+		"max_bytes_month": require.MaxBytesMonth,
+		"expired_at":      require.ExpiredAt,
+	}
+	respBody, err := s.required.SendForm(ctx, "admin/info/waf_common_limit/new", "admin/new/waf_common_limit", formData)
+	if err != nil {
+		return err
+	}
+	ruleIdBase, err := s.parser.GetRuleIdByColumnName(ctx, respBody, require.GlobalLimitName)
+	if err != nil {
+		return err
+	}
+	if ruleIdBase == "" {
+		res, err := s.parser.ParseAlert(string(respBody))
+		if err != nil {
+			return err
+		}
+		return fmt.Errorf(res)
+	}
+	ruleId, err := cast.ToIntE(ruleIdBase)
+	if err != nil {
+		return err
+	}
+	tcpLimitRuleId, err := s.tcpLimit.AddTcpLimit(ctx, &v1.GeneralLimitRequireRequest{
+		Tag:    require.GlobalLimitName,
+		HostId: req.HostId,
+		RuleId: ruleId,
+		Uid:    req.Uid,
+	})
+	if err != nil {
+		return err
+	}
+	udpLimitRuleId, err := s.udpLimit.AddUdpLimit(ctx, &v1.GeneralLimitRequireRequest{
+		Tag:    require.GlobalLimitName,
+		HostId: req.HostId,
+		RuleId: ruleId,
+		Uid:    req.Uid,
+	})
+	if err != nil {
+		return err
+	}
+	webLimitRuleId, err := s.webLimit.AddWebLimit(ctx, &v1.GeneralLimitRequireRequest{
+		Tag:    require.GlobalLimitName,
+		HostId: req.HostId,
+		RuleId: ruleId,
+		Uid:    req.Uid,
+	})
+	if err != nil {
+		return err
+	}
+	gateWayGroupId, err := s.gateWayGroup.AddGatewayGroup(ctx, v1.AddGateWayGroupRequest{
+		Name:    require.GlobalLimitName,
+		Comment: req.Comment,
+	})
+	if err != nil {
+		return err
+	}
+	err = s.globalLimitRepository.AddGlobalLimit(ctx, &model.GlobalLimit{
+		HostId:          req.HostId,
+		RuleId:          cast.ToInt(ruleId),
+		GlobalLimitName: require.GlobalLimitName,
+		Comment:         req.Comment,
+		TcpLimitRuleId:  tcpLimitRuleId,
+		UdpLimitRuleId:  udpLimitRuleId,
+		WebLimitRuleId:  webLimitRuleId,
+		GatewayGroupId:  gateWayGroupId,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (s *globalLimitService) EditGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
+	if err := s.globalLimitRepository.UpdateGlobalLimitByHostId(ctx, &model.GlobalLimit{
+		HostId:  req.HostId,
+		Comment: req.Comment,
+	}); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (s *globalLimitService) DeleteGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error {
+	if err := s.globalLimitRepository.DeleteGlobalLimitByHostId(ctx, int64(req.HostId)); err != nil {
+		return err
+	}
+	return nil
+}

+ 177 - 29
internal/service/host.go

@@ -9,9 +9,14 @@ import (
 	"strings"
 )
 
+// HostService 接口定义
 type HostService interface {
 	GetHost(ctx context.Context, id int64) (*model.Host, error)
 	GetGameShieldConfig(ctx context.Context, hostId int) (v1.GameShieldHostBackendConfigResponse, error)
+	GetGlobalLimitConfig(ctx context.Context, hostId int) (v1.GlobalLimitConfigResponse, error)
+	GetTcpLimitConfig(ctx context.Context, hostId int) (v1.TcpLimitRequest, error)
+	GetUdpLimitConfig(ctx context.Context, hostId int) (v1.UdpLimitRequest, error)
+	GetWebLimitConfig(ctx context.Context, hostId int) (v1.WebLimitRequest, error)
 }
 
 func NewHostService(
@@ -24,13 +29,31 @@ func NewHostService(
 	}
 }
 
+// 常量定义,包含新增的配置项名称
 const (
-	ConfigOnlineDevices  = "在线设备数"
-	ConfigRuleEntries    = "规则条目"
-	ConfigMaxBandwidth   = "高带宽转发规则条目"
-	ConfigSourceMachines = "支持源机"
+	ConfigOnlineDevices        = "在线设备数"
+	ConfigRuleEntries          = "规则条目"
+	ConfigMaxBandwidth         = "高带宽转发规则条目"
+	ConfigSourceMachines       = "支持源机"
+	ConfigBps                  = "最大带宽"
+	ConfigMaxBytesMonth        = "每月流量"
+	ConfigTcpConnCount         = "TCP连接次数"
+	ConfigTcpConnDuration      = "TCP连接时长"
+	ConfigTcpMaxConnCount      = "TCP最大连接数"
+	ConfigUdpQosPacketCount    = "UDPQPS包数"
+	ConfigUdpQosPacketDuration = "UDPQPS周期"
+	ConfigUdpMaxConnCount      = "UDP最大会话数"
+	ConfigWebQpsCount          = "WebQPS连接次数"
+	ConfigWebQpsDuration       = "WebQPS周期"
 )
 
+// unitSuffixMap 存储需要去除的单位后缀
+var unitSuffixMap = map[string]string{
+	ConfigOnlineDevices: "个",
+	ConfigRuleEntries:   "个",
+	ConfigMaxBandwidth:  "条",
+}
+
 type hostService struct {
 	*Service
 	hostRepository repository.HostRepository
@@ -40,6 +63,7 @@ func (s *hostService) GetHost(ctx context.Context, id int64) (*model.Host, error
 	return s.hostRepository.GetHost(ctx, id)
 }
 
+// GetHostConfig 保持不变,它是一个通用的底层数据获取方法。
 func (s *hostService) GetHostConfig(ctx context.Context, hostId int) ([]map[string]string, error) {
 	configOptions, err := s.hostRepository.GetHostConfig(ctx, hostId)
 	if err != nil {
@@ -93,46 +117,170 @@ func (s *hostService) GetHostConfig(ctx context.Context, hostId int) ([]map[stri
 	return data, nil
 }
 
-func (s *hostService) tidyGetGameShieldConfig(ctx context.Context, configName string, optionName string) (map[string]int, error) {
+// cleanConfigOptionName 简化后的清理函数,直接返回清理后的字符串。
+func (s *hostService) cleanConfigOptionName(configName string, optionName string) string {
 	// 根据配置名称去除相应的单位后缀
-	switch configName {
-	case ConfigOnlineDevices, ConfigRuleEntries:
-		optionName = strings.TrimSuffix(optionName, "个")
-	case ConfigMaxBandwidth:
-		optionName = strings.TrimSuffix(optionName, "条")
+	if suffix, ok := unitSuffixMap[configName]; ok {
+		optionName = strings.TrimSuffix(optionName, suffix)
+	}
+	return optionName
+}
+
+// getHostConfigsMap 新增的辅助函数,用于获取所有清理后的配置映射。
+func (s *hostService) getHostConfigsMap(ctx context.Context, hostId int) (map[string]string, error) {
+	baseData, err := s.GetHostConfig(ctx, hostId)
+	if err != nil {
+		return nil, err
 	}
 
-	// 转换为整数并返回
-	return map[string]int{configName: cast.ToInt(optionName)}, nil
+	configsMap := make(map[string]string)
+	for _, item := range baseData {
+		configName := item["config_name"]
+		optionName := item["option_name"]
+		// 将清理后的值存储到 map 中
+		configsMap[configName] = s.cleanConfigOptionName(configName, optionName)
+	}
+	return configsMap, nil
 }
+
 func (s *hostService) GetGameShieldConfig(ctx context.Context, hostId int) (v1.GameShieldHostBackendConfigResponse, error) {
-	baseData, err := s.GetHostConfig(ctx, hostId)
+	// 调用新辅助函数获取处理好的配置映射
+	configsMap, err := s.getHostConfigsMap(ctx, hostId)
 	if err != nil {
 		return v1.GameShieldHostBackendConfigResponse{}, err
 	}
 
 	var data v1.GameShieldHostBackendConfigResponse
+	var parseErr error // 用于统一处理类型转换错误
 
-	for _, item := range baseData {
-		configName := item["config_name"]
-		optionName := item["option_name"]
+	// 从映射中获取值并进行类型转换
+	if val, ok := configsMap[ConfigOnlineDevices]; ok {
+		data.OnlineDevicesCount, parseErr = cast.ToInt64E(val)
+		if parseErr != nil {
+			return data, parseErr
+		}
+	}
+	if val, ok := configsMap[ConfigRuleEntries]; ok {
+		data.RuleEntriesCount, parseErr = cast.ToInt64E(val)
+		if parseErr != nil {
+			return data, parseErr
+		}
+	}
+	if val, ok := configsMap[ConfigMaxBandwidth]; ok {
+		data.MaxBandwidthCount, parseErr = cast.ToInt64E(val)
+		if parseErr != nil {
+			return data, parseErr
+		}
+	}
+	if val, ok := configsMap[ConfigSourceMachines]; ok {
+		data.SourceMachinesCount, parseErr = cast.ToInt64E(val)
+		if parseErr != nil {
+			return data, parseErr
+		}
+	}
+	return data, nil
+}
 
-		res, err := s.tidyGetGameShieldConfig(ctx, configName, optionName)
-		if err != nil {
-			return v1.GameShieldHostBackendConfigResponse{}, err
+func (s *hostService) GetGlobalLimitConfig(ctx context.Context, hostId int) (v1.GlobalLimitConfigResponse, error) {
+	configsMap, err := s.getHostConfigsMap(ctx, hostId)
+	if err != nil {
+		return v1.GlobalLimitConfigResponse{}, err
+	}
+	data := v1.GlobalLimitConfigResponse{
+		MaxBytesMonth: "0",
+		Bps:           "0",
+	}
+	if val, ok := configsMap[ConfigBps]; ok {
+		data.Bps = val
+	}
+	if val, ok := configsMap[ConfigMaxBytesMonth]; ok {
+		data.MaxBytesMonth = val
+	}
+	return data, nil
+}
+
+// GetTcpLimitConfig 修正返回类型,并使用新的辅助函数
+func (s *hostService) GetTcpLimitConfig(ctx context.Context, hostId int) (v1.TcpLimitRequest, error) {
+	configsMap, err := s.getHostConfigsMap(ctx, hostId)
+	if err != nil {
+		return v1.TcpLimitRequest{}, err
+	}
+	data := v1.TcpLimitRequest{
+		ConnCount:    0,
+		ConnDuration: "0s",
+		MaxConnCount: 0,
+	}
+	var parseErr error
+
+	if val, ok := configsMap[ConfigTcpConnCount]; ok {
+		data.ConnCount, parseErr = cast.ToIntE(val)
+		if parseErr != nil {
+			return data, parseErr
+		}
+	}
+	if val, ok := configsMap[ConfigTcpConnDuration]; ok {
+		data.ConnDuration = val
+	}
+	if val, ok := configsMap[ConfigTcpMaxConnCount]; ok {
+		data.MaxConnCount, parseErr = cast.ToIntE(val)
+		if parseErr != nil {
+			return data, parseErr
 		}
+	}
+	return data, nil // 返回结构体
+}
 
-		// 使用switch直接设置对应字段
-		switch configName {
-		case ConfigOnlineDevices:
-			data.OnlineDevicesCount = int64(res[configName])
-		case ConfigRuleEntries:
-			data.RuleEntriesCount = int64(res[configName])
-		case ConfigMaxBandwidth:
-			data.MaxBandwidthCount = int64(res[configName])
-		case ConfigSourceMachines:
-			data.SourceMachinesCount = int64(res[configName])
+// GetUdpLimitConfig
+func (s *hostService) GetUdpLimitConfig(ctx context.Context, hostId int) (v1.UdpLimitRequest, error) {
+	configsMap, err := s.getHostConfigsMap(ctx, hostId)
+	if err != nil {
+		return v1.UdpLimitRequest{}, err
+	}
+	data := v1.UdpLimitRequest{
+		QosPacketCount:    0,
+		QosPacketDuration: "0s",
+		MaxConnCount:      0,
+	}
+	var parseErr error
+
+	if val, ok := configsMap[ConfigUdpQosPacketCount]; ok {
+		data.QosPacketCount, parseErr = cast.ToIntE(val)
+		if parseErr != nil {
+			return data, parseErr
+		}
+	}
+	if val, ok := configsMap[ConfigUdpQosPacketDuration]; ok {
+		data.QosPacketDuration = val
+	}
+	if val, ok := configsMap[ConfigUdpMaxConnCount]; ok {
+		data.MaxConnCount, parseErr = cast.ToIntE(val)
+		if parseErr != nil {
+			return data, parseErr
 		}
 	}
 	return data, nil
 }
+
+// GetWebLimitConfig 修正返回类型,并使用新的辅助函数
+func (s *hostService) GetWebLimitConfig(ctx context.Context, hostId int) (v1.WebLimitRequest, error) {
+	configsMap, err := s.getHostConfigsMap(ctx, hostId)
+	if err != nil {
+		return v1.WebLimitRequest{}, err
+	}
+	data := v1.WebLimitRequest{
+		QpsCount:    0,
+		QpsDuration: "0s",
+	}
+	var parseErr error
+
+	if val, ok := configsMap[ConfigWebQpsCount]; ok {
+		data.QpsCount, parseErr = cast.ToIntE(val)
+		if parseErr != nil {
+			return data, parseErr
+		}
+	}
+	if val, ok := configsMap[ConfigWebQpsDuration]; ok {
+		data.QpsDuration = val
+	}
+	return data, nil
+}

+ 63 - 0
internal/service/parser.go

@@ -16,6 +16,7 @@ type ParserService interface {
 	GetRuleId(ctx context.Context, htmlBytes []byte) (string, error)
 	ParseSDKOnlineHTMLTable(htmlContent string) ([]v1.SDKInfo, error)
 	CheckSDKKeyStatus(htmlData string, sdkKeyToFind string) error
+	GetRuleIdByColumnName(ctx context.Context, htmlBytes []byte, columnName string) (string, error)
 }
 
 func NewParserService(
@@ -84,6 +85,68 @@ func (s *parserService) GetRuleId(ctx context.Context, htmlBytes []byte) (string
 	return strings.TrimSpace(id), nil
 }
 
+func (s *parserService) GetRuleIdByColumnName(ctx context.Context, htmlBytes []byte, name string) (string, error) {
+	// 1. 定义我们用来搜索的列所有可能的名称。
+	possibleKeyNames := []string{"标签", "网关组名称"}
+
+	// 2. 解析HTML。
+	reader := bytes.NewReader(htmlBytes)
+	doc, err := goquery.NewDocumentFromReader(reader)
+	if err != nil {
+		return "", fmt.Errorf("failed to parse html: %w", err)
+	}
+
+	// 3. 动态查找第一个匹配的“关键字列”的索引。
+	headerRow := doc.Find("table.table tbody tr:first-child")
+	if headerRow.Length() == 0 {
+		return "", fmt.Errorf("table header row not found")
+	}
+
+	keyColumnIndex := -1
+	// 我们使用 EachWithBreak,一旦找到有效的列就立即停止搜索,提高效率。
+	headerRow.Find("th").EachWithBreak(func(index int, th *goquery.Selection) bool {
+		headerText := strings.TrimSpace(th.Text())
+		// 检查当前的表头文本是否匹配我们预设的任何一个可能名称。
+		for _, possibleName := range possibleKeyNames {
+			if headerText == possibleName {
+				keyColumnIndex = index
+				return false // 找到了,立即停止遍历表头(th)。
+			}
+		}
+		return true // 没找到,继续遍历下一个表头(th)。
+	})
+
+	// 4. 检查我们是否找到了任何一个可能的关键字列。
+	if keyColumnIndex == -1 {
+		return "", fmt.Errorf("找不到任何一个指定的关键字列: %v", possibleKeyNames)
+	}
+
+	// 5. 遍历数据行以查找匹配的行。
+	var foundID string
+	var found bool
+	doc.Find("table.table tbody tr").Slice(1, goquery.ToEnd).EachWithBreak(func(i int, row *goquery.Selection) bool {
+		// 使用动态找到的索引来获取正确的单元格。
+		keyCell := row.Find("td").Eq(keyColumnIndex)
+		keyText := strings.TrimSpace(keyCell.Text())
+
+		if keyText == name {
+			// 如果关键字匹配,就从固定位置(第二个<td>,索引为1)获取值。
+			idCell := row.Find("td").Eq(1)
+			foundID = strings.TrimSpace(idCell.Text())
+			found = true
+			return false // 找到了目标行,停止循环。
+		}
+		return true // 不是目标行,继续。
+	})
+
+	// 6. 返回结果,如果未找到则返回错误。
+	if !found {
+		return "", fmt.Errorf("找不到关键字列值为 '%s' 的行", name)
+	}
+
+	return foundID, nil
+}
+
 // 解析 Sdk在线情况 表格
 func (s *parserService) ParseSDKOnlineHTMLTable(htmlContent string) ([]v1.SDKInfo, error) {
 	// 创建goquery文档

+ 58 - 28
internal/service/tcplimit.go

@@ -6,13 +6,14 @@ import (
 	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+	"github.com/spf13/cast"
 	"strconv"
 )
 
 type TcpLimitService interface {
 	GetTcpLimit(ctx context.Context, id int64) (*model.TcpLimit, error)
-	AddTcpLimit(ctx context.Context, req *v1.TcpLimitRequest) (string, error)
-	UpdateTcpLimit(ctx context.Context, req *v1.TcpLimitRequest) (string, error)
+	AddTcpLimit(ctx context.Context, req *v1.GeneralLimitRequireRequest) (int, error)
+	UpdateTcpLimit(ctx context.Context, req *v1.TcpLimitSendRequest) error
 	DeleteTcpLimit(ctx context.Context, TcpWebLimitId int) (string, error)
 }
 
@@ -22,6 +23,7 @@ func NewTcpLimitService(
 	required RequiredService,
 	parser ParserService,
 	crawler CrawlerService,
+	host HostService,
 ) TcpLimitService {
 	return &tcpLimitService{
 		Service:            service,
@@ -29,6 +31,7 @@ func NewTcpLimitService(
 		required:           required,
 		parser:             parser,
 		crawler:            crawler,
+		host:               host,
 	}
 }
 
@@ -38,64 +41,91 @@ type tcpLimitService struct {
 	required           RequiredService
 	parser             ParserService
 	crawler            CrawlerService
+	host               HostService
 }
 
 func (s *tcpLimitService) GetTcpLimit(ctx context.Context, id int64) (*model.TcpLimit, error) {
 	return s.tcpLimitRepository.GetTcpLimit(ctx, id)
 }
 
-func (s *tcpLimitService) AddTcpLimit(ctx context.Context, req *v1.TcpLimitRequest) (string, error) {
+func (s *tcpLimitService) Required(ctx context.Context, req v1.GeneralLimitRequireRequest) (*v1.TcpLimitSendRequest, error) {
+	configCount, err := s.host.GetTcpLimitConfig(ctx, req.HostId)
+	if err != nil {
+		return nil, fmt.Errorf("获取配置限制失败: %w", err)
+	}
+	return &v1.TcpLimitSendRequest{
+		Tag:          req.Tag,
+		ConnCount:    configCount.ConnCount,
+		ConnDuration: configCount.ConnDuration,
+		MaxConnCount: configCount.MaxConnCount,
+		RuleId:       req.RuleId,
+	}, nil
+}
+func (s *tcpLimitService) AddTcpLimit(ctx context.Context, req *v1.GeneralLimitRequireRequest) (int, error) {
+	required, err := s.Required(ctx, *req)
+	if err != nil {
+		return 0, err
+	}
 	formData := map[string]interface{}{
-		"tag":             req.Tag,
-		"conn_count":      req.ConnCount,
-		"conn_duration":   req.ConnDuration,
-		"bps":             req.Bps,
-		"max_bytes_month": req.MaxBytesMonth,
-		"expired_at":      "",
+		"tag":                 req.Tag,
+		"conn_count":          required.ConnCount,
+		"conn_duration":       required.ConnDuration,
+		"max_conn_count":      required.MaxConnCount,
+		"waf_common_limit_id": required.RuleId,
+		"comment":             "",
 	}
 	respBody, err := s.required.SendForm(ctx, "admin/info/waf_tcp_limit/new", "admin/new/waf_tcp_limit", formData)
 	if err != nil {
-		return "", err
+		return 0, err
 	}
 	// 解析响应内容中的 alert 消息
 	res, err := s.parser.ParseAlert(string(respBody))
 	if err != nil {
-		return "", err
+		return 0, err
 	}
 	if res != "" {
-		return "", fmt.Errorf(res)
+		return 0, fmt.Errorf(res)
 	}
-	tcpLimitId, err := s.parser.GetRuleId(ctx, respBody)
+	tcpLimitIdBase, err := s.parser.GetRuleIdByColumnName(ctx, respBody, req.Tag)
 	if err != nil {
-		return "", err
+		return 0, err
+	}
+	tcpLimitId, err := cast.ToIntE(tcpLimitIdBase)
+	if err != nil {
+		return 0, err
 	}
-	fmt.Println("=================================================", tcpLimitId)
-	return "", nil
+	if tcpLimitId == 0 {
+		res, err := s.parser.ParseAlert(string(respBody))
+		if err != nil {
+			return 0, err
+		}
+		return 0, fmt.Errorf(res)
+	}
+	return tcpLimitId, nil
 }
 
-func (s *tcpLimitService) UpdateTcpLimit(ctx context.Context, req *v1.TcpLimitRequest) (string, error) {
+func (s *tcpLimitService) UpdateTcpLimit(ctx context.Context, req *v1.TcpLimitSendRequest) error {
 	formData := map[string]interface{}{
-		"tag":              req.Tag,
-		"waf_tcp_limit_id": req.WafTcpLimitId,
-		"conn_count":       req.ConnCount,
-		"conn_duration":    req.ConnDuration,
-		"bps":              req.Bps,
-		"max_bytes_month":  req.MaxBytesMonth,
-		"expired_at":       "",
+		"tag":                 req.Tag,
+		"conn_count":          req.ConnCount,
+		"conn_duration":       req.ConnDuration,
+		"max_conn_count":      req.MaxConnCount,
+		"waf_common_limit_id": req.RuleId,
+		"comment":             "",
 	}
 	respBody, err := s.required.SendForm(ctx, "admin/info/waf_tcp_limit/edit?&__goadmin_edit_pk="+strconv.Itoa(req.WafTcpLimitId), "admin/edit/waf_tcp_limit", formData)
 	if err != nil {
-		return "", err
+		return err
 	}
 	// 解析响应内容中的 alert 消息
 	res, err := s.parser.ParseAlert(string(respBody))
 	if err != nil {
-		return "", err
+		return err
 	}
 	if res != "" {
-		return "", fmt.Errorf(res)
+		return fmt.Errorf(res)
 	}
-	return "", nil
+	return nil
 }
 
 func (s *tcpLimitService) DeleteTcpLimit(ctx context.Context, TcpWebLimitId int) (string, error) {

+ 53 - 24
internal/service/udplimit.go

@@ -6,13 +6,14 @@ import (
 	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+	"github.com/spf13/cast"
 	"strconv"
 )
 
 type UdpLimitService interface {
 	GetUdpLimit(ctx context.Context, id int64) (*model.UdpLimit, error)
-	AddUdpLimit(ctx context.Context, req *v1.UdpLimitRequest) (string, error)
-	UpdateUdpLimit(ctx context.Context, req *v1.UdpLimitRequest) (string, error)
+	AddUdpLimit(ctx context.Context, req *v1.GeneralLimitRequireRequest) (int, error)
+	UpdateUdpLimit(ctx context.Context, req *v1.UdpLimitSendRequest) error
 	DeleteUdpLimit(ctx context.Context, UdpLimitId int) (string, error)
 }
 
@@ -22,6 +23,7 @@ func NewUdpLimitService(
 	required RequiredService,
 	crawler CrawlerService,
 	parser ParserService,
+	host HostService,
 ) UdpLimitService {
 	return &udpLimitService{
 		Service:            service,
@@ -29,6 +31,7 @@ func NewUdpLimitService(
 		required:           required,
 		crawler:            crawler,
 		parser:             parser,
+		host:               host,
 	}
 }
 
@@ -38,66 +41,92 @@ type udpLimitService struct {
 	required           RequiredService
 	crawler            CrawlerService
 	parser             ParserService
+	host               HostService
 }
 
+func (s *udpLimitService) Required(ctx context.Context, req v1.GeneralLimitRequireRequest) (v1.UdpLimitSendRequest, error) {
+	config, err := s.host.GetUdpLimitConfig(ctx, req.HostId)
+	if err != nil {
+		return v1.UdpLimitSendRequest{}, fmt.Errorf("获取配置限制失败: %w", err)
+	}
+	return v1.UdpLimitSendRequest{
+		Tag:               req.Tag,
+		QosPacketCount:    config.QosPacketCount,
+		QosPacketDuration: config.QosPacketDuration,
+		MaxConnCount:      config.MaxConnCount,
+		RuleId:            req.RuleId,
+	}, nil
+}
 func (s *udpLimitService) GetUdpLimit(ctx context.Context, id int64) (*model.UdpLimit, error) {
 	return s.udpLimitRepository.GetUdpLimit(ctx, id)
 }
 
-func (s *udpLimitService) AddUdpLimit(ctx context.Context, req *v1.UdpLimitRequest) (string, error) {
+func (s *udpLimitService) AddUdpLimit(ctx context.Context, req *v1.GeneralLimitRequireRequest) (int, error) {
+	required, err := s.Required(ctx, *req)
+	if err != nil {
+		return 0, err
+	}
 	formData := map[string]interface{}{
 		"tag":                 req.Tag,
-		"qos_packet_count":    req.QosPacketCount,
-		"qos_packet_duration": req.QosPacketDuration,
-		"max_conn_count":      req.MaxConnCount,
-		"bps":                 req.Bps,
-		"max_bytes_month":     req.MaxBytesMonth,
-		"expired_at":          "",
+		"qos_packet_count":    required.QosPacketCount,
+		"qos_packet_duration": required.QosPacketDuration,
+		"max_conn_count":      required.MaxConnCount,
+		"waf_common_limit_id": required.RuleId,
+		"comment":             "",
 	}
 	respBody, err := s.required.SendForm(ctx, "admin/info/waf_udp_limit/new", "admin/new/waf_udp_limit", formData)
 	if err != nil {
-		return "", err
+		return 0, err
 	}
 	// 解析响应内容中的 alert 消息
 	res, err := s.parser.ParseAlert(string(respBody))
 	if err != nil {
-		return "", err
+		return 0, err
 	}
 	if res != "" {
-		return "", fmt.Errorf(res)
+		return 0, fmt.Errorf(res)
 	}
-	udpLimitId, err := s.parser.GetRuleId(ctx, respBody)
+	udpLimitIdBase, err := s.parser.GetRuleIdByColumnName(ctx, respBody, req.Tag)
 	if err != nil {
-		return "", err
+		return 0, err
+	}
+	udpLimitId, err := cast.ToIntE(udpLimitIdBase)
+	if err != nil {
+		return 0, err
+	}
+	if udpLimitId == 0 {
+		res, err := s.parser.ParseAlert(string(respBody))
+		if err != nil {
+			return 0, err
+		}
+		return 0, fmt.Errorf(res)
 	}
-	fmt.Println("=================================================", udpLimitId)
-	return "", nil
+	return udpLimitId, nil
 }
 
-func (s *udpLimitService) UpdateUdpLimit(ctx context.Context, req *v1.UdpLimitRequest) (string, error) {
+func (s *udpLimitService) UpdateUdpLimit(ctx context.Context, req *v1.UdpLimitSendRequest) error {
 	formData := map[string]interface{}{
 		"tag":                 req.Tag,
 		"waf_udp_limit_id":    req.WafUdpLimitId,
 		"qos_packet_count":    req.QosPacketCount,
 		"qos_packet_duration": req.QosPacketDuration,
 		"max_conn_count":      req.MaxConnCount,
-		"bps":                 req.Bps,
-		"max_bytes_month":     req.MaxBytesMonth,
-		"expired_at":          "",
+		"waf_common_limit_id": req.RuleId,
+		"comment":             "",
 	}
 	respBody, err := s.required.SendForm(ctx, "admin/info/waf_udp_limit/edit?&__goadmin_edit_pk="+strconv.Itoa(req.WafUdpLimitId), "admin/edit/waf_udp_limit", formData)
 	if err != nil {
-		return "", err
+		return err
 	}
 	// 解析响应内容中的 alert 消息
 	res, err := s.parser.ParseAlert(string(respBody))
 	if err != nil {
-		return "", err
+		return err
 	}
 	if res != "" {
-		return "", fmt.Errorf(res)
+		return fmt.Errorf(res)
 	}
-	return "", nil
+	return nil
 }
 
 func (s *udpLimitService) DeleteUdpLimit(ctx context.Context, WafUdpLimitId int) (string, error) {

+ 57 - 28
internal/service/weblimit.go

@@ -6,13 +6,14 @@ import (
 	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+	"github.com/spf13/cast"
 	"strconv"
 )
 
 type WebLimitService interface {
 	GetWebLimit(ctx context.Context, id int64) (*model.WebLimit, error)
-	AddWebLimit(ctx context.Context, req *v1.WebLimitRequest) (string, error)
-	UpdateWebLimit(ctx context.Context, req *v1.WebLimitRequest) (string, error)
+	AddWebLimit(ctx context.Context, req *v1.GeneralLimitRequireRequest) (int, error)
+	UpdateWebLimit(ctx context.Context, req *v1.WebLimitSendRequest) error
 	DeleteWebLimit(ctx context.Context, wafWebId int) (string, error)
 }
 
@@ -22,6 +23,7 @@ func NewWebLimitService(
 	require RequiredService,
 	parser ParserService,
 	crawler CrawlerService,
+	host HostService,
 ) WebLimitService {
 	return &webLimitService{
 		Service:            service,
@@ -29,6 +31,7 @@ func NewWebLimitService(
 		required:           require,
 		parser:             parser,
 		crawler:            crawler,
+		host:               host,
 	}
 }
 
@@ -38,65 +41,91 @@ type webLimitService struct {
 	required           RequiredService
 	parser             ParserService
 	crawler            CrawlerService
+	host               HostService
+}
+
+func (s *webLimitService) Required(ctx context.Context, req v1.GeneralLimitRequireRequest) (v1.WebLimitSendRequest, error) {
+	config, err := s.host.GetWebLimitConfig(ctx, req.HostId)
+	if err != nil {
+		return v1.WebLimitSendRequest{}, fmt.Errorf("获取配置限制失败: %w", err)
+	}
+	return v1.WebLimitSendRequest{
+		Tag:         req.Tag,
+		QpsCount:    config.QpsCount,
+		QpsDuration: config.QpsDuration,
+		RuleId:      req.RuleId,
+	}, nil
 }
 
 func (s *webLimitService) GetWebLimit(ctx context.Context, id int64) (*model.WebLimit, error) {
 	return s.webLimitRepository.GetWebLimit(ctx, id)
 }
 
-func (s *webLimitService) AddWebLimit(ctx context.Context, req *v1.WebLimitRequest) (string, error) {
+func (s *webLimitService) AddWebLimit(ctx context.Context, req *v1.GeneralLimitRequireRequest) (int, error) {
+	required, err := s.Required(ctx, *req)
+	if err != nil {
+		return 0, err
+	}
 	formData := map[string]interface{}{
-		"tag":             req.Tag,
-		"qps_count":       req.QpsCount,
-		"qps_duration":    req.QpsDuration,
-		"bps":             req.Bps,
-		"max_bytes_month": req.MaxBytesMonth,
-		"expired_at":      "",
+		"tag":                 req.Tag,
+		"qps_count":           required.QpsCount,
+		"qps_duration":        required.QpsDuration,
+		"waf_common_limit_id": required.RuleId,
+		"comment":             "",
 	}
 
 	respBody, err := s.required.SendForm(ctx, "admin/info/waf_web_limit/new", "admin/new/waf_web_limit", formData)
 	if err != nil {
-		return "", err
+		return 0, err
 	}
 	// 解析响应内容中的 alert 消息
 	res, err := s.parser.ParseAlert(string(respBody))
 	if err != nil {
-		return "", err
+		return 0, err
 	}
 	if res != "" {
-		return "", fmt.Errorf(res)
+		return 0, fmt.Errorf(res)
 	}
-	webLimitId, err := s.parser.GetRuleId(ctx, respBody)
+	webLimitIdBase, err := s.parser.GetRuleIdByColumnName(ctx, respBody, req.Tag)
 	if err != nil {
-		return "", err
+		return 0, err
+	}
+	webLimitId, err := cast.ToIntE(webLimitIdBase)
+	if err != nil {
+		return 0, err
 	}
-	fmt.Println("=================================================", webLimitId)
-	return "", nil
+	if webLimitId == 0 {
+		res, err := s.parser.ParseAlert(string(respBody))
+		if err != nil {
+			return 0, err
+		}
+		return 0, fmt.Errorf(res)
+	}
+	return webLimitId, nil
 }
 
-func (s *webLimitService) UpdateWebLimit(ctx context.Context, req *v1.WebLimitRequest) (string, error) {
+func (s *webLimitService) UpdateWebLimit(ctx context.Context, req *v1.WebLimitSendRequest) error {
 	formData := map[string]interface{}{
-		"tag":              req.Tag,
-		"waf_web_limit_id": req.WafWebLimitId,
-		"qps_count":        req.QpsCount,
-		"qps_duration":     req.QpsDuration,
-		"bps":              req.Bps,
-		"max_bytes_month":  req.MaxBytesMonth,
-		"expired_at":       "",
+		"waf_web_limit_id":    req.WafWebLimitId,
+		"tag":                 req.Tag,
+		"qps_count":           req.QpsCount,
+		"qps_duration":        req.QpsDuration,
+		"waf_common_limit_id": req.RuleId,
+		"comment":             "",
 	}
 	respBody, err := s.required.SendForm(ctx, "admin/info/waf_web_limit/edit?&__goadmin_edit_pk="+strconv.Itoa(req.WafWebLimitId), "admin/edit/waf_web_limit", formData)
 	if err != nil {
-		return "", err
+		return err
 	}
 	// 解析响应内容中的 alert 消息
 	res, err := s.parser.ParseAlert(string(respBody))
 	if err != nil {
-		return "", err
+		return err
 	}
 	if res != "" {
-		return "", fmt.Errorf(res)
+		return fmt.Errorf(res)
 	}
-	return "", nil
+	return nil
 }
 
 func (s *webLimitService) DeleteWebLimit(ctx context.Context, WafWebLimitId int) (string, error) {