Documentation
¶
Overview ¶
Package push handles Web Push subscriptions and notification delivery for self-hosted Caffeine installs. It persists browser push subscriptions in the same SQLite database the rest of the app uses and fans out notifications on "shot finished" and "analysis ready" events.
Index ¶
- type Payload
- type Preferences
- type Sender
- type Service
- type Store
- func (s *Store) Close() error
- func (s *Store) Count(ctx context.Context) (int, error)
- func (s *Store) Delete(ctx context.Context, endpoint string) error
- func (s *Store) GetVAPID(ctx context.Context) (*VAPID, error)
- func (s *Store) List(ctx context.Context) ([]Subscription, error)
- func (s *Store) SaveVAPID(ctx context.Context, v VAPID) error
- func (s *Store) Upsert(ctx context.Context, sub Subscription) error
- type Subscription
- type VAPID
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Payload ¶
type Payload struct {
Title string `json:"title"`
Body string `json:"body"`
// Tag collapses multiple notifications in the same category into a
// single entry on the device (so a run of back-to-back shots doesn't
// spam the notification center).
Tag string `json:"tag,omitempty"`
// URL is the path the PWA should navigate to when the user taps the
// notification. Must be same-origin; the SW uses clients.openWindow.
URL string `json:"url,omitempty"`
// Kind lets the SW / UI disambiguate without string-matching titles.
Kind string `json:"kind,omitempty"`
}
Payload is the JSON body we deliver to the service worker. The SW parses it in its 'push' handler and turns it into a Notification.
type Preferences ¶
type Preferences struct {
OnShotFinished bool `json:"on_shot_finished"`
OnAnalysisReady bool `json:"on_analysis_ready"`
}
Preferences captures the per-subscription event filters.
type Sender ¶
type Sender interface {
SendNotification(message []byte, sub *webpush.Subscription, options *webpush.Options) (*http.Response, error)
}
Sender is the subset of webpush used by Service. Extracted so tests can feed a fake without spinning up a push service.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service sends push notifications to every stored subscription that opted in for the given event. All public methods are non-blocking: they hand the work off to a background goroutine so they can be called from latency-sensitive spots (recorder flush, analysis completion) without holding anything up.
func NewService ¶
NewService builds a Service. Callers should only construct one per process; it's safe for concurrent use.
func (*Service) NotifyAnalysisReady ¶
NotifyAnalysisReady fires when the auto-analyzer has saved a critique.
func (*Service) NotifyShotFinished ¶
NotifyShotFinished fires when a live shot has been persisted. Runs in its own goroutine — callers need not block.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps access to push_subscriptions + push_vapid.
func OpenStore ¶
OpenStore opens the push store at path. Safe to point at the same file other internal/* packages use; tables don't collide.
func (*Store) Count ¶
Count returns the number of stored subscriptions. Handy for the settings UI status line.
func (*Store) GetVAPID ¶
GetVAPID returns the persisted VAPID keypair or (nil, nil) if none is stored yet.
func (*Store) List ¶
func (s *Store) List(ctx context.Context) ([]Subscription, error)
List returns every subscription. Order is stable (oldest first) so the caller can reason about fan-out timing if it cares.
func (*Store) SaveVAPID ¶
SaveVAPID persists the keypair. The table is pinned to a single row (id=1) so this is effectively a replace.
func (*Store) Upsert ¶
func (s *Store) Upsert(ctx context.Context, sub Subscription) error
Upsert inserts-or-updates a subscription keyed on endpoint. The endpoint URL is effectively the browser's stable identifier for this (origin, installation) pair; reusing it lets a browser that re-subscribes — say after a permission toggle — overwrite the old row instead of piling up orphans.
type Subscription ¶
type Subscription struct {
Endpoint string
P256dh string
Auth string
OnShotFinished bool
OnAnalysisReady bool
UserAgent string
CreatedAt time.Time
UpdatedAt time.Time
}
Subscription is a stored browser push subscription.
type VAPID ¶
VAPID is the server identity used to sign outbound push requests.
func LoadOrGenerateVAPID ¶
func LoadOrGenerateVAPID(ctx context.Context, store *Store, envPub, envPriv, subject string) (VAPID, error)
LoadOrGenerateVAPID returns the persisted VAPID keypair, generating and persisting a fresh one on first run. Env-supplied values (if both publicKey and privateKey are non-empty) always win and are written back into the store so subsequent restarts stay stable if the env var is removed.
subject is the "Subscriber" claim embedded in VAPID-signed requests. Push services use it to reach out to the server owner if something misbehaves; mailto: URLs are the canonical form but any URL works.