Live video on the AT Protocol
1package notifications
2
3import (
4 "encoding/base64"
5 "encoding/json"
6 "fmt"
7
8 firebase "firebase.google.com/go/v4"
9 "firebase.google.com/go/v4/messaging"
10 "golang.org/x/net/context"
11 "google.golang.org/api/option"
12 "stream.place/streamplace/pkg/log"
13)
14
15type FirebaseNotifier interface {
16 Blast(ctx context.Context, tokens []string, golive *NotificationBlast) error
17}
18
19type FirebaseNotifierS struct {
20 app *firebase.App
21}
22
23type GoogleCredential struct {
24 ProjectID string `json:"project_id"`
25}
26
27type NotificationBlast struct {
28 Title string `json:"title"`
29 Body string `json:"body"`
30 Data map[string]string `json:"data"`
31}
32
33func MakeFirebaseNotifier(ctx context.Context, serviceAccountJSONb64 string) (FirebaseNotifier, error) {
34 // string can optionally be base64-encoded
35 serviceAccountJSON := serviceAccountJSONb64
36 dec, err := base64.StdEncoding.DecodeString(serviceAccountJSONb64)
37 if err == nil {
38 // succeeded, cool! use that.
39 serviceAccountJSON = string(dec)
40 }
41 var cred GoogleCredential
42 err = json.Unmarshal([]byte(serviceAccountJSON), &cred)
43 if err != nil {
44 return nil, fmt.Errorf("error trying to discover project_id: %w", err)
45 }
46 conf := &firebase.Config{
47 ProjectID: cred.ProjectID,
48 }
49 opt := option.WithCredentialsJSON([]byte(serviceAccountJSON))
50 app, err := firebase.NewApp(ctx, conf, opt)
51 if err != nil {
52 return nil, fmt.Errorf("failed to initialize Firebase app: %w", err)
53 }
54 return &FirebaseNotifierS{app: app}, nil
55}
56
57// refactor me when we have >500 users
58func (f *FirebaseNotifierS) Blast(ctx context.Context, tokens []string, blast *NotificationBlast) error {
59 client, err := f.app.Messaging(ctx)
60 if err != nil {
61 return err
62 }
63
64 notification := &messaging.MulticastMessage{
65 Tokens: tokens,
66 Data: blast.Data,
67 Notification: &messaging.Notification{
68 Title: blast.Title,
69 Body: blast.Body,
70 },
71 Android: &messaging.AndroidConfig{
72 Priority: "high",
73 Notification: &messaging.AndroidNotification{
74 Sound: "default",
75 },
76 },
77 APNS: &messaging.APNSConfig{
78 Headers: map[string]string{
79 "apns-priority": "10",
80 },
81 Payload: &messaging.APNSPayload{
82 Aps: &messaging.Aps{
83 Sound: "default",
84 },
85 },
86 },
87 }
88 res, err := client.SendEachForMulticast(ctx, notification)
89 if err != nil {
90 return err
91 }
92 log.Log(ctx, "notification blast successful", "successCount", res.SuccessCount, "failureCount", res.FailureCount)
93 return nil
94}