Переглянути джерело

refactor(internal): 重构 GlobalLimitService 添加访问控制规则

-移除了不必要的导入和调试代码- 添加了 AccessRules 和 AccessRuleRules 结构体用于访问控制- 使用 errgroup 替代 sync.WaitGroup 和互斥锁,简化并发控制
- 更新了 AddGlobalLimit 方法,增加了访问控制规则的处理
- 在 HTTP 路由中添加了新的 API 接口
fusu 2 місяців тому
батько
коміт
4d8c76bc2c

+ 11 - 0
api/v1/globalLimit.go

@@ -26,3 +26,14 @@ type GeneralLimitRequireRequest struct {
 	Tag    string `json:"tag" form:"tag" binding:"required"`
 	RuleId int    `json:"rule_id" form:"rule_id" binding:"required"`
 }
+
+type AccessRules struct {
+	Mode string `json:"mode" form:"mode" default:"deny"`
+	Default string   `json:"default" form:"default" default:"allow"`
+	Rules   []AccessRuleRules `json:"rules" form:"rules"`
+}
+
+type AccessRuleRules struct {
+	Rule   string `json:"rule" form:"rule"`
+	Action string `json:"action" form:"action" default:"deny"`
+}

+ 2 - 2
api/v1/tcpForwarding.go

@@ -2,7 +2,7 @@ package v1
 
 type TcpForwardingDataSend struct {
 	WafTcpId          int    `form:"waf_tcp_id" json:"waf_tcp_id"`
-	Tag               string `form:"tag" json:"tag" binding:"required"`
+	Tag               string `form:"tag" json:"tag"`
 	Port              string    `form:"port" json:"port" binding:"required"`
 	WafGatewayGroupId int    `form:"waf_gateway_group_id" json:"waf_gateway_group_id"`
 	WafTcpLimitRuleId int    `form:"waf_tcp_limit_id" json:"waf_tcp_limit_id"`
@@ -23,7 +23,7 @@ type TcpForwardingDataSend struct {
 type TcpForwardingDataRequest struct {
 	Id                int    `form:"id" json:"id"`
 	WafTcpId          int    `form:"waf_tcp_id" json:"waf_tcp_id"`
-	Tag               string `form:"tag" json:"tag" binding:"required"`
+	Tag               string `form:"tag" json:"tag"`
 	Port              string    `form:"port" json:"port" binding:"required"`
 	WafGatewayGroupId int    `form:"waf_gateway_group_id" json:"waf_gateway_group_id"`
 	WafTcpLimitRuleId int    `form:"waf_tcp_limit_id" json:"waf_tcp_limit_id"`

+ 25 - 3
api/v1/udpForwarding.go

@@ -1,8 +1,8 @@
 package v1
 
-type UdpForwardingData struct {
+type UdpForwardingDataSend struct {
 	WafUdpId          int    `form:"waf_udp_id" json:"waf_udp_id"`
-	Tag               string `form:"tag" json:"tag" binding:"required"`
+	Tag               string `form:"tag" json:"tag"`
 	Port              int    `form:"port" json:"port" binding:"required"`
 	WafGatewayGroupId int    `form:"waf_gateway_group_id" json:"waf_gateway_group_id"`
 	WafUdpLimitId     int    `form:"waf_udp_limit_id" json:"waf_udp_limit_id"`
@@ -20,6 +20,28 @@ type UdpForwardingData struct {
 	Comment           string `form:"comment" json:"comment"`
 }
 
+
+type UdpForwardingDataRequest struct {
+	Id                int    `form:"id" json:"id"`
+	WafUdpId          int    `form:"waf_udp_id" json:"waf_udp_id"`
+	Tag               string `form:"tag" json:"tag"`
+	Port              int    `form:"port" json:"port" binding:"required"`
+	WafGatewayGroupId int    `form:"waf_gateway_group_id" json:"waf_gateway_group_id"`
+	WafUdpLimitId     int    `form:"waf_udp_limit_id" json:"waf_udp_limit_id"`
+	CcPacketCount     int    `form:"cc_packet_count" json:"cc_packet_count" default:"0"`
+	CcPacketDuration  string `form:"cc_packet_duration" json:"cc_packet_duration" default:"0s"`
+	CcCount           int    `form:"cc_count" json:"cc_count" default:"0"`
+	CcDuration        string `form:"cc_duration" json:"cc_duration" default:"0s"`
+	CcBlockCount      int    `form:"cc_block_count" json:"cc_block_count" default:"0"`
+	CcBlockDuration   string `form:"cc_block_duration" json:"cc_block_duration" default:"0s"`
+	SessionTimeout    string    `form:"session_timeout" json:"session_timeout" default:"60s"`
+	BackendList       []string `form:"backend_list" json:"backend_list"`
+	AllowIpList       []string `form:"allow_ip_list" json:"allow_ip_list"`
+	DenyIpList        []string `form:"deny_ip_list" json:"deny_ip_list"`
+	AccessRule        string `form:"access_rule" json:"access_rule"`
+	Comment           string `form:"comment" json:"comment"`
+}
+
 type DeleteUdpForwardingRequest struct {
 	WafUdpId int `form:"waf_udp_id" json:"waf_udp_id" binding:"required"`
 }
@@ -28,7 +50,7 @@ type UdpForwardingRequest struct {
 	HostId            int `form:"host_id" json:"host_id" binding:"required"`
 	Uid               int `form:"uid" json:"uid" binding:"required"`
 	Id                int `form:"id" json:"id"`
-	UdpForwardingData UdpForwardingData
+	UdpForwardingData UdpForwardingDataRequest
 }
 
 type UdpForwardingRequire struct {

+ 7 - 0
api/v1/wafformatter.go

@@ -6,5 +6,12 @@ type GlobalRequire struct {
 	Comment           string `form:"comment" json:"comment" binding:"required"`
 	WafGatewayGroupId int    `form:"waf_gateway_group_id" json:"waf_gateway_group_id"`
 	LimitRuleId       int    `form:"limit_id" json:"limit_id"`
+	Domain            string `form:"domain" json:"domain"`
 	Tag               string `form:"tag" json:"tag" binding:"required"`
 }
+
+type GetForwardingRequest struct {
+	HostId            int    `form:"host_id" json:"host_id" binding:"required"`
+	Uid               int    `form:"uid" json:"uid" binding:"required"`
+	Id                int    `form:"id" json:"id" binding:"required"`
+}

+ 41 - 4
api/v1/webForwarding.go

@@ -1,8 +1,8 @@
 package v1
 
-type WebForwardingData struct {
+type WebForwardingDataSend struct {
 	WafWebId           int    `form:"waf_web_id" json:"waf_web_id"`
-	Tag                string `form:"tag" json:"tag" binding:"required"`
+	Tag                string `form:"tag" json:"tag"`
 	Port               int    `form:"port" json:"port" binding:"required"`
 	Domain             string `form:"domain" json:"domain"`
 	CustomHost         string `form:"custom_host" json:"custom_host"`
@@ -20,7 +20,7 @@ type WebForwardingData struct {
 	Cc5xxDuration      string `form:"cc_5xx_duration" json:"cc_5xx_duration" default:"0s"`
 	Cc5xxBlockCount    int    `form:"cc_5xx_block_count" json:"cc_5xx_block_count" default:"0"`
 	Cc5xxBlockDuration string `form:"cc_5xx_block_duration" json:"cc_5xx_block_duration" default:"0s"`
-	BackendList        string `form:"backend_list" json:"backend_list"`
+	BackendList        []BackendList `form:"backend_list" json:"backend_list"`
 	AllowIpList        string `form:"allow_ip_list" json:"allow_ip_list"`
 	DenyIpList         string `form:"deny_ip_list" json:"deny_ip_list"`
 	AccessRule         string `form:"access_rule" json:"access_rule"`
@@ -28,6 +28,36 @@ type WebForwardingData struct {
 	Comment            string `form:"comment" json:"comment"`
 }
 
+
+type WebForwardingDataRequest struct {
+	Id                 int    `form:"id" json:"id"`
+	WafWebId           int    `form:"waf_web_id" json:"waf_web_id"`
+	Tag                string `form:"tag" json:"tag"`
+	Port               int    `form:"port" json:"port" binding:"required"`
+	Domain             string `form:"domain" json:"domain"`
+	CustomHost         string `form:"custom_host" json:"custom_host"`
+	WafGatewayGroupId  int    `form:"waf_gateway_group_id" json:"waf_gateway_group_id"`
+	WafWebLimitId      int    `form:"waf_web_limit_id" json:"waf_web_limit_id"`
+	CcCount            int    `form:"cc_count" json:"cc_count" default:"0"`
+	CcDuration         string `form:"cc_duration" json:"cc_duration" default:"0s"`
+	CcBlockCount       int    `form:"cc_block_count" json:"cc_block_count" default:"0"`
+	CcBlockDuration    string `form:"cc_block_duration" json:"cc_block_duration" default:"0s"`
+	Cc4xxCount         int    `form:"cc_4xx_count" json:"cc_4xx_count" default:"0"`
+	Cc4xxDuration      string `form:"cc_4xx_duration" json:"cc_4xx_duration" default:"0s"`
+	Cc4xxBlockCount    int    `form:"cc_4xx_block_count" json:"cc_4xx_block_count" default:"0"`
+	Cc4xxBlockDuration string `form:"cc_4xx_block_duration" json:"cc_4xx_block_duration" default:"0s"`
+	Cc5xxCount         int    `form:"cc_5xx_count" json:"cc_5xx_count" default:"0"`
+	Cc5xxDuration      string `form:"cc_5xx_duration" json:"cc_5xx_duration" default:"0s"`
+	Cc5xxBlockCount    int    `form:"cc_5xx_block_count" json:"cc_5xx_block_count" default:"0"`
+	Cc5xxBlockDuration string `form:"cc_5xx_block_duration" json:"cc_5xx_block_duration" default:"0s"`
+	BackendList        []BackendList `form:"backend_list" json:"backend_list"`
+	AllowIpList        []string `form:"allow_ip_list" json:"allow_ip_list"`
+	DenyIpList         []string `form:"deny_ip_list" json:"deny_ip_list"`
+	AccessRule         string `form:"access_rule" json:"access_rule"`
+	IsHttps            int    `form:"is_https" json:"is_https" default:"0"`
+	Comment            string `form:"comment" json:"comment"`
+}
+
 type DeleteWebForwardingRequest struct {
 	WafWebId int `form:"waf_web_id" json:"waf_web_id" binding:"required"`
 }
@@ -36,7 +66,7 @@ type WebForwardingRequest struct {
 	Id                 int    `form:"id" json:"id"`
 	HostId            int `form:"host_id" json:"host_id" binding:"required"`
 	Uid               int `form:"uid" json:"uid" binding:"required"`
-	WebForwardingData WebForwardingData
+	WebForwardingData WebForwardingDataRequest `form:"data" json:"data"`
 }
 
 type WebForwardingRequire struct {
@@ -47,3 +77,10 @@ type WebForwardingRequire struct {
 	WafWebLimitRuleId int    `form:"waf_web_limit_id" json:"waf_web_limit_id"`
 	Tag               string `form:"tag" json:"tag" binding:"required"`
 }
+
+type BackendList struct {
+	Addr     string `json:"addr,omitempty" form:"addr"`
+	Protocol string `json:"protocol,omitempty" form:"protocol"`
+	Timeout  string `json:"timeout,omitempty" form:"timeout" default:"30s"`
+	ProxyV1  bool `json:"proxy_v1,omitempty" form:"proxy_v1" default:"false"`
+}

+ 3 - 3
cmd/server/wire/wire_gen.go

@@ -60,16 +60,16 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 	gameShieldBackendHandler := handler.NewGameShieldBackendHandler(handlerHandler, gameShieldBackendService)
 	webForwardingRepository := repository.NewWebForwardingRepository(repositoryRepository)
 	globalLimitRepository := repository.NewGlobalLimitRepository(repositoryRepository)
-	wafFormatterService := service.NewWafFormatterService(serviceService, globalLimitRepository, hostRepository, requiredService, parserService)
+	tcpforwardingRepository := repository.NewTcpforwardingRepository(repositoryRepository)
+	udpForWardingRepository := repository.NewUdpForWardingRepository(repositoryRepository)
+	wafFormatterService := service.NewWafFormatterService(serviceService, globalLimitRepository, hostRepository, requiredService, parserService, tcpforwardingRepository, udpForWardingRepository, webForwardingRepository, hostService)
 	webForwardingService := service.NewWebForwardingService(serviceService, requiredService, webForwardingRepository, crawlerService, parserService, wafFormatterService)
 	webForwardingHandler := handler.NewWebForwardingHandler(handlerHandler, webForwardingService)
 	webLimitRepository := repository.NewWebLimitRepository(repositoryRepository)
 	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, globalLimitRepository, hostRepository, wafFormatterService)
 	tcpforwardingHandler := handler.NewTcpforwardingHandler(handlerHandler, tcpforwardingService)
-	udpForWardingRepository := repository.NewUdpForWardingRepository(repositoryRepository)
 	udpForWardingService := service.NewUdpForWardingService(serviceService, udpForWardingRepository, requiredService, parserService, crawlerService, globalLimitRepository, hostRepository, wafFormatterService)
 	udpForWardingHandler := handler.NewUdpForWardingHandler(handlerHandler, udpForWardingService)
 	tcpLimitRepository := repository.NewTcpLimitRepository(repositoryRepository)

+ 11 - 10
go.mod

@@ -29,7 +29,7 @@ require (
 	github.com/swaggo/swag v1.16.4
 	github.com/tidwall/gjson v1.18.0
 	go.uber.org/zap v1.26.0
-	golang.org/x/crypto v0.37.0
+	golang.org/x/crypto v0.39.0
 	google.golang.org/grpc v1.55.1
 	gorm.io/driver/mysql v1.5.7
 	gorm.io/driver/postgres v1.5.11
@@ -61,12 +61,12 @@ require (
 	github.com/go-openapi/swag v0.22.9 // indirect
 	github.com/go-playground/locales v0.14.1 // indirect
 	github.com/go-playground/universal-translator v0.18.1 // indirect
-	github.com/go-playground/validator/v10 v10.14.1 // indirect
+	github.com/go-playground/validator/v10 v10.26.0 // indirect
 	github.com/go-sql-driver/mysql v1.7.1 // indirect
 	github.com/gobwas/glob v0.2.3 // indirect
 	github.com/goccy/go-json v0.10.5 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
-	github.com/golang/snappy v0.0.4 // indirect
+	github.com/golang/snappy v1.0.0 // indirect
 	github.com/google/go-querystring v1.1.0 // indirect
 	github.com/google/uuid v1.3.1 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
@@ -81,9 +81,9 @@ require (
 	github.com/jinzhu/now v1.1.5 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/klauspost/compress v1.16.7 // indirect
+	github.com/klauspost/compress v1.18.0 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.10 // indirect
-	github.com/leodido/go-urn v1.2.4 // indirect
+	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/magiconair/properties v1.8.10 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
@@ -96,6 +96,7 @@ require (
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.9 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/qiniu/qmgo v1.1.9 // indirect
 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 	github.com/robfig/cron/v3 v3.0.1 // indirect
 	github.com/sanity-io/litter v1.5.5 // indirect
@@ -125,11 +126,11 @@ require (
 	go.uber.org/multierr v1.11.0 // indirect
 	golang.org/x/arch v0.3.0 // indirect
 	golang.org/x/exp v0.0.0-20221208152030-732eee02a75a // indirect
-	golang.org/x/net v0.39.0 // indirect
-	golang.org/x/sync v0.13.0 // indirect
-	golang.org/x/sys v0.32.0 // indirect
-	golang.org/x/text v0.24.0 // indirect
-	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+	golang.org/x/net v0.41.0 // indirect
+	golang.org/x/sync v0.15.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
+	golang.org/x/text v0.26.0 // indirect
+	golang.org/x/tools v0.33.0 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
 	google.golang.org/protobuf v1.33.0 // indirect
 	gopkg.in/fsnotify.v1 v1.0.0-00010101000000-000000000000 // indirect

+ 38 - 0
go.sum

@@ -148,14 +148,20 @@ github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/
 github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw=
 github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE=
 github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
 github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
 github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
 github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
 github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
+github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
 github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
@@ -202,6 +208,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
+github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -305,10 +313,13 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U=
 github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
 github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
+github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
+github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
 github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
@@ -323,8 +334,11 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
 github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
 github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
 github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
@@ -383,6 +397,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/qiniu/qmgo v1.1.9 h1:3G3h9RLyjIUW9YSAQEPP2WqqNnboZ2Z/zO3mugjVb3E=
+github.com/qiniu/qmgo v1.1.9/go.mod h1:aba4tNSlMWrwUhe7RdILfwBRIgvBujt1y10X+T1YZSI=
 github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o=
 github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk=
 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@@ -494,6 +510,7 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
 go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
 go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
 go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
 go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
 go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -531,10 +548,14 @@ golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
 golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
 golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
 golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
+golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
+golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -578,6 +599,7 @@ golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
 golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -627,6 +649,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
 golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
 golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
+golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
+golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -655,9 +679,12 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
 golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
+golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -713,10 +740,14 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
 golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -724,7 +755,9 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
 golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -741,9 +774,12 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
 golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
 golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
+golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -807,6 +843,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
+golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

+ 12 - 0
internal/handler/tcpforwarding.go

@@ -24,6 +24,18 @@ func NewTcpforwardingHandler(
 }
 
 func (h *TcpforwardingHandler) GetTcpforwarding(ctx *gin.Context) {
+	req := new(v1.GetForwardingRequest)
+	if err := ctx.ShouldBind(req); err != nil {
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
+		return
+	}
+	defaults.SetDefaults(req)
+	res, err := h.tcpforwardingService.GetTcpforwarding(ctx, *req)
+	if err != nil {
+		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
+		return
+	}
+	v1.HandleSuccess(ctx, res)
 
 }
 

+ 18 - 7
internal/handler/udpforwarding.go

@@ -24,7 +24,18 @@ func NewUdpForWardingHandler(
 }
 
 func (h *UdpForWardingHandler) GetUdpForWarding(ctx *gin.Context) {
-
+	req := new(v1.GetForwardingRequest)
+	if err := ctx.ShouldBind(req); err != nil {
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
+		return
+	}
+	defaults.SetDefaults(req)
+	res, err := h.udpForWardingService.GetUdpForWarding(ctx, *req)
+	if err != nil {
+		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
+		return
+	}
+	v1.HandleSuccess(ctx, res)
 }
 
 func (h *UdpForWardingHandler) AddUdpForWarding(ctx *gin.Context) {
@@ -35,12 +46,12 @@ func (h *UdpForWardingHandler) AddUdpForWarding(ctx *gin.Context) {
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.udpForWardingService.AddUdpForwarding(ctx, req)
+	 err := h.udpForWardingService.AddUdpForwarding(ctx, req)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 
 }
 
@@ -52,12 +63,12 @@ func (h *UdpForWardingHandler) EditUdpForWarding(ctx *gin.Context) {
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.udpForWardingService.EditUdpForwarding(ctx, req)
+	err := h.udpForWardingService.EditUdpForwarding(ctx, req)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 }
 
 func (h *UdpForWardingHandler) DeleteUdpForWarding(ctx *gin.Context) {
@@ -67,10 +78,10 @@ func (h *UdpForWardingHandler) DeleteUdpForWarding(ctx *gin.Context) {
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.udpForWardingService.DeleteUdpForwarding(ctx, req.WafUdpId)
+	 err := h.udpForWardingService.DeleteUdpForwarding(ctx, req.WafUdpId)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 }

+ 18 - 6
internal/handler/webforwarding.go

@@ -24,7 +24,19 @@ func NewWebForwardingHandler(
 }
 
 func (h *WebForwardingHandler) GetWebForwarding(ctx *gin.Context) {
+	req := new(v1.GetForwardingRequest)
 
+	if err := ctx.ShouldBind(req); err != nil {
+		v1.HandleError(ctx, http.StatusBadRequest, v1.ErrBadRequest, err.Error())
+		return
+	}
+	defaults.SetDefaults(req)
+	res, err := h.webForwardingService.GetWebForwarding(ctx, *req)
+	if err != nil {
+		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
+		return
+	}
+	v1.HandleSuccess(ctx, res)
 }
 
 func (h *WebForwardingHandler) AddWebForwarding(ctx *gin.Context) {
@@ -35,12 +47,12 @@ func (h *WebForwardingHandler) AddWebForwarding(ctx *gin.Context) {
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.webForwardingService.AddWebForwarding(ctx, req)
+	 err := h.webForwardingService.AddWebForwarding(ctx, req)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 }
 
 func (h *WebForwardingHandler) EditWebForwarding(ctx *gin.Context) {
@@ -51,12 +63,12 @@ func (h *WebForwardingHandler) EditWebForwarding(ctx *gin.Context) {
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.webForwardingService.EditWebForwarding(ctx, req)
+	 err := h.webForwardingService.EditWebForwarding(ctx, req)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 }
 
 func (h *WebForwardingHandler) DeleteWebForwarding(ctx *gin.Context) {
@@ -66,10 +78,10 @@ func (h *WebForwardingHandler) DeleteWebForwarding(ctx *gin.Context) {
 		return
 	}
 	defaults.SetDefaults(req)
-	res, err := h.webForwardingService.DeleteWebForwarding(ctx, req.WafWebId)
+	 err := h.webForwardingService.DeleteWebForwarding(ctx, req.WafWebId)
 	if err != nil {
 		v1.HandleError(ctx, http.StatusInternalServerError, err, err.Error())
 		return
 	}
-	v1.HandleSuccess(ctx, res)
+	v1.HandleSuccess(ctx, nil)
 }

+ 26 - 1
internal/model/udpforwarding.go

@@ -1,9 +1,14 @@
 package model
 
+import (
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"time"
+)
+
 type UdpForWarding struct {
 	Id                   int `gorm:"primary"`
 	HostId               int `gorm:"not null"`
-	RuleId               int `gorm:"not null"`
+	WafUdpId             int `gorm:"not null"` // 修改为与TCP转发一致的命名
 	Tag                  string `gorm:"null"`
 	Port                 string `gorm:"not null"`
 	WafGatewayGroupId    int `gorm:"not null"`
@@ -18,8 +23,28 @@ type UdpForWarding struct {
 	CcBlockDuration      string `gorm:"null"`
 	SessionTimeout       string `gorm:"null"`
 	Comment              string `gorm:"null"`
+	CreatedAt            time.Time
+	UpdatedAt            time.Time
 }
 
 func (m *UdpForWarding) TableName() string {
     return "shd_waf_udp"
 }
+
+// UdpForwardingRule 用于存储UDP转发规则
+type UdpForwardingRule struct {
+	ID          primitive.ObjectID `bson:"_id,omitempty"`
+	Uid         int                `bson:"uid" json:"uid"`
+	HostId      int                `bson:"host_id" json:"host_id"`
+	UdpId       int                `bson:"udp_id" json:"udp_id"`
+	BackendList []string           `bson:"backend_list" json:"backend_list"`
+	AllowIpList []string           `bson:"allow_ip_list" json:"allow_ip_list"`
+	DenyIpList  []string           `bson:"deny_ip_list" json:"deny_ip_list"`
+	AccessRule  string             `bson:"access_rule" json:"access_rule"`
+	CreatedAt   time.Time          `bson:"created_at" json:"created_at"`
+	UpdatedAt   time.Time          `bson:"updated_at" json:"updated_at"`
+}
+
+func (m *UdpForwardingRule) CollectionName() string {
+	return "udp_forwarding_rules"
+}

+ 35 - 9
internal/model/webforwarding.go

@@ -1,9 +1,15 @@
 package model
 
+import (
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"time"
+)
+
 type WebForwarding struct {
 	Id                   int `gorm:"primary"`
 	HostId               int `gorm:"not null"`
-	RuleId               int `gorm:"not null"`
+	WafWebId             int `gorm:"not null"` // 修改为与TCP转发一致的命名
 	Tag                  string `gorm:"null"`
 	Port                 string `gorm:"not null"`
 	Domain               string `gorm:"null"`
@@ -14,18 +20,38 @@ type WebForwarding struct {
 	CcDuration           string `gorm:"null"`
 	CcBlockCount         int `gorm:"null"`
 	CcBlockDuration      string `gorm:"null"`
-	Cc4xxCount           int `gorm:"null"`
-	Cc4xxDuration        string `gorm:"null"`
-	Cc4xxBlockCount      int `gorm:"null"`
-	Cc4xxBlockDuration   string `gorm:"null"`
-	Cc5xxCount           int `gorm:"null"`
-	Cc5xxDuration        string `gorm:"null"`
-	Cc5xxBlockCount      int `gorm:"null"`
-	Cc5xxBlockDuration   string `gorm:"null"`
+	Cc4xxCount           int `gorm:"column:cc_4xx_count;null"`
+	Cc4xxDuration        string `gorm:"column:cc_4xx_duration;null"`
+	Cc4xxBlockCount      int `gorm:"column:cc_4xx_block_count;null"`
+	Cc4xxBlockDuration   string `gorm:"column:cc_4xx_block_duration;null"`
+	Cc5xxCount           int `gorm:"column:cc_5xx_count;null"`
+	Cc5xxDuration        string `gorm:"column:cc_5xx_duration;null"`
+	Cc5xxBlockCount      int `gorm:"column:cc_5xx_block_count;null"`
+	Cc5xxBlockDuration   string `gorm:"column:cc_5xx_block_duration;null"`
 	IsHttps              int `gorm:"null"`
 	Comment              string `gorm:"null"`
+	CreatedAt            time.Time
+	UpdatedAt            time.Time
 }
 
 func (m *WebForwarding) TableName() string {
     return "shd_waf_web"
 }
+
+// WebForwardingRule 用于存储Web转发规则
+type WebForwardingRule struct {
+	ID          primitive.ObjectID `bson:"_id,omitempty"`
+	Uid         int                `bson:"uid" json:"uid"`
+	HostId      int                `bson:"host_id" json:"host_id"`
+	WebId       int                `bson:"web_id" json:"web_id"`
+	BackendList []v1.BackendList   `bson:"backend_list" json:"backend_list"`
+	AllowIpList []string           `bson:"allow_ip_list" json:"allow_ip_list"`
+	DenyIpList  []string           `bson:"deny_ip_list" json:"deny_ip_list"`
+	AccessRule  string             `bson:"access_rule" json:"access_rule"`
+	CreatedAt   time.Time          `bson:"created_at" json:"created_at"`
+	UpdatedAt   time.Time          `bson:"updated_at" json:"updated_at"`
+}
+
+func (m *WebForwardingRule) CollectionName() string {
+	return "web_forwarding_rules"
+}

+ 32 - 1
internal/repository/tcpforwarding.go

@@ -2,10 +2,12 @@ package repository
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo"
 	"time"
 )
 
@@ -15,8 +17,10 @@ type TcpforwardingRepository interface {
 	EditTcpforwarding(ctx context.Context, req *model.Tcpforwarding) error
 	DeleteTcpforwarding(ctx context.Context, id int64) error
 	GetTcpforwardingWafTcpIdById(ctx context.Context, id int) (int, error)
+	GetTcpForwardingPortCountByHostId(ctx context.Context, hostId int) (int64, error)
 	AddTcpforwardingIps(ctx context.Context,req model.TcpForwardingRule) (primitive.ObjectID, error)
 	EditTcpforwardingIps(ctx context.Context, req model.TcpForwardingRule) error
+	GetTcpForwardingByID(ctx context.Context, tcpId int) (*model.TcpForwardingRule, error)
 }
 
 func NewTcpforwardingRepository(
@@ -33,7 +37,9 @@ type tcpforwardingRepository struct {
 
 func (r *tcpforwardingRepository) GetTcpforwarding(ctx context.Context, id int64) (*model.Tcpforwarding, error) {
 	var tcpforwarding model.Tcpforwarding
-
+	if err := r.db.Where("id = ?", id).First(&tcpforwarding).Error; err != nil {
+		return nil, err
+	}
 	return &tcpforwarding, nil
 }
 
@@ -68,6 +74,13 @@ func (r *tcpforwardingRepository) GetTcpforwardingWafTcpIdById(ctx context.Conte
 
 }
 
+func (r *tcpforwardingRepository) GetTcpForwardingPortCountByHostId(ctx context.Context, hostId int) (int64, error) {
+	var count int64
+	if err := r.db.Model(&model.Tcpforwarding{}).Where("host_id = ?", hostId).Count(&count).Error; err != nil {
+		return 0, err
+	}
+	return count, nil
+}
 
 //mongodb 插入
 func (r *tcpforwardingRepository) AddTcpforwardingIps(ctx context.Context,req model.TcpForwardingRule) (primitive.ObjectID, error) {
@@ -131,4 +144,22 @@ func (r *tcpforwardingRepository) EditTcpforwardingIps(ctx context.Context, req
 
 	return nil
 
+}
+
+func (r *tcpforwardingRepository) GetTcpForwardingByID(ctx context.Context, tcpId int) (*model.TcpForwardingRule, error) {
+
+	collection := r.mongoDB.Collection("tcp_forwarding_rules")
+
+	var res model.TcpForwardingRule
+
+	err := collection.Find(ctx, bson.M{"tcp_id": tcpId}).One(&res)
+
+	if err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return nil, fmt.Errorf("记录不存在")
+		}
+		return nil, fmt.Errorf("查询MongoDB失败: %w", err)
+	}
+
+	return &res, nil
 }

+ 117 - 7
internal/repository/udpforwarding.go

@@ -2,14 +2,25 @@ package repository
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo"
+	"time"
 )
 
 type UdpForWardingRepository interface {
 	GetUdpForWarding(ctx context.Context, id int64) (*model.UdpForWarding, error)
-	AddUdpForwarding(ctx context.Context, req *model.UdpForWarding) error
+	AddUdpForwarding(ctx context.Context, req *model.UdpForWarding) (int, error)
 	EditUdpForwarding(ctx context.Context, req *model.UdpForWarding) error
 	DeleteUdpForwarding(ctx context.Context, id int64) error
+	GetUdpForwardingWafUdpIdById(ctx context.Context, id int) (int, error)
+	GetUdpForwardingPortCountByHostId(ctx context.Context, hostId int) (int64, error)
+	AddUdpForwardingIps(ctx context.Context, req model.UdpForwardingRule) (primitive.ObjectID, error)
+	EditUdpForwardingIps(ctx context.Context, req model.UdpForwardingRule) error
+	GetTcpForwardingByID(ctx context.Context, udpId int) (*model.UdpForwardingRule, error)
 }
 
 func NewUdpForWardingRepository(
@@ -26,27 +37,126 @@ type udpForWardingRepository struct {
 
 func (r *udpForWardingRepository) GetUdpForWarding(ctx context.Context, id int64) (*model.UdpForWarding, error) {
 	var udpForWarding model.UdpForWarding
+	if err := r.db.Where("id = ?", id).First(&udpForWarding).Error; err != nil {
+		return nil, err
+	}
 
 	return &udpForWarding, nil
 }
 
-func (r *udpForWardingRepository) AddUdpForwarding(ctx context.Context, req *model.UdpForWarding) error {
-	if err := r.db.Create(&req).Error; err != nil {
-		return err
+func (r *udpForWardingRepository) AddUdpForwarding(ctx context.Context, req *model.UdpForWarding) (int, error) {
+	if err := r.db.Create(req).Error; err != nil {
+		return 0, err
 	}
-	return nil
+	return req.Id, nil
 }
 
 func (r *udpForWardingRepository) EditUdpForwarding(ctx context.Context, req *model.UdpForWarding) error {
-	if err := r.db.Updates(&req).Error; err != nil {
+	if err := r.db.Updates(req).Error; err != nil {
 		return err
 	}
 	return nil
 }
 
 func (r *udpForWardingRepository) DeleteUdpForwarding(ctx context.Context, id int64) error {
-	if err := r.db.Delete(&model.UdpForWarding{}, id).Error; err != nil {
+	if err := r.db.Where("id = ?", id).Delete(&model.UdpForWarding{}).Error; err != nil {
 		return err
 	}
 	return nil
 }
+
+func (r *udpForWardingRepository) GetUdpForwardingWafUdpIdById(ctx context.Context, id int) (int, error) {
+	var WafUdpId int
+
+	if err := r.db.Model(&model.UdpForWarding{}).Where("id = ?", id).Select("waf_udp_id").Find(&WafUdpId).Error; err != nil {
+		return 0, err
+	}
+	return WafUdpId, nil
+}
+
+func (r *udpForWardingRepository) GetUdpForwardingPortCountByHostId(ctx context.Context, hostId int) (int64, error)  {
+	var count int64
+	if err := r.db.Model(&model.UdpForWarding{}).Where("host_id = ?", hostId).Count(&count).Error; err != nil {
+		return 0, err
+	}
+	return count, nil
+}
+
+
+// mongodb 插入
+func (r *udpForWardingRepository) AddUdpForwardingIps(ctx context.Context, req model.UdpForwardingRule) (primitive.ObjectID, error) {
+	collection := r.mongoDB.Collection("udp_forwarding_rules")
+	req.CreatedAt = time.Now()
+	result, err := collection.InsertOne(ctx, req)
+	if err != nil {
+		return primitive.NilObjectID, fmt.Errorf("插入MongoDB失败: %w", err)
+	}
+
+	// 返回插入文档的ID
+	return result.InsertedID.(primitive.ObjectID), nil
+}
+
+func (r *udpForWardingRepository) EditUdpForwardingIps(ctx context.Context, req model.UdpForwardingRule) error {
+	collection := r.mongoDB.Collection("udp_forwarding_rules")
+	updateData := bson.M{}
+
+	if req.Uid != 0 {
+		updateData["uid"] = req.Uid
+	}
+
+	if req.HostId != 0 {
+		updateData["host_id"] = req.HostId
+	}
+
+	if req.UdpId != 0 {
+		updateData["udp_id"] = req.UdpId
+	}
+
+	if req.AccessRule != "" {
+		updateData["access_rule"] = req.AccessRule
+	}
+
+	if len(req.BackendList) > 0 {
+		updateData["backend_list"] = req.BackendList
+	}
+
+	if len(req.AllowIpList) > 0 {
+		updateData["allow_ip_list"] = req.AllowIpList
+	}
+
+	if len(req.DenyIpList) > 0 {
+		updateData["deny_ip_list"] = req.DenyIpList
+	}
+
+	// 始终更新更新时间
+	updateData["updated_at"] = time.Now()
+
+	// 如果没有任何字段需要更新,则直接返回
+	if len(updateData) == 0 {
+		return nil
+	}
+
+	// 执行更新
+	update := bson.M{"$set": updateData}
+	 err := collection.UpdateOne(ctx, bson.M{"udp_id": req.UdpId}, update)
+	if err != nil {
+		return fmt.Errorf("更新MongoDB文档失败: %w", err)
+	}
+
+	return nil
+}
+
+func (r *udpForWardingRepository) GetTcpForwardingByID(ctx context.Context, udpId int) (*model.UdpForwardingRule, error) {
+
+	collection := r.mongoDB.Collection("udp_forwarding_rules")
+	var result model.UdpForwardingRule
+	err := collection.Find(ctx, bson.M{"udp_id": udpId}).One(&result)
+	if err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return nil, nil
+		}
+		return nil, fmt.Errorf("从MongoDB中获取文档失败: %w", err)
+	}
+	return &result, nil
+
+}

+ 144 - 8
internal/repository/webforwarding.go

@@ -2,14 +2,27 @@ package repository
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
+	"github.com/qiniu/qmgo"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo"
+	"time"
 )
 
 type WebForwardingRepository interface {
 	GetWebForwarding(ctx context.Context, id int64) (*model.WebForwarding, error)
-	AddWebForwarding(ctx context.Context, req *model.WebForwarding) error
+	AddWebForwarding(ctx context.Context, req *model.WebForwarding) (int, error)
 	EditWebForwarding(ctx context.Context, req *model.WebForwarding) error
 	DeleteWebForwarding(ctx context.Context, id int64) error
+	GetWebForwardingWafWebIdById(ctx context.Context, id int) (int, error)
+	GetWebForwardingPortCountByHostId(ctx context.Context, hostId int) (int64, error)
+	GetWebForwardingDomainCountByHostId(ctx context.Context, hostId int) (int64, []string, error)
+	AddWebForwardingIps(ctx context.Context, req model.WebForwardingRule) (primitive.ObjectID, error)
+	EditWebForwardingIps(ctx context.Context, req model.WebForwardingRule) error
+	GetWebForwardingByID(ctx context.Context, webId int) (*model.WebForwardingRule, error)
 }
 
 func NewWebForwardingRepository(
@@ -26,27 +39,150 @@ type webForwardingRepository struct {
 
 func (r *webForwardingRepository) GetWebForwarding(ctx context.Context, id int64) (*model.WebForwarding, error) {
 	var webForwarding model.WebForwarding
-
+	if err := r.db.WithContext(ctx).Where("id = ?", id).First(&webForwarding).Error; err != nil {
+		return nil, err
+	}
 	return &webForwarding, nil
 }
 
-func (r *webForwardingRepository) AddWebForwarding(ctx context.Context, req *model.WebForwarding) error {
-	if err := r.db.Create(&req).Error; err != nil {
-		return err
+func (r *webForwardingRepository) AddWebForwarding(ctx context.Context, req *model.WebForwarding) (int, error) {
+	if err := r.db.WithContext(ctx).Create(req).Error; err != nil {
+		return 0, err
 	}
-	return nil
+	return req.Id, nil
 }
 
 func (r *webForwardingRepository) EditWebForwarding(ctx context.Context, req *model.WebForwarding) error {
-	if err := r.db.Updates(&req).Error; err != nil {
+	if err := r.db.WithContext(ctx).Updates(req).Error; err != nil {
 		return err
 	}
 	return nil
 }
 
 func (r *webForwardingRepository) DeleteWebForwarding(ctx context.Context, id int64) error {
-	if err := r.db.Where("id = ?", id).Delete(&model.WebForwarding{}).Error; err != nil {
+	if err := r.db.WithContext(ctx).Where("id = ?", id).Delete(&model.WebForwarding{}).Error; err != nil {
 		return err
 	}
 	return nil
 }
+
+func (r *webForwardingRepository) GetWebForwardingWafWebIdById(ctx context.Context, id int) (int, error) {
+	var WafWebId int
+
+	if err := r.db.Model(&model.WebForwarding{}).WithContext(ctx).Where("id = ?", id).Select("waf_web_id").Find(&WafWebId).Error; err != nil {
+		return 0, err
+	}
+	return WafWebId, nil
+}
+
+func (r *webForwardingRepository) GetWebForwardingPortCountByHostId(ctx context.Context, hostId int) (int64, error) {
+	var count int64
+	if err := r.db.Model(&model.WebForwarding{}).WithContext(ctx).Where("host_id = ?", hostId).Count(&count).Error; err != nil {
+		return 0, err
+	}
+	return count, nil
+}
+
+func (r *webForwardingRepository) GetWebForwardingDomainCountByHostId(ctx context.Context, hostId int) (int64, []string, error) {
+	var distinctDomains []string
+	err := r.db.Model(&model.WebForwarding{}).WithContext(ctx).
+		Distinct(). // 确保我们只获取唯一的 domain 值
+		Where("host_id = ? AND domain IS NOT NULL AND domain != ''", hostId). // 额外添加 domain != '' 以排除空字符串
+		Pluck("domain", &distinctDomains).Error
+
+	if err != nil {
+		return 0, nil, err
+	}
+	count := int64(len(distinctDomains))
+
+	return count, distinctDomains, nil
+}
+
+
+// mongodb 插入
+func (r *webForwardingRepository) AddWebForwardingIps(ctx context.Context, req model.WebForwardingRule) (primitive.ObjectID, error) {
+	collection := r.mongoDB.Collection("web_forwarding_rules")
+	req.CreatedAt = time.Now()
+	result, err := collection.InsertOne(ctx, req)
+	if err != nil {
+		return primitive.NilObjectID, fmt.Errorf("插入MongoDB失败: %w", err)
+	}
+
+	// 返回插入文档的ID
+	return result.InsertedID.(primitive.ObjectID), nil
+}
+
+func (r *webForwardingRepository) EditWebForwardingIps(ctx context.Context, req model.WebForwardingRule) error {
+	collection := r.mongoDB.Collection("web_forwarding_rules")
+	updateData := bson.M{}
+
+	if req.Uid != 0 {
+		updateData["uid"] = req.Uid
+	}
+
+	if req.HostId != 0 {
+		updateData["host_id"] = req.HostId
+	}
+
+	if req.WebId != 0 {
+		updateData["web_id"] = req.WebId
+	}
+
+	if req.AccessRule != "" {
+		updateData["access_rule"] = req.AccessRule
+	}
+
+	if len(req.BackendList) > 0 {
+		updateData["backend_list"] = req.BackendList
+	}
+
+	if len(req.AllowIpList) > 0 {
+		updateData["allow_ip_list"] = req.AllowIpList
+	}
+
+	if len(req.DenyIpList) > 0 {
+		updateData["deny_ip_list"] = req.DenyIpList
+	}
+
+	// 始终更新更新时间
+	updateData["updated_at"] = time.Now()
+
+	// 如果没有任何字段需要更新,则直接返回
+	if len(updateData) == 0 {
+		return nil
+	}
+
+	// 执行更新
+	update := bson.M{"$set": updateData}
+	 err := collection.UpdateOne(ctx, bson.M{"web_id": req.WebId}, update)
+	if err != nil {
+		return fmt.Errorf("更新MongoDB文档失败: %w", err)
+	}
+
+	return nil
+}
+
+func (r *webForwardingRepository) GetWebForwardingByID(ctx context.Context, webId int) (*model.WebForwardingRule, error) {
+
+	// 获取集合
+	collection := r.mongoDB.Collection("web_forwarding_rules")
+
+	// 创建一个结构体来存储查询到的文档
+	var rule model.WebForwardingRule
+
+	// 使用 FindByID 方法来查找文档
+	// FindByID 是 QMgo 封装的一个方便的方法,它内部会构建查询 _id = id
+	err := collection.Find(ctx, qmgo.M{"web_id": webId}).One(&rule) // QMgo 的 FindOne 返回一个 QueryBuilder,接着调用 .One() 来执行查询并解码到 rule
+
+	if err != nil {
+		if errors.Is(err, mongo.ErrNoDocuments) {
+			return nil, fmt.Errorf("记录不存在")
+		}
+		// 其他错误
+		return nil, fmt.Errorf("查询MongoDB失败: %w", err)
+	}
+
+	// 返回找到的文档
+	return &rule, nil
+}
+

+ 3 - 0
internal/server/http.go

@@ -91,6 +91,7 @@ func NewHTTPServer(
 			noAuthRouter.POST("/gameShield/delete", ipAllowlistMiddleware, gameShieldHandler.DeleteGameShield)
 			noAuthRouter.POST("/gameShield/getOnline", ipAllowlistMiddleware, gameShieldHandler.GetGameShieldOnlineList)
 			noAuthRouter.POST("/gameShield/IsExistKey", gameShieldHandler.IsExistGameShieldKey)
+			noAuthRouter.POST("/webForward/get", ipAllowlistMiddleware, webForwardingHandler.GetWebForwarding)
 			noAuthRouter.POST("/webForward/add", ipAllowlistMiddleware, webForwardingHandler.AddWebForwarding)
 			noAuthRouter.POST("/webForward/edit", ipAllowlistMiddleware, webForwardingHandler.EditWebForwarding)
 			noAuthRouter.POST("/webForward/delete", ipAllowlistMiddleware, webForwardingHandler.DeleteWebForwarding)
@@ -98,8 +99,10 @@ func NewHTTPServer(
 			noAuthRouter.POST("/webLimit/edit", ipAllowlistMiddleware, weblimitHandler.EditWebLimit)
 			noAuthRouter.POST("/webLimit/delete", ipAllowlistMiddleware, weblimitHandler.DeleteWebLimit)
 			noAuthRouter.POST("/tcpForward/add", ipAllowlistMiddleware, tcpForwardingHandler.AddTcpForwarding)
+			noAuthRouter.POST("/tcpForward/get", ipAllowlistMiddleware, tcpForwardingHandler.GetTcpforwarding)
 			noAuthRouter.POST("/tcpForward/edit", ipAllowlistMiddleware, tcpForwardingHandler.EditTcpForwarding)
 			noAuthRouter.POST("/tcpForward/delete", ipAllowlistMiddleware, tcpForwardingHandler.DeleteTcpForwarding)
+			noAuthRouter.POST("/udpForward/get", ipAllowlistMiddleware, udpForwardingHandler.GetUdpForWarding)
 			noAuthRouter.POST("/udpForward/add", ipAllowlistMiddleware, udpForwardingHandler.AddUdpForWarding)
 			noAuthRouter.POST("/udpForward/edit", ipAllowlistMiddleware, udpForwardingHandler.EditUdpForWarding)
 			noAuthRouter.POST("/udpForward/delete", ipAllowlistMiddleware, udpForwardingHandler.DeleteUdpForWarding)

+ 0 - 2
internal/service/gameshieldbackend.go

@@ -4,7 +4,6 @@ import (
 	"context"
 	"fmt"
 	"github.com/AlekSi/pointer"
-	"github.com/davecgh/go-spew/spew"
 	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"
@@ -120,7 +119,6 @@ func (s *gameShieldBackendService) GameShieldBackend(ctx context.Context, req *v
 	}
 	tokenUrl := s.Url + "admin/info/rule/edit?&__goadmin_edit_pk=" + strconv.Itoa(require.RuleId) + "_" + require.DunName
 	tokens, err := s.crawlerService.GetFormTokens(ctx, tokenUrl, require.Cookie)
-	spew.Dump(tokens)
 	if err != nil {
 		return "", 0, err
 	}

+ 26 - 44
internal/service/globallimit.go

@@ -8,10 +8,8 @@ import (
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
 	"github.com/spf13/cast"
 	"github.com/spf13/viper"
+	"golang.org/x/sync/errgroup"
 	"strconv"
-	"sync"
-
-	"github.com/sourcegraph/conc"
 )
 
 type GlobalLimitService interface {
@@ -130,85 +128,69 @@ func (s *globalLimitService) AddGlobalLimit(ctx context.Context, req v1.GlobalLi
 	if err != nil {
 		return err
 	}
-	// 使用conc库并发执行API调用
 	var tcpLimitRuleId, udpLimitRuleId, webLimitRuleId int
-	var mu sync.Mutex // 用于保护共享变量
-
-	// 为每个并发调用创建独立的请求参数(深拷贝)
-	// 避免共享同一个指针可能导致的数据竞争
-
 
-	// 创建一个WaitGroup来协调多个并发任务
-	wg := conc.NewWaitGroup()
+	g, gCtx := errgroup.WithContext(ctx)
 
 	// 启动tcpLimit调用 - 使用独立的请求参数副本
-	wg.Go(func() {
-		// 为该goroutine创建独立的请求参数副本
+	g.Go(func() error {
 		tcpLimitReq := &v1.GeneralLimitRequireRequest{
 			Tag:    require.GlobalLimitName,
 			HostId: req.HostId,
 			RuleId: ruleId,
 			Uid:    req.Uid,
 		}
-		result, e := s.tcpLimit.AddTcpLimit(ctx, tcpLimitReq)
+		result, e := s.tcpLimit.AddTcpLimit(gCtx, tcpLimitReq)
 		if e != nil {
-			// 只在修改共享的错误变量时加锁
-			mu.Lock()
-			err = e
-			mu.Unlock()
-		} else {
-			// 不需要加锁,因为tcpLimitRuleId只被这一个goroutine修改
+			return fmt.Errorf("tcpLimit调用失败: %w", e)
+		}
+		if result != 0 {
 			tcpLimitRuleId = result
+			return nil
 		}
+		return fmt.Errorf("tcpLimit调用失败,Id为 %d", result)
 	})
 
 	// 启动udpLimit调用 - 使用独立的请求参数副本
-	wg.Go(func() {
-		// 为该goroutine创建独立的请求参数副本
+	g.Go(func() error {
 		udpLimitReq := &v1.GeneralLimitRequireRequest{
 			Tag:    require.GlobalLimitName,
 			HostId: req.HostId,
 			RuleId: ruleId,
 			Uid:    req.Uid,
 		}
-		result, e := s.udpLimit.AddUdpLimit(ctx, udpLimitReq)
+		result, e := s.udpLimit.AddUdpLimit(gCtx, udpLimitReq)
 		if e != nil {
-			// 只在修改共享的错误变量时加锁
-			mu.Lock()
-			err = e
-			mu.Unlock()
-		} else {
-			// 不需要加锁,因为udpLimitRuleId只被这一个goroutine修改
+			return fmt.Errorf("udpLimit调用失败: %w", e)
+		}
+		if result != 0 {
 			udpLimitRuleId = result
+			return nil
 		}
+		return fmt.Errorf("udpLimit调用失败,Id为 %d", result)
 	})
 
+
 	// 启动webLimit调用 - 使用独立的请求参数副本
-	wg.Go(func() {
-		// 为该goroutine创建独立的请求参数副本
+	g.Go(func() error {
 		webLimitReq := &v1.GeneralLimitRequireRequest{
 			Tag:    require.GlobalLimitName,
 			HostId: req.HostId,
 			RuleId: ruleId,
 			Uid:    req.Uid,
 		}
-		result, e := s.webLimit.AddWebLimit(ctx, webLimitReq)
+		result, e := s.webLimit.AddWebLimit(gCtx, webLimitReq)
 		if e != nil {
-			// 只在修改共享的错误变量时加锁
-			mu.Lock()
-			err = e
-			mu.Unlock()
-		} else {
-			// 不需要加锁,因为webLimitRuleId只被这一个goroutine修改
+			return fmt.Errorf("webLimit调用失败: %w", e)
+		}
+		if result != 0 {
 			webLimitRuleId = result
+			return nil
 		}
+		return fmt.Errorf("webLimit调用失败,Id为 %d", result)
 	})
 
-	// 等待所有调用完成
-	wg.Wait()
-
-	// 检查是否有错误发生
-	if err != nil {
+	if err := g.Wait(); err != nil {
 		return err
 	}
 	err = s.globalLimitRepository.AddGlobalLimit(ctx, &model.GlobalLimit{
@@ -219,7 +201,7 @@ func (s *globalLimitService) AddGlobalLimit(ctx context.Context, req v1.GlobalLi
 		TcpLimitRuleId:  tcpLimitRuleId,
 		UdpLimitRuleId:  udpLimitRuleId,
 		WebLimitRuleId:  webLimitRuleId,
-		GatewayGroupId:  5,
+		GatewayGroupId:  5,// TODO: 临时写死
 	})
 	if err != nil {
 		return err

+ 61 - 4
internal/service/tcpforwarding.go

@@ -2,15 +2,17 @@ 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"
+	"golang.org/x/sync/errgroup"
 	"strconv"
 	"strings"
 )
 
 type TcpforwardingService interface {
-	GetTcpforwarding(ctx context.Context, id int64) (*model.Tcpforwarding, error)
+	GetTcpforwarding(ctx context.Context, req v1.GetForwardingRequest) (v1.TcpForwardingDataRequest, error)
 	AddTcpForwarding(ctx context.Context, req *v1.TcpForwardingRequest)  error
 	EditTcpForwarding(ctx context.Context, req *v1.TcpForwardingRequest)  error
 	DeleteTcpForwarding(ctx context.Context, wafTcpId int) error
@@ -49,8 +51,56 @@ type tcpforwardingService struct {
 	wafformatter WafFormatterService
 }
 
-func (s *tcpforwardingService) GetTcpforwarding(ctx context.Context, id int64) (*model.Tcpforwarding, error) {
-	return s.tcpforwardingRepository.GetTcpforwarding(ctx, id)
+func (s *tcpforwardingService) GetTcpforwarding(ctx context.Context, req v1.GetForwardingRequest) (v1.TcpForwardingDataRequest, error) {
+	var tcpForwarding model.Tcpforwarding
+	var backend model.TcpForwardingRule
+	var err error
+
+	g, gCtx := errgroup.WithContext(ctx)
+	g.Go(func() error {
+		res, e := s.tcpforwardingRepository.GetTcpforwarding(gCtx, int64(req.Id))
+		if e != nil {
+			return fmt.Errorf("GetTcpforwarding failed: %w", e)
+		}
+		if res != nil {
+			tcpForwarding = *res
+		}
+		return nil
+	})
+
+	g.Go(func() error {
+		res, e := s.tcpforwardingRepository.GetTcpForwardingByID(gCtx, req.Id)
+		if e != nil {
+			return fmt.Errorf("GetTcpforwardingIps failed: %w", e)
+		}
+		if res != nil {
+			backend = *res
+		}
+		return nil
+	})
+	if err = g.Wait(); err != nil {
+		return v1.TcpForwardingDataRequest{}, err
+	}
+
+	return v1.TcpForwardingDataRequest{
+		Id:               tcpForwarding.Id,
+		WafTcpId:         tcpForwarding.WafTcpId,
+		Tag:              tcpForwarding.Tag,
+		Port:             tcpForwarding.Port,
+		Comment:          tcpForwarding.Comment,
+		WafGatewayGroupId: tcpForwarding.WafGatewayGroupId,
+		WafTcpLimitRuleId: tcpForwarding.TcpLimitRuleId,
+		CcCount:           tcpForwarding.CcCount,
+		CcDuration:        tcpForwarding.CcDuration,
+		CcBlockCount:      tcpForwarding.CcBlockCount,
+		CcBlockDuration:   tcpForwarding.CcBlockDuration,
+		BackendProtocol:   tcpForwarding.BackendProtocol,
+		BackendTimeout:    tcpForwarding.BackendTimeout,
+		BackendList:       backend.BackendList,
+		AllowIpList:       backend.AllowIpList,
+		DenyIpList:        backend.DenyIpList,
+		AccessRule:        backend.AccessRule,
+	}, nil
 }
 
 func (s *tcpforwardingService) require(ctx context.Context,req v1.GlobalRequire) (v1.GlobalRequire, error) {
@@ -89,6 +139,7 @@ func (s *tcpforwardingService) buildTcpForwardingModel(req *v1.TcpForwardingData
 		Port:    req.Port,
 		Tag:     require.Tag,
 		Comment: req.Comment,
+		TcpLimitRuleId: require.LimitRuleId,
 		WafGatewayGroupId: require.WafGatewayGroupId,
 		CcCount: req.CcCount,
 		CcDuration: req.CcDuration,
@@ -121,7 +172,9 @@ func (s *tcpforwardingService) prepareWafData(ctx context.Context, req *v1.TcpFo
 	if err != nil {
 		return v1.GlobalRequire{}, nil, err
 	}
-
+	if require.WafGatewayGroupId == 0 || require.LimitRuleId == 0 {
+		return v1.GlobalRequire{}, nil, fmt.Errorf("请先配置实例")
+	}
 	// 2. 将字符串切片拼接成字符串,用于 WAF API
 	backendListStr := strings.Join(req.TcpForwardingData.BackendList, "\n")
 	allowIpListStr := strings.Join(req.TcpForwardingData.AllowIpList, "\n")
@@ -158,6 +211,10 @@ func (s *tcpforwardingService) AddTcpForwarding(ctx context.Context, req *v1.Tcp
 	if err != nil {
 		return err
 	}
+	err = s.wafformatter.validateWafPortCount(ctx, require.HostId)
+	if err != nil {
+		return err
+	}
 	wafTcpId, err := s.wafformatter.sendFormData(ctx, "admin/info/waf_tcp/new", "admin/new/waf_tcp", formData)
 	if err != nil {
 		return err

+ 163 - 41
internal/service/udpforwarding.go

@@ -2,18 +2,20 @@ package service
 
 import (
 	"context"
-	"github.com/davecgh/go-spew/spew"
+	"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"
+	"golang.org/x/sync/errgroup"
 	"strconv"
+	"strings"
 )
 
 type UdpForWardingService interface {
-	GetUdpForWarding(ctx context.Context, id int64) (*model.UdpForWarding, error)
-	AddUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) (string, error)
-	EditUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) (string, error)
-	DeleteUdpForwarding(ctx context.Context, wafUdpId int) (string, error)
+	GetUdpForWarding(ctx context.Context,req v1.GetForwardingRequest) (v1.UdpForwardingDataRequest, error)
+	AddUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) error
+	EditUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) error
+	DeleteUdpForwarding(ctx context.Context, wafUdpId int) error
 }
 
 func NewUdpForWardingService(
@@ -57,14 +59,67 @@ func (s *udpForWardingService) require(ctx context.Context,req v1.GlobalRequire)
 	}
 	return res, nil
 }
-func (s *udpForWardingService) GetUdpForWarding(ctx context.Context, id int64) (*model.UdpForWarding, error) {
-	return s.udpForWardingRepository.GetUdpForWarding(ctx, id)
+func (s *udpForWardingService) GetUdpForWarding(ctx context.Context,req v1.GetForwardingRequest) (v1.UdpForwardingDataRequest, error) {
+	var udpForWarding model.UdpForWarding
+	var backend model.UdpForwardingRule
+	var err error
+	g, gCtx := errgroup.WithContext(ctx)
+	g.Go(func() error {
+		res, e := s.udpForWardingRepository.GetUdpForWarding(gCtx, int64(req.Id))
+		if e != nil {
+			return fmt.Errorf("GetUdpForWarding failed: %w", e)
+		}
+		if res != nil {
+			udpForWarding = *res
+		}
+		return nil
+	})
+	g.Go(func() error {
+		res, e := s.udpForWardingRepository.GetTcpForwardingByID(gCtx, req.Id)
+		if e != nil {
+			return fmt.Errorf("GetUdpForWardingByID failed: %w", e)
+		}
+		if res != nil {
+			backend = *res
+		}
+		return nil
+	})
+	if err = g.Wait(); err != nil {
+		return v1.UdpForwardingDataRequest{}, err
+	}
+	portInt, err := strconv.Atoi(udpForWarding.Port)
+	if err != nil {
+		return v1.UdpForwardingDataRequest{}, err
+	}
+
+	return v1.UdpForwardingDataRequest{
+		Id:                 udpForWarding.Id,
+		WafUdpId:           udpForWarding.WafUdpId,
+		Tag:                udpForWarding.Tag,
+		Port:               portInt,
+		WafGatewayGroupId:  udpForWarding.WafGatewayGroupId,
+		WafUdpLimitId:      udpForWarding.UdpLimitRuleId,
+		CcPacketCount:      udpForWarding.CcPacketCount,
+		CcPacketDuration:   udpForWarding.CcPacketDuration,
+		CcCount:            udpForWarding.CcCount,
+		CcDuration:         udpForWarding.CcDuration,
+		CcBlockCount:       udpForWarding.CcBlockCount,
+		CcBlockDuration:    udpForWarding.CcBlockDuration,
+		SessionTimeout:     udpForWarding.SessionTimeout,
+		BackendList:         backend.BackendList,
+		AllowIpList:        backend.AllowIpList,
+		DenyIpList:         backend.DenyIpList,
+		AccessRule:         backend.AccessRule,
+		Comment:            udpForWarding.Comment,
+
+	}, nil
 }
 
-func (s *udpForWardingService) buildWafFormData(req *v1.UdpForwardingData, require v1.GlobalRequire) map[string]interface{} {
+func (s *udpForWardingService) buildWafFormData(req *v1.UdpForwardingDataSend, require v1.GlobalRequire) map[string]interface{} {
 	return map[string]interface{}{
-		"tag":               require.Tag,
-		"port":              req.Port,
+		"waf_udp_id":           req.WafUdpId,
+		"tag":                  require.Tag,
+		"port":                 req.Port,
 		"waf_gateway_group_id": require.WafGatewayGroupId,
 		"waf_udp_limit_id":     require.LimitRuleId,
 		"cc_packet_count":      req.CcPacketCount,
@@ -82,10 +137,10 @@ func (s *udpForWardingService) buildWafFormData(req *v1.UdpForwardingData, requi
 	}
 }
 
-func (s *udpForWardingService) buildUdpForwardingModel(req *v1.UdpForwardingData, ruleId int, require v1.GlobalRequire) *model.UdpForWarding {
+func (s *udpForWardingService) buildUdpForwardingModel(req *v1.UdpForwardingDataRequest, ruleId int, require v1.GlobalRequire) *model.UdpForWarding {
 	return &model.UdpForWarding{
 		HostId: 			  require.HostId,
-		RuleId:               ruleId,
+		WafUdpId:             ruleId,
 		Tag:                  require.Tag,
 		Port:                 strconv.Itoa(req.Port),
 		WafGatewayGroupId:    require.WafGatewayGroupId,
@@ -103,55 +158,122 @@ func (s *udpForWardingService) buildUdpForwardingModel(req *v1.UdpForwardingData
 	}
 }
 
-func (s *udpForWardingService) AddUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) (string, error) {
+func (s *udpForWardingService) buildUdpRuleModel(reqData *v1.UdpForwardingDataRequest, require v1.GlobalRequire, localDbId int) *model.UdpForwardingRule {
+	return &model.UdpForwardingRule{
+		Uid:         require.Uid,
+		HostId:      require.HostId,
+		UdpId:       localDbId, // 关联到本地数据库的主记录 ID
+		BackendList: reqData.BackendList,
+		AllowIpList: reqData.AllowIpList,
+		DenyIpList:  reqData.DenyIpList,
+		AccessRule:  reqData.AccessRule,
+	}
+}
+
+func (s *udpForWardingService) prepareWafData(ctx context.Context, req *v1.UdpForwardingRequest) (v1.GlobalRequire, map[string]interface{}, error) {
+	// 1. 获取必要的全局信息
 	require, err := s.require(ctx, v1.GlobalRequire{
-		HostId: req.HostId,
-		Uid:    req.Uid,
+		HostId:  req.HostId,
+		Uid:     req.Uid,
 		Comment: req.UdpForwardingData.Comment,
 	})
-	spew.Dump(require)
 	if err != nil {
-		return "", err
+		return v1.GlobalRequire{}, nil, err
+	}
+
+	if require.LimitRuleId == 0 || require.WafGatewayGroupId == 0 {
+		return v1.GlobalRequire{}, nil, fmt.Errorf("请先配置实例")
+	}
+
+	// 2. 将字符串切片拼接成字符串,用于 WAF API
+	backendListStr := strings.Join(req.UdpForwardingData.BackendList, "\n")
+	allowIpListStr := strings.Join(req.UdpForwardingData.AllowIpList, "\n")
+	denyIpListStr := strings.Join(req.UdpForwardingData.DenyIpList, "\n")
+
+	// 3. 创建用于构建 WAF 表单的数据结构
+	formDataBase := v1.UdpForwardingDataSend{
+		Tag:               require.Tag,
+		WafUdpId:          req.UdpForwardingData.WafUdpId,
+		WafGatewayGroupId: require.WafGatewayGroupId,
+		WafUdpLimitId: require.LimitRuleId,
+		Port:              req.UdpForwardingData.Port,
+		CcPacketCount:     req.UdpForwardingData.CcPacketCount,
+		CcPacketDuration:  req.UdpForwardingData.CcPacketDuration,
+		CcCount:           req.UdpForwardingData.CcCount,
+		CcDuration:        req.UdpForwardingData.CcDuration,
+		CcBlockCount:      req.UdpForwardingData.CcBlockCount,
+		CcBlockDuration:   req.UdpForwardingData.CcBlockDuration,
+		SessionTimeout:    req.UdpForwardingData.SessionTimeout,
+		BackendList:       backendListStr,
+		AllowIpList:       allowIpListStr,
+		DenyIpList:        denyIpListStr,
+		AccessRule:        req.UdpForwardingData.AccessRule,
+		Comment:           req.UdpForwardingData.Comment,
+	}
+
+	// 4. 构建 WAF 表单数据映射
+	formData := s.buildWafFormData(&formDataBase, require)
+
+	return require, formData, nil
+}
+
+func (s *udpForWardingService) AddUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) error {
+	require, formData, err := s.prepareWafData(ctx, req)
+	if err != nil {
+		return err
+	}
+	err = s.wafformatter.validateWafPortCount(ctx, require.HostId)
+	if err != nil {
+		return err
 	}
-	formData := s.buildWafFormData(&req.UdpForwardingData, require)
 	wafUdpId, err := s.wafformatter.sendFormData(ctx, "admin/info/waf_udp/new", "admin/new/waf_udp", formData)
 	if err != nil {
-		return "", err
+		return err
 	}
+
 	udpModel := s.buildUdpForwardingModel(&req.UdpForwardingData, wafUdpId, require)
-	if err := s.udpForWardingRepository.AddUdpForwarding(ctx, udpModel); err != nil {
-		return "", err
+
+	id, err := s.udpForWardingRepository.AddUdpForwarding(ctx, udpModel)
+	if err != nil {
+		return err
+	}
+	udpRuleModel := s.buildUdpRuleModel(&req.UdpForwardingData, require, id)
+	if _, err = s.udpForWardingRepository.AddUdpForwardingIps(ctx, *udpRuleModel); err != nil {
+		return err
 	}
-	return "", nil
+	return nil
 }
 
-func (s *udpForWardingService) EditUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) (string, error) {
-	require, err := s.require(ctx, v1.GlobalRequire{
-		HostId: req.HostId,
-		Uid:    req.Uid,
-		Comment: req.UdpForwardingData.Comment,
-	})
+func (s *udpForWardingService) EditUdpForwarding(ctx context.Context, req *v1.UdpForwardingRequest) error {
+	WafUdpId, err := s.udpForWardingRepository.GetUdpForwardingWafUdpIdById(ctx, req.Id)
+	if err != nil {
+		return err
+	}
+	req.UdpForwardingData.WafUdpId = WafUdpId
+	require, formData, err := s.prepareWafData(ctx, req)
 	if err != nil {
-		return "", err
+		return err
 	}
-	formData := s.buildWafFormData(&req.UdpForwardingData, require)
 	_, err = s.wafformatter.sendFormData(ctx, "admin/info/waf_udp/edit?&__goadmin_edit_pk="+strconv.Itoa(req.UdpForwardingData.WafUdpId), "admin/edit/waf_udp", formData)
 	if err != nil {
-		return "", err
+		return err
 	}
-
-	udpMdel := s.buildUdpForwardingModel(&req.UdpForwardingData, req.UdpForwardingData.WafUdpId, require)
-	udpMdel.Id = req.Id
-	if err := s.udpForWardingRepository.EditUdpForwarding(ctx, udpMdel); err != nil {
-		return "", err
+	udpModel := s.buildUdpForwardingModel(&req.UdpForwardingData, req.UdpForwardingData.WafUdpId, require)
+	udpModel.Id = req.Id
+	if err = s.udpForWardingRepository.EditUdpForwarding(ctx, udpModel); err != nil {
+		return err
 	}
-	return "", nil
+	udpRuleModel := s.buildUdpRuleModel(&req.UdpForwardingData, require, req.Id)
+	if err = s.udpForWardingRepository.EditUdpForwardingIps(ctx, *udpRuleModel); err != nil {
+		return err
+	}
+	return nil
 }
 
-func (s *udpForWardingService) DeleteUdpForwarding(ctx context.Context, wafUdpId int) (string, error) {
-	res, err := s.crawler.DeleteRule(ctx, wafUdpId, "admin/delete/waf_udp?page=1&__pageSize=10&__sort=waf_udp_id&__sort_type=desc")
+func (s *udpForWardingService) DeleteUdpForwarding(ctx context.Context, wafUdpId int) error {
+	_, err := s.crawler.DeleteRule(ctx, wafUdpId, "admin/delete/waf_udp?page=1&__pageSize=10&__sort=waf_udp_id&__sort_type=desc")
 	if err != nil {
-		return "", err
+		return err
 	}
-	return res, nil
+	return nil
 }

+ 56 - 1
internal/service/wafformatter.go

@@ -6,13 +6,15 @@ import (
 	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
 	"github.com/spf13/cast"
-
+	"slices"
 	"strconv"
 )
 
 type WafFormatterService interface {
 	require(ctx context.Context, req v1.GlobalRequire, category string) (v1.GlobalRequire, error)
 	sendFormData(ctx context.Context,addTokenUrl string,addSendUrl string,formData map[string]interface{}) (int, error)
+	validateWafPortCount(ctx context.Context, hostId int) error
+	validateWafDomainCount(ctx context.Context, req v1.GlobalRequire) error
 }
 func NewWafFormatterService(
     service *Service,
@@ -20,6 +22,10 @@ func NewWafFormatterService(
 	hostRep repository.HostRepository,
 	required RequiredService,
 	parser ParserService,
+	tcpforwardingRep repository.TcpforwardingRepository,
+	udpForWardingRep repository.UdpForWardingRepository,
+	webForwardingRep repository.WebForwardingRepository,
+	host HostService,
 ) WafFormatterService {
 	return &wafFormatterService{
 		Service:        service,
@@ -27,6 +33,10 @@ func NewWafFormatterService(
 		hostRep: hostRep,
 		required: required,
 		parser: parser,
+		tcpforwardingRep: tcpforwardingRep,
+		udpForWardingRep: udpForWardingRep,
+		webForwardingRep: webForwardingRep,
+		host : host,
 	}
 }
 
@@ -36,6 +46,10 @@ type wafFormatterService struct {
 	hostRep repository.HostRepository
 	required RequiredService
 	parser ParserService
+	tcpforwardingRep repository.TcpforwardingRepository
+	udpForWardingRep repository.UdpForWardingRepository
+	webForwardingRep repository.WebForwardingRepository
+	host HostService
 }
 
 func (s *wafFormatterService) require(ctx context.Context,req v1.GlobalRequire,category string) (v1.GlobalRequire, error) {
@@ -82,4 +96,45 @@ func (s *wafFormatterService) sendFormData(ctx context.Context,addTokenUrl strin
 		return 0,err
 	}
 	return ruleId, nil
+}
+
+func (s *wafFormatterService) validateWafPortCount(ctx context.Context, hostId int) error {
+	congfig, err := s.host.GetGlobalLimitConfig(ctx, hostId)
+	if err != nil {
+		return err
+	}
+	tcpCount, err := s.tcpforwardingRep.GetTcpForwardingPortCountByHostId(ctx, hostId)
+	if err != nil {
+		return err
+	}
+	udpCount, err := s.udpForWardingRep.GetUdpForwardingPortCountByHostId(ctx, hostId)
+	if err != nil {
+		return err
+	}
+	webCount, err := s.webForwardingRep.GetWebForwardingPortCountByHostId(ctx, hostId)
+	if err != nil {
+		return err
+	}
+	if int64(congfig.PortCount) > tcpCount + udpCount + webCount {
+		return nil
+	}
+	return fmt.Errorf("端口数量超出套餐限制,已配置%d个端口,套餐限制为%d个端口", tcpCount+udpCount+webCount, congfig.PortCount)
+}
+
+func (s *wafFormatterService) validateWafDomainCount(ctx context.Context, req v1.GlobalRequire) error {
+	congfig, err := s.host.GetGlobalLimitConfig(ctx, req.HostId)
+	if err != nil {
+		return err
+	}
+	domainCount, domainSlice, err := s.webForwardingRep.GetWebForwardingDomainCountByHostId(ctx, req.HostId)
+	if err != nil {
+		return err
+	}
+	if !slices.Contains(domainSlice, req.Domain) {
+		domainCount += 1
+		if domainCount > int64(congfig.DomainCount) {
+			return fmt.Errorf("域名数量已达到上限,已配置%d个域名,套餐限制为%d个域名", domainCount, congfig.DomainCount)
+		}
+	}
+	return nil
 }

+ 213 - 43
internal/service/webforwarding.go

@@ -2,17 +2,22 @@ package service
 
 import (
 	"context"
+	"encoding/json"
+	"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"
+	"golang.org/x/sync/errgroup"
 	"strconv"
+	"strings"
 )
 
 type WebForwardingService interface {
-	GetWebForwarding(ctx context.Context, id int64) (*model.WebForwarding, error)
-	AddWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) (string, error)
-	EditWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) (string, error)
-	DeleteWebForwarding(ctx context.Context, wafWebId int) (string, error)
+	GetWebForwarding(ctx context.Context, req v1.GetForwardingRequest) (v1.WebForwardingDataRequest, error)
+	AddWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) error
+	EditWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) error
+	DeleteWebForwarding(ctx context.Context, wafWebId int) error
 }
 
 func NewWebForwardingService(
@@ -43,21 +48,114 @@ type webForwardingService struct {
 }
 
 func (s *webForwardingService) require(ctx context.Context,req v1.GlobalRequire) (v1.GlobalRequire, error) {
-	res, err := s.wafformatter.require(ctx, req, "web")
-	if err != nil {
+	var err error
+	var res v1.GlobalRequire
+	g, gCtx := errgroup.WithContext(ctx)
+
+	g.Go(func() error {
+		result, e := s.wafformatter.require(gCtx, req, "web")
+		if e != nil {
+			return e
+		}
+		res = result
+		return nil
+	})
+
+	g.Go(func() error {
+		e := s.wafformatter.validateWafDomainCount(gCtx, req)
+		if e != nil {
+			return e
+		}
+		return nil
+	})
+	if err 		= g.Wait(); err != nil {
 		return v1.GlobalRequire{}, err
 	}
 	return res, nil
 }
 
-func (s *webForwardingService) GetWebForwarding(ctx context.Context, id int64) (*model.WebForwarding, error) {
-	return s.webForwardingRepository.GetWebForwarding(ctx, id)
+func (s *webForwardingService) GetWebForwarding(ctx context.Context, req v1.GetForwardingRequest) (v1.WebForwardingDataRequest, error) {
+	var webForwarding model.WebForwarding
+	var backend model.WebForwardingRule
+	var err error
+	g, gCtx := errgroup.WithContext(ctx)
+	g.Go(func() error {
+		res, e := s.webForwardingRepository.GetWebForwarding(gCtx, int64(req.Id))
+		if e != nil {
+			// 直接返回错误,errgroup 会捕获它
+			return fmt.Errorf("GetWebForwarding failed: %w", e)
+		}
+		if res != nil {
+			webForwarding = *res
+		}
+		return nil
+	})
+
+	g.Go(func() error {
+		res, e := s.webForwardingRepository.GetWebForwardingByID(ctx, req.Id)
+		if e != nil {
+			return fmt.Errorf("GetWebForwardingByID failed: %w", e)
+		}
+		if res != nil {
+			backend = *res
+		}
+		return nil
+	})
+
+	if err := g.Wait(); err != nil {
+		return v1.WebForwardingDataRequest{}, err
+	}
+
+	portInt, err := cast.ToIntE(webForwarding.Port)
+	if err != nil {
+		return v1.WebForwardingDataRequest{}, err
+	}
+	return v1.WebForwardingDataRequest{
+		Id:                  webForwarding.Id,
+		WafWebId:            webForwarding.WafWebId,
+		Tag:                 webForwarding.Tag,
+		Port:                portInt,
+		Domain:              webForwarding.Domain,
+		CustomHost:          webForwarding.CustomHost,
+		WafWebLimitId:      webForwarding.WebLimitRuleId,
+		WafGatewayGroupId:   webForwarding.WafGatewayGroupId,
+		CcCount:             webForwarding.CcCount,
+		CcDuration:          webForwarding.CcDuration,
+		CcBlockCount:        webForwarding.CcBlockCount,
+		CcBlockDuration:     webForwarding.CcBlockDuration,
+		Cc4xxCount:          webForwarding.Cc4xxCount,
+		Cc4xxDuration:       webForwarding.Cc4xxDuration,
+		Cc4xxBlockCount:     webForwarding.Cc4xxBlockCount,
+		Cc4xxBlockDuration:  webForwarding.Cc4xxBlockDuration,
+		Cc5xxCount:          webForwarding.Cc5xxCount,
+		Cc5xxDuration:       webForwarding.Cc5xxDuration,
+		Cc5xxBlockCount:     webForwarding.Cc5xxBlockCount,
+		Cc5xxBlockDuration:  webForwarding.Cc5xxBlockDuration,
+		IsHttps:             webForwarding.IsHttps,
+		Comment:             webForwarding.Comment,
+		BackendList:         backend.BackendList,
+		AllowIpList:         backend.AllowIpList,
+		DenyIpList:          backend.DenyIpList,
+		AccessRule:          backend.AccessRule,
+	}, nil
 }
 
 // buildWafFormData 辅助函数,用于构建通用的 formData
-func (s *webForwardingService) buildWafFormData(req *v1.WebForwardingData, require v1.GlobalRequire) map[string]interface{} {
+func (s *webForwardingService) buildWafFormData(req *v1.WebForwardingDataSend, require v1.GlobalRequire) map[string]interface{} {
+	// 将BackendList序列化为JSON字符串
+	backendJSON, err := json.MarshalIndent(req.BackendList, "", " ")
+	var backendStr interface{}
+	if err != nil {
+		// 如果序列化失败,使用空数组
+		backendStr = "[]"
+	} else {
+		// 成功序列化后,使用JSON字符串
+		backendStr = string(backendJSON)
+	}
+
 	return map[string]interface{}{
-		"tag":                   req.Tag,
+		"waf_web_id":            req.WafWebId,
+		"tag":                   require.Tag,
 		"port":                  req.Port,
 		"domain":                req.Domain,
 		"custom_host":           req.CustomHost,
@@ -75,7 +173,7 @@ func (s *webForwardingService) buildWafFormData(req *v1.WebForwardingData, requi
 		"cc_5xx_duration":       req.Cc5xxDuration,
 		"cc_5xx_block_count":    req.Cc5xxBlockCount,
 		"cc_5xx_block_duration": req.Cc5xxBlockDuration,
-		"backend_list":          req.BackendList,
+		"backend":          	 backendStr,
 		"allow_ip_list":         req.AllowIpList,
 		"deny_ip_list":          req.DenyIpList,
 		"access_rule":           req.AccessRule,
@@ -86,11 +184,11 @@ func (s *webForwardingService) buildWafFormData(req *v1.WebForwardingData, requi
 
 // buildWebForwardingModel 辅助函数,用于构建通用的 WebForwarding 模型
 // ruleId 是从 WAF 系统获取的 ID
-func (s *webForwardingService) buildWebForwardingModel(req *v1.WebForwardingData,ruleId int, require v1.GlobalRequire) *model.WebForwarding {
+func (s *webForwardingService) buildWebForwardingModel(req *v1.WebForwardingDataRequest,ruleId int, require v1.GlobalRequire) *model.WebForwarding {
 	return &model.WebForwarding{
 		HostId: 			require.HostId,
-		RuleId:             ruleId,
-		Tag:                req.Tag,
+		WafWebId:           ruleId,
+		Tag:                require.Tag,
 		Port:               strconv.Itoa(req.Port),
 		Domain:             req.Domain,
 		CustomHost:         req.CustomHost,
@@ -113,58 +211,130 @@ func (s *webForwardingService) buildWebForwardingModel(req *v1.WebForwardingData
 	}
 }
 
-func (s *webForwardingService) AddWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) (string, error) {
+func (s *webForwardingService) buildWebRuleModel(reqData *v1.WebForwardingDataRequest, require v1.GlobalRequire, localDbId int) *model.WebForwardingRule {
+	return &model.WebForwardingRule{
+		Uid:         require.Uid,
+		HostId:      require.HostId,
+		WebId:       localDbId, // 关联到本地数据库的主记录 ID
+		BackendList: reqData.BackendList,
+		AllowIpList: reqData.AllowIpList,
+		DenyIpList:  reqData.DenyIpList,
+		AccessRule:  reqData.AccessRule,
+	}
+}
+
+func (s *webForwardingService) prepareWafData(ctx context.Context, req *v1.WebForwardingRequest) (v1.GlobalRequire, map[string]interface{}, error) {
+	// 1. 获取必要的全局信息
 	require, err := s.require(ctx, v1.GlobalRequire{
-		HostId: req.HostId,
-		Uid:    req.Uid,
+		HostId:  req.HostId,
+		Uid:     req.Uid,
 		Comment: req.WebForwardingData.Comment,
+		Domain:  req.WebForwardingData.Domain,
 	})
 	if err != nil {
-		return "", err
+		return v1.GlobalRequire{}, nil, err
+	}
+	if require.WafGatewayGroupId == 0 || require.LimitRuleId == 0 {
+		return v1.GlobalRequire{}, nil, fmt.Errorf("请先配置实例")
+	}
+
+	// 2. 将字符串切片拼接成字符串,用于 WAF API
+	allowIpListStr := strings.Join(req.WebForwardingData.AllowIpList, "\n")
+	denyIpListStr := strings.Join(req.WebForwardingData.DenyIpList, "\n")
+
+	// 3. 创建用于构建 WAF 表单的数据结构
+	formDataBase := v1.WebForwardingDataSend{
+		Tag:                 require.Tag,
+		WafWebId:            req.WebForwardingData.WafWebId,
+		WafGatewayGroupId:   require.WafGatewayGroupId,
+		WafWebLimitId:   require.LimitRuleId,
+		Port:                req.WebForwardingData.Port,
+		Domain:              req.WebForwardingData.Domain,
+		CustomHost:          req.WebForwardingData.CustomHost,
+		CcCount:             req.WebForwardingData.CcCount,
+		CcDuration:          req.WebForwardingData.CcDuration,
+		CcBlockCount:        req.WebForwardingData.CcBlockCount,
+		CcBlockDuration:     req.WebForwardingData.CcBlockDuration,
+		Cc4xxCount:          req.WebForwardingData.Cc4xxCount,
+		Cc4xxDuration:       req.WebForwardingData.Cc4xxDuration,
+		Cc4xxBlockCount:     req.WebForwardingData.Cc4xxBlockCount,
+		Cc4xxBlockDuration:  req.WebForwardingData.Cc4xxBlockDuration,
+		Cc5xxCount:          req.WebForwardingData.Cc5xxCount,
+		Cc5xxDuration:       req.WebForwardingData.Cc5xxDuration,
+		Cc5xxBlockCount:     req.WebForwardingData.Cc5xxBlockCount,
+		Cc5xxBlockDuration:  req.WebForwardingData.Cc5xxBlockDuration,
+		IsHttps:             req.WebForwardingData.IsHttps,
+		BackendList:         req.WebForwardingData.BackendList,
+		AllowIpList:         allowIpListStr,
+		DenyIpList:          denyIpListStr,
+		AccessRule:          req.WebForwardingData.AccessRule,
+		Comment:             req.WebForwardingData.Comment,
+	}
+
+	// 4. 构建 WAF 表单数据映射
+	formData := s.buildWafFormData(&formDataBase, require)
+
+	return require, formData, nil
+}
+
+func (s *webForwardingService) AddWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) error {
+	require, formData, err := s.prepareWafData(ctx, req)
+	if err != nil {
+		return err
+	}
+	err = s.wafformatter.validateWafPortCount(ctx, require.HostId)
+	if err != nil {
+		return err
 	}
-	formData := s.buildWafFormData(&req.WebForwardingData, require)
 	wafWebId, err := s.wafformatter.sendFormData(ctx, "admin/info/waf_web/new", "admin/new/waf_web", formData)
 	if err != nil {
-		return "", err
+		return err
 	}
+
 	webModel := s.buildWebForwardingModel(&req.WebForwardingData, wafWebId, require)
 
-	if err := s.webForwardingRepository.AddWebForwarding(ctx, webModel); err != nil {
-		return "", err
+	id, err := s.webForwardingRepository.AddWebForwarding(ctx, webModel)
+	if err != nil {
+		return err
+	}
+	webRuleModel := s.buildWebRuleModel(&req.WebForwardingData, require, id)
+	if _, err = s.webForwardingRepository.AddWebForwardingIps(ctx, *webRuleModel); err != nil {
+		return err
 	}
-	return "", nil
+	return nil
 }
 
-func (s *webForwardingService) EditWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) (string, error) {
-	require, err := s.require(ctx, v1.GlobalRequire{
-		HostId: req.HostId,
-		Uid:    req.Uid,
-		Comment: req.WebForwardingData.Comment,
-	})
+func (s *webForwardingService) EditWebForwarding(ctx context.Context, req *v1.WebForwardingRequest) error {
+	WafWebId, err := s.webForwardingRepository.GetWebForwardingWafWebIdById(ctx, req.Id)
 	if err != nil {
-		return "", err
+		return err
 	}
-	formData := s.buildWafFormData(&req.WebForwardingData, require)
-	_, err = s.wafformatter.sendFormData(ctx, "admin/info/waf_web/edit?&__goadmin_edit_pk="+strconv.Itoa(req.WebForwardingData.WafWebId), "admin/edit/waf_web", formData)
+	req.WebForwardingData.WafWebId = WafWebId
+	require, formData, err := s.prepareWafData(ctx, req)
 	if err != nil {
-		return "", err
+		return err
 	}
 
+	_, err = s.wafformatter.sendFormData(ctx, "admin/info/waf_web/edit?&__goadmin_edit_pk="+strconv.Itoa(req.WebForwardingData.WafWebId), "admin/edit/waf_web", formData)
+	if err != nil {
+		return err
+	}
 	webModel := s.buildWebForwardingModel(&req.WebForwardingData, req.WebForwardingData.WafWebId, require)
 	webModel.Id = req.Id
-
-
-	if err := s.webForwardingRepository.AddWebForwarding(ctx, webModel); err != nil {
-		return "", err
+	if err = s.webForwardingRepository.EditWebForwarding(ctx, webModel); err != nil {
+		return err
 	}
-
-	return "", nil
+	webRuleModel := s.buildWebRuleModel(&req.WebForwardingData, require, req.Id)
+	if err = s.webForwardingRepository.EditWebForwardingIps(ctx, *webRuleModel); err != nil {
+		return err
+	}
+	return nil
 }
 
-func (s *webForwardingService) DeleteWebForwarding(ctx context.Context, wafWebId int) (string, error) {
-	res, err := s.crawler.DeleteRule(ctx, wafWebId, "admin/delete/waf_web?page=1&__pageSize=10&__sort=waf_web_id&__sort_type=desc")
+func (s *webForwardingService) DeleteWebForwarding(ctx context.Context, wafWebId int) error {
+	_, err := s.crawler.DeleteRule(ctx, wafWebId, "admin/delete/waf_web?page=1&__pageSize=10&__sort=waf_web_id&__sort_type=desc")
 	if err != nil {
-		return "", err
+		return err
 	}
-	return res, nil
+	return nil
 }