package business import ( "context" "encoding/json" "kra/internal/biz/business" "kra/internal/service/dto" "math" "strconv" "strings" "unicode/utf8" ) type AlertRuleUsecase interface { List(context.Context, business.AlertRuleFilter, ...business.ListOption) ([]*business.AlertRule, int64, error) Find(context.Context, uint64) (*business.AlertRule, error) Types(context.Context) ([]string, error) Save(context.Context, *business.AlertRule) (uint64, error) Delete(context.Context, uint64) error Toggle(context.Context, uint64, int) error } type AlertRuleService struct{ uc AlertRuleUsecase } func NewAlertRuleService(uc *business.AlertRuleUsecase) *AlertRuleService { return &AlertRuleService{uc: uc} } func alertRuleResponse(r *business.AlertRule) *dto.AlertRuleResponse { var threshold *json.Number if r.MomThreshold != nil { n := json.Number(*r.MomThreshold) threshold = &n } return &dto.AlertRuleResponse{ID: r.ID, RuleName: r.Name, RuleType: r.Type, RuleTypeLabel: business.AlertRuleTypeLabel(r.Type), MonitorMetric: r.Metric, MonitorMetricLabel: business.AlertMetricLabel(r.Metric), StatPeriodDays: r.StatPeriodDays, MomDirection: r.MomDirection, MomDirectionLabel: business.AlertDirectionLabel(r.MomDirection), MomThreshold: threshold, UnloginDays: r.UnloginDays, MonitorScope: r.MonitorScope, WarningColor: r.WarningColor, CreatorID: r.CreatorID, CreatorName: r.CreatorName, Enabled: r.Enabled, CreatedAt: localTime(&r.CreatedAt), UpdatedAt: localTime(&r.UpdatedAt), RuleDescription: r.Description()} } func (s *AlertRuleService) List(ctx context.Context, req *dto.AlertRuleQuery) (*dto.AlertRulePage, error) { if req == nil { return nil, business.ErrAlertRuleInput } filter := business.AlertRuleFilter{Name: req.RuleName, Type: req.RuleType} if req.MonitorMetric != "" { n, err := strconv.Atoi(req.MonitorMetric) if err != nil || n < 1 || n > 3 { return nil, business.ErrAlertRuleInput } filter.Metric = &n } page, size := req.Page, req.PageSize if page < 1 { page = 1 } if size < 1 { size = 10 } if size > 500 { size = 500 } if page > int(^uint(0)>>1)/size { return nil, business.ErrAlertRuleInput } rows, total, err := s.uc.List(ctx, filter, business.ListOffset((page-1)*size), business.ListLimit(size)) if err != nil { return nil, err } out := &dto.AlertRulePage{Rows: make([]*dto.AlertRuleResponse, 0, len(rows)), Total: total} for _, r := range rows { out.Rows = append(out.Rows, alertRuleResponse(r)) } return out, nil } func (s *AlertRuleService) Find(ctx context.Context, id uint64) (*dto.AlertRuleResponse, error) { if id == 0 { return nil, business.ErrAlertRuleInput } rule, err := s.uc.Find(ctx, id) if err != nil { return nil, err } return alertRuleResponse(rule), nil } func (s *AlertRuleService) Types(ctx context.Context) ([]string, error) { return s.uc.Types(ctx) } func (s *AlertRuleService) Save(ctx context.Context, req *dto.AlertRuleRequest) (uint64, error) { if req == nil || strings.TrimSpace(req.RuleName) == "" || utf8.RuneCountInString(req.RuleName) > 100 || strings.TrimSpace(req.RuleType) == "" || strings.TrimSpace(req.WarningColor) == "" || len(req.WarningColor) > 20 { return 0, business.ErrAlertRuleInput } for _, n := range []*int{req.StatPeriodDays, req.UnloginDays} { if n != nil && (*n > math.MaxInt32 || *n < math.MinInt32) { return 0, business.ErrAlertRuleInput } } rule := &business.AlertRule{ID: req.ID, Name: req.RuleName, Type: req.RuleType, Metric: req.MonitorMetric, StatPeriodDays: req.StatPeriodDays, MomDirection: req.MomDirection, UnloginDays: req.UnloginDays, WarningColor: req.WarningColor} if req.MomThreshold != nil { value := req.MomThreshold.String() rule.MomThreshold = &value } return s.uc.Save(ctx, rule) } func (s *AlertRuleService) Delete(ctx context.Context, id uint64) error { if id == 0 { return business.ErrAlertRuleInput } return s.uc.Delete(ctx, id) } func (s *AlertRuleService) Toggle(ctx context.Context, id uint64, enabled int) error { if id == 0 { return business.ErrAlertRuleInput } return s.uc.Toggle(ctx, id, enabled) }