123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- package service
- import (
- "context"
- "fmt"
- "github.com/AlekSi/pointer"
- v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
- "github.com/go-nunu/nunu-layout-advanced/internal/model"
- "github.com/go-nunu/nunu-layout-advanced/internal/repository"
- "github.com/spf13/cast"
- "github.com/spf13/viper"
- "go.uber.org/zap"
- "strconv"
- "strings"
- )
- type GameShieldBackendService interface {
- GetGameShieldBackend(ctx context.Context, id int64) (*model.GameShieldBackend, error)
- GameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, int, error)
- AddGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error)
- EditGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error)
- DeleteGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error)
- GetGameShieldRequired(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (*v1.GetGameShieldRequiredResponse, int, error)
- }
- func NewGameShieldBackendService(
- service *Service,
- gameShieldBackendRepository repository.GameShieldBackendRepository,
- gameShieldRepository repository.GameShieldRepository,
- crawlerService CrawlerService,
- gameShieldPublicIpService GameShieldPublicIpService,
- duedate DuedateService,
- formatter FormatterService,
- parser ParserService,
- required RequiredService,
- conf *viper.Viper,
- shieldService GameShieldService,
- hostService HostService,
- ) GameShieldBackendService {
- return &gameShieldBackendService{
- Service: service,
- gameShieldBackendRepository: gameShieldBackendRepository,
- gameShieldRepository: gameShieldRepository,
- crawlerService: crawlerService,
- gameShieldPublicIpService: gameShieldPublicIpService,
- duedate: duedate,
- formatter: formatter,
- parser: parser,
- required: required,
- Url: conf.GetString("crawler.Url"),
- shieldService: shieldService,
- hostService: hostService,
- }
- }
- type gameShieldBackendService struct {
- *Service
- gameShieldBackendRepository repository.GameShieldBackendRepository
- crawlerService CrawlerService
- gameShieldRepository repository.GameShieldRepository
- gameShieldPublicIpService GameShieldPublicIpService
- duedate DuedateService
- formatter FormatterService
- Url string
- parser ParserService
- required RequiredService
- shieldService GameShieldService
- hostService HostService
- }
- func (s *gameShieldBackendService) GetGameShieldRequired(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (*v1.GetGameShieldRequiredResponse, int, error) {
- var res v1.GetGameShieldRequiredResponse
- var err error
- var count int
- if req.Uid == 0 {
- return nil, 0, fmt.Errorf("uid is required")
- }
- res.ExpiredAt, err = s.duedate.NextDueDate(ctx, req.Uid, req.HostId)
- if err != nil {
- return nil, 0, err
- }
- gameShield, err := s.gameShieldRepository.GetGameShieldByHostId(ctx, req.HostId)
- if err != nil {
- return nil, 0, err
- }
- res.RuleId = gameShield.RuleId
- oldBackend, err := s.gameShieldBackendRepository.GetGameShieldBackendByHostId(ctx, req.HostId)
- if err != nil {
- return nil, 0, err
- }
- if len(oldBackend) != 0 {
- count = oldBackend[0].KeySort
- }
- OldBackend, err := s.formatter.OldFormat(ctx, oldBackend)
- res.Backend, err = s.formatter.FormatBackendData(ctx, req, OldBackend, count)
- if err != nil {
- return nil, 0, err
- }
- res.Cookie, err = s.crawlerService.GetLoginCookie(ctx)
- if err != nil {
- return nil, 0, err
- }
- res.DunName = gameShield.DunName
- return &res, count, nil
- }
- func (s *gameShieldBackendService) GetGameShieldBackend(ctx context.Context, id int64) (*model.GameShieldBackend, error) {
- res, err := s.gameShieldBackendRepository.GetGameShieldBackendById(ctx, id)
- if err != nil {
- return nil, err
- }
- return res, nil
- }
- func (s *gameShieldBackendService) GameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, int, error) {
- require, count, err := s.GetGameShieldRequired(ctx, req)
- if err != nil {
- return "", 0, err
- }
- 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)
- if err != nil {
- return "", 0, err
- }
- configCount, err := s.hostService.GetGameShieldConfig(ctx, req.HostId)
- if err != nil {
- return "", 0, fmt.Errorf("获取配置限制失败: %w", err)
- }
- formData := map[string]interface{}{
- "app_name": require.DunName,
- "gateway_group_id": 4,
- "backend": require.Backend,
- "rule_id": require.RuleId,
- "expired_at": require.ExpiredAt,
- "max_device_count": configCount.OnlineDevicesCount,
- "sdk_args": "--max-bandwidth 1000K",
- "__go_admin_previous_": tokens["previous"],
- "__go_admin_t_": tokens["t"],
- }
- sendUrl := s.Url + "admin/edit/rule"
- respBody, err := s.crawlerService.SendFormData(ctx, sendUrl, require.Cookie, formData)
- if err != nil {
- return "", 0, err
- }
- // 解析响应内容中的 alert 消息
- res, err := s.parser.ParseAlert(string(respBody))
- if err != nil {
- return "", 0, err
- }
- if res != "" {
- return "", 0, fmt.Errorf(res)
- }
- KeyAndField, err := s.required.GetKeyAndField(ctx, require.DunName, "rule_id")
- if err != nil {
- return "", 0, err
- }
- timeBase, err := s.gameShieldRepository.GetGameShieldNextduedate(ctx, int64(req.Uid), req.HostId)
- if err != nil {
- return "", 0, err
- }
- timestampSec, err := strconv.ParseInt(timeBase, 10, 64)
- if err != nil {
- return "", 0, err
- }
- if err := s.gameShieldRepository.UpdateGameShieldByHostId(ctx, &model.GameShield{HostId: req.HostId, Key: KeyAndField.Key, ExpireTime: timestampSec}); err != nil {
- return "", 0, err
- }
- return res, count, nil
- }
- func (s *gameShieldBackendService) AddGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error) {
- res, count, err := s.GameShieldBackend(ctx, req)
- if err != nil {
- return "", err
- }
- saveData, err := s.formatter.TidyFormatBackendData(ctx, req, count)
- if err != nil {
- return "", err
- }
- if err := s.SaveGameShieldBackend(ctx, saveData, req.HostId); err != nil {
- return "", err
- }
- return res, nil
- }
- func (s *gameShieldBackendService) EditGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error) {
- // 1. 获取当前所有数据库记录
- currentData, err := s.gameShieldBackendRepository.GetGameShieldBackendByHostId(ctx, req.HostId)
- if err != nil {
- return "", fmt.Errorf("获取当前配置失败: %w", err)
- }
- s.logger.Info("当前配置", zap.Any("配置", currentData))
- // 2. 创建当前记录的副本用于模拟修改
- simulatedData := make([]model.GameShieldBackend, len(currentData))
- copy(simulatedData, currentData)
- // 3. 创建ID到索引的映射,方便查找和修改
- idToIndex := make(map[int64]int)
- for i, item := range simulatedData {
- idToIndex[int64(item.Id)] = i
- }
- // 4. 在副本上应用修改
- for _, v := range req.Items {
- if v.Id == 0 {
- return "", fmt.Errorf("id 不能为空")
- }
- // 查找对应记录
- idx, exists := idToIndex[int64(v.Id)]
- if !exists {
- return "", fmt.Errorf("ID为%d的记录不存在", v.Id)
- }
- // 更新记录(只更新需要修改的字段)
- simulatedData[idx].SourceMachineIP = v.SourceMachineIP
- simulatedData[idx].ConnectPort = v.ConnectPort
- simulatedData[idx].Protocol = v.Protocol
- simulatedData[idx].SdkPort = v.SdkPort
- simulatedData[idx].SdkIp = v.SdkIp
- simulatedData[idx].Type = v.Type
- //获取指针的值
- simulatedData[idx].MaxBandwidth = pointer.GetInt(v.MaxBandwidth)
- }
- s.logger.Info("模拟修改后的数据", zap.Any("data", simulatedData))
- // 5. 使用模拟修改后的数据进行验证
- // 转换数据格式
- simulatedBackend, err := s.formatter.OldFormat(ctx, simulatedData)
- if err != nil {
- return "", fmt.Errorf("格式化模拟数据失败: %w", err)
- }
- // 验证修改后的配置
- err = s.formatter.ValidateBackendData(ctx, simulatedBackend, req.HostId)
- if err != nil {
- return "", fmt.Errorf("验证失败: %w", err)
- }
- // 6. 验证通过,执行实际的数据库修改
- for _, v := range req.Items {
- if err := s.gameShieldBackendRepository.EditGameShieldBackend(ctx, &v); err != nil {
- return "", fmt.Errorf("修改数据失败(ID:%d): %w", v.Id, err)
- }
- }
- // 7. 更新远程配置
- res, _, err := s.GameShieldBackend(ctx, &v1.GameShieldBackendArrayRequest{
- HostId: req.HostId,
- Uid: req.Uid,
- Items: nil,
- })
- if err != nil {
- return "", fmt.Errorf("更新配置失败: %w", err)
- }
- return res, nil
- }
- func (s *gameShieldBackendService) DeleteGameShieldBackend(ctx context.Context, req *v1.GameShieldBackendArrayRequest) (string, error) {
- for _, v := range req.Items {
- if err := s.gameShieldBackendRepository.DeleteGameShieldBackend(ctx, int64(v.Id)); err != nil {
- return "", err
- }
- }
- res, _, err := s.GameShieldBackend(ctx, &v1.GameShieldBackendArrayRequest{HostId: req.HostId, Uid: req.Uid, Items: nil})
- if err != nil {
- return "", err
- }
- return res, nil
- }
- func (s *gameShieldBackendService) SaveGameShieldBackend(ctx context.Context, req map[string]v1.SendGameShieldBackend, hostId int) error {
- for k, v := range req {
- parts := strings.Split(v.Addr[0], ":")
- keyName := strings.Split(k, "key")[1]
- key, err := strconv.Atoi(keyName)
- if err != nil {
- return err
- }
- if v.Type != "pc" {
- v.SdkIp = "127.0.0.1"
- }
- if v.MaxBandwidth == "100m" {
- v.MaxBandwidth = "1"
- } else {
- v.MaxBandwidth = "0"
- }
- if v.Protocol != "http" {
- v.Host = ""
- }
- if err := s.gameShieldBackendRepository.AddGameShieldBackend(ctx,
- &model.GameShieldBackend{
- HostId: hostId,
- KeySort: key,
- SourceMachineIP: parts[0],
- Protocol: v.Protocol,
- ProxyAddr: v.ProxyAddr,
- ConnectPort: parts[1],
- SdkIp: v.SdkIp,
- SdkPort: strconv.Itoa(v.SdkPort),
- Type: v.Type,
- MaxBandwidth: cast.ToInt(v.MaxBandwidth),
- Host: v.Host,
- Remark: v.Remark,
- }); err != nil {
- return err
- }
- }
- return nil
- }
|