Documentation
¶
Overview ¶
Package notify provides durable, rule-filtered owner notifications. Channel secrets never appear in API responses, delivery logs, or transport errors.
Index ¶
- Constants
- Variables
- func ChannelKindDescriptors() []extend.Descriptor
- func EventKindDescriptors() []extend.Descriptor
- func PurgeGrantTx(ctx context.Context, tx *sql.Tx, viewerID int64, grantHash string) error
- func PurgeViewerTx(ctx context.Context, tx *sql.Tx, viewerID int64) error
- func RunMonitor(input io.Reader) error
- type Channel
- type ChannelKind
- type Event
- type FavoriteEpisodeDetector
- type Heartbeat
- type KindRegistry
- type Options
- type PushKeys
- type PushSubscription
- type Service
- func (s *Service) BackupFailed(ctx context.Context, err error) error
- func (s *Service) Channels(ctx context.Context) ([]Channel, error)
- func (s *Service) Drain(ctx context.Context) error
- func (s *Service) Emit(ctx context.Context, e Event) error
- func (s *Service) EmitOnce(ctx context.Context, key string, e Event) (bool, error)
- func (s *Service) HTTPClient() *http.Client
- func (s *Service) Handler() http.Handler
- func (s *Service) Heartbeat(ctx context.Context) error
- func (s *Service) HeartbeatSettings(ctx context.Context, redact bool) (Heartbeat, error)
- func (s *Service) Kinds() *KindRegistry
- func (s *Service) MigrateSecrets(ctx context.Context) (int, error)
- func (s *Service) ObserveIndexer(e newznab.Event)
- func (s *Service) ObservePlayback(ev playback.Event)
- func (s *Service) RegisterChannelKind(k ChannelKind) error
- func (s *Service) Run(ctx context.Context)
- func (s *Service) SampleHealth(ctx context.Context) error
- func (s *Service) Save(ctx context.Context, c Channel) error
- func (s *Service) SaveHeartbeat(ctx context.Context, h Heartbeat) error
- func (s *Service) Subscribe(fn func(Event)) func()
- func (s *Service) TitleAvailable(ctx context.Context, title string) error
- func (s *Service) TitleAvailableOnce(ctx context.Context, key, title string) error
- func (s *Service) UpdateAvailable(ctx context.Context, current, version string) error
- func (s *Service) WatchProcess(executable string) (func(bool) error, error)
- type ViewerAlerts
- type ViewerPush
- func (p *ViewerPush) Drain(ctx context.Context) error
- func (p *ViewerPush) PublicKey(ctx context.Context, viewer *core.User) (string, error)
- func (p *ViewerPush) PurgeViewer(ctx context.Context, viewerID int64) error
- func (p *ViewerPush) Register(ctx context.Context, viewer *core.User, subscription PushSubscription, ...) error
- func (p *ViewerPush) Registered(ctx context.Context, viewer *core.User, endpoint string) (bool, error)
- func (p *ViewerPush) Unregister(ctx context.Context, viewer *core.User, endpoint string) error
Constants ¶
const Redacted = "[configured]"
Variables ¶
var Kinds = eventKindIDs()
Kinds lists every event kind Ether accepts. Definitions live in events.go.
Functions ¶
func ChannelKindDescriptors ¶ added in v0.3.3
func ChannelKindDescriptors() []extend.Descriptor
ChannelKindDescriptors returns the built-in channelKind descriptors for the extend registry.
func EventKindDescriptors ¶ added in v0.3.3
func EventKindDescriptors() []extend.Descriptor
EventKindDescriptors returns the built-in eventKind descriptors for the extend registry.
func PurgeGrantTx ¶ added in v0.3.0
func PurgeViewerTx ¶ added in v0.3.0
PurgeViewerTx and PurgeGrantTx participate in the same transaction that deactivates membership or revokes a device grant.
func RunMonitor ¶ added in v0.2.4
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 {
ID string `json:"id"`
Name string `json:"name"`
Kind string `json:"kind"`
Enabled bool `json:"enabled"`
Events []string `json:"events"`
Settings map[string]string `json:"settings,omitempty"`
Secrets map[string]string `json:"secrets,omitempty"`
PerMinute int `json:"perMinute"`
DigestMinutes int `json:"digestMinutes"`
}
Channel is one notification destination. Kind-specific values live in Settings (plain) and Secrets (sealed at rest, redacted by the owner API), keyed by the field names of the kind's schema (kinds.go).
func (*Channel) SetSubscription ¶ added in v0.3.3
func (c *Channel) SetSubscription(p *PushSubscription)
SetSubscription stores p as the channel's subscription secret.
func (Channel) Subscription ¶ added in v0.2.4
func (c Channel) Subscription() (*PushSubscription, error)
Subscription decodes the browser push subscription held in Secrets.
type ChannelKind ¶ added in v0.3.3
type ChannelKind struct {
ID string
Owner string // extend.Builtin or a plugin id
Label extend.Text
Hint extend.Text
Icon string
Order int
Fields []extend.SettingsField
SendTest bool
Selectable bool
Formats []string
MaxLength int
Validate func(c Channel) error
Deliver func(ctx context.Context, s *Service, c Channel, e Event) error
}
ChannelKind is one way notifications can be delivered: a settings schema the console renders, validation, and delivery. Built-ins and (through Service.RegisterChannelKind) plugin kinds use the same shape; each kind becomes a channelKind descriptor in the extend registry.
func BuiltinChannelKinds ¶ added in v0.3.3
func BuiltinChannelKinds() []ChannelKind
BuiltinChannelKinds returns Ether's own channel kinds, ordered as in the console picker.
func (ChannelKind) Descriptor ¶ added in v0.3.3
func (k ChannelKind) Descriptor() extend.Descriptor
Descriptor returns the kind as a channelKind descriptor.
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.
type KindRegistry ¶ added in v0.3.3
type KindRegistry struct {
// contains filtered or unexported fields
}
KindRegistry holds the channel kinds a service can validate and deliver. It is safe for concurrent use; the plugin host registers plugin kinds here as plugins are installed.
func NewKindRegistry ¶ added in v0.3.3
func NewKindRegistry(kinds ...ChannelKind) *KindRegistry
NewKindRegistry returns a registry holding kinds.
func (*KindRegistry) Get ¶ added in v0.3.3
func (r *KindRegistry) Get(id string) (ChannelKind, bool)
Get returns one kind.
func (*KindRegistry) List ¶ added in v0.3.3
func (r *KindRegistry) List() []ChannelKind
List returns every kind, ordered for pickers.
func (*KindRegistry) Register ¶ added in v0.3.3
func (r *KindRegistry) Register(k ChannelKind) error
Register adds a kind. IDs must be unique; plugin kinds are namespaced by their descriptor but share this delivery table by full descriptor id.
func (*KindRegistry) RemovePlugin ¶ added in v0.3.3
func (r *KindRegistry) RemovePlugin(id, owner string)
RemovePlugin removes a plugin's channel kind without affecting built-ins.
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
// Kinds is the channel-kind registry; nil uses the built-ins.
Kinds *KindRegistry
}
type PushSubscription ¶ added in v0.2.4
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func (*Service) BackupFailed ¶ added in v0.2.48
BackupFailed reports a scheduled backup that did not complete.
func (*Service) EmitOnce ¶ added in v0.2.48
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) HTTPClient ¶ added in v0.3.3
HTTPClient is the client channel kinds deliver with.
func (*Service) Heartbeat ¶ added in v0.2.4
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 (*Service) Kinds ¶ added in v0.3.3
func (s *Service) Kinds() *KindRegistry
Kinds returns the service's channel-kind registry.
func (*Service) MigrateSecrets ¶ added in v0.2.4
MigrateSecrets seals channel secrets stored in plaintext, rewrites flat pre-registry channel rows in the new {settings, secrets} shape, and seals the push identity. It 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 ¶
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 ¶
ObservePlayback only enqueues; network delivery runs separately in Run.
func (*Service) RegisterChannelKind ¶ added in v0.3.3
func (s *Service) RegisterChannelKind(k ChannelKind) error
RegisterChannelKind adds a channel kind (plugin kinds; WS9f).
func (*Service) Run ¶
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 ¶
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) SaveHeartbeat ¶ added in v0.2.4
func (*Service) Subscribe ¶ added in v0.3.3
Subscribe observes successfully emitted events, independent of channel selection.
func (*Service) TitleAvailable ¶
TitleAvailable lets the discovery/watchlist flow publish availability.
func (*Service) TitleAvailableOnce ¶ added in v0.2.48
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
UpdateAvailable announces a release once per version.
func (*Service) WatchProcess ¶ added in v0.2.4
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
Enabled defaults to false for every viewer without an explicit preference.
func (*ViewerAlerts) SetEnabled ¶ added in v0.3.0
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) 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.