-
Notifications
You must be signed in to change notification settings - Fork 0
/
notifications.go
124 lines (100 loc) · 2.89 KB
/
notifications.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package main
import (
"encoding/json"
"fmt"
"os"
"sync"
"github.com/SherClockHolmes/webpush-go"
)
// https://github.com/nakamauwu/nakama/blob/main/web_push_subscription.go
// Sends notification to all subscriptions in database
func SendNotifications(notification *Notification) error {
fmt.Println("sending notification:\n", notification)
subs, err := getSubscriptions()
if err != nil {
return err
}
if len(subs) == 0 {
fmt.Println("there are no active subscriptions")
return nil
}
message, err := json.Marshal(notification)
if err != nil {
return fmt.Errorf("could not json marshal notification: %w", err)
}
var wg sync.WaitGroup
fmt.Println("sending", len(subs), "notifications")
for _, sub := range subs {
wg.Add(1)
pushSubscription := sub
go func() {
defer wg.Done()
err := sendWebPushNotification(pushSubscription, message)
if err != nil {
fmt.Print(err)
return
}
fmt.Println("notification", pushSubscription.id, "sent")
}()
}
wg.Wait()
fmt.Println("finished sending notifications")
return nil
}
// Retrieves all subscriptions from database
func getSubscriptions() ([]Subscription, error) {
query := "SELECT * FROM \"PushSubscriptions\";"
rows, err := DB.Query(query)
if err != nil {
return nil, fmt.Errorf("could not retrieve subscriptions from databse: %w", err)
}
defer rows.Close()
var subs []Subscription
for rows.Next() {
var sub Subscription
err := rows.Scan(&sub.id, &sub.createdAt, &sub.pushSubscription)
if err != nil {
continue
}
subs = append(subs, sub)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("could not sql query iterate over user web push subscriptions: %w", err)
}
return subs, nil
}
// Sends push notification to subscription
func sendWebPushNotification(rawSub Subscription, message []byte) error {
sub := &webpush.Subscription{}
err := json.Unmarshal([]byte(rawSub.pushSubscription), sub)
if err != nil {
return fmt.Errorf("could not json unmarshal web push subscription: %w", err)
}
resp, err := webpush.SendNotification(message, sub, &webpush.Options{
Subscriber: "mailto:keadr23@gmail.com",
VAPIDPrivateKey: os.Getenv("VAPID_PRIVATE_KEY"),
VAPIDPublicKey: os.Getenv("VAPID_PUBLIC_KEY"),
TTL: 18000, // 5 hours
})
if err != nil {
return fmt.Errorf("could not send web push notification: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode == 400 || resp.StatusCode == 410 {
fmt.Printf("deleting stale subscription: ID: %v createdAt: %v\n", rawSub.id, rawSub.createdAt)
err := deleteWebPushSubscription(rawSub.id)
if err != nil {
return err
}
}
return nil
}
// Deletes subscription from database
func deleteWebPushSubscription(id int) error {
query := "DELETE FROM \"PushSubscriptions\" where id = $1;"
_, err := DB.Exec(query, id)
if err != nil {
return fmt.Errorf("could not delete subscription from database: %w", err)
}
return nil
}