feat: 增加推送通知配置

This commit is contained in:
yml2213
2026-06-19 16:28:49 +08:00
parent a4cdc3e806
commit 5ff1ea40b0
15 changed files with 1376 additions and 51 deletions
@@ -0,0 +1,149 @@
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")
}
}