@@ -3,6 +3,8 @@ package mqttpubsub
3
3
import (
4
4
"encoding/json"
5
5
"fmt"
6
+ "sync"
7
+ "time"
6
8
7
9
log "github.com/Sirupsen/logrus"
8
10
"github.com/brocaar/loraserver/models"
@@ -14,19 +16,23 @@ import (
14
16
type Backend struct {
15
17
conn mqtt.Client
16
18
txPacketChan chan models.TXPacket
19
+ gateways map [lorawan.EUI64 ]struct {}
20
+ mutex sync.RWMutex
17
21
}
18
22
19
23
// NewBackend creates a new Backend.
20
24
func NewBackend (server , username , password string ) (* Backend , error ) {
21
25
b := Backend {
22
26
txPacketChan : make (chan models.TXPacket ),
27
+ gateways : make (map [lorawan.EUI64 ]struct {}),
23
28
}
24
29
25
30
opts := mqtt .NewClientOptions ()
26
31
opts .AddBroker (server )
27
32
opts .SetUsername (username )
28
33
opts .SetPassword (password )
29
- opts .SetClientID ("lora-semtech-bridge" )
34
+ opts .SetOnConnectHandler (b .onConnected )
35
+ opts .SetConnectionLostHandler (b .onConnectionLost )
30
36
31
37
log .WithField ("server" , server ).Info ("backend/mqttpubsub: connecting to MQTT server" )
32
38
b .conn = mqtt .NewClient (opts )
@@ -50,22 +56,30 @@ func (b *Backend) TXPacketChan() chan models.TXPacket {
50
56
// SubscribeGatewayTX subscribes the backend to the gateway TXPacket
51
57
// topic (packets the gateway needs to transmit).
52
58
func (b * Backend ) SubscribeGatewayTX (mac lorawan.EUI64 ) error {
59
+ defer b .mutex .Unlock ()
60
+ b .mutex .Lock ()
61
+
53
62
topic := fmt .Sprintf ("gateway/%s/tx" , mac .String ())
54
63
log .WithField ("topic" , topic ).Info ("backend/mqttpubsub: subscribing to topic" )
55
64
if token := b .conn .Subscribe (topic , 0 , b .txPacketHandler ); token .Wait () && token .Error () != nil {
56
65
return token .Error ()
57
66
}
67
+ b .gateways [mac ] = struct {}{}
58
68
return nil
59
69
}
60
70
61
71
// UnSubscribeGatewayTX unsubscribes the backend from the gateway TXPacket
62
72
// topic.
63
73
func (b * Backend ) UnSubscribeGatewayTX (mac lorawan.EUI64 ) error {
74
+ defer b .mutex .Unlock ()
75
+ b .mutex .Lock ()
76
+
64
77
topic := fmt .Sprintf ("gateway/%s/tx" , mac .String ())
65
78
log .WithField ("topic" , topic ).Info ("backend/mqttpubsub: unsubscribing from topic" )
66
79
if token := b .conn .Unsubscribe (topic ); token .Wait () && token .Error () != nil {
67
80
return token .Error ()
68
81
}
82
+ delete (b .gateways , mac )
69
83
return nil
70
84
}
71
85
@@ -102,3 +116,29 @@ func (b *Backend) txPacketHandler(c mqtt.Client, msg mqtt.Message) {
102
116
}
103
117
b .txPacketChan <- txPacket
104
118
}
119
+
120
+ func (b * Backend ) onConnected (c mqtt.Client ) {
121
+ defer b .mutex .RUnlock ()
122
+ b .mutex .RLock ()
123
+
124
+ log .Info ("backend/mqttpubsub: connected to mqtt server" )
125
+ if len (b .gateways ) > 0 {
126
+ for {
127
+ log .WithField ("topic_count" , len (b .gateways )).Info ("Backend/mqttpubsub: re-registering to gateway topics" )
128
+ topics := make (map [string ]byte )
129
+ for k := range b .gateways {
130
+ topics [fmt .Sprintf ("gateway/%s/tx" , k )] = 0
131
+ }
132
+ if token := b .conn .SubscribeMultiple (topics , b .txPacketHandler ); token .Wait () && token .Error () != nil {
133
+ log .WithField ("topic_count" , len (topics )).Errorf ("backend/mqttpubsub: subscribe multiple failed: %s" , token .Error ())
134
+ time .Sleep (time .Second )
135
+ continue
136
+ }
137
+ return
138
+ }
139
+ }
140
+ }
141
+
142
+ func (b * Backend ) onConnectionLost (c mqtt.Client , reason error ) {
143
+ log .Errorf ("backend/mqttpubsub: mqtt connection error: %s" , reason )
144
+ }
0 commit comments