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

push

package
v0.36.21 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package push handles Web Push subscriptions and notification delivery. Subscriptions and the singleton VAPID keypair live in the shared Postgres database.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CandidateOther added in v0.33.2

func CandidateOther(primary string, names []string) string

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.

func NewFactory

func NewFactory(d *sql.DB) *Factory

NewFactory wraps the shared pool.

func (*Factory) DB

func (f *Factory) DB() *sql.DB

DB exposes the shared pool. Used by main.go to load/generate the global VAPID keypair, which lives at push_vapid.id=1 and isn't scoped to any user.

func (*Factory) For

func (f *Factory) For(userID uuid.UUID) *Store

For returns the *Store for userID, constructing one on first sight.

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"`
	OnSoftwareUpdate bool `json:"on_software_update"`
}

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

func NewService(store *Store, vapid VAPID, logger *slog.Logger) *Service

NewService builds a Service. Callers should only construct one per process; it's safe for concurrent use.

func (*Service) NotifyAnomaly

func (s *Service) NotifyAnomaly(store *Store, title, body, deepLink string)

NotifyAnomaly fires when an anomaly is detected for the user. Scoped to the user via store.

func (*Service) NotifyChargingDone

func (s *Service) NotifyChargingDone(store *Store, sessionID, summary string)

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

func (s *Service) NotifyPlugInReminder(store *Store, soc int)

NotifyPlugInReminder fires when the vehicle is parked at home below a configured SoC threshold. Scoped to the user via store.

func (*Service) NotifySoftwareUpdate added in v0.36.10

func (s *Service) NotifySoftwareUpdate(store *Store, vehicle, version, notesURL string, installed bool)

NotifySoftwareUpdate fires when a vehicle is offered a new software version (installed=false) or its installed version changed (installed=true). Scoped to the user via store. notesURL is the release-notes link, opened by tapping the notification; it must be an https URL, anything else is dropped and the tap opens the app.

func (*Service) PublicKey

func (s *Service) PublicKey() string

PublicKey exposes the VAPID public key so the API layer can return it to the frontend for pushManager.subscribe().

func (*Service) SendTest

func (s *Service) SendTest(ctx context.Context, store *Store, endpoint string) error

SendTest delivers a single test notification to one endpoint. The store must be scoped to the requesting user so we don't leak test pings across tenants.

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

func NewServerStore(db *sql.DB) *Store

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 OpenStore

func OpenStore(db *sql.DB, userID uuid.UUID) (*Store, error)

OpenStore binds a pooled connection to a user_id. The pool is owned by the caller.

func (*Store) Close

func (s *Store) Close() error

Close is a no-op; the pool is managed by main.

func (*Store) Count

func (s *Store) Count(ctx context.Context) (int, error)

Count returns the number of stored subscriptions for this user.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, endpoint string) error

Delete removes a subscription. No-op if absent.

func (*Store) GetVAPID

func (s *Store) GetVAPID(ctx context.Context) (*VAPID, error)

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.

func (*Store) SaveVAPID

func (s *Store) SaveVAPID(ctx context.Context, v VAPID) error

SaveVAPID persists the keypair at id=1 (singleton row).

func (*Store) Upsert

func (s *Store) Upsert(ctx context.Context, sub Subscription) error

Upsert inserts or updates a subscription keyed on (user_id, endpoint).

type Subscription

type Subscription struct {
	Endpoint         string
	P256dh           string
	Auth             string
	OnChargingDone   bool
	OnPlugInReminder bool
	OnAnomaly        bool
	OnSoftwareUpdate bool
	UserAgent        string
	CreatedAt        time.Time
	UpdatedAt        time.Time
}

Subscription is a stored browser push subscription.

type VAPID

type VAPID struct {
	PublicKey  string
	PrivateKey string
	Subject    string
}

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.

Jump to

Keyboard shortcuts

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