5
5
"crypto/tls"
6
6
"crypto/x509"
7
7
"encoding/json"
8
- "fmt"
9
8
"io/ioutil"
10
9
"sync"
11
10
"text/template"
@@ -18,12 +17,30 @@ import (
18
17
log "github.com/sirupsen/logrus"
19
18
)
20
19
20
+ // BackendConfig holds the MQTT pub-sub backend configuration.
21
+ type BackendConfig struct {
22
+ Server string
23
+ Username string
24
+ Password string
25
+ QOS uint8 `mapstructure:"qos"`
26
+ CleanSession bool `mapstructure:"clean_session"`
27
+ ClientID string `mapstructure:"client_id"`
28
+ CACert string `mapstructure:"ca_cert"`
29
+ TLSCert string `mapstructure:"tls_cert"`
30
+ TLSKey string `mapstructure:"tls_key"`
31
+ UplinkTopicTemplate string `mapstructure:"uplink_topic_template"`
32
+ DownlinkTopicTemplate string `mapstructure:"downlink_topic_template"`
33
+ StatsTopicTemplate string `mapstructure:"stats_topic_template"`
34
+ AckTopicTemplate string `mapstructure:"ack_topic_template"`
35
+ }
36
+
21
37
// Backend implements a MQTT pub-sub backend.
22
38
type Backend struct {
23
39
conn mqtt.Client
24
40
txPacketChan chan gw.TXPacketBytes
25
41
gateways map [lorawan.EUI64 ]struct {}
26
42
mutex sync.RWMutex
43
+ config BackendConfig
27
44
28
45
UplinkTemplate * template.Template
29
46
DownlinkTemplate * template.Template
@@ -32,54 +49,57 @@ type Backend struct {
32
49
}
33
50
34
51
// NewBackend creates a new Backend.
35
- func NewBackend (server , username , password , cafile , certFile , certKeyFile , uplinkTopic , downlinkTopic , statsTopic , ackTopic string ) (* Backend , error ) {
52
+ func NewBackend (c BackendConfig ) (* Backend , error ) {
36
53
var err error
37
54
38
55
b := Backend {
39
56
txPacketChan : make (chan gw.TXPacketBytes ),
40
57
gateways : make (map [lorawan.EUI64 ]struct {}),
58
+ config : c ,
41
59
}
42
60
43
- b .UplinkTemplate , err = template .New ("uplink" ).Parse (uplinkTopic )
61
+ b .UplinkTemplate , err = template .New ("uplink" ).Parse (b . config . UplinkTopicTemplate )
44
62
if err != nil {
45
63
return nil , errors .Wrap (err , "parse uplink template error" )
46
64
}
47
65
48
- b .DownlinkTemplate , err = template .New ("downlink" ).Parse (downlinkTopic )
66
+ b .DownlinkTemplate , err = template .New ("downlink" ).Parse (b . config . DownlinkTopicTemplate )
49
67
if err != nil {
50
68
return nil , errors .Wrap (err , "parse downlink template error" )
51
69
}
52
70
53
- b .StatsTemplate , err = template .New ("stats" ).Parse (statsTopic )
71
+ b .StatsTemplate , err = template .New ("stats" ).Parse (b . config . StatsTopicTemplate )
54
72
if err != nil {
55
73
return nil , errors .Wrap (err , "parse stats template error" )
56
74
}
57
75
58
- b .AckTemplate , err = template .New ("ack" ).Parse (ackTopic )
76
+ b .AckTemplate , err = template .New ("ack" ).Parse (b . config . AckTopicTemplate )
59
77
if err != nil {
60
78
return nil , errors .Wrap (err , "parse ack template error" )
61
79
}
62
80
63
81
opts := mqtt .NewClientOptions ()
64
- opts .AddBroker (server )
65
- opts .SetUsername (username )
66
- opts .SetPassword (password )
82
+ opts .AddBroker (b .config .Server )
83
+ opts .SetUsername (b .config .Username )
84
+ opts .SetPassword (b .config .Password )
85
+ opts .SetCleanSession (b .config .CleanSession )
86
+ opts .SetClientID (b .config .ClientID )
67
87
opts .SetOnConnectHandler (b .onConnected )
68
88
opts .SetConnectionLostHandler (b .onConnectionLost )
69
89
70
- tlsconfig , err := NewTLSConfig (cafile , certFile , certKeyFile )
90
+ tlsconfig , err := NewTLSConfig (b . config . CACert , b . config . TLSCert , b . config . TLSKey )
71
91
if err != nil {
72
92
log .WithError (err ).WithFields (log.Fields {
73
- "ca_cert" : cafile ,
74
- "tls_cert" : certFile ,
75
- "tls_key" : certKeyFile ,
93
+ "ca_cert" : b . config . CACert ,
94
+ "tls_cert" : b . config . TLSCert ,
95
+ "tls_key" : b . config . TLSKey ,
76
96
}).Fatal ("error loading mqtt certificate files" )
77
97
}
78
98
if tlsconfig != nil {
79
99
opts .SetTLSConfig (tlsconfig )
80
100
}
81
101
82
- log .WithField ("server" , server ).Info ("backend: connecting to mqtt broker" )
102
+ log .WithField ("server" , b . config . Server ).Info ("backend: connecting to mqtt broker" )
83
103
b .conn = mqtt .NewClient (opts )
84
104
if token := b .conn .Connect (); token .Wait () && token .Error () != nil {
85
105
return nil , token .Error ()
@@ -146,11 +166,14 @@ func (b *Backend) SubscribeGatewayTX(mac lorawan.EUI64) error {
146
166
147
167
topic := bytes .NewBuffer (nil )
148
168
if err := b .DownlinkTemplate .Execute (topic , struct { MAC lorawan.EUI64 }{mac }); err != nil {
149
- return errors .Wrap (err , "execute uplink template error" )
169
+ return errors .Wrap (err , "execute downlink template error" )
150
170
}
151
171
152
- log .WithField ("topic" , topic .String ()).Info ("backend: subscribing to topic" )
153
- if token := b .conn .Subscribe (topic .String (), 0 , b .txPacketHandler ); token .Wait () && token .Error () != nil {
172
+ log .WithFields (log.Fields {
173
+ "topic" : topic .String (),
174
+ "qos" : b .config .QOS ,
175
+ }).Info ("backend: subscribing to topic" )
176
+ if token := b .conn .Subscribe (topic .String (), b .config .QOS , b .txPacketHandler ); token .Wait () && token .Error () != nil {
154
177
return token .Error ()
155
178
}
156
179
b .gateways [mac ] = struct {}{}
@@ -165,7 +188,7 @@ func (b *Backend) UnSubscribeGatewayTX(mac lorawan.EUI64) error {
165
188
166
189
topic := bytes .NewBuffer (nil )
167
190
if err := b .DownlinkTemplate .Execute (topic , struct { MAC lorawan.EUI64 }{mac }); err != nil {
168
- return errors .Wrap (err , "execute uplink template error" )
191
+ return errors .Wrap (err , "execute downlink template error" )
169
192
}
170
193
171
194
log .WithField ("topic" , topic .String ()).Info ("backend: unsubscribing from topic" )
@@ -201,8 +224,11 @@ func (b *Backend) publish(mac lorawan.EUI64, topicTemplate *template.Template, v
201
224
if err != nil {
202
225
return err
203
226
}
204
- log .WithField ("topic" , topic .String ()).Info ("backend: publishing packet" )
205
- if token := b .conn .Publish (topic .String (), 0 , false , bytes ); token .Wait () && token .Error () != nil {
227
+ log .WithFields (log.Fields {
228
+ "topic" : topic .String (),
229
+ "qos" : b .config .QOS ,
230
+ }).Info ("backend: publishing packet" )
231
+ if token := b .conn .Publish (topic .String (), b .config .QOS , false , bytes ); token .Wait () && token .Error () != nil {
206
232
return token .Error ()
207
233
}
208
234
return nil
@@ -228,7 +254,13 @@ func (b *Backend) onConnected(c mqtt.Client) {
228
254
log .WithField ("topic_count" , len (b .gateways )).Info ("backend: re-registering to gateway topics" )
229
255
topics := make (map [string ]byte )
230
256
for k := range b .gateways {
231
- topics [fmt .Sprintf ("gateway/%s/tx" , k )] = 0
257
+ topic := bytes .NewBuffer (nil )
258
+ if err := b .DownlinkTemplate .Execute (topic , struct { MAC lorawan.EUI64 }{k }); err != nil {
259
+ log .WithError (err ).Error ("backend: execute downlink template error" )
260
+ time .Sleep (time .Second )
261
+ continue
262
+ }
263
+ topics [topic .String ()] = b .config .QOS
232
264
}
233
265
if token := b .conn .SubscribeMultiple (topics , b .txPacketHandler ); token .Wait () && token .Error () != nil {
234
266
log .WithField ("topic_count" , len (topics )).Errorf ("backend: subscribe multiple failed: %s" , token .Error ())
0 commit comments