浏览代码

feat(tcp/udp forwarding): 添加 proxy 功能支持

- 在 TcpForwarding 和 UdpForwarding 模型中添加 Proxy 字段
- 实现 ProxyService 接口,提供反向代理相关功能
- 在 TcpForwardingService 和 UdpForwardingService 中集成 ProxyService- 添加创建和编辑时处理 proxy 的逻辑
fusu 4 周之前
父节点
当前提交
88dbfdfeec

+ 1 - 0
api/v1/tcpForwarding.go

@@ -8,6 +8,7 @@ type TcpForwardingDataRequest struct {
 	Port              string   `form:"port" json:"port" validate:"required,numeric,min=1,max=65535"`
 	BackendList       []string `form:"backendList" json:"backendList" validate:"required,dive,hostport"`
 	Comment           string   `form:"comment" json:"comment" validate:"max=50"`
+	Proxy             bool     `form:"proxy" json:"proxy" default:"false"`
 }
 
 type DeleteTcpForwardingRequest struct {

+ 34 - 0
internal/model/proxy.go

@@ -0,0 +1,34 @@
+package model
+
+type Proxy struct {
+	Id                       int64  `gorm:"column:id"`
+	AdminId                  int64  `gorm:"column:adminId"`
+	UserId                   int64  `gorm:"column:userId"`
+	TemplateId               int64  `gorm:"column:templateId"`
+	IsOn                     int64  `gorm:"column:isOn"`
+	Scheduling               string `gorm:"column:scheduling"`
+	PrimaryOrigins           string `gorm:"column:primaryOrigins"`
+	BackupOrigins            string `gorm:"column:backupOrigins"`
+	StripPrefix              string `gorm:"column:stripPrefix"`
+	RequestHostType          int32  `gorm:"column:requestHostType"`
+	RequestHost              string `gorm:"column:requestHost"`
+	RequestHostExcludingPort bool   `gorm:"column:requestHostExcludingPort"`
+	RequestURI               string `gorm:"column:requestURI"`
+	AutoFlush                bool   `gorm:"column:autoFlush"`
+	AddHeaders               string `gorm:"column:addHeaders"`
+	State                    int64  `gorm:"column:state"`
+	CreatedAt                int64  `gorm:"column:createdAt"`
+	ConnTimeout              string `gorm:"column:connTimeout"`
+	ReadTimeout              string `gorm:"column:readTimeout"`
+	IdleTimeout              string `gorm:"column:idleTimeout"`
+	MaxConns                 int64  `gorm:"column:maxConns"`
+	MaxIdleConns             int64  `gorm:"column:maxIdleConns"`
+	ProxyProtocol            string `gorm:"column:proxyProtocol"`
+	FollowRedirects          bool   `gorm:"column:followRedirects"`
+	Retry50X                 bool   `gorm:"column:retry50X"`
+	Retry40X                 bool   `gorm:"column:retry40X"`
+}
+
+func (m *Proxy) TableName() string {
+    return "cloud_reverse_proxies"
+}

+ 1 - 0
internal/model/tcpforwarding.go

@@ -11,6 +11,7 @@ type Tcpforwarding struct {
 	CdnWebId            int `gorm:"not null"`
 	Port                 string `gorm:"not null"`
 	Comment              string `gorm:"null"`
+	Proxy 				bool `gorm:"not null"`
 	CreatedAt            time.Time
 	UpdatedAt            time.Time
 }

+ 1 - 0
internal/model/udpforwarding.go

@@ -11,6 +11,7 @@ type UdpForWarding struct {
 	CdnWebId            int `gorm:"not null"`
 	Port                 string `gorm:"not null"`
 	Comment              string `gorm:"null"`
+	Proxy 				bool `gorm:"not null"`
 	CreatedAt            time.Time
 	UpdatedAt            time.Time
 }

+ 57 - 0
internal/repository/proxy.go

@@ -0,0 +1,57 @@
+package repository
+
+import (
+	"context"
+	"encoding/json"
+	"github.com/go-nunu/nunu-layout-advanced/internal/model"
+)
+
+type ProxyRepository interface {
+	// 获取反向代理ID
+	GetProxyId(ctx context.Context, cndWebId int64) (int64, error)
+	GetProxy(ctx context.Context, id int64) (*model.Proxy, error)
+}
+
+func NewProxyRepository(
+	repository *Repository,
+) ProxyRepository {
+	return &proxyRepository{
+		Repository: repository,
+	}
+}
+
+type proxyRepository struct {
+	*Repository
+}
+
+// 获取反向代理ID
+func (r *proxyRepository) GetProxyId(ctx context.Context, cndWebId int64) (int64, error) {
+	type ReverseProxy struct {
+		IsOn bool
+		IsPrior bool
+		ReverseProxyId int64
+	}
+	var reverseProxyByte string
+	if err := r.DBWithName(ctx,"cdn").WithContext(ctx).Table("cloud_servers").Where("id = ?", cndWebId).Select("reverseProxy").Scan(&reverseProxyByte).Error; err != nil {
+		return 0, err
+	}
+	var proxyData ReverseProxy
+	if reverseProxyByte != "" {
+		if err := json.Unmarshal([]byte(reverseProxyByte), &proxyData); err != nil {
+			return 0, err
+		}
+		return proxyData.ReverseProxyId, nil
+	}
+
+	return 0, nil
+
+}
+
+func (r *proxyRepository) GetProxy(ctx context.Context, id int64) (*model.Proxy, error) {
+	var res model.Proxy
+	if err := r.DBWithName(ctx,"cdn").Table("cloud_reverse_proxies").Where("id = ?", id).First(&res).Error; err != nil {
+		return nil, err
+	}
+	return &res, nil
+
+}

+ 4 - 1
internal/repository/tcpforwarding.go

@@ -56,7 +56,10 @@ func (r *tcpforwardingRepository) AddTcpforwarding(ctx context.Context, req *mod
 }
 
 func (r *tcpforwardingRepository) EditTcpforwarding(ctx context.Context, req *model.Tcpforwarding) error {
-	if err := r.db.Updates(req).Error; err != nil {
+	data := map[string]interface{}{
+		"proxy" : req.Proxy,
+	}
+	if err := r.db.Updates(req).Updates(data).Error; err != nil {
 		return err
 	}
 	return nil

+ 4 - 1
internal/repository/udpforwarding.go

@@ -57,7 +57,10 @@ func (r *udpForWardingRepository) AddUdpForwarding(ctx context.Context, req *mod
 }
 
 func (r *udpForWardingRepository) EditUdpForwarding(ctx context.Context, req *model.UdpForWarding) error {
-	if err := r.db.Updates(req).Error; err != nil {
+	data := map[string]interface{}{
+		"proxy" : req.Proxy,
+	}
+	if err := r.db.Updates(req).Updates(data).Error; err != nil {
 		return err
 	}
 	return nil

+ 1 - 0
internal/repository/webforwarding.go

@@ -65,6 +65,7 @@ func (r *webForwardingRepository) EditWebForwarding(ctx context.Context, req *mo
 	forceUpdateFields := map[string]interface{}{
 		"domain": req.Domain,
 		"is_https": req.IsHttps,
+		"proxy" : req.Proxy,
 	}
 	// 核心逻辑:
 	// 1. Model(req): 定位要更新的记录。

+ 90 - 0
internal/service/proxy.go

@@ -0,0 +1,90 @@
+package service
+
+import (
+	"context"
+	"encoding/json"
+	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"
+)
+
+type ProxyService interface {
+	GetProxyId (ctx context.Context, cdnWebId int64) (int64, error)
+	GetProxy (ctx context.Context, id int64) (*model.Proxy, error)
+	GetProxyData (ctx context.Context, cdnWebId int64) (*model.Proxy, error)
+	EditProxy (ctx context.Context, cdnWebId int64, req v1.ProxyProtocolJSON) error
+}
+func NewProxyService(
+    service *Service,
+	proxyRep repository.ProxyRepository,
+	cdn CdnService,
+
+) ProxyService {
+	return &proxyService{
+		Service:        service,
+		proxyRep: proxyRep,
+		cdn: cdn,
+	}
+}
+
+type proxyService struct {
+	*Service
+	proxyRep repository.ProxyRepository
+	cdn CdnService
+}
+
+func (s *proxyService) GetProxyId (ctx context.Context, cdnWebId int64) (int64, error) {
+	id, err := s.proxyRep.GetProxyId(ctx, cdnWebId)
+	if err != nil {
+		return 0, err
+	}
+	return id, nil
+}
+
+func (s *proxyService) GetProxy (ctx context.Context, id int64) (*model.Proxy, error) {
+	res, err := s.proxyRep.GetProxy(ctx, id)
+	if err != nil {
+		return nil, err
+	}
+	return res, nil
+}
+
+func (s *proxyService) GetProxyData (ctx context.Context, cdnWebId int64) (*model.Proxy, error) {
+	id,err := s.proxyRep.GetProxyId(ctx, cdnWebId)
+	if err != nil {
+		return nil, err
+	}
+	data, err := s.proxyRep.GetProxy(ctx, id)
+	if err != nil {
+		return nil, err
+	}
+	return data, nil
+}
+
+func (r *proxyService) EditProxy(ctx context.Context,cdnWebId int64, req v1.ProxyProtocolJSON) error {
+	proxyData, err := r.GetProxyData(ctx, cdnWebId)
+	if err != nil {
+		return err
+	}
+	var reqJson []byte
+	reqJson, err = json.Marshal(req)
+	if err != nil {
+		return err
+	}
+	if err := r.cdn.EditProxy(ctx, v1.Proxy{
+		ReverseProxyId: proxyData.Id,
+		RequestHostType: proxyData.RequestHostType,
+		RequestHost: proxyData.RequestHost,
+		RequestHostExcludingPort: proxyData.RequestHostExcludingPort,
+		RequestURI: proxyData.RequestURI,
+		StripPrefix: proxyData.StripPrefix,
+		AutoFlush: proxyData.AutoFlush,
+		ProxyProtocolJSON: reqJson,
+		FollowRedirects: proxyData.FollowRedirects,
+		Retry50X: proxyData.Retry50X,
+		Retry40X: proxyData.Retry40X,
+	}); err != nil {
+		return err
+	}
+	return nil
+}

+ 25 - 1
internal/service/tcpforwarding.go

@@ -31,6 +31,7 @@ func NewTcpforwardingService(
 	hostRep repository.HostRepository,
 	wafformatter WafFormatterService,
 	cdn CdnService,
+	proxy ProxyService,
 ) TcpforwardingService {
 	return &tcpforwardingService{
 		Service:                 service,
@@ -42,6 +43,7 @@ func NewTcpforwardingService(
 		hostRep:                 hostRep,
 		wafformatter:            wafformatter,
 		cdn:                     cdn,
+		proxy:                   proxy,
 	}
 }
 
@@ -55,6 +57,7 @@ type tcpforwardingService struct {
 	hostRep      repository.HostRepository
 	wafformatter WafFormatterService
 	cdn CdnService
+	proxy ProxyService
 }
 
 
@@ -196,7 +199,16 @@ func (s *tcpforwardingService) AddTcpForwarding(ctx context.Context, req *v1.Tcp
 		}
 	}
 
-
+	// 开启proxy
+	if req.TcpForwardingData.Proxy {
+		err = s.proxy.EditProxy(ctx,tcpId, v1.ProxyProtocolJSON{
+			IsOn: true,
+			Version: 1,
+		})
+		if err != nil {
+			return err
+		}
+	}
 
 	tcpModel := s.buildTcpForwardingModel(&req.TcpForwardingData, int(tcpId), require)
 
@@ -258,6 +270,18 @@ func (s *tcpforwardingService) EditTcpForwarding(ctx context.Context, req *v1.Tc
 		}
 	}
 
+
+	//修改Proxy
+	if oldData.Proxy != req.TcpForwardingData.Proxy {
+		err = s.proxy.EditProxy(ctx, int64(oldData.CdnWebId), v1.ProxyProtocolJSON{
+			IsOn:    req.TcpForwardingData.Proxy,
+			Version: 1,
+		})
+		if err != nil {
+			return err
+		}
+	}
+
 	// 异步任务:将IP添加到白名单
 	ipData, err := s.tcpforwardingRepository.GetTcpForwardingIpsByID(ctx, req.TcpForwardingData.Id)
 	if err != nil {