Documentation
¶
Overview ¶
Package push handles Web Push subscriptions and notification delivery. Subscriptions and the singleton VAPID keypair live in the shared Postgres database.
Index ¶
- func CandidateOther(primary string, names []string) string
- type Factory
- type NetworkConfirm
- type Payload
- type Preferences
- type Sender
- type Service
- func (s *Service) NotifyAnomaly(store *Store, title, body, deepLink string)
- func (s *Service) NotifyChargingDone(store *Store, sessionID, summary string)
- func (s *Service) NotifyNetworkConfirm(store *Store, userKey string, e NetworkConfirm, pending int)
- func (s *Service) NotifyPlugInReminder(store *Store, soc int)
- func (s *Service) PublicKey() string
- func (s *Service) SendTest(ctx context.Context, store *Store, endpoint string) error
- 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 ¶
func CandidateOther ¶ added in v0.33.2
CandidateOther picks the second distinct network from detection evidence candidates (names in nearest-first order); "" when none.
Types ¶
type Factory ¶
type Factory struct {
// contains filtered or unexported fields
}
Factory hands out per-user *Store instances. push.Store wraps (db, userID); the per-user split is for routing, not for per-user-VAPID — the VAPID keypair is global (push_vapid.id = 1) and any *Store can read it.
type NetworkConfirm ¶ added in v0.33.2
type NetworkConfirm struct {
ChargeID string
// Network is the detected network's display name ("" if unmatched).
Network string
// Other is a second, co-located network, if the evidence has one.
Other string
Cost float64
Rate float64
KWh float64
// Matched is false when nothing was within range (no price).
Matched bool
// State is "estimated" or "needs_confirmation".
State string
}
NetworkConfirm is what the close hook knows about an auto-priced charge. Cost/Rate are zero when nothing matched.
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.
func NetworkConfirmPayload ¶ added in v0.33.2
func NetworkConfirmPayload(e NetworkConfirm) Payload
NetworkConfirmPayload builds the notification for e, using the contract's three wordings.
type Preferences ¶
type Preferences struct {
OnChargingDone bool `json:"on_charging_done"`
OnPlugInReminder bool `json:"on_plug_in_reminder"`
OnAnomaly bool `json:"on_anomaly"`
}
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) NotifyAnomaly ¶
NotifyAnomaly fires when an anomaly is detected for the user. Scoped to the user via store.
func (*Service) NotifyChargingDone ¶
NotifyChargingDone fires when a charge session reaches its terminal state. The provided store must be scoped to the owning user.
func (*Service) NotifyNetworkConfirm ¶ added in v0.33.2
func (s *Service) NotifyNetworkConfirm(store *Store, userKey string, e NetworkConfirm, pending int)
NotifyNetworkConfirm sends the confirm-or-change push for an auto-priced DC fast charge, rate limited per user. userKey scopes the limiter (the user id); pending is how many charges the user has open for confirmation, used in the collapsed summary. The limiter is per-process: with several pods a user can see up to confirmPerWindow per pod.
func (*Service) NotifyPlugInReminder ¶
NotifyPlugInReminder fires when the vehicle is parked at home below a configured SoC threshold. Scoped to the user via store.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store wraps access to push_subscriptions + push_vapid. Scoped to a single user_id; the VAPID keypair is global (push_vapid.id = 1).
func NewServerStore ¶
NewServerStore returns a *Store usable only for VAPID Get/Save. Subscription ops will fail (userID is zero); that's by design — VAPID is the only push state that's truly server-wide.
func (*Store) GetVAPID ¶
GetVAPID returns the persisted VAPID keypair or (nil, nil) if none is stored yet. The keypair is shared across all users of this install.
func (*Store) List ¶
func (s *Store) List(ctx context.Context) ([]Subscription, error)
List returns every subscription for this user, oldest first.
type Subscription ¶
type Subscription struct {
Endpoint string
P256dh string
Auth string
OnChargingDone bool
OnPlugInReminder bool
OnAnomaly 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.