owncast/notifications/browser/browser.go

90 lines
2.1 KiB
Go

package browser
import (
"encoding/json"
"github.com/SherClockHolmes/webpush-go"
"github.com/owncast/owncast/core/data"
"github.com/pkg/errors"
)
// Browser is an instance of the Browser service.
type Browser struct {
datastore *data.Datastore
privateKey string
publicKey string
}
// New will create a new instance of the Browser service.
func New(datastore *data.Datastore, publicKey, privateKey string) (*Browser, error) {
return &Browser{
datastore: datastore,
privateKey: privateKey,
publicKey: publicKey,
}, nil
}
// GenerateBrowserPushKeys will create the VAPID keys required for web push notifications.
func GenerateBrowserPushKeys() (string, string, error) {
privateKey, publicKey, err := webpush.GenerateVAPIDKeys()
if err != nil {
return "", "", errors.Wrap(err, "error generating web push keys")
}
return privateKey, publicKey, nil
}
// Send will send a browser push notification to the given subscription.
func (b *Browser) Send(
subscription string,
title string,
body string,
) (bool, error) {
type message struct {
Title string `json:"title"`
Body string `json:"body"`
Icon string `json:"icon"`
}
m := message{
Title: title,
Body: body,
Icon: "/logo/external",
}
d, err := json.Marshal(m)
if err != nil {
return false, errors.Wrap(err, "error marshalling web push message")
}
// Decode subscription
s := &webpush.Subscription{}
if err := json.Unmarshal([]byte(subscription), s); err != nil {
return false, errors.Wrap(err, "error decoding destination subscription")
}
// Send Notification
resp, err := webpush.SendNotification(d, s, &webpush.Options{
VAPIDPublicKey: b.publicKey,
VAPIDPrivateKey: b.privateKey,
Topic: "owncast-go-live",
TTL: 120,
// Not really the subscriber, but a contact point for the sender.
Subscriber: "owncast@owncast.online",
})
if err != nil {
return false, errors.Wrap(err, "error sending browser push notification")
}
if resp == nil {
return false, errors.New("no response from web push server")
}
defer resp.Body.Close()
if resp.StatusCode == 410 {
return true, nil
}
return false, err
}