package adminpush import ( "context" "encoding/json" "errors" "strings" "hfb_sys/backend/internal/integrations/push" ) var ( ErrDependencyUnavailable = errors.New("dependency unavailable") ErrChannelNotFound = errors.New("push channel not found") ErrRuleNotFound = errors.New("push rule not found") ErrInvalidChannel = errors.New("invalid channel type or config") ) type Service struct { repo *Repository } func NewService(repo *Repository) *Service { return &Service{repo: repo} } func (s *Service) ListChannels(ctx context.Context) ([]ChannelDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } return s.repo.ListChannels(ctx) } func (s *Service) CreateChannel(ctx context.Context, req CreateChannelRequest) (*ChannelDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } if req.Name == "" || req.Type == "" { return nil, ErrInvalidChannel } if err := validateChannelConfig(req.Type, req.Config); err != nil { return nil, err } return s.repo.CreateChannel(ctx, req) } func (s *Service) UpdateChannel(ctx context.Context, id uint64, req UpdateChannelRequest) (*ChannelDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } if req.Config != nil { current, err := s.repo.GetChannel(ctx, id) if err != nil { return nil, err } if err := validateChannelConfig(current.Type, *req.Config); err != nil { return nil, err } } return s.repo.UpdateChannel(ctx, id, req) } func (s *Service) DeleteChannel(ctx context.Context, id uint64) error { if s.repo == nil { return ErrDependencyUnavailable } return s.repo.DeleteChannel(ctx, id) } func (s *Service) ListRules(ctx context.Context) ([]RuleDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } return s.repo.ListRules(ctx) } func (s *Service) UpdateRule(ctx context.Context, id uint64, req UpdateRuleRequest) (*RuleDTO, error) { if s.repo == nil { return nil, ErrDependencyUnavailable } if req.Threshold != nil && *req.Threshold < 1 { return nil, ErrInvalidChannel } return s.repo.UpdateRule(ctx, id, req) } func (s *Service) TestChannel(ctx context.Context, id uint64) error { if s.repo == nil { return ErrDependencyUnavailable } ch, err := s.repo.GetChannel(ctx, id) if err != nil { return err } provider, err := buildProvider(ch.Type, ch.Config) if err != nil { return err } return provider.Send(ctx, push.Message{ Title: "推送测试", Content: "这是一条测试消息,如果你收到了说明推送配置正确。", }) } func validateChannelConfig(channelType string, cfg json.RawMessage) error { switch channelType { case "bark": var c struct { DeviceKey string `json:"device_key"` } if err := json.Unmarshal(cfg, &c); err != nil || strings.TrimSpace(c.DeviceKey) == "" { return ErrInvalidChannel } case "wpush": var c struct { APIKey string `json:"api_key"` } if err := json.Unmarshal(cfg, &c); err != nil || strings.TrimSpace(c.APIKey) == "" { return ErrInvalidChannel } default: return ErrInvalidChannel } return nil } func buildProvider(channelType string, cfg json.RawMessage) (push.Provider, error) { switch channelType { case "bark": var c struct { DeviceKey string `json:"device_key"` Server string `json:"server"` } if err := json.Unmarshal(cfg, &c); err != nil { return nil, err } return push.NewBarkProvider(push.BarkConfig{DeviceKey: c.DeviceKey, Server: c.Server}) case "wpush": var c struct { APIKey string `json:"api_key"` } if err := json.Unmarshal(cfg, &c); err != nil { return nil, err } return push.NewWPushProvider(push.WPushConfig{APIKey: c.APIKey}) default: return nil, errors.New("unknown channel type") } }