/
mqttEngine.go
159 lines (115 loc) · 2.72 KB
/
mqttEngine.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package main
import (
"encoding/json"
"net/url"
"sync"
"time"
"github.com/yosssi/gmq/mqtt"
"github.com/yosssi/gmq/mqtt/client"
)
type mqttEngine struct {
murl *url.URL
cli *client.Client
cliLock sync.Mutex
connected bool
//publisher *publisher
pubTicker *time.Ticker
pollTicker *time.Ticker
}
func newMqttEngine() (*mqttEngine, error) {
murl, err := url.Parse(*mqttURL)
if err != nil {
return nil, err
}
mq := &mqttEngine{}
// Create an MQTT Client.
cli := client.New(&client.Options{
ErrorHandler: mq.handleClientError,
})
mq.murl = murl
mq.cli = cli
mq.attemptConnect()
//mq.publisher = publisher
mq.pollTicker = time.NewTicker(time.Second * 1)
mq.pubTicker = time.NewTicker(time.Second * 15)
go poll(mq)
go publish(mq,"Ready to publish")
return mq, nil
}
func (mq *mqttEngine) attemptConnect() bool {
log.Debugf("Attempt Connect")
mq.cliLock.Lock()
defer mq.cliLock.Unlock()
if mq.connected {
log.Debugf("already connected")
return mq.connected
}
log.Debugf("connecting to %s", mq.murl.Host)
co := &client.ConnectOptions{
Network: mq.murl.Scheme,
Address: mq.murl.Host,
ClientID: []byte("mqtt-webbrick"),
}
if mq.murl.User != nil {
co.UserName = []byte(mq.murl.User.Username())
if pass, ok := mq.murl.User.Password(); ok {
co.Password = []byte(pass)
}
}
// Connect to the MQTT Server.
if err := mq.cli.Connect(co); err != nil {
log.Errorf("failed to connect: %s", err)
mq.connected = false
} else {
mq.connected = true
}
return mq.connected
}
func (mq *mqttEngine) handleClientError(err error) {
log.Errorf("client error: %s", err)
mq.cliLock.Lock()
defer mq.cliLock.Unlock()
mq.connected = false
go func() {
if err := mq.cli.Disconnect(); err != nil {
log.Errorf("client disconnect error: %s", err)
}
log.Debugf("client disconnected")
}()
}
func (mq *mqttEngine) disconnect() error {
if mq.connected {
return mq.cli.Disconnect()
}
return nil
}
func publish(mq *mqttEngine, message string) {
for t := range mq.pubTicker.C {
//metrics := mq.publisher.export()
if !mq.attemptConnect() {
log.Warningf("publish failed: not connected")
}
payload, _ := json.Marshal(struct {
Time int64 `json:"ts"`
Payload map[string]interface{} `json:"payload"`
}{
Time: t.Unix(),
Payload: []byte(message),
})
log.Debugf("publishing to %s length %d", wbTopic, len(payload))
err := mq.cli.Publish(&client.PublishOptions{
QoS: mqtt.QoS0,
TopicName: []byte(wbTopic),
Message: payload,
})
if err != nil {
log.Errorf("error publishing: %s", err)
}
}
}
func poll(mq *mqttEngine) {
for _ = range mq.pollTicker.C {
//log.Debugf("Flush at %v", t)
mq.publisher.flush()
}
}