Files
dns-autoresolver/internal/notify/dispatch.go
T

79 lines
2.1 KiB
Go

package notify
import (
"context"
"errors"
"net/http"
"time"
"github.com/google/uuid"
"github.com/vasyakrg/dns-autoresolver/internal/store"
)
// ChannelStore is the narrow store dependency Dispatcher needs: the set of
// enabled notification channels for a project.
type ChannelStore interface {
ListEnabledChannels(ctx context.Context, projectID uuid.UUID) ([]store.Channel, error)
}
// Decryptor decrypts a channel's stored secret (bot token, signing key, ...).
type Decryptor interface {
Decrypt(enc string) ([]byte, error)
}
// Dispatcher fans an Event out to every enabled channel of a project,
// picking the Notifier implementation by channel type. A failure on one
// channel does not stop delivery to the others; all errors are aggregated
// via errors.Join.
type Dispatcher struct {
store ChannelStore
cipher Decryptor
byType map[string]Notifier
}
// NewDispatcher builds a Dispatcher wired with the default Telegram and
// Webhook notifiers.
func NewDispatcher(store ChannelStore, cipher Decryptor) *Dispatcher {
return &Dispatcher{
store: store,
cipher: cipher,
byType: map[string]Notifier{
"telegram": &Telegram{BaseURL: "https://api.telegram.org", HTTP: &http.Client{Timeout: 15 * time.Second}},
"webhook": &Webhook{HTTP: &http.Client{
Timeout: 15 * time.Second,
Transport: newWebhookTransport(false),
}},
},
}
}
// Send delivers ev to every enabled channel of projectID. Errors from
// individual channels are aggregated (via errors.Join) rather than aborting
// delivery to the remaining channels.
func (d *Dispatcher) Send(ctx context.Context, projectID uuid.UUID, ev Event) error {
channels, err := d.store.ListEnabledChannels(ctx, projectID)
if err != nil {
return err
}
var errs []error
for _, ch := range channels {
n, ok := d.byType[ch.Type]
if !ok {
continue
}
secret := ""
if ch.SecretEnc != "" {
b, err := d.cipher.Decrypt(ch.SecretEnc)
if err != nil {
errs = append(errs, err)
continue
}
secret = string(b)
}
if err := n.Send(ctx, ch.Config, secret, ev); err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...)
}