Support for Firebase ~poll keepalive topic that wakes up iOS devices every 20 minutes

This commit is contained in:
Philipp Heckel 2022-05-25 21:39:46 -04:00
parent 98b56c2f06
commit af76a2606d
4 changed files with 33 additions and 2 deletions

View file

@ -38,6 +38,10 @@ some known issues, which will be addressed in follow-up releases).
## ntfy server v1.24.0 (UNRELEASED)
**Features:**
* Regularly send Firebase keepalive messages to ~poll topic to support self-hosted servers (no ticket)
**Bugs:**
* Support emails without `Content-Type` ([#265](https://github.com/binwiederhier/ntfy/issues/265), thanks to [@dmbonsall](https://github.com/dmbonsall))

View file

@ -13,7 +13,8 @@ const (
DefaultAtSenderInterval = 10 * time.Second
DefaultMinDelay = 10 * time.Second
DefaultMaxDelay = 3 * 24 * time.Hour
DefaultFirebaseKeepaliveInterval = 3 * time.Hour // Not too frequently to save battery
DefaultFirebaseKeepaliveInterval = 3 * time.Hour // ~control topic (Android), not too frequently to save battery
DefaultFirebasePollInterval = 20 * time.Minute // ~poll topic (iOS), max. 2-3 times per hour (see docs)
)
// Defines all global and per-visitor limits
@ -67,6 +68,7 @@ type Config struct {
WebRootIsApp bool
AtSenderInterval time.Duration
FirebaseKeepaliveInterval time.Duration
FirebasePollInterval time.Duration
SMTPSenderAddr string
SMTPSenderUser string
SMTPSenderPass string
@ -117,6 +119,7 @@ func NewConfig() *Config {
MaxDelay: DefaultMaxDelay,
AtSenderInterval: DefaultAtSenderInterval,
FirebaseKeepaliveInterval: DefaultFirebaseKeepaliveInterval,
FirebasePollInterval: DefaultFirebasePollInterval,
TotalTopicLimit: DefaultTotalTopicLimit,
VisitorSubscriptionLimit: DefaultVisitorSubscriptionLimit,
VisitorAttachmentTotalSizeLimit: DefaultVisitorAttachmentTotalSizeLimit,

View file

@ -91,6 +91,7 @@ var (
const (
firebaseControlTopic = "~control" // See Android if changed
firebasePollTopic = "~poll" // See iOS if changed
emptyMessageBody = "triggered" // Used if message body is empty
defaultAttachmentMessage = "You received a file: %s" // Used if message body is empty, and there is an attachment
encodingBase64 = "base64"
@ -1074,7 +1075,12 @@ func (s *Server) runFirebaseKeepaliver() {
select {
case <-time.After(s.config.FirebaseKeepaliveInterval):
if err := s.firebase(newKeepaliveMessage(firebaseControlTopic)); err != nil {
log.Printf("error sending Firebase keepalive message: %s", err.Error())
log.Printf("error sending Firebase keepalive message to %s: %s", firebaseControlTopic, err.Error())
}
case <-time.After(s.config.FirebasePollInterval):
log.Printf("Sending to timer topic %s", firebasePollTopic)
if err := s.firebase(newKeepaliveMessage(firebasePollTopic)); err != nil {
log.Printf("error sending Firebase keepalive message to %s: %s", firebasePollTopic, err.Error())
}
case <-s.closeChan:
return

View file

@ -80,6 +80,24 @@ func toFirebaseMessage(m *message, auther auth.Auther) (*messaging.Message, erro
"event": m.Event,
"topic": m.Topic,
}
// Silent notification; only 2-3 per hour are allowed; delivery not guaranteed
// See https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app
apnsData := make(map[string]interface{})
for k, v := range data {
apnsData[k] = v
}
apnsConfig = &messaging.APNSConfig{
Headers: map[string]string{
"apns-push-type": "background",
"apns-priority": "5",
},
Payload: &messaging.APNSPayload{
Aps: &messaging.Aps{
ContentAvailable: true,
},
CustomData: apnsData,
},
}
case messageEvent:
allowForward := true
if auther != nil {