소스 검색

feat(gameShield): 重构游戏盾公共 IP 逻辑

- 修改 GameShieldPublicIpService 接口,增加新方法以支持新逻辑- 实现游戏盾公共 IP 的分配和更新逻辑
- 添加中间表 GameShieldUserIp 以记录用户和 IP 的绑定关系
- 优化用户 IP 获取流程,支持分配新的 IP 或使用旧的 IP
- 调整格式化后端数据的逻辑,根据 Checked 字段决定是否使用代理地址
fusu 3 달 전
부모
커밋
d4ea914933

+ 1 - 1
api/v1/GameShield.go

@@ -5,7 +5,7 @@ type GameShieldSubmitRequest struct {
 	AppIp       string `json:"app_ip" form:"app_ip" binding:"required"`
 	AppName     string `json:"app_name" form:"app_name" binding:"required"`
 	RuleId      int    `json:"rule_id" form:"rule_id"`
-	Checked     bool   `json:"checked" form:"checked"`
+	Checked     int    `json:"checked" form:"checked"`
 	Id          int    `json:"id" form:"id"`
 	Uid         int    `json:"uid" form:"uid"`
 	SdkArgs     string `json:"sdk_args" form:"sdk_args"`

+ 16 - 0
api/v1/tcpLimit.go

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

+ 5 - 0
api/v1/udpLimit.go

@@ -0,0 +1,5 @@
+package v1
+
+type UdpLimitRequest struct {
+	Count int `json:"count"`
+}

+ 15 - 0
api/v1/webLimit.go

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

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

@@ -29,6 +29,9 @@ var repositorySet = wire.NewSet(
 	repository.NewWebForwardingRepository,
 	repository.NewTcpforwardingRepository,
 	repository.NewUdpForWardingRepository,
+	repository.NewGameShieldUserIpRepository,
+	repository.NewWebLimitRepository,
+	repository.NewTcpLimitRepository,
 )
 
 var serviceSet = wire.NewSet(
@@ -44,6 +47,9 @@ var serviceSet = wire.NewSet(
 	service.NewWebForwardingService,
 	service.NewTcpforwardingService,
 	service.NewUdpForWardingService,
+	service.NewGameShieldUserIpService,
+	service.NewWebLimitService,
+	service.NewTcpLimitService,
 )
 
 var handlerSet = wire.NewSet(
@@ -54,6 +60,9 @@ var handlerSet = wire.NewSet(
 	handler.NewWebForwardingHandler,
 	handler.NewTcpforwardingHandler,
 	handler.NewUdpForWardingHandler,
+	handler.NewGameShieldUserIpHandler,
+	handler.NewWebLimitHandler,
+	handler.NewTcpLimitHandler,
 )
 
 var jobSet = wire.NewSet(

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

@@ -38,7 +38,8 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 	parserService := service.NewParserService(serviceService)
 	crawlerService := service.NewCrawlerService(serviceService, parserService, viperViper)
 	gameShieldPublicIpRepository := repository.NewGameShieldPublicIpRepository(repositoryRepository)
-	gameShieldPublicIpService := service.NewGameShieldPublicIpService(serviceService, gameShieldPublicIpRepository)
+	gameShieldUserIpRepository := repository.NewGameShieldUserIpRepository(repositoryRepository)
+	gameShieldPublicIpService := service.NewGameShieldPublicIpService(serviceService, gameShieldPublicIpRepository, gameShieldUserIpRepository)
 	duedateService := service.NewDuedateService(serviceService, gameShieldRepository)
 	formatterService := service.NewFormatterService(serviceService, gameShieldPublicIpService)
 	requiredService := service.NewRequiredService(serviceService, crawlerService, viperViper)
@@ -47,13 +48,19 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 	webForwardingRepository := repository.NewWebForwardingRepository(repositoryRepository)
 	webForwardingService := service.NewWebForwardingService(serviceService, requiredService, webForwardingRepository, crawlerService, parserService)
 	webForwardingHandler := handler.NewWebForwardingHandler(handlerHandler, webForwardingService)
+	webLimitRepository := repository.NewWebLimitRepository(repositoryRepository)
+	webLimitService := service.NewWebLimitService(serviceService, webLimitRepository, requiredService, parserService, crawlerService)
+	webLimitHandler := handler.NewWebLimitHandler(handlerHandler, webLimitService)
 	tcpforwardingRepository := repository.NewTcpforwardingRepository(repositoryRepository)
 	tcpforwardingService := service.NewTcpforwardingService(serviceService, tcpforwardingRepository, parserService, requiredService, crawlerService)
 	tcpforwardingHandler := handler.NewTcpforwardingHandler(handlerHandler, tcpforwardingService)
 	udpForWardingRepository := repository.NewUdpForWardingRepository(repositoryRepository)
 	udpForWardingService := service.NewUdpForWardingService(serviceService, udpForWardingRepository, requiredService, parserService, crawlerService)
 	udpForWardingHandler := handler.NewUdpForWardingHandler(handlerHandler, udpForWardingService)
-	httpServer := server.NewHTTPServer(logger, viperViper, jwtJWT, userHandler, gameShieldHandler, webForwardingHandler, tcpforwardingHandler, udpForWardingHandler)
+	tcpLimitRepository := repository.NewTcpLimitRepository(repositoryRepository)
+	tcpLimitService := service.NewTcpLimitService(serviceService, tcpLimitRepository, requiredService, parserService, crawlerService)
+	tcpLimitHandler := handler.NewTcpLimitHandler(handlerHandler, tcpLimitService)
+	httpServer := server.NewHTTPServer(logger, viperViper, jwtJWT, userHandler, gameShieldHandler, webForwardingHandler, webLimitHandler, tcpforwardingHandler, udpForWardingHandler, tcpLimitHandler)
 	jobJob := job.NewJob(transaction, logger, sidSid)
 	userJob := job.NewUserJob(jobJob, userRepository)
 	jobServer := server.NewJobServer(logger, userJob)
@@ -64,11 +71,11 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 
 // wire.go:
 
-var repositorySet = wire.NewSet(repository.NewDB, repository.NewRepository, repository.NewTransaction, repository.NewUserRepository, repository.NewGameShieldRepository, repository.NewGameShieldPublicIpRepository, repository.NewWebForwardingRepository, repository.NewTcpforwardingRepository, repository.NewUdpForWardingRepository)
+var repositorySet = wire.NewSet(repository.NewDB, repository.NewRepository, repository.NewTransaction, repository.NewUserRepository, repository.NewGameShieldRepository, repository.NewGameShieldPublicIpRepository, repository.NewWebForwardingRepository, repository.NewTcpforwardingRepository, repository.NewUdpForWardingRepository, repository.NewGameShieldUserIpRepository, repository.NewWebLimitRepository, repository.NewTcpLimitRepository)
 
-var serviceSet = wire.NewSet(service.NewService, service.NewUserService, service.NewGameShieldService, service.NewCrawlerService, service.NewGameShieldPublicIpService, service.NewDuedateService, service.NewFormatterService, service.NewParserService, service.NewRequiredService, service.NewWebForwardingService, service.NewTcpforwardingService, service.NewUdpForWardingService)
+var serviceSet = wire.NewSet(service.NewService, service.NewUserService, service.NewGameShieldService, service.NewCrawlerService, service.NewGameShieldPublicIpService, service.NewDuedateService, service.NewFormatterService, service.NewParserService, service.NewRequiredService, service.NewWebForwardingService, service.NewTcpforwardingService, service.NewUdpForWardingService, service.NewGameShieldUserIpService, service.NewWebLimitService, service.NewTcpLimitService)
 
-var handlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler, handler.NewGameShieldHandler, handler.NewGameShieldPublicIpHandler, handler.NewWebForwardingHandler, handler.NewTcpforwardingHandler, handler.NewUdpForWardingHandler)
+var handlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler, handler.NewGameShieldHandler, handler.NewGameShieldPublicIpHandler, handler.NewWebForwardingHandler, handler.NewTcpforwardingHandler, handler.NewUdpForWardingHandler, handler.NewGameShieldUserIpHandler, handler.NewWebLimitHandler, handler.NewTcpLimitHandler)
 
 var jobSet = wire.NewSet(job.NewJob, job.NewUserJob)
 

+ 1 - 0
go.sum

@@ -234,6 +234,7 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe
 github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
 github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k=
 github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=

+ 3 - 3
internal/handler/gameshieldpublicip.go

@@ -11,11 +11,11 @@ type GameShieldPublicIpHandler struct {
 }
 
 func NewGameShieldPublicIpHandler(
-    handler *Handler,
-    gameShieldPublicIpService service.GameShieldPublicIpService,
+	handler *Handler,
+	gameShieldPublicIpService service.GameShieldPublicIpService,
 ) *GameShieldPublicIpHandler {
 	return &GameShieldPublicIpHandler{
-		Handler:      handler,
+		Handler:                   handler,
 		gameShieldPublicIpService: gameShieldPublicIpService,
 	}
 }

+ 1 - 1
internal/model/gameshield.go

@@ -13,7 +13,7 @@ type GameShield struct {
 	Uid            int
 	HostId         string
 	AppIp          string
-	Checked        bool
+	Checked        int
 }
 
 func (m *GameShield) TableName() string {

+ 4 - 4
internal/model/gameshieldpublicip.go

@@ -3,10 +3,10 @@ package model
 import "time"
 
 type GameShieldPublicIp struct {
-	Id         int    `gorm:"primarykey"`
-	Uid        int    `gorm:"null"`
-	Ip         string `gorm:"null"`
-	CreateTime time.Time
+	Id        int       `gorm:"primarykey"`
+	Ip        string    `gorm:"null"`
+	CreatedAt time.Time `gorm:"column:create_time"`
+	UpdatedAt time.Time `gorm:"column:update_time"`
 }
 
 func (m *GameShieldPublicIp) TableName() string {

+ 26 - 19
internal/repository/gameshieldpublicip.go

@@ -3,14 +3,14 @@ package repository
 import (
 	"context"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
-	"gorm.io/gorm/clause"
 )
 
 type GameShieldPublicIpRepository interface {
 	GetGameShieldPublicIp(ctx context.Context, id int64) (*model.GameShieldPublicIp, error)
-	GetGameShieldPublicUserIp(ctx context.Context, uid int) (string, error)
-	AddGameShieldPublicUserIp(ctx context.Context) (string, error)
-	UpdateGameShieldPublicUserIp(ctx context.Context, uid int, ip string) error
+	GetGameShieldPublicUserIp(ctx context.Context, id int) (string, error)
+	GetGameShieldPublicUserIpByNew(ctx context.Context) (model.GameShieldPublicIp, error)
+	UpdateGameShieldPublicUserIp(ctx context.Context, id int, updateTime string) error
+	GetGameShieldPublicUserIpByOld(ctx context.Context) (model.GameShieldPublicIp, error)
 }
 
 func NewGameShieldPublicIpRepository(
@@ -31,33 +31,40 @@ func (r *gameShieldPublicIpRepository) GetGameShieldPublicIp(ctx context.Context
 	return &gameShieldPublicIp, nil
 }
 
-func (r *gameShieldPublicIpRepository) GetGameShieldPublicUserIp(ctx context.Context, uid int) (string, error) {
+func (r *gameShieldPublicIpRepository) GetGameShieldPublicUserIp(ctx context.Context, id int) (string, error) {
 	var ip string
-	if err := r.DB(ctx).Model(&model.GameShieldPublicIp{}).Select("ip").Where("uid = ?", uid).Scan(&ip).Error; err != nil {
+	if err := r.DB(ctx).Model(&model.GameShieldPublicIp{}).Select("ip").Where("id = ?", id).Scan(&ip).Error; err != nil {
 		return "", err
 	}
 	return ip, nil
 }
 
-func (r *gameShieldPublicIpRepository) AddGameShieldPublicUserIp(ctx context.Context) (string, error) {
-	var ip string
+func (r *gameShieldPublicIpRepository) GetGameShieldPublicUserIpByNew(ctx context.Context) (model.GameShieldPublicIp, error) {
+	var res model.GameShieldPublicIp
 	if err := r.DB(ctx).Model(&model.GameShieldPublicIp{}).Select("ip").
-		Where("uid IS NULL").
-		Order("RAND()").
-		Clauses(clause.Locking{Strength: "UPDATE"}).
-		Limit(1).
-		Scan(&ip).Error; err != nil {
-		return "", err
+		Where("update_time IS NULL").
+		Order("id ASC").
+		Scan(&res).Error; err != nil {
+		return model.GameShieldPublicIp{}, err
 	}
-	return ip, nil
+	return res, nil
 }
 
-func (r *gameShieldPublicIpRepository) UpdateGameShieldPublicUserIp(ctx context.Context, uid int, ip string) error {
+func (r *gameShieldPublicIpRepository) UpdateGameShieldPublicUserIp(ctx context.Context, id int, updateTime string) error {
 	if err := r.DB(ctx).Model(&model.GameShieldPublicIp{}).
-		Where("uid IS NULL").
-		Where("ip = ?", ip).
-		Update("uid", uid).Error; err != nil {
+		Where("id = ?", id).
+		Update("update_time", updateTime).Error; err != nil {
 		return err
 	}
 	return nil
 }
+
+func (r *gameShieldPublicIpRepository) GetGameShieldPublicUserIpByOld(ctx context.Context) (model.GameShieldPublicIp, error) {
+	var res model.GameShieldPublicIp
+	if err := r.DB(ctx).Model(&model.GameShieldPublicIp{}).
+		Order("update_time ASC").
+		Scan(&res).Error; err != nil {
+		return model.GameShieldPublicIp{}, err
+	}
+	return res, nil
+}

+ 9 - 0
internal/server/http.go

@@ -21,8 +21,11 @@ func NewHTTPServer(
 	userHandler *handler.UserHandler,
 	gameShieldHandler *handler.GameShieldHandler,
 	webForwardingHandler *handler.WebForwardingHandler,
+	weblimitHandler *handler.WebLimitHandler,
 	tcpForwardingHandler *handler.TcpforwardingHandler,
 	udpForwardingHandler *handler.UdpForWardingHandler,
+	tcpLimitHandler *handler.TcpLimitHandler,
+
 ) *http.Server {
 	gin.SetMode(gin.DebugMode)
 	s := http.NewServer(
@@ -69,12 +72,18 @@ func NewHTTPServer(
 			noAuthRouter.POST("/webForward/add", webForwardingHandler.AddWebForwarding)
 			noAuthRouter.POST("/webForward/edit", webForwardingHandler.EditWebForwarding)
 			noAuthRouter.POST("/webForward/delete", webForwardingHandler.DeleteWebForwarding)
+			noAuthRouter.POST("/webLimit/add", weblimitHandler.AddWebLimit)
+			noAuthRouter.POST("/webLimit/edit", weblimitHandler.EditWebLimit)
+			noAuthRouter.POST("/webLimit/delete", weblimitHandler.DeleteWebLimit)
 			noAuthRouter.POST("/tcpForward/add", tcpForwardingHandler.AddTcpForwarding)
 			noAuthRouter.POST("/tcpForward/edit", tcpForwardingHandler.EditTcpForwarding)
 			noAuthRouter.POST("/tcpForward/delete", tcpForwardingHandler.DeleteTcpForwarding)
 			noAuthRouter.POST("/udpForward/add", udpForwardingHandler.AddUdpForWarding)
 			noAuthRouter.POST("/udpForward/edit", udpForwardingHandler.EditUdpForWarding)
 			noAuthRouter.POST("/udpForward/delete", udpForwardingHandler.DeleteUdpForWarding)
+			noAuthRouter.POST("/tcpLimit/add", tcpLimitHandler.AddTcpLimit)
+			noAuthRouter.POST("/tcpLimit/edit", tcpLimitHandler.EditTcpLimit)
+			noAuthRouter.POST("/tcpLimit/delete", tcpLimitHandler.DeleteTcpLimit)
 		}
 		// Non-strict permission routing group
 		noStrictAuthRouter := v1.Group("/").Use(middleware.NoStrictAuth(jwt, logger))

+ 7 - 11
internal/service/formatter.go

@@ -5,6 +5,7 @@ import (
 	"encoding/json"
 	"fmt"
 	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+
 	"github.com/spf13/cast"
 	"strconv"
 )
@@ -32,13 +33,9 @@ type formatterService struct {
 func (service *formatterService) FormatBackendData(ctx context.Context, req *v1.GameShieldSubmitRequest) (string, error) {
 	output := make(map[string]map[string]interface{})
 
-	var userIp string
-	if !req.Checked {
-		var err error
-		userIp, err = service.gameShieldPublicIpService.GetUserIp(ctx, req.Uid)
-		if err != nil {
-			return "", err
-		}
+	userIp, err := service.gameShieldPublicIpService.GetUserIp(ctx, req.Uid)
+	if err != nil {
+		return "", err
 	}
 	if len(req.Data) == 0 {
 		return "", fmt.Errorf("data is required")
@@ -69,11 +66,10 @@ func (service *formatterService) FormatBackendData(ctx context.Context, req *v1.
 		}
 
 		if innerMap["protocol"] != "udp" {
-			if req.Checked {
-				itemMap["proxy_addr"] = fmt.Sprintf("%s:%s", innerMap["source_machineIP"], "32353")
-			} else {
-				itemMap["proxy_addr"] = userIp + ":32353"
+			if req.Checked == 1 {
+				itemMap["agent_addr"] = fmt.Sprintf("%s:%s", innerMap["source_machineIP"], "23350")
 			}
+			itemMap["proxy_addr"] = userIp + ":32353"
 		} else {
 			itemMap["proxy_addr"] = ""
 			itemMap["udp_session_timeout"] = "300s"

+ 1 - 1
internal/service/gameshield.go

@@ -89,7 +89,7 @@ func (service *gameShieldService) SubmitGameShield(ctx context.Context, req *v1.
 	}
 	formData := map[string]interface{}{
 		"app_name":         req.AppName,
-		"gateway_group_id": 2,
+		"gateway_group_id": 4,
 		"backend":          require.Backend,
 		"expired_at":       require.ExpiredAt,
 		"max_device_count": 0,

+ 41 - 20
internal/service/gameshieldpublicip.go

@@ -3,17 +3,18 @@ package service
 import (
 	"context"
 	"errors"
-	"fmt"
 	"github.com/go-nunu/nunu-layout-advanced/internal/model"
 	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
+
 	"gorm.io/gorm"
+	"time"
 )
 
 type GameShieldPublicIpService interface {
 	GetGameShieldPublicIp(ctx context.Context, id int64) (*model.GameShieldPublicIp, error)
 	GetGameShieldPublicUserIp(ctx context.Context, uid int) (string, error)
-	AddGameShieldPublicUserIp(ctx context.Context) (string, error)
-	UpdateGameShieldPublicUserIp(ctx context.Context, uid int, ip string) error
+	GetGameShieldPublicUserIpByNew(ctx context.Context) (model.GameShieldPublicIp, error)
+	UpdateGameShieldPublicUserIp(ctx context.Context, uid int, updateTime string) error
 
 	GetUserIp(ctx context.Context, uid int) (string, error)
 }
@@ -21,16 +22,19 @@ type GameShieldPublicIpService interface {
 func NewGameShieldPublicIpService(
 	service *Service,
 	gameShieldPublicIpRepository repository.GameShieldPublicIpRepository,
+	gameShieldUserIpRepository repository.GameShieldUserIpRepository,
 ) GameShieldPublicIpService {
 	return &gameShieldPublicIpService{
 		Service:                      service,
 		gameShieldPublicIpRepository: gameShieldPublicIpRepository,
+		gameShieldUserIpRepository:   gameShieldUserIpRepository,
 	}
 }
 
 type gameShieldPublicIpService struct {
 	*Service
 	gameShieldPublicIpRepository repository.GameShieldPublicIpRepository
+	gameShieldUserIpRepository   repository.GameShieldUserIpRepository
 }
 
 func (s *gameShieldPublicIpService) GetGameShieldPublicIp(ctx context.Context, id int64) (*model.GameShieldPublicIp, error) {
@@ -38,53 +42,70 @@ func (s *gameShieldPublicIpService) GetGameShieldPublicIp(ctx context.Context, i
 }
 
 func (s *gameShieldPublicIpService) GetGameShieldPublicUserIp(ctx context.Context, uid int) (string, error) {
-	ip, err := s.gameShieldPublicIpRepository.GetGameShieldPublicUserIp(ctx, uid)
+	ipId, err := s.gameShieldUserIpRepository.GetGameShieldUserIpByUid(ctx, int64(uid))
+	if err != nil {
+		return "", err
+	}
+	if ipId == 0 {
+		return "", gorm.ErrRecordNotFound
+	}
+	ip, err := s.gameShieldPublicIpRepository.GetGameShieldPublicUserIp(ctx, ipId)
 	if err != nil {
-		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return "", fmt.Errorf("该用户未绑定IP")
-		}
 		return "", err
 	}
 	return ip, nil
 }
 
-func (s *gameShieldPublicIpService) AddGameShieldPublicUserIp(ctx context.Context) (string, error) {
-	ip, err := s.gameShieldPublicIpRepository.AddGameShieldPublicUserIp(ctx)
+func (s *gameShieldPublicIpService) GetGameShieldPublicUserIpByNew(ctx context.Context) (model.GameShieldPublicIp, error) {
+	res, err := s.gameShieldPublicIpRepository.GetGameShieldPublicUserIpByNew(ctx)
 	if err != nil {
-		if errors.Is(err, gorm.ErrRecordNotFound) {
-			return "", fmt.Errorf("没有足够的IP: %w", err)
-		}
-		return "", err
+		return model.GameShieldPublicIp{}, err
 	}
-	return ip, nil
+	return res, nil
 }
 
-func (s *gameShieldPublicIpService) UpdateGameShieldPublicUserIp(ctx context.Context, uid int, ip string) error {
-	if err := s.gameShieldPublicIpRepository.UpdateGameShieldPublicUserIp(ctx, uid, ip); err != nil {
+func (s *gameShieldPublicIpService) UpdateGameShieldPublicUserIp(ctx context.Context, id int, updateTime string) error {
+	if err := s.gameShieldPublicIpRepository.UpdateGameShieldPublicUserIp(ctx, id, updateTime); err != nil {
 		return err
 	}
 	return nil
 }
 
 func (s *gameShieldPublicIpService) GetUserIp(ctx context.Context, uid int) (string, error) {
+	var ip string
+
 	ip, err := s.GetGameShieldPublicUserIp(ctx, uid)
 	if err == nil {
 		return ip, nil
 	}
-
+	var ipId int
 	// 如果不是记录未找到,直接返回错误
 	if !errors.Is(err, gorm.ErrRecordNotFound) {
 		return "", err
 	}
 
 	// 分配新 IP(可能失败)
-	ip, err = s.AddGameShieldPublicUserIp(ctx)
+	res, err := s.GetGameShieldPublicUserIpByNew(ctx)
 	if err != nil {
 		return "", err
 	}
-
+	ip = res.Ip
+	ipId = res.Id
+	if len(ip) == 0 {
+		res, err := s.gameShieldPublicIpRepository.GetGameShieldPublicUserIpByOld(ctx)
+		if err != nil {
+			return "", err
+		}
+		ip = res.Ip
+		ipId = res.Id
+	}
 	// 更新绑定关系
-	if err := s.UpdateGameShieldPublicUserIp(ctx, uid, ip); err != nil {
+	var updateTime string
+	updateTime = time.Now().Format("2006-01-02 15:04:05")
+	if err := s.UpdateGameShieldPublicUserIp(ctx, ipId, updateTime); err != nil {
+		return "", err
+	}
+	if err := s.gameShieldUserIpRepository.AddGameShieldUserIp(ctx, &model.GameShieldUserIp{Uid: uid, IpId: ipId}); err != nil {
 		return "", err
 	}
 	return ip, nil