Initial public release of birdwatch-relay
This commit is contained in:
commit
c176f2ad24
17 changed files with 2025 additions and 0 deletions
57
internal/notify/dispatcher.go
Normal file
57
internal/notify/dispatcher.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// Dispatcher fan-outs an event payload to every registered device, encrypting
|
||||
// the payload to each device's X25519 public key (NaCl sealed box) and sending
|
||||
// the ciphertext via Firebase Cloud Messaging.
|
||||
|
||||
package notify
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/cyrilinait/birdwatch-relay/internal/crypto"
|
||||
"github.com/cyrilinait/birdwatch-relay/internal/fcm"
|
||||
"github.com/cyrilinait/birdwatch-relay/internal/storage"
|
||||
)
|
||||
|
||||
type Dispatcher struct {
|
||||
store *storage.Store
|
||||
sender *fcm.Sender
|
||||
}
|
||||
|
||||
func NewDispatcher(store *storage.Store, sender *fcm.Sender) *Dispatcher {
|
||||
return &Dispatcher{store: store, sender: sender}
|
||||
}
|
||||
|
||||
// Send fans the payload out to every registered device. The payload is sealed
|
||||
// to each device's public key independently — Google FCM only ever sees
|
||||
// ciphertext + the device token. Errors per device are logged but do not stop
|
||||
// the rest of the fanout.
|
||||
func (d *Dispatcher) Send(ctx context.Context, payload []byte) {
|
||||
devices, err := d.store.ListAll()
|
||||
if err != nil {
|
||||
slog.Error("dispatcher: list devices failed", "err", err)
|
||||
return
|
||||
}
|
||||
if len(devices) == 0 {
|
||||
slog.Debug("dispatcher: no registered devices, dropping event")
|
||||
return
|
||||
}
|
||||
var sent, failed int
|
||||
for _, dev := range devices {
|
||||
ct, err := crypto.Seal(payload, dev.PublicKey)
|
||||
if err != nil {
|
||||
slog.Error("dispatcher: seal failed", "err", err, "device_id", dev.ID)
|
||||
failed++
|
||||
continue
|
||||
}
|
||||
if err := d.sender.SendCiphertext(ctx, dev.FCMToken, ct); err != nil {
|
||||
slog.Warn("dispatcher: fcm send failed", "err", err, "device_id", dev.ID)
|
||||
failed++
|
||||
continue
|
||||
}
|
||||
sent++
|
||||
}
|
||||
slog.Info("dispatcher fanout", "sent", sent, "failed", failed, "total", len(devices))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue