This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

perf: use FCM's multicast push request to batch-send notifications

+60 -39
+9 -6
firebase.go
··· 13 13 14 14 var firebaseClient *firebase.App 15 15 16 - func (msg Message) SendToFirebase(groupId string, sub Subscription) error { 17 - fcm, err := firebaseClient.Messaging(context.Background()) 16 + func (msg Message) SendToFirebase(groupId string, subs []Subscription) error { 17 + fcm, err := firebaseClient.Messaging(firebaseCtx) 18 18 if err != nil { 19 19 return fmt.Errorf("while initializing FCM client: %w", err) 20 20 } 21 21 22 22 message := msg.FirebaseMessage(groupId) 23 - message.Token = sub.FirebaseToken() 24 - _, err = fcm.Send(context.Background(), &message) 23 + message.Tokens = make([]string, len(subs)) 24 + for i, sub := range subs { 25 + message.Tokens[i] = sub.FirebaseToken() 26 + } 25 27 28 + _, err = fcm.SendEachForMulticast(firebaseCtx, &message) 26 29 return err 27 30 } 28 31 29 - func (msg Message) FirebaseMessage(groupId string) messaging.Message { 32 + func (msg Message) FirebaseMessage(groupId string) messaging.MulticastMessage { 30 33 clickAction := "" 31 34 if len(msg.Actions) > 0 { 32 35 clickAction = msg.Actions[0].Label 33 36 } 34 - return messaging.Message{ 37 + return messaging.MulticastMessage{ 35 38 Data: map[string]string{ 36 39 "original": msg.JSONString(), 37 40 },
+27 -20
messages.go
··· 36 36 37 37 ll.Log("Sending", "green", "notification for %s on %s to %d users (%d subscriptions)", msg.Event, msg.ChurrosObjectId, len(users), len(subs)) 38 38 39 - var wg sync.WaitGroup 40 - 41 - wg.Add(len(subs)) 42 - 43 - // Parallelize sending the notifications 39 + // Separate native and webpush subscriptions 40 + nativeSubs := make([]Subscription, 0, len(subs)) 41 + webpushSubs := make([]Subscription, 0, len(subs)) 44 42 for _, sub := range subs { 45 - ll.Debug("sending notification to %#v", sub) 46 - go func(wg *sync.WaitGroup, sub Subscription) { 47 - if sub.IsWebpush() { 48 - err := msg.SendWebPush(group, sub) 49 - if err != nil { 50 - ll.ErrorDisplay("could not send webpush notification", err) 51 - } 52 - } else { 53 - err := msg.SendToFirebase(group, sub) 54 - if err != nil { 55 - ll.ErrorDisplay("could not send firebase notification", err) 56 - } 57 - } 58 - wg.Done() 59 - }(&wg, sub) 43 + if sub.IsNative() { 44 + nativeSubs = append(nativeSubs, sub) 45 + } else if sub.IsWebpush() { 46 + webpushSubs = append(webpushSubs, sub) 47 + } else { 48 + ll.Warn("invalid subscription %#v", sub) 49 + } 60 50 } 61 51 52 + var wg sync.WaitGroup 53 + wg.Add(2) 54 + go func(wg *sync.WaitGroup) { 55 + defer wg.Done() 56 + err := msg.SendToFirebase(group, nativeSubs) 57 + if err != nil { 58 + ll.ErrorDisplay("could not send notification via firebase", err) 59 + } 60 + }(&wg) 61 + go func(wg *sync.WaitGroup) { 62 + defer wg.Done() 63 + err := msg.SendWebPush(group, webpushSubs) 64 + if err != nil { 65 + ll.ErrorDisplay("could not send notification via webpush", err) 66 + } 67 + }(&wg) 62 68 wg.Wait() 69 + 63 70 return nil 64 71 } 65 72
+24 -13
webpush.go
··· 2 2 3 3 import ( 4 4 "encoding/json" 5 - "fmt" 6 5 "strings" 6 + "sync" 7 7 8 8 "git.inpt.fr/churros/notella/db" 9 9 "github.com/SherClockHolmes/webpush-go" ··· 65 65 } 66 66 } 67 67 68 - func (msg Message) SendWebPush(groupId string, sub Subscription) error { 68 + func (msg Message) SendWebPush(groupId string, subs []Subscription) error { 69 + 69 70 jsoned, err := json.Marshal(msg.WebPush(groupId)) 70 71 if err != nil { 71 72 ll.ErrorDisplay("could not marshal notification to json", err) 72 73 } 73 74 74 - resp, err := webpush.SendNotification(jsoned, &sub.Webpush, &webpush.Options{ 75 - TTL: 30, 76 - Subscriber: config.ContactEmail, 77 - VAPIDPublicKey: config.VapidPublicKey, 78 - VAPIDPrivateKey: config.VapidPrivateKey, 79 - }) 80 - if err != nil { 81 - return fmt.Errorf("could not send notification to %s: %w", sub.Owner.Uid, err) 82 - } 75 + var wg sync.WaitGroup 76 + wg.Add(len(subs)) 77 + for _, sub := range subs { 78 + go func(wg *sync.WaitGroup, sub Subscription) { 79 + resp, err := webpush.SendNotification(jsoned, &sub.Webpush, &webpush.Options{ 80 + TTL: 30, 81 + Subscriber: config.ContactEmail, 82 + VAPIDPublicKey: config.VapidPublicKey, 83 + VAPIDPrivateKey: config.VapidPrivateKey, 84 + }) 85 + wg.Done() 86 + 87 + if err != nil { 88 + ll.ErrorDisplay("could not send notification to %s", err, sub.Owner.Uid) 89 + } 90 + 91 + if resp.StatusCode >= 400 { 92 + ll.ErrorDisplay("could not send notification to %s", err, sub.Owner.Uid) 93 + } 83 94 84 - if resp.StatusCode >= 400 { 85 - return fmt.Errorf("could not send notification to %s: %s", sub.Owner.Uid, resp.Status) 95 + }(&wg, sub) 86 96 } 97 + wg.Wait() 87 98 88 99 return nil 89 100 }