Help us shape the future of Go! Take the 2026 Go Developer Survey

notify

package
v0.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 3, 2026 License: GPL-3.0 Imports: 37 Imported by: 0

Documentation

Overview

Package notify provides durable, rule-filtered owner notifications. Channel secrets never appear in API responses, delivery logs, or transport errors.

Index

Constants

View Source
const Redacted = "[configured]"

Variables

View Source
var Kinds = []string{"server.started", "server.stopping", "server.crash", "provider.recovered", "indexer.recovered", "cache.recovered", "playback.start", "playback.stop", "playback.error", "playback.failover", "provider.outage", "indexer.outage", "indexer.budget", "cache.full", "cert.renewed", "update.available", "backup.failed", "user.joined", "title.available", "newsletter.weekly", "test"}

Functions

func PurgeGrantTx added in v0.3.0

func PurgeGrantTx(ctx context.Context, tx *sql.Tx, viewerID int64, grantHash string) error

func PurgeViewerTx added in v0.3.0

func PurgeViewerTx(ctx context.Context, tx *sql.Tx, viewerID int64) error

PurgeViewerTx and PurgeGrantTx participate in the same transaction that deactivates membership or revokes a device grant.

func RunMonitor added in v0.2.4

func RunMonitor(input io.Reader) error

RunMonitor is used only by the executable's notification-monitor entry point. A killed host, network outage, or supervisor killing the whole process group also stops this watcher. An external uptime monitor is required for those.

Types

type Channel

type Channel struct {
	SMTPMode      string            `json:"smtpMode,omitempty"`
	Subscription  *PushSubscription `json:"subscription,omitempty"`
	ID            string            `json:"id"`
	Name          string            `json:"name"`
	Kind          string            `json:"kind"`
	Enabled       bool              `json:"enabled"`
	Events        []string          `json:"events"`
	Endpoint      string            `json:"endpoint"`
	Token         string            `json:"token"`
	Target        string            `json:"target"`
	Username      string            `json:"username"`
	Password      string            `json:"password"`
	From          string            `json:"from"`
	To            string            `json:"to"`
	PerMinute     int               `json:"perMinute"`
	DigestMinutes int               `json:"digestMinutes"`
}

type Event

type Event struct {
	HTML    string    `json:"html,omitempty"`
	Kind    string    `json:"kind"`
	Title   string    `json:"title"`
	Message string    `json:"message"`
	At      time.Time `json:"at"`
}

type EventInfo added in v0.2.4

type EventInfo struct {
	Kind        string `json:"kind"`
	Description string `json:"description"`
	Automatic   bool   `json:"automatic"`
}

EventInfo distinguishes automatic producers from owner API integrations. Existing event identifiers remain accepted for compatibility.

type FavoriteEpisodeDetector added in v0.3.0

type FavoriteEpisodeDetector struct {
	Preferences *ViewerAlerts
	// Episodes must return only visible, currently favorited shows and episodes.
	Episodes func(context.Context, *core.User) ([]core.Title, error)
	Now      func() time.Time
}

FavoriteEpisodeDetector scans only currently authorized favorites. The caller runs it under the cluster leader lease. The database uniqueness constraint also protects against overlap during a leader handoff.

func (*FavoriteEpisodeDetector) Scan added in v0.3.0

type Heartbeat added in v0.2.4

type Heartbeat struct {
	Enabled  bool   `json:"enabled"`
	Endpoint string `json:"endpoint"`
}

type Options

type Options struct {
	// NodeID names this node on the queue rows it claims; a random id is
	// used when empty.
	NodeID     string
	Providers  func() []usenet.ProviderStats
	CacheUsage func() (int64, int64)
	Client     *http.Client
	Now        func() time.Time
	Logger     *slog.Logger
	// Sealer protects stored channel secrets and the push identity
	// (secrets.go); nil stores them as given.
	Sealer config.FieldSealer
}

type PushKeys added in v0.2.4

type PushKeys struct {
	Auth   string `json:"auth"`
	P256dh string `json:"p256dh"`
}

type PushSubscription added in v0.2.4

type PushSubscription struct {
	Endpoint string   `json:"endpoint"`
	Keys     PushKeys `json:"keys"`
}

type Service

type Service struct {
	// contains filtered or unexported fields
}

func New

func New(db *sql.DB, opts Options) *Service

func (*Service) BackupFailed added in v0.2.48

func (s *Service) BackupFailed(ctx context.Context, err error) error

BackupFailed reports a scheduled backup that did not complete.

func (*Service) Channels

func (s *Service) Channels(ctx context.Context) ([]Channel, error)

func (*Service) Drain

func (s *Service) Drain(ctx context.Context) error

func (*Service) Emit

func (s *Service) Emit(ctx context.Context, e Event) error

func (*Service) EmitOnce added in v0.2.48

func (s *Service) EmitOnce(ctx context.Context, key string, e Event) (bool, error)

EmitOnce emits e unless an event was already emitted under key, and reports whether it emitted. The key and the queued deliveries commit in one transaction: a crash or a failed enqueue leaves neither, so a later attempt emits it.

func (*Service) Handler

func (s *Service) Handler() http.Handler

Handler is an owner-only API; mount with /notifications stripped.

func (*Service) Heartbeat added in v0.2.4

func (s *Service) Heartbeat(ctx context.Context) error

Heartbeat is called only after a successful local HTTP probe. The remote monitor must alert when these one-minute pings stop (allow a three-minute grace).

func (*Service) HeartbeatSettings added in v0.2.4

func (s *Service) HeartbeatSettings(ctx context.Context, redact bool) (Heartbeat, error)

func (*Service) MigrateSecrets added in v0.2.4

func (s *Service) MigrateSecrets(ctx context.Context) (int, error)

MigrateSecrets seals channel secrets and the push identity stored in plaintext and returns how many rows it rewrote. A row is replaced only if it is unchanged since read, so it is safe to rerun on any node; a row that does not open is left untouched and reported in the error.

func (*Service) ObserveIndexer

func (s *Service) ObserveIndexer(e newznab.Event)

ObserveIndexer alerts once per outage, retrying failed queue writes at most once a minute. Database waits never hold the shared health mutex.

func (*Service) ObservePlayback

func (s *Service) ObservePlayback(ev playback.Event)

ObservePlayback only enqueues; network delivery runs separately in Run.

func (*Service) Run

func (s *Service) Run(ctx context.Context)

Run is the single queue consumer. Failed sends are recorded without automatic retry, avoiding duplicate delivery when an upstream timeout is ambiguous.

func (*Service) SampleHealth

func (s *Service) SampleHealth(ctx context.Context) error

SampleHealth emits one alert on entering an unhealthy state, rather than one alert for every sample. Normal recovery allows a later outage to alert again.

func (*Service) Save

func (s *Service) Save(ctx context.Context, c Channel) error

func (*Service) SaveHeartbeat added in v0.2.4

func (s *Service) SaveHeartbeat(ctx context.Context, h Heartbeat) error

func (*Service) TitleAvailable

func (s *Service) TitleAvailable(ctx context.Context, title string) error

TitleAvailable lets the discovery/watchlist flow publish availability.

func (*Service) TitleAvailableOnce added in v0.2.48

func (s *Service) TitleAvailableOnce(ctx context.Context, key, title string) error

TitleAvailableOnce publishes availability once per key (an episode, say), however often a caller retries after a failure or crash.

func (*Service) UpdateAvailable added in v0.2.48

func (s *Service) UpdateAvailable(ctx context.Context, current, version string) error

UpdateAvailable announces a release once per version.

func (*Service) WatchProcess added in v0.2.4

func (s *Service) WatchProcess(executable string) (func(bool) error, error)

WatchProcess starts a small independent delivery process. The returned function must be called on normal exit, with clean=false for a fatal run error. A panic must be allowed to terminate the parent so that EOF reaches the watcher.

type ViewerAlerts added in v0.3.0

type ViewerAlerts struct {
	DB     *sql.DB
	Active func(context.Context, int64) (*core.User, error)
	Now    func() time.Time
}

ViewerAlerts keeps viewer notification settings separate from owner channels. Active must consult current membership, not a cached viewer supplied by the caller.

func (*ViewerAlerts) Enabled added in v0.3.0

func (s *ViewerAlerts) Enabled(ctx context.Context, viewer *core.User) (bool, error)

Enabled defaults to false for every viewer without an explicit preference.

func (*ViewerAlerts) SetEnabled added in v0.3.0

func (s *ViewerAlerts) SetEnabled(ctx context.Context, viewer *core.User, enabled bool) error

SetEnabled records the time of each off-to-on transition so detection can suppress episodes already aired before a viewer opted in.

type ViewerPush added in v0.3.0

type ViewerPush struct {
	Notifications *Service
	Preferences   *ViewerAlerts
	Allowed       func(context.Context, *core.User, core.RatingKey) (bool, error)
	Now           func() time.Time
	// Send is optional and permits offline tests; nil uses the web-push transport.
	Send func(context.Context, PushSubscription, Event) error
}

ViewerPush uses viewer-owned destinations, separate from owner channels. Allowed must recheck the favorite show and current episode/show policy.

func (*ViewerPush) Drain added in v0.3.0

func (p *ViewerPush) Drain(ctx context.Context) error

Drain claims recent alerts once per destination across nodes. Claims are intentionally at-most-once: a crash or send failure does not replay a push. Old alerts and alerts preceding subscription or opt-in are never sent.

func (*ViewerPush) PublicKey added in v0.3.0

func (p *ViewerPush) PublicKey(ctx context.Context, viewer *core.User) (string, error)

func (*ViewerPush) PurgeViewer added in v0.3.0

func (p *ViewerPush) PurgeViewer(ctx context.Context, viewerID int64) error

PurgeViewer removes all destinations after membership deactivation or revocation.

func (*ViewerPush) Register added in v0.3.0

func (p *ViewerPush) Register(ctx context.Context, viewer *core.User, subscription PushSubscription, grantHash string) error

Register associates a browser endpoint with its current viewer only.

func (*ViewerPush) Registered added in v0.3.0

func (p *ViewerPush) Registered(ctx context.Context, viewer *core.User, endpoint string) (bool, error)

Registered reports whether this exact browser endpoint belongs to the viewer.

func (*ViewerPush) Unregister added in v0.3.0

func (p *ViewerPush) Unregister(ctx context.Context, viewer *core.User, endpoint string) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL