170 lines
4.2 KiB
Go
170 lines
4.2 KiB
Go
|
package services
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"crypto/tls"
|
||
|
"firebase.google.com/go/messaging"
|
||
|
"fmt"
|
||
|
"git.solsynth.dev/hydrogen/dealer/pkg/proto"
|
||
|
"github.com/jordan-wright/email"
|
||
|
"github.com/rs/zerolog/log"
|
||
|
"github.com/sideshow/apns2"
|
||
|
payload2 "github.com/sideshow/apns2/payload"
|
||
|
"github.com/spf13/viper"
|
||
|
"net/smtp"
|
||
|
"net/textproto"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
var deliveryTaskQueue = make(chan any, 256)
|
||
|
|
||
|
func PublishDeliveryTask(task any) {
|
||
|
deliveryTaskQueue <- task
|
||
|
}
|
||
|
|
||
|
func ConsumeDeliveryTasks() {
|
||
|
for {
|
||
|
task := <-deliveryTaskQueue
|
||
|
switch tk := task.(type) {
|
||
|
case *proto.DeliverEmailRequest:
|
||
|
if tk.GetEmail().HtmlBody != nil {
|
||
|
_ = SendMailHTML(tk.GetTo(), tk.GetEmail().GetSubject(), tk.GetEmail().GetHtmlBody())
|
||
|
} else {
|
||
|
_ = SendMail(tk.GetTo(), tk.GetEmail().GetSubject(), tk.GetEmail().GetTextBody())
|
||
|
}
|
||
|
case *proto.DeliverNotificationRequest:
|
||
|
switch tk.GetProvider() {
|
||
|
case "firebase":
|
||
|
_ = PushFirebaseNotify(tk.GetDeviceToken(), tk.GetNotify())
|
||
|
case "apple":
|
||
|
_ = PushAppleNotify(tk.GetDeviceToken(), tk.GetNotify())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func PushFirebaseNotify(token string, in *proto.NotifyRequest) error {
|
||
|
if ExtFire == nil {
|
||
|
return fmt.Errorf("firebase push notification is unavailable")
|
||
|
}
|
||
|
|
||
|
start := time.Now()
|
||
|
|
||
|
ctx := context.Background()
|
||
|
client, err := ExtFire.Messaging(ctx)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to create firebase client")
|
||
|
}
|
||
|
|
||
|
var image string
|
||
|
if in.Picture != nil {
|
||
|
image = *in.Picture
|
||
|
}
|
||
|
var subtitle string
|
||
|
if in.Subtitle != nil {
|
||
|
subtitle = "\n" + *in.Subtitle
|
||
|
}
|
||
|
message := &messaging.Message{
|
||
|
Notification: &messaging.Notification{
|
||
|
Title: in.Title,
|
||
|
Body: subtitle + in.Body,
|
||
|
ImageURL: image,
|
||
|
},
|
||
|
Token: token,
|
||
|
}
|
||
|
|
||
|
if response, err := client.Send(ctx, message); err != nil {
|
||
|
log.Warn().Err(err).Msg("An error occurred when notify subscriber via FCM...")
|
||
|
} else {
|
||
|
log.Debug().
|
||
|
Dur("elapsed", time.Since(start)).
|
||
|
Str("response", response).
|
||
|
Msg("Push a notify via firebase")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func PushAppleNotify(token string, in *proto.NotifyRequest) error {
|
||
|
if ExtAPNS == nil {
|
||
|
return fmt.Errorf("apple push notification is unavailable")
|
||
|
}
|
||
|
|
||
|
start := time.Now()
|
||
|
|
||
|
data := payload2.
|
||
|
NewPayload().
|
||
|
AlertTitle(in.GetTitle()).
|
||
|
AlertBody(in.GetBody()).
|
||
|
Category(in.GetTopic()).
|
||
|
Sound("default").
|
||
|
MutableContent()
|
||
|
if in.Avatar != nil {
|
||
|
data = data.Custom("avatar", *in.Avatar)
|
||
|
}
|
||
|
if in.Picture != nil {
|
||
|
data = data.Custom("picture", *in.Picture)
|
||
|
}
|
||
|
rawData, err := data.MarshalJSON()
|
||
|
if err != nil {
|
||
|
log.Warn().Err(err).Msg("An error occurred when preparing to notify subscriber via APNs...")
|
||
|
}
|
||
|
payload := &apns2.Notification{
|
||
|
DeviceToken: token,
|
||
|
Topic: viper.GetString("apns_topic"),
|
||
|
Payload: rawData,
|
||
|
}
|
||
|
|
||
|
if resp, err := ExtAPNS.Push(payload); err != nil {
|
||
|
log.Warn().Err(err).Msg("An error occurred when notify subscriber via APNs...")
|
||
|
} else {
|
||
|
log.Debug().
|
||
|
Dur("elapsed", time.Since(start)).
|
||
|
Str("reason", resp.Reason).
|
||
|
Int("status", resp.StatusCode).
|
||
|
Msg("Push a notify via firebase")
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func SendMail(target string, subject string, content string) error {
|
||
|
mail := &email.Email{
|
||
|
To: []string{target},
|
||
|
From: viper.GetString("mailer.name"),
|
||
|
Subject: subject,
|
||
|
Text: []byte(content),
|
||
|
Headers: textproto.MIMEHeader{},
|
||
|
}
|
||
|
return mail.SendWithTLS(
|
||
|
fmt.Sprintf("%s:%d", viper.GetString("mailer.smtp_host"), viper.GetInt("mailer.smtp_port")),
|
||
|
smtp.PlainAuth(
|
||
|
"",
|
||
|
viper.GetString("mailer.username"),
|
||
|
viper.GetString("mailer.password"),
|
||
|
viper.GetString("mailer.smtp_host"),
|
||
|
),
|
||
|
&tls.Config{ServerName: viper.GetString("mailer.smtp_host")},
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func SendMailHTML(target string, subject string, content string) error {
|
||
|
mail := &email.Email{
|
||
|
To: []string{target},
|
||
|
From: viper.GetString("mailer.name"),
|
||
|
Subject: subject,
|
||
|
HTML: []byte(content),
|
||
|
Headers: textproto.MIMEHeader{},
|
||
|
}
|
||
|
return mail.SendWithTLS(
|
||
|
fmt.Sprintf("%s:%d", viper.GetString("mailer.smtp_host"), viper.GetInt("mailer.smtp_port")),
|
||
|
smtp.PlainAuth(
|
||
|
"",
|
||
|
viper.GetString("mailer.username"),
|
||
|
viper.GetString("mailer.password"),
|
||
|
viper.GetString("mailer.smtp_host"),
|
||
|
),
|
||
|
&tls.Config{ServerName: viper.GetString("mailer.smtp_host")},
|
||
|
)
|
||
|
}
|