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