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" "github.com/spf13/viper" "golang.org/x/sync/errgroup" "strconv" "time" ) type GlobalLimitService interface { GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error) AddGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error EditGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error DeleteGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error EditGlobalLimitBySnail(ctx context.Context, req v1.GlobalLimitEditRequest) error } func NewGlobalLimitService( service *Service, globalLimitRepository repository.GlobalLimitRepository, duedate DuedateService, crawler CrawlerService, conf *viper.Viper, required RequiredService, parser ParserService, host HostService, tcpLimit TcpLimitService, udpLimit UdpLimitService, webLimit WebLimitService, gateWayGroup GatewayGroupService, hostRep repository.HostRepository, gateWayGroupRep repository.GatewayGroupRepository, cdnService CdnService, ) GlobalLimitService { return &globalLimitService{ Service: service, globalLimitRepository: globalLimitRepository, duedate: duedate, crawler: crawler, Url: conf.GetString("crawler.Url"), required: required, parser: parser, host: host, tcpLimit: tcpLimit, udpLimit: udpLimit, webLimit: webLimit, gateWayGroup: gateWayGroup, hostRep: hostRep, gateWayGroupRep: gateWayGroupRep, cdnService: cdnService, } } type globalLimitService struct { *Service globalLimitRepository repository.GlobalLimitRepository duedate DuedateService crawler CrawlerService Url string required RequiredService parser ParserService host HostService tcpLimit TcpLimitService udpLimit UdpLimitService webLimit WebLimitService gateWayGroup GatewayGroupService hostRep repository.HostRepository gateWayGroupRep repository.GatewayGroupRepository cdnService CdnService } func (s *globalLimitService) GetCdnUserId(ctx context.Context, uid int64) (int64, error) { data, err := s.globalLimitRepository.GetGlobalLimitFirst(ctx, uid) if err != nil { return 0, err } if data != nil && data.CdnUid != 0 { return int64(data.CdnUid), nil } userInfo,err := s.globalLimitRepository.GetUserInfo(ctx, uid) if err != nil { return 0, err } userId, err := s.cdnService.AddUser(ctx, v1.User{ Username: userInfo.Username, Email: userInfo.Email, Fullname: userInfo.Username, Mobile: userInfo.PhoneNumber, }) if err != nil { return 0, err } return userId, nil } func (s *globalLimitService) AddGroupId(ctx context.Context,groupName string) (int64, error) { groupId, err := s.cdnService.CreateGroup(ctx, v1.Group{ Name: groupName, }) if err != nil { return 0, err } return groupId, nil } func (s *globalLimitService) GlobalLimitRequire(ctx context.Context, req v1.GlobalLimitRequest) (res v1.GlobalLimitRequireResponse, err error) { res.ExpiredAt, err = s.duedate.NextDueDate(ctx, req.Uid, req.HostId) if err != nil { return v1.GlobalLimitRequireResponse{}, err } configCount, err := s.host.GetGlobalLimitConfig(ctx, req.HostId) if err != nil { return v1.GlobalLimitRequireResponse{}, fmt.Errorf("获取配置限制失败: %w", err) } bpsInt, err := strconv.Atoi(configCount.Bps) if err != nil { return v1.GlobalLimitRequireResponse{}, err } resultFloat := float64(bpsInt) / 2.0 / 8.0 res.Bps = strconv.FormatFloat( resultFloat, 'f', -1, 64) + "M" res.MaxBytesMonth = configCount.MaxBytesMonth res.Operator = configCount.Operator res.IpCount = configCount.IpCount domain, err := s.hostRep.GetDomainById(ctx, req.HostId) if err != nil { return v1.GlobalLimitRequireResponse{}, err } res.GlobalLimitName = strconv.Itoa(req.Uid) + "_" + strconv.Itoa(req.HostId) + "_" + domain return res, nil } func (s *globalLimitService) GetGlobalLimit(ctx context.Context, id int64) (*model.GlobalLimit, error) { return s.globalLimitRepository.GetGlobalLimit(ctx, id) } func (s *globalLimitService) AddGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error { isExist, err := s.globalLimitRepository.IsGlobalLimitExistByHostId(ctx, int64(req.HostId)) if err != nil { return err } if isExist { return fmt.Errorf("配置限制已存在") } require, err := s.GlobalLimitRequire(ctx, req) if err != nil { return err } g, gCtx := errgroup.WithContext(ctx) var gatewayGroupId int var userId int64 var groupId int64 g.Go(func() error { gatewayGroupId, e := s.gateWayGroupRep.GetGatewayGroupWhereHostIdNull(gCtx, require.Operator, require.IpCount) if e != nil { return e } if gatewayGroupId == 0 { return fmt.Errorf("获取网关组失败") } return nil }) g.Go(func() error { res, e := s.GetCdnUserId(gCtx, int64(req.Uid)) if e != nil { return e } if res == 0 { return fmt.Errorf("获取cdn用户失败") } userId = res return nil }) g.Go(func() error { res, e := s.AddGroupId(gCtx, require.GlobalLimitName) if e != nil { return e } if res == 0 { return fmt.Errorf("创建规则分组失败") } return nil }) if err = g.Wait(); err != nil { return err } ruleId, err := s.cdnService.BindPlan(ctx, v1.Plan{ }) err = s.globalLimitRepository.AddGlobalLimit(ctx, &model.GlobalLimit{ HostId: req.HostId, Uid: req.Uid, RuleId: , CdnUid: int(userId), Comment: req.Comment, ExpiredAt: require.ExpiredAt, }) if err != nil { return err } return nil } func (s *globalLimitService) EditGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error { require, err := s.GlobalLimitRequire(ctx, req) if err != nil { return err } formData := map[string]interface{}{ "tag": require.GlobalLimitName, "bps": require.Bps, "max_bytes_month": require.MaxBytesMonth, "expired_at": require.ExpiredAt, } data, err := s.globalLimitRepository.GetGlobalLimitByHostId(ctx, int64(req.HostId)) if err != nil { return err } respBody, err := s.required.SendForm(ctx, "admin/info/waf_common_limit/edit?&__goadmin_edit_pk="+strconv.Itoa(data.RuleId), "admin/edit/waf_common_limit", formData) if err != nil { return err } res, err := s.parser.ParseAlert(string(respBody)) if err != nil { return err } if res != "" { return fmt.Errorf(res) } t, err := time.Parse("2006-01-02 15:04:05", require.ExpiredAt) if err != nil { return err } expiredAt := t.Unix() if err := s.globalLimitRepository.UpdateGlobalLimitByHostId(ctx, &model.GlobalLimit{ HostId: req.HostId, Comment: req.Comment, ExpiredAt: expiredAt, }); err != nil { return err } return nil } func (s *globalLimitService) EditGlobalLimitBySnail(ctx context.Context, req v1.GlobalLimitEditRequest) error { configCount, err := s.host.GetGlobalLimitConfig(ctx, req.HostId) if err != nil { return fmt.Errorf("获取配置限制失败: %w", err) } data, err := s.globalLimitRepository.GetGlobalLimitByHostId(ctx, int64(req.HostId)) if err != nil { return err } t := time.Unix(req.ExpiredAt, 0) expiredAt := t.Format("2006-01-02 15:04:05") formData := map[string]interface{}{ "tag": data.GlobalLimitName, "bps": configCount.Bps, "max_bytes_month": configCount.MaxBytesMonth, "expired_at": expiredAt, } respBody, err := s.required.SendForm(ctx, "admin/info/waf_common_limit/edit?&__goadmin_edit_pk="+strconv.Itoa(req.RuleId), "admin/edit/waf_common_limit", formData) if err != nil { return err } if respBody == nil { return nil } return nil } func (s *globalLimitService) DeleteGlobalLimit(ctx context.Context, req v1.GlobalLimitRequest) error { if err := s.globalLimitRepository.DeleteGlobalLimitByHostId(ctx, int64(req.HostId)); err != nil { return err } return nil }