143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
firebase "firebase.google.com/go/v4"
|
|
"firebase.google.com/go/v4/messaging"
|
|
"google.golang.org/api/option"
|
|
)
|
|
|
|
type FCMConfig interface {
|
|
GetCredentialsFile() string
|
|
GetProjectID() string
|
|
}
|
|
|
|
type FCMClient interface {
|
|
SendNotification(ctx context.Context, token string, title string, body string, data map[string]string) error
|
|
SendMulticastNotification(ctx context.Context, tokens []string, title string, body string, data map[string]string) error
|
|
SendToTopic(ctx context.Context, topic string, title string, body string, data map[string]string) error
|
|
}
|
|
|
|
type fcmClient struct {
|
|
messaging *messaging.Client
|
|
}
|
|
|
|
func NewFCMClient(cfg FCMConfig) (FCMClient, error) {
|
|
ctx := context.Background()
|
|
|
|
opt := option.WithCredentialsFile(cfg.GetCredentialsFile())
|
|
|
|
app, err := firebase.NewApp(ctx, &firebase.Config{
|
|
ProjectID: cfg.GetProjectID(),
|
|
}, opt)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize firebase app: %w", err)
|
|
}
|
|
|
|
msgClient, err := app.Messaging(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to initialize firebase messaging client: %w", err)
|
|
}
|
|
|
|
return &fcmClient{
|
|
messaging: msgClient,
|
|
}, nil
|
|
}
|
|
|
|
// SendNotification sends a push notification to a single device token.
|
|
func (f *fcmClient) SendNotification(ctx context.Context, token string, title string, body string, data map[string]string) error {
|
|
message := &messaging.Message{
|
|
Token: token,
|
|
Notification: &messaging.Notification{
|
|
Title: title,
|
|
Body: body,
|
|
},
|
|
Data: data,
|
|
Android: &messaging.AndroidConfig{
|
|
Priority: "high",
|
|
},
|
|
APNS: &messaging.APNSConfig{
|
|
Payload: &messaging.APNSPayload{
|
|
Aps: &messaging.Aps{
|
|
Sound: "default",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := f.messaging.Send(ctx, message)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send FCM notification: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SendMulticastNotification sends a push notification to multiple device tokens.
|
|
func (f *fcmClient) SendMulticastNotification(ctx context.Context, tokens []string, title string, body string, data map[string]string) error {
|
|
if len(tokens) == 0 {
|
|
return nil
|
|
}
|
|
|
|
message := &messaging.MulticastMessage{
|
|
Tokens: tokens,
|
|
Notification: &messaging.Notification{
|
|
Title: title,
|
|
Body: body,
|
|
},
|
|
Data: data,
|
|
Android: &messaging.AndroidConfig{
|
|
Priority: "high",
|
|
},
|
|
APNS: &messaging.APNSConfig{
|
|
Payload: &messaging.APNSPayload{
|
|
Aps: &messaging.Aps{
|
|
Sound: "default",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
batchResp, err := f.messaging.SendEachForMulticast(ctx, message)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send FCM multicast notification: %w", err)
|
|
}
|
|
|
|
if batchResp.FailureCount > 0 {
|
|
return fmt.Errorf("FCM multicast: %d/%d messages failed to send", batchResp.FailureCount, len(tokens))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SendToTopic sends a push notification to all devices subscribed to a topic.
|
|
func (f *fcmClient) SendToTopic(ctx context.Context, topic string, title string, body string, data map[string]string) error {
|
|
message := &messaging.Message{
|
|
Topic: topic,
|
|
Notification: &messaging.Notification{
|
|
Title: title,
|
|
Body: body,
|
|
},
|
|
Data: data,
|
|
Android: &messaging.AndroidConfig{
|
|
Priority: "high",
|
|
},
|
|
APNS: &messaging.APNSConfig{
|
|
Payload: &messaging.APNSPayload{
|
|
Aps: &messaging.Aps{
|
|
Sound: "default",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
_, err := f.messaging.Send(ctx, message)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to send FCM topic notification: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|