Skip to content

Commit 63206f8

Browse files
author
Philipp Heckel
committed
Firebase keepalive, supports #56
1 parent de0c41e commit 63206f8

File tree

4 files changed

+93
-12
lines changed

4 files changed

+93
-12
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ dist/
22
build/
33
.idea/
44
server/docs/
5+
tools/fbsend/fbsend
56
*.iml

config/config.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import (
77

88
// Defines default config settings
99
const (
10-
DefaultListenHTTP = ":80"
11-
DefaultCacheDuration = 12 * time.Hour
12-
DefaultKeepaliveInterval = 30 * time.Second
13-
DefaultManagerInterval = time.Minute
14-
DefaultAtSenderInterval = 10 * time.Second
15-
DefaultMinDelay = 10 * time.Second
16-
DefaultMaxDelay = 3 * 24 * time.Hour
17-
DefaultMessageLimit = 512
10+
DefaultListenHTTP = ":80"
11+
DefaultCacheDuration = 12 * time.Hour
12+
DefaultKeepaliveInterval = 30 * time.Second
13+
DefaultManagerInterval = time.Minute
14+
DefaultAtSenderInterval = 10 * time.Second
15+
DefaultMinDelay = 10 * time.Second
16+
DefaultMaxDelay = 3 * 24 * time.Hour
17+
DefaultMessageLimit = 512
18+
DefaultFirebaseKeepaliveInterval = time.Hour
1819
)
1920

2021
// Defines all the limits
@@ -40,6 +41,7 @@ type Config struct {
4041
KeepaliveInterval time.Duration
4142
ManagerInterval time.Duration
4243
AtSenderInterval time.Duration
44+
FirebaseKeepaliveInterval time.Duration
4345
MessageLimit int
4446
MinDelay time.Duration
4547
MaxDelay time.Duration
@@ -66,6 +68,7 @@ func New(listenHTTP string) *Config {
6668
MinDelay: DefaultMinDelay,
6769
MaxDelay: DefaultMaxDelay,
6870
AtSenderInterval: DefaultAtSenderInterval,
71+
FirebaseKeepaliveInterval: DefaultFirebaseKeepaliveInterval,
6972
GlobalTopicLimit: DefaultGlobalTopicLimit,
7073
VisitorRequestLimitBurst: DefaultVisitorRequestLimitBurst,
7174
VisitorRequestLimitReplenish: DefaultVisitorRequestLimitReplenish,

server/server.go

+31-4
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ var (
105105
errHTTPTooManyRequests = &errHTTP{http.StatusTooManyRequests, http.StatusText(http.StatusTooManyRequests)}
106106
)
107107

108+
const (
109+
firebaseControlTopic = "~control" // See Android if changed
110+
)
111+
108112
// New instantiates a new Server. It creates the cache and adds a Firebase
109113
// subscriber (if configured).
110114
func New(conf *config.Config) (*Server, error) {
@@ -152,9 +156,17 @@ func createFirebaseSubscriber(conf *config.Config) (subscriber, error) {
152156
return nil, err
153157
}
154158
return func(m *message) error {
155-
_, err := msg.Send(context.Background(), &messaging.Message{
156-
Topic: m.Topic,
157-
Data: map[string]string{
159+
var data map[string]string // Matches https://ntfy.sh/docs/subscribe/api/#json-message-format
160+
switch m.Event {
161+
case keepaliveEvent, openEvent:
162+
data = map[string]string{
163+
"id": m.ID,
164+
"time": fmt.Sprintf("%d", m.Time),
165+
"event": m.Event,
166+
"topic": m.Topic,
167+
}
168+
case messageEvent:
169+
data = map[string]string{
158170
"id": m.ID,
159171
"time": fmt.Sprintf("%d", m.Time),
160172
"event": m.Event,
@@ -163,7 +175,11 @@ func createFirebaseSubscriber(conf *config.Config) (subscriber, error) {
163175
"tags": strings.Join(m.Tags, ","),
164176
"title": m.Title,
165177
"message": m.Message,
166-
},
178+
}
179+
}
180+
_, err := msg.Send(context.Background(), &messaging.Message{
181+
Topic: m.Topic,
182+
Data: data,
167183
})
168184
return err
169185
}, nil
@@ -188,6 +204,17 @@ func (s *Server) Run() error {
188204
}
189205
}
190206
}()
207+
if s.firebase != nil {
208+
go func() {
209+
ticker := time.NewTicker(s.config.FirebaseKeepaliveInterval)
210+
for {
211+
<-ticker.C
212+
if err := s.firebase(newKeepaliveMessage(firebaseControlTopic)); err != nil {
213+
log.Printf("error sending Firebase keepalive message: %s", err.Error())
214+
}
215+
}
216+
}()
217+
}
191218
listenStr := fmt.Sprintf("%s/http", s.config.ListenHTTP)
192219
if s.config.ListenHTTPS != "" {
193220
listenStr += fmt.Sprintf(" %s/https", s.config.ListenHTTPS)

tools/fbsend/main.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package main
2+
3+
import (
4+
"context"
5+
firebase "firebase.google.com/go"
6+
"firebase.google.com/go/messaging"
7+
"flag"
8+
"fmt"
9+
"google.golang.org/api/option"
10+
"os"
11+
"strings"
12+
)
13+
14+
func main() {
15+
conffile := flag.String("config", "/etc/fbsend/fbsend.json", "config file")
16+
flag.Parse()
17+
if flag.NArg() < 2 {
18+
fail("Syntax: fbsend [-config FILE] topic key=value ...")
19+
}
20+
topic := flag.Arg(0)
21+
data := make(map[string]string)
22+
for i := 1; i < flag.NArg(); i++ {
23+
kv := strings.SplitN(flag.Arg(i), "=", 2)
24+
if len(kv) != 2 {
25+
fail(fmt.Sprintf("Invalid argument: %s (%v)", flag.Arg(i), kv))
26+
}
27+
data[kv[0]] = kv[1]
28+
}
29+
fb, err := firebase.NewApp(context.Background(), nil, option.WithCredentialsFile(*conffile))
30+
if err != nil {
31+
fail(err.Error())
32+
}
33+
msg, err := fb.Messaging(context.Background())
34+
if err != nil {
35+
fail(err.Error())
36+
}
37+
_, err = msg.Send(context.Background(), &messaging.Message{
38+
Topic: topic,
39+
Data: data,
40+
})
41+
if err != nil {
42+
fail(err.Error())
43+
}
44+
fmt.Println("Sent successfully")
45+
}
46+
47+
func fail(s string) {
48+
fmt.Println(s)
49+
os.Exit(1)
50+
}

0 commit comments

Comments
 (0)