Browse Source

feat(service): 增加主机配置获取功能

- 新增 HostService 接口和 hostService 结构体
- 实现 GetHost 和 GetGameShieldConfig 方法
- 添加主机配置相关模型和仓库- 更新 FormatterService 以使用新的主机配置信息
fusu 2 months ago
parent
commit
acb9496c5c

+ 1 - 1
api/v1/GameShield.go

@@ -1,7 +1,7 @@
 package v1
 package v1
 
 
 type GameShieldSubmitRequest struct {
 type GameShieldSubmitRequest struct {
-	HostId  string `json:"host_id" form:"host_id" binding:"required"`
+	HostId  int    `json:"host_id" form:"host_id" binding:"required"`
 	AppName string `json:"app_name" form:"app_name" binding:"required"`
 	AppName string `json:"app_name" form:"app_name" binding:"required"`
 	RuleId  int    `json:"rule_id" form:"rule_id"`
 	RuleId  int    `json:"rule_id" form:"rule_id"`
 	Id      int    `json:"id" form:"id"`
 	Id      int    `json:"id" form:"id"`

+ 1 - 1
api/v1/gameShieldBackend.go

@@ -12,7 +12,7 @@ type GameShieldBackendRequest struct {
 	SdkPort         string    `json:"sdk_port" form:"sdk_port"`
 	SdkPort         string    `json:"sdk_port" form:"sdk_port"`
 	SdkIp           string    `json:"sdk_ip" form:"sdk_ip"`
 	SdkIp           string    `json:"sdk_ip" form:"sdk_ip"`
 	Type            string    `json:"type" form:"type"`
 	Type            string    `json:"type" form:"type"`
-	MaxBandwidth    string    `json:"max_bandwidth" form:"max_bandwidth"`
+	MaxBandwidth    int       `json:"max_bandwidth" form:"max_bandwidth"`
 	Checked         string    `json:"checked" form:"checked"`
 	Checked         string    `json:"checked" form:"checked"`
 	CreatedAt       time.Time `json:"created_at" form:"created_at"`
 	CreatedAt       time.Time `json:"created_at" form:"created_at"`
 	UpdatedAt       time.Time `json:"updated_at" form:"updated_at"`
 	UpdatedAt       time.Time `json:"updated_at" form:"updated_at"`

+ 24 - 0
api/v1/host.go

@@ -0,0 +1,24 @@
+package v1
+
+type HostConfigOption struct {
+	RelID    int
+	ConfigID int
+	OptionID int
+}
+
+type ProductConfigOption struct {
+	ID         int
+	OptionName string
+}
+
+type ProductConfigOptionSub struct {
+	ID         int
+	OptionName string
+}
+
+type GameShieldHostBackendConfigResponse struct {
+	RuleEntriesCount    int64
+	SourceMachinesCount int64
+	MaxBandwidthCount   int64
+	OnlineDevicesCount  int64
+}

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

@@ -37,6 +37,7 @@ var repositorySet = wire.NewSet(
 	repository.NewUdpLimitRepository,
 	repository.NewUdpLimitRepository,
 	repository.NewGameShieldBackendRepository,
 	repository.NewGameShieldBackendRepository,
 	repository.NewGameShieldSdkIpRepository,
 	repository.NewGameShieldSdkIpRepository,
+	repository.NewHostRepository,
 )
 )
 
 
 var serviceSet = wire.NewSet(
 var serviceSet = wire.NewSet(
@@ -58,6 +59,7 @@ var serviceSet = wire.NewSet(
 	service.NewUdpLimitService,
 	service.NewUdpLimitService,
 	service.NewGameShieldBackendService,
 	service.NewGameShieldBackendService,
 	service.NewGameShieldSdkIpService,
 	service.NewGameShieldSdkIpService,
+	service.NewHostService,
 )
 )
 
 
 var handlerSet = wire.NewSet(
 var handlerSet = wire.NewSet(
@@ -74,6 +76,7 @@ var handlerSet = wire.NewSet(
 	handler.NewUdpLimitHandler,
 	handler.NewUdpLimitHandler,
 	handler.NewGameShieldBackendHandler,
 	handler.NewGameShieldBackendHandler,
 	handler.NewGameShieldSdkIpHandler,
 	handler.NewGameShieldSdkIpHandler,
+	handler.NewHostHandler,
 )
 )
 
 
 var jobSet = wire.NewSet(
 var jobSet = wire.NewSet(

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

@@ -45,13 +45,15 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 	gameShieldUserIpRepository := repository.NewGameShieldUserIpRepository(repositoryRepository)
 	gameShieldUserIpRepository := repository.NewGameShieldUserIpRepository(repositoryRepository)
 	gameShieldPublicIpService := service.NewGameShieldPublicIpService(serviceService, gameShieldPublicIpRepository, gameShieldUserIpRepository)
 	gameShieldPublicIpService := service.NewGameShieldPublicIpService(serviceService, gameShieldPublicIpRepository, gameShieldUserIpRepository)
 	duedateService := service.NewDuedateService(serviceService, gameShieldRepository)
 	duedateService := service.NewDuedateService(serviceService, gameShieldRepository)
-	formatterService := service.NewFormatterService(serviceService, gameShieldPublicIpService)
+	gameShieldBackendRepository := repository.NewGameShieldBackendRepository(repositoryRepository)
+	hostRepository := repository.NewHostRepository(repositoryRepository)
+	hostService := service.NewHostService(serviceService, hostRepository)
+	formatterService := service.NewFormatterService(serviceService, gameShieldPublicIpService, gameShieldBackendRepository, hostService)
 	requiredService := service.NewRequiredService(serviceService, crawlerService, viperViper)
 	requiredService := service.NewRequiredService(serviceService, crawlerService, viperViper)
 	gameShieldSdkIpRepository := repository.NewGameShieldSdkIpRepository(repositoryRepository)
 	gameShieldSdkIpRepository := repository.NewGameShieldSdkIpRepository(repositoryRepository)
 	gameShieldSdkIpService := service.NewGameShieldSdkIpService(serviceService, gameShieldSdkIpRepository)
 	gameShieldSdkIpService := service.NewGameShieldSdkIpService(serviceService, gameShieldSdkIpRepository)
 	gameShieldService := service.NewGameShieldService(serviceService, gameShieldRepository, crawlerService, gameShieldPublicIpService, duedateService, formatterService, parserService, requiredService, viperViper, gameShieldSdkIpService)
 	gameShieldService := service.NewGameShieldService(serviceService, gameShieldRepository, crawlerService, gameShieldPublicIpService, duedateService, formatterService, parserService, requiredService, viperViper, gameShieldSdkIpService)
 	gameShieldHandler := handler.NewGameShieldHandler(handlerHandler, gameShieldService, crawlerService)
 	gameShieldHandler := handler.NewGameShieldHandler(handlerHandler, gameShieldService, crawlerService)
-	gameShieldBackendRepository := repository.NewGameShieldBackendRepository(repositoryRepository)
 	gameShieldBackendService := service.NewGameShieldBackendService(serviceService, gameShieldBackendRepository, gameShieldRepository, crawlerService, gameShieldPublicIpService, duedateService, formatterService, parserService, requiredService, viperViper, gameShieldService)
 	gameShieldBackendService := service.NewGameShieldBackendService(serviceService, gameShieldBackendRepository, gameShieldRepository, crawlerService, gameShieldPublicIpService, duedateService, formatterService, parserService, requiredService, viperViper, gameShieldService)
 	gameShieldBackendHandler := handler.NewGameShieldBackendHandler(handlerHandler, gameShieldBackendService)
 	gameShieldBackendHandler := handler.NewGameShieldBackendHandler(handlerHandler, gameShieldBackendService)
 	webForwardingRepository := repository.NewWebForwardingRepository(repositoryRepository)
 	webForwardingRepository := repository.NewWebForwardingRepository(repositoryRepository)
@@ -83,11 +85,11 @@ func NewWire(viperViper *viper.Viper, logger *log.Logger) (*app.App, func(), err
 
 
 // wire.go:
 // wire.go:
 
 
-var repositorySet = wire.NewSet(repository.NewDB, repository.NewRepository, repository.NewTransaction, repository.NewUserRepository, repository.NewGameShieldRepository, repository.NewGameShieldPublicIpRepository, repository.NewWebForwardingRepository, repository.NewTcpforwardingRepository, repository.NewUdpForWardingRepository, repository.NewGameShieldUserIpRepository, repository.NewWebLimitRepository, repository.NewTcpLimitRepository, repository.NewUdpLimitRepository, repository.NewGameShieldBackendRepository, repository.NewGameShieldSdkIpRepository)
+var repositorySet = wire.NewSet(repository.NewDB, repository.NewRepository, repository.NewTransaction, repository.NewUserRepository, repository.NewGameShieldRepository, repository.NewGameShieldPublicIpRepository, repository.NewWebForwardingRepository, repository.NewTcpforwardingRepository, repository.NewUdpForWardingRepository, repository.NewGameShieldUserIpRepository, repository.NewWebLimitRepository, repository.NewTcpLimitRepository, repository.NewUdpLimitRepository, repository.NewGameShieldBackendRepository, repository.NewGameShieldSdkIpRepository, repository.NewHostRepository)
 
 
-var serviceSet = wire.NewSet(service.NewService, service.NewUserService, service.NewGameShieldService, service.NewCrawlerService, service.NewGameShieldPublicIpService, service.NewDuedateService, service.NewFormatterService, service.NewParserService, service.NewRequiredService, service.NewWebForwardingService, service.NewTcpforwardingService, service.NewUdpForWardingService, service.NewGameShieldUserIpService, service.NewWebLimitService, service.NewTcpLimitService, service.NewUdpLimitService, service.NewGameShieldBackendService, service.NewGameShieldSdkIpService)
+var serviceSet = wire.NewSet(service.NewService, service.NewUserService, service.NewGameShieldService, service.NewCrawlerService, service.NewGameShieldPublicIpService, service.NewDuedateService, service.NewFormatterService, service.NewParserService, service.NewRequiredService, service.NewWebForwardingService, service.NewTcpforwardingService, service.NewUdpForWardingService, service.NewGameShieldUserIpService, service.NewWebLimitService, service.NewTcpLimitService, service.NewUdpLimitService, service.NewGameShieldBackendService, service.NewGameShieldSdkIpService, service.NewHostService)
 
 
-var handlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler, handler.NewGameShieldHandler, handler.NewGameShieldPublicIpHandler, handler.NewWebForwardingHandler, handler.NewTcpforwardingHandler, handler.NewUdpForWardingHandler, handler.NewGameShieldUserIpHandler, handler.NewWebLimitHandler, handler.NewTcpLimitHandler, handler.NewUdpLimitHandler, handler.NewGameShieldBackendHandler, handler.NewGameShieldSdkIpHandler)
+var handlerSet = wire.NewSet(handler.NewHandler, handler.NewUserHandler, handler.NewGameShieldHandler, handler.NewGameShieldPublicIpHandler, handler.NewWebForwardingHandler, handler.NewTcpforwardingHandler, handler.NewUdpForWardingHandler, handler.NewGameShieldUserIpHandler, handler.NewWebLimitHandler, handler.NewTcpLimitHandler, handler.NewUdpLimitHandler, handler.NewGameShieldBackendHandler, handler.NewGameShieldSdkIpHandler, handler.NewHostHandler)
 
 
 var jobSet = wire.NewSet(job.NewJob, job.NewUserJob)
 var jobSet = wire.NewSet(job.NewJob, job.NewUserJob)
 
 

+ 25 - 0
internal/handler/host.go

@@ -0,0 +1,25 @@
+package handler
+
+import (
+	"github.com/gin-gonic/gin"
+	"github.com/go-nunu/nunu-layout-advanced/internal/service"
+)
+
+type HostHandler struct {
+	*Handler
+	hostService service.HostService
+}
+
+func NewHostHandler(
+	handler *Handler,
+	hostService service.HostService,
+) *HostHandler {
+	return &HostHandler{
+		Handler:     handler,
+		hostService: hostService,
+	}
+}
+
+func (h *HostHandler) GetHost(ctx *gin.Context) {
+
+}

+ 1 - 1
internal/model/gameshield.go

@@ -10,7 +10,7 @@ type GameShield struct {
 	Key            string
 	Key            string
 	AddTime        time.Time
 	AddTime        time.Time
 	Uid            int
 	Uid            int
-	HostId         string
+	HostId         int
 	Checked        int
 	Checked        int
 	DunName        string
 	DunName        string
 	ExpireTime     int64 `gorm:"type:bigint"`
 	ExpireTime     int64 `gorm:"type:bigint"`

+ 1 - 1
internal/model/gameshieldbackend.go

@@ -13,7 +13,7 @@ type GameShieldBackend struct {
 	SdkPort         string
 	SdkPort         string
 	SdkIp           string `gorm:"null"`
 	SdkIp           string `gorm:"null"`
 	Type            string
 	Type            string
-	MaxBandwidth    string
+	MaxBandwidth    int `gorm:"not null;type:tinyint"`
 	CreatedAt       time.Time
 	CreatedAt       time.Time
 	UpdatedAt       time.Time
 	UpdatedAt       time.Time
 }
 }

+ 13 - 0
internal/model/host.go

@@ -0,0 +1,13 @@
+package model
+
+type Host struct {
+	Id       int `gorm:"primarykey"`
+	Relid    int
+	Configid int
+	Optionid int
+	Qty      int
+}
+
+func (m *Host) TableName() string {
+	return "shd_host_config_options"
+}

+ 4 - 4
internal/repository/gameshield.go

@@ -13,7 +13,7 @@ type GameShieldRepository interface {
 	UpdateGameShield(ctx context.Context, gameShield *model.GameShield) error
 	UpdateGameShield(ctx context.Context, gameShield *model.GameShield) error
 	DeleteGameShield(ctx context.Context, ruleId int) error
 	DeleteGameShield(ctx context.Context, ruleId int) error
 	GetGameShieldIsBuy(ctx context.Context, uid int64) (int64, error)
 	GetGameShieldIsBuy(ctx context.Context, uid int64) (int64, error)
-	GetGameShieldNextduedate(ctx context.Context, uid int64, productID string) (string, error)
+	GetGameShieldNextduedate(ctx context.Context, uid int64, productID int) (string, error)
 	GetGameShieldNameByDunName(ctx context.Context, appName string) (string, error)
 	GetGameShieldNameByDunName(ctx context.Context, appName string) (string, error)
 	GetGameShieldHostIdByDunName(ctx context.Context, hostId string) (string, error)
 	GetGameShieldHostIdByDunName(ctx context.Context, hostId string) (string, error)
 	GetGameShieldRuleIdByAppName(ctx context.Context, appName string) (int, error)
 	GetGameShieldRuleIdByAppName(ctx context.Context, appName string) (int, error)
@@ -22,7 +22,7 @@ type GameShieldRepository interface {
 	GetHostById(ctx context.Context, id int) (string, error)
 	GetHostById(ctx context.Context, id int) (string, error)
 	GetSoonExpiredGameShields(ctx context.Context, daysThreshold int) ([]*model.GameShield, error)
 	GetSoonExpiredGameShields(ctx context.Context, daysThreshold int) ([]*model.GameShield, error)
 	GetExpiredGameShields(ctx context.Context) ([]*model.GameShield, error)
 	GetExpiredGameShields(ctx context.Context) ([]*model.GameShield, error)
-	SyncExpireTimeFromHostNextDueDate(ctx context.Context, uid int, hostId string) error
+	SyncExpireTimeFromHostNextDueDate(ctx context.Context, uid int, hostId int) error
 	GetAllGameShield(ctx context.Context) ([]*model.GameShield, error)
 	GetAllGameShield(ctx context.Context) ([]*model.GameShield, error)
 }
 }
 
 
@@ -87,7 +87,7 @@ func (r *gameShieldRepository) GetGameShieldIsBuy(ctx context.Context, uid int64
 	return count, nil
 	return count, nil
 }
 }
 
 
-func (r *gameShieldRepository) GetGameShieldNextduedate(ctx context.Context, uid int64, productID string) (string, error) {
+func (r *gameShieldRepository) GetGameShieldNextduedate(ctx context.Context, uid int64, productID int) (string, error) {
 	var nextDueDate string
 	var nextDueDate string
 	err := r.DB(ctx).Table("shd_host").
 	err := r.DB(ctx).Table("shd_host").
 		Select("nextduedate").
 		Select("nextduedate").
@@ -195,7 +195,7 @@ func (r *gameShieldRepository) GetExpiredGameShields(ctx context.Context) ([]*mo
 }
 }
 
 
 // SyncExpireTimeFromHostNextDueDate 同步host表的nextduedate到game_shield表的ExpireTime
 // SyncExpireTimeFromHostNextDueDate 同步host表的nextduedate到game_shield表的ExpireTime
-func (r *gameShieldRepository) SyncExpireTimeFromHostNextDueDate(ctx context.Context, uid int, hostId string) error {
+func (r *gameShieldRepository) SyncExpireTimeFromHostNextDueDate(ctx context.Context, uid int, hostId int) error {
 	var nextduedate int64
 	var nextduedate int64
 
 
 	// 先从shd_host表获取nextduedate
 	// 先从shd_host表获取nextduedate

+ 24 - 0
internal/repository/gameshieldbackend.go

@@ -12,6 +12,8 @@ type GameShieldBackendRepository interface {
 	EditGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendRequest) error
 	EditGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendRequest) error
 	DeleteGameShieldBackend(ctx context.Context, id int64) error
 	DeleteGameShieldBackend(ctx context.Context, id int64) error
 	GetGameShieldBackendByHostId(ctx context.Context, hostId int) ([]model.GameShieldBackend, error)
 	GetGameShieldBackendByHostId(ctx context.Context, hostId int) ([]model.GameShieldBackend, error)
+	GetGameShieldBackendConfigCountByHostId(ctx context.Context, hostId int) (*v1.GameShieldHostBackendConfigResponse, error)
+	GetGameShieldBackendSourceMachineIpByHostId(ctx context.Context, hostId int) ([]string, error)
 }
 }
 
 
 func NewGameShieldBackendRepository(
 func NewGameShieldBackendRepository(
@@ -62,3 +64,25 @@ func (r *gameShieldBackendRepository) GetGameShieldBackendByHostId(ctx context.C
 	}
 	}
 	return gameShieldBackend, nil
 	return gameShieldBackend, nil
 }
 }
+
+func (r *gameShieldBackendRepository) GetGameShieldBackendConfigCountByHostId(ctx context.Context, hostId int) (*v1.GameShieldHostBackendConfigResponse, error) {
+	var res v1.GameShieldHostBackendConfigResponse
+	if err := r.DB(ctx).Model(&model.GameShieldBackend{}).Where("host_id = ?", hostId).Count(&res.RuleEntriesCount).Error; err != nil {
+		return nil, err
+	}
+	if err := r.DB(ctx).Model(&model.GameShieldBackend{}).Where("host_id = ?", hostId).Distinct("source_machine_ip").Count(&res.SourceMachinesCount).Error; err != nil {
+		return nil, err
+	}
+	if err := r.DB(ctx).Model(&model.GameShieldBackend{}).Where("host_id = ?", hostId).Where("max_bandwidth = ?", 1).Count(&res.MaxBandwidthCount).Error; err != nil {
+		return nil, err
+	}
+	return &res, nil
+}
+
+func (r *gameShieldBackendRepository) GetGameShieldBackendSourceMachineIpByHostId(ctx context.Context, hostId int) ([]string, error) {
+	var res []string
+	if err := r.DB(ctx).Model(&model.GameShieldBackend{}).Where("host_id = ?", hostId).Distinct("source_machine_ip").Pluck("source_machine_ip", &res).Error; err != nil {
+		return nil, err
+	}
+	return res, nil
+}

+ 56 - 0
internal/repository/host.go

@@ -0,0 +1,56 @@
+package repository
+
+import (
+	"context"
+	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
+	"github.com/go-nunu/nunu-layout-advanced/internal/model"
+)
+
+type HostRepository interface {
+	GetHost(ctx context.Context, id int64) (*model.Host, error)
+	GetHostConfig(ctx context.Context, hostId int) ([]*model.Host, error)
+	GetProductConfigOption(ctx context.Context, id []int) ([]v1.ProductConfigOption, error)
+	GetProductConfigOptionSub(ctx context.Context, id []int) ([]v1.ProductConfigOptionSub, error)
+}
+
+func NewHostRepository(
+	repository *Repository,
+) HostRepository {
+	return &hostRepository{
+		Repository: repository,
+	}
+}
+
+type hostRepository struct {
+	*Repository
+}
+
+func (r *hostRepository) GetHost(ctx context.Context, id int64) (*model.Host, error) {
+	var host model.Host
+
+	return &host, nil
+}
+
+func (r *hostRepository) GetHostConfig(ctx context.Context, hostId int) ([]*model.Host, error) {
+	var res []*model.Host
+	if err := r.DB(ctx).Where("relid = ?", hostId).Find(&res).Error; err != nil {
+		return nil, err
+	}
+	return res, nil
+}
+
+func (r *hostRepository) GetProductConfigOption(ctx context.Context, id []int) ([]v1.ProductConfigOption, error) {
+	var res []v1.ProductConfigOption
+	if err := r.DB(ctx).Table("shd_product_config_options").Where("id IN ?", id).Find(&res).Error; err != nil {
+		return nil, err
+	}
+	return res, nil
+}
+
+func (r *hostRepository) GetProductConfigOptionSub(ctx context.Context, id []int) ([]v1.ProductConfigOptionSub, error) {
+	var res []v1.ProductConfigOptionSub
+	if err := r.DB(ctx).Table("shd_product_config_options_sub").Where("id IN ?", id).Find(&res).Error; err != nil {
+		return nil, err
+	}
+	return res, nil
+}

+ 2 - 2
internal/service/duedate.go

@@ -9,7 +9,7 @@ import (
 )
 )
 
 
 type DuedateService interface {
 type DuedateService interface {
-	NextDueDate(ctx context.Context, uid int, hostId string) (string, error)
+	NextDueDate(ctx context.Context, uid int, hostId int) (string, error)
 }
 }
 
 
 func NewDuedateService(
 func NewDuedateService(
@@ -28,7 +28,7 @@ type duedateService struct {
 	gameShieldRepository repository.GameShieldRepository
 	gameShieldRepository repository.GameShieldRepository
 }
 }
 
 
-func (service *duedateService) NextDueDate(ctx context.Context, uid int, productID string) (string, error) {
+func (service *duedateService) NextDueDate(ctx context.Context, uid int, productID int) (string, error) {
 	timeStr, err := service.gameShieldRepository.GetGameShieldNextduedate(ctx, int64(uid), productID)
 	timeStr, err := service.gameShieldRepository.GetGameShieldNextduedate(ctx, int64(uid), productID)
 	if timeStr == "0" || timeStr == "" {
 	if timeStr == "0" || timeStr == "" {
 		return "", err
 		return "", err

+ 83 - 33
internal/service/formatter.go

@@ -6,7 +6,9 @@ import (
 	"fmt"
 	"fmt"
 	v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
 	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/model"
+	"github.com/go-nunu/nunu-layout-advanced/internal/repository"
 	"maps"
 	"maps"
+	"slices"
 	"sort"
 	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -25,17 +27,23 @@ type FormatterService interface {
 func NewFormatterService(
 func NewFormatterService(
 	service *Service,
 	service *Service,
 	gameShieldPublicIpService GameShieldPublicIpService,
 	gameShieldPublicIpService GameShieldPublicIpService,
+	gameShieldBackendRepository repository.GameShieldBackendRepository,
+	hostService HostService,
 
 
 ) FormatterService {
 ) FormatterService {
 	return &formatterService{
 	return &formatterService{
-		Service:                   service,
-		gameShieldPublicIpService: gameShieldPublicIpService,
+		Service:                     service,
+		gameShieldPublicIpService:   gameShieldPublicIpService,
+		gameShieldBackendRepository: gameShieldBackendRepository,
+		hostService:                 hostService,
 	}
 	}
 }
 }
 
 
 type formatterService struct {
 type formatterService struct {
 	*Service
 	*Service
-	gameShieldPublicIpService GameShieldPublicIpService
+	gameShieldPublicIpService   GameShieldPublicIpService
+	gameShieldBackendRepository repository.GameShieldBackendRepository
+	hostService                 HostService
 }
 }
 
 
 func (service *formatterService) FormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, oldFormat map[string]v1.SendGameShieldBackend, keyCounter int) (string, error) {
 func (service *formatterService) FormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, oldFormat map[string]v1.SendGameShieldBackend, keyCounter int) (string, error) {
@@ -117,84 +125,126 @@ func (service *formatterService) OldFormat(ctx context.Context, req *[]model.Gam
 }
 }
 
 
 func (service *formatterService) TidyFormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, keyCounter int) (map[string]v1.SendGameShieldBackend, error) {
 func (service *formatterService) TidyFormatBackendData(ctx context.Context, req *v1.GameShieldBackendArrayRequest, keyCounter int) (map[string]v1.SendGameShieldBackend, error) {
+	// 初始化输出映射
 	output := make(map[string]v1.SendGameShieldBackend)
 	output := make(map[string]v1.SendGameShieldBackend)
+
+	// 获取所需基础数据
 	userIp, err := service.gameShieldPublicIpService.GetUserIp(ctx, req.Uid)
 	userIp, err := service.gameShieldPublicIpService.GetUserIp(ctx, req.Uid)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+
+	oldCount, err := service.gameShieldBackendRepository.GetGameShieldBackendConfigCountByHostId(ctx, req.HostId)
+	if err != nil {
+		return nil, err
+	}
+
+	oldMachineIp, err := service.gameShieldBackendRepository.GetGameShieldBackendSourceMachineIpByHostId(ctx, req.HostId)
+	if err != nil {
+		return nil, err
+	}
+
+	configCount, err := service.hostService.GetGameShieldConfig(ctx, req.HostId)
+	if err != nil {
+		return nil, err
+	}
+
+	// 遍历请求中的所有项目
 	for _, item := range req.Items {
 	for _, item := range req.Items {
-		// 提取必要字段
-		sourceIP := item.SourceMachineIP // 假设结构体中有这个字段
+		// 检查并验证源机器IP
+		sourceIP := item.SourceMachineIP
 		if sourceIP == "" {
 		if sourceIP == "" {
-			return nil, fmt.Errorf("没有有效源IP的配置") // 跳过没有有效源IP的配置
+			return nil, fmt.Errorf("没有有效源IP的配置")
+		}
+		// 检查源机器IP是否为新增
+		if !slices.Contains(oldMachineIp, sourceIP) {
+			oldCount.SourceMachinesCount++
+			if oldCount.SourceMachinesCount > configCount.SourceMachinesCount {
+				return nil, fmt.Errorf("超出最大源机数量")
+			}
 		}
 		}
 
 
-		protocol := item.Protocol // 假设结构体中有这个字段
+		// 验证协议
+		protocol := item.Protocol
 		if protocol == "" {
 		if protocol == "" {
-			return nil, fmt.Errorf("没有有效协议的配置") // 跳过没有有效协议的配置
+			return nil, fmt.Errorf("没有有效协议的配置")
 		}
 		}
-		// 获取端口数组
+
+		// 获取并验证端口配置
 		conPorts := service.FormatPort(ctx, item.ConnectPort)
 		conPorts := service.FormatPort(ctx, item.ConnectPort)
 		sdkPorts := service.FormatPort(ctx, item.SdkPort)
 		sdkPorts := service.FormatPort(ctx, item.SdkPort)
 
 
+		// 验证端口数量匹配
+		if len(sdkPorts) > 0 && len(conPorts) != len(sdkPorts) {
+			return nil, fmt.Errorf("端口数量不匹配")
+		}
+
+		// 验证规则条目数量
+		oldCount.RuleEntriesCount += int64(len(conPorts))
+		if oldCount.RuleEntriesCount > configCount.RuleEntriesCount {
+			return nil, fmt.Errorf("超出最大规则数量")
+		}
+
 		// 处理每一对端口
 		// 处理每一对端口
 		for i := 0; i < len(conPorts); i++ {
 		for i := 0; i < len(conPorts); i++ {
 			keyCounter++
 			keyCounter++
 			key := fmt.Sprintf("key%d", keyCounter)
 			key := fmt.Sprintf("key%d", keyCounter)
 
 
-			// 使用数组中的具体端口
-			addr := fmt.Sprintf("%s:%d", sourceIP, conPorts[i])
-
+			// 构建基本的后端配置项
 			itemMap := v1.SendGameShieldBackend{
 			itemMap := v1.SendGameShieldBackend{
-				Addr:     []string{addr},
+				Addr:     []string{fmt.Sprintf("%s:%d", sourceIP, conPorts[i])},
 				Protocol: protocol,
 				Protocol: protocol,
+				Type:     item.Type,
 			}
 			}
 
 
-			//// 设置主机名(如果存在)
-			//if item.Host != "" {
-			//	itemMap["host"] = item.Host
-			//}
-
-			// 根据协议设置不同属性
+			// 根据协议类型设置属性
 			if protocol != "udp" {
 			if protocol != "udp" {
+				// 非UDP协议的配置
 				if item.Checked == "agent" {
 				if item.Checked == "agent" {
 					itemMap.AgentAddr = fmt.Sprintf("%s:%s", sourceIP, "23350")
 					itemMap.AgentAddr = fmt.Sprintf("%s:%s", sourceIP, "23350")
 				}
 				}
 				itemMap.ProxyAddr = userIp + ":32353"
 				itemMap.ProxyAddr = userIp + ":32353"
-
 			} else {
 			} else {
+				// UDP协议的配置
 				itemMap.ProxyAddr = ""
 				itemMap.ProxyAddr = ""
 				itemMap.UdpSessionTimeout = "300s"
 				itemMap.UdpSessionTimeout = "300s"
 			}
 			}
-			itemMap.Type = item.Type
-			if item.Type != "pc" {
-				itemMap.SdkIp = ""
-			} else {
+
+			// 根据设备类型设置SDK IP
+			if item.Type == "pc" {
 				itemMap.SdkIp = item.SdkIp
 				itemMap.SdkIp = item.SdkIp
+			} else {
+				itemMap.SdkIp = ""
 			}
 			}
 
 
-			if item.MaxBandwidth == "1" {
+			// 处理最大带宽设置
+			if item.MaxBandwidth == 1 {
+				oldCount.MaxBandwidthCount++
+				if oldCount.MaxBandwidthCount > configCount.MaxBandwidthCount {
+					return nil, fmt.Errorf("超出最大带宽数量")
+				}
 				itemMap.MaxBandwidth = "50m"
 				itemMap.MaxBandwidth = "50m"
 			} else {
 			} else {
 				itemMap.MaxBandwidth = ""
 				itemMap.MaxBandwidth = ""
 			}
 			}
-			// 设置SDK端口 - 使用数组中的具体端口
-			if len(sdkPorts) != 0 {
-				if sdkPorts[i] <= 1024 {
-					if item.Type == "mobile" {
-						return nil, fmt.Errorf("移动端不支持SSH端口")
-					}
+
+			// 设置SDK端口(如果存在)
+			if len(sdkPorts) > 0 {
+				sdkPort := sdkPorts[i]
+				// 检查移动端的SSH端口限制
+				if sdkPort <= 1024 && item.Type == "mobile" {
+					return nil, fmt.Errorf("移动端不支持SSH端口")
 				}
 				}
-				itemMap.SdkPort = sdkPorts[i]
+				itemMap.SdkPort = sdkPort
 			}
 			}
 
 
+			// 将配置项添加到输出映射
 			output[key] = itemMap
 			output[key] = itemMap
 		}
 		}
 	}
 	}
 
 
 	return output, nil
 	return output, nil
 }
 }
-
 func (service *formatterService) Sort(ctx context.Context, mapData map[string]v1.SendGameShieldBackend) (map[string]v1.SendGameShieldBackend, error) {
 func (service *formatterService) Sort(ctx context.Context, mapData map[string]v1.SendGameShieldBackend) (map[string]v1.SendGameShieldBackend, error) {
 	var keys []int
 	var keys []int
 	for key := range mapData {
 	for key := range mapData {

+ 4 - 9
internal/service/gameshield.go

@@ -16,7 +16,7 @@ type GameShieldService interface {
 	EditGameShield(ctx context.Context, req *v1.GameShieldSubmitRequest) (string, error)
 	EditGameShield(ctx context.Context, req *v1.GameShieldSubmitRequest) (string, error)
 	DeleteGameShield(ctx context.Context, req int) (string, error)
 	DeleteGameShield(ctx context.Context, req int) (string, error)
 	GetGameShieldKey(ctx context.Context, id int) (string, error)
 	GetGameShieldKey(ctx context.Context, id int) (string, error)
-	GetKeyAndEditGameShield(ctx context.Context, hostId string, dunName string) (string, error)
+	GetKeyAndEditGameShield(ctx context.Context, hostId int, dunName string) (string, error)
 }
 }
 
 
 func NewGameShieldService(
 func NewGameShieldService(
@@ -68,17 +68,12 @@ func (service *gameShieldService) SubmitGameShield(ctx context.Context, req *v1.
 		return "", fmt.Errorf("应用名称已存在")
 		return "", fmt.Errorf("应用名称已存在")
 	}
 	}
 
 
-	hostIdInt, err := strconv.Atoi(req.HostId)
-	if err != nil {
-		return "", fmt.Errorf("转换hostId失败: %v", err)
-	}
-
 	// 调用IP生成服务
 	// 调用IP生成服务
-	if err := service.gameShieldSdkIp.GenerateMultipleLoopbackIps(ctx, req.Uid, hostIdInt); err != nil {
+	if err := service.gameShieldSdkIp.GenerateMultipleLoopbackIps(ctx, req.Uid, req.HostId); err != nil {
 		return "", fmt.Errorf("生成IP地址失败: %w", err)
 		return "", fmt.Errorf("生成IP地址失败: %w", err)
 	}
 	}
 
 
-	dunName := strconv.Itoa(req.Uid) + "_hostId" + req.HostId
+	dunName := strconv.Itoa(req.Uid) + "_hostId" + strconv.Itoa(req.HostId)
 	formData := map[string]interface{}{
 	formData := map[string]interface{}{
 		"app_name":         dunName,
 		"app_name":         dunName,
 		"gateway_group_id": 4,
 		"gateway_group_id": 4,
@@ -158,7 +153,7 @@ func (service *gameShieldService) GetGameShieldKey(ctx context.Context, hostId i
 	return res, nil
 	return res, nil
 }
 }
 
 
-func (service *gameShieldService) GetKeyAndEditGameShield(ctx context.Context, hostId string, dunName string) (string, error) {
+func (service *gameShieldService) GetKeyAndEditGameShield(ctx context.Context, hostId int, dunName string) (string, error) {
 	key, err := service.crawlerService.GetKey(ctx, dunName)
 	key, err := service.crawlerService.GetKey(ctx, dunName)
 	if err != nil {
 	if err != nil {
 		return "", err
 		return "", err

+ 3 - 3
internal/service/gameshieldbackend.go

@@ -69,7 +69,7 @@ func (s *gameShieldBackendService) GetGameShieldRequired(ctx context.Context, re
 	if req.Uid == 0 {
 	if req.Uid == 0 {
 		return nil, 0, fmt.Errorf("uid is required")
 		return nil, 0, fmt.Errorf("uid is required")
 	}
 	}
-	res.ExpiredAt, err = s.duedate.NextDueDate(ctx, req.Uid, strconv.Itoa(req.HostId))
+	res.ExpiredAt, err = s.duedate.NextDueDate(ctx, req.Uid, req.HostId)
 	if err != nil {
 	if err != nil {
 		return nil, 0, err
 		return nil, 0, err
 	}
 	}
@@ -143,7 +143,7 @@ func (s *gameShieldBackendService) GameShieldBackend(ctx context.Context, req *v
 	if err != nil {
 	if err != nil {
 		return "", 0, err
 		return "", 0, err
 	}
 	}
-	timeBase, err := s.gameShieldRepository.GetGameShieldNextduedate(ctx, int64(req.Uid), strconv.Itoa(req.HostId))
+	timeBase, err := s.gameShieldRepository.GetGameShieldNextduedate(ctx, int64(req.Uid), req.HostId)
 	if err != nil {
 	if err != nil {
 		return "", 0, err
 		return "", 0, err
 	}
 	}
@@ -151,7 +151,7 @@ func (s *gameShieldBackendService) GameShieldBackend(ctx context.Context, req *v
 	if err != nil {
 	if err != nil {
 		return "", 0, err
 		return "", 0, err
 	}
 	}
-	if err := s.gameShieldRepository.UpdateGameShieldByHostId(ctx, &model.GameShield{HostId: strconv.Itoa(req.HostId), Key: KeyAndField.Key, ExpireTime: timestampSec}); err != nil {
+	if err := s.gameShieldRepository.UpdateGameShieldByHostId(ctx, &model.GameShield{HostId: req.HostId, Key: KeyAndField.Key, ExpireTime: timestampSec}); err != nil {
 		return "", 0, err
 		return "", 0, err
 	}
 	}
 	return res, count, nil
 	return res, count, nil

+ 138 - 0
internal/service/host.go

@@ -0,0 +1,138 @@
+package service
+
+import (
+	"context"
+	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"
+	"strings"
+)
+
+type HostService interface {
+	GetHost(ctx context.Context, id int64) (*model.Host, error)
+	GetGameShieldConfig(ctx context.Context, hostId int) (v1.GameShieldHostBackendConfigResponse, error)
+}
+
+func NewHostService(
+	service *Service,
+	hostRepository repository.HostRepository,
+) HostService {
+	return &hostService{
+		Service:        service,
+		hostRepository: hostRepository,
+	}
+}
+
+const (
+	ConfigOnlineDevices  = "在线设备数"
+	ConfigRuleEntries    = "规则条目"
+	ConfigMaxBandwidth   = "高带宽转发规则条目"
+	ConfigSourceMachines = "支持源机"
+)
+
+type hostService struct {
+	*Service
+	hostRepository repository.HostRepository
+}
+
+func (s *hostService) GetHost(ctx context.Context, id int64) (*model.Host, error) {
+	return s.hostRepository.GetHost(ctx, id)
+}
+
+func (s *hostService) GetHostConfig(ctx context.Context, hostId int) ([]map[string]string, error) {
+	configOptions, err := s.hostRepository.GetHostConfig(ctx, hostId)
+	if err != nil {
+		return nil, err
+	}
+	// 2. 收集ID和建立映射关系
+	var configIDs []int
+	var optionIDs []int
+	optionMap := make(map[int]int)
+	for _, item := range configOptions {
+		configIDs = append(configIDs, item.Configid)
+		optionIDs = append(optionIDs, item.Optionid)
+		optionMap[item.Configid] = item.Optionid
+	}
+	// 3. 获取配置和选项数据
+	var configs []v1.ProductConfigOption
+	if len(configIDs) > 0 {
+		configs, err = s.hostRepository.GetProductConfigOption(ctx, configIDs)
+		if err != nil {
+			return nil, err
+		}
+	}
+	var options []v1.ProductConfigOptionSub
+	if len(optionIDs) > 0 {
+		options, err = s.hostRepository.GetProductConfigOptionSub(ctx, optionIDs)
+		if err != nil {
+			return nil, err
+		}
+	}
+	// 4. 转换选项为关联数组
+	optionsByID := make(map[int]v1.ProductConfigOptionSub)
+	for _, option := range options {
+		optionsByID[option.ID] = option
+	}
+
+	// 5. 构建结果数据
+	var data []map[string]string
+	for _, config := range configs {
+		optionID := optionMap[config.ID]
+
+		var optionName string
+		if opt, ok := optionsByID[optionID]; ok {
+			optionName = opt.OptionName
+		}
+
+		data = append(data, map[string]string{
+			"config_name": config.OptionName,
+			"option_name": optionName,
+		})
+	}
+	return data, nil
+}
+
+func (s *hostService) tidyGetGameShieldConfig(ctx context.Context, configName string, optionName string) (map[string]int, error) {
+	// 根据配置名称去除相应的单位后缀
+	switch configName {
+	case ConfigOnlineDevices, ConfigRuleEntries:
+		optionName = strings.TrimSuffix(optionName, "个")
+	case ConfigMaxBandwidth:
+		optionName = strings.TrimSuffix(optionName, "条")
+	}
+
+	// 转换为整数并返回
+	return map[string]int{configName: cast.ToInt(optionName)}, nil
+}
+func (s *hostService) GetGameShieldConfig(ctx context.Context, hostId int) (v1.GameShieldHostBackendConfigResponse, error) {
+	baseData, err := s.GetHostConfig(ctx, hostId)
+	if err != nil {
+		return v1.GameShieldHostBackendConfigResponse{}, err
+	}
+
+	var data v1.GameShieldHostBackendConfigResponse
+
+	for _, item := range baseData {
+		configName := item["config_name"]
+		optionName := item["option_name"]
+
+		res, err := s.tidyGetGameShieldConfig(ctx, configName, optionName)
+		if err != nil {
+			return v1.GameShieldHostBackendConfigResponse{}, err
+		}
+
+		// 使用switch直接设置对应字段
+		switch configName {
+		case ConfigOnlineDevices:
+			data.OnlineDevicesCount = int64(res[configName])
+		case ConfigRuleEntries:
+			data.RuleEntriesCount = int64(res[configName])
+		case ConfigMaxBandwidth:
+			data.MaxBandwidthCount = int64(res[configName])
+		case ConfigSourceMachines:
+			data.SourceMachinesCount = int64(res[configName])
+		}
+	}
+	return data, nil
+}