Persist offline mqtt events in the queueDir and replay (#7037)

This commit is contained in:
Praveen raj Mani
2019-01-14 12:39:00 +05:30
committed by Harshavardhana
parent 8757c963ba
commit 6571641735
27 changed files with 1507 additions and 265 deletions
+102 -32
View File
@@ -19,11 +19,15 @@ import (
"errors"
"fmt"
"net"
"net/http"
"net/url"
"os"
"reflect"
"sync/atomic"
"time"
"github.com/eclipse/paho.mqtt.golang/packets"
"golang.org/x/net/proxy"
"golang.org/x/net/websocket"
)
@@ -34,10 +38,14 @@ func signalError(c chan<- error, err error) {
}
}
func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration) (net.Conn, error) {
func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration, headers http.Header) (net.Conn, error) {
switch uri.Scheme {
case "ws":
conn, err := websocket.Dial(uri.String(), "mqtt", fmt.Sprintf("http://%s", uri.Host))
config, _ := websocket.NewConfig(uri.String(), fmt.Sprintf("http://%s", uri.Host))
config.Protocol = []string{"mqtt"}
config.Header = headers
config.Dialer = &net.Dialer{Timeout: timeout}
conn, err := websocket.DialConfig(config)
if err != nil {
return nil, err
}
@@ -47,6 +55,8 @@ func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration) (net.
config, _ := websocket.NewConfig(uri.String(), fmt.Sprintf("https://%s", uri.Host))
config.Protocol = []string{"mqtt"}
config.TlsConfig = tlsc
config.Header = headers
config.Dialer = &net.Dialer{Timeout: timeout}
conn, err := websocket.DialConfig(config)
if err != nil {
return nil, err
@@ -54,7 +64,23 @@ func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration) (net.
conn.PayloadType = websocket.BinaryFrame
return conn, err
case "tcp":
conn, err := net.DialTimeout("tcp", uri.Host, timeout)
allProxy := os.Getenv("all_proxy")
if len(allProxy) == 0 {
conn, err := net.DialTimeout("tcp", uri.Host, timeout)
if err != nil {
return nil, err
}
return conn, nil
}
proxyDialer := proxy.FromEnvironment()
conn, err := proxyDialer.Dial("tcp", uri.Host)
if err != nil {
return nil, err
}
return conn, nil
case "unix":
conn, err := net.DialTimeout("unix", uri.Host, timeout)
if err != nil {
return nil, err
}
@@ -64,11 +90,30 @@ func openConnection(uri *url.URL, tlsc *tls.Config, timeout time.Duration) (net.
case "tls":
fallthrough
case "tcps":
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: timeout}, "tcp", uri.Host, tlsc)
allProxy := os.Getenv("all_proxy")
if len(allProxy) == 0 {
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: timeout}, "tcp", uri.Host, tlsc)
if err != nil {
return nil, err
}
return conn, nil
}
proxyDialer := proxy.FromEnvironment()
conn, err := proxyDialer.Dial("tcp", uri.Host)
if err != nil {
return nil, err
}
return conn, nil
tlsConn := tls.Client(conn, tlsc)
err = tlsConn.Handshake()
if err != nil {
conn.Close()
return nil, err
}
return tlsConn, nil
}
return nil, errors.New("Unknown protocol")
}
@@ -92,7 +137,7 @@ func incoming(c *client) {
case c.ibound <- cp:
// Notify keepalive logic that we recently received a packet
if c.options.KeepAlive != 0 {
c.packetResp <- struct{}{}
atomic.StoreInt64(&c.lastReceived, time.Now().Unix())
}
case <-c.stop:
// This avoids a deadlock should a message arrive while shutting down.
@@ -136,6 +181,7 @@ func outgoing(c *client) {
if err := msg.Write(c.conn); err != nil {
ERROR.Println(NET, "outgoing stopped with error", err)
pub.t.setError(err)
signalError(c.errors, err)
return
}
@@ -160,6 +206,9 @@ func outgoing(c *client) {
DEBUG.Println(NET, "obound priority msg to write, type", reflect.TypeOf(msg.p))
if err := msg.p.Write(c.conn); err != nil {
ERROR.Println(NET, "outgoing stopped with error", err)
if msg.t != nil {
msg.t.setError(err)
}
signalError(c.errors, err)
return
}
@@ -172,11 +221,7 @@ func outgoing(c *client) {
}
// Reset ping timer after sending control packet.
if c.options.KeepAlive != 0 {
select {
case c.keepaliveReset <- struct{}{}:
default:
DEBUG.Println(NET, "couldn't send keepalive signal in outbound as channel full")
}
atomic.StoreInt64(&c.lastSent, time.Now().Unix())
}
}
}
@@ -199,20 +244,22 @@ func alllogic(c *client) {
switch m := msg.(type) {
case *packets.PingrespPacket:
DEBUG.Println(NET, "received pingresp")
c.pingResp <- struct{}{}
atomic.StoreInt32(&c.pingOutstanding, 0)
case *packets.SubackPacket:
DEBUG.Println(NET, "received suback, id:", m.MessageID)
token := c.getToken(m.MessageID).(*SubscribeToken)
DEBUG.Println(NET, "granted qoss", m.ReturnCodes)
for i, qos := range m.ReturnCodes {
token.subResult[token.subs[i]] = qos
token := c.getToken(m.MessageID)
switch t := token.(type) {
case *SubscribeToken:
DEBUG.Println(NET, "granted qoss", m.ReturnCodes)
for i, qos := range m.ReturnCodes {
t.subResult[t.subs[i]] = qos
}
}
token.flowComplete()
c.freeID(m.MessageID)
case *packets.UnsubackPacket:
DEBUG.Println(NET, "received unsuback, id:", m.MessageID)
token := c.getToken(m.MessageID).(*UnsubscribeToken)
token.flowComplete()
c.getToken(m.MessageID).flowComplete()
c.freeID(m.MessageID)
case *packets.PublishPacket:
DEBUG.Println(NET, "received publish, msgId:", m.MessageID)
@@ -221,21 +268,14 @@ func alllogic(c *client) {
case 2:
c.incomingPubChan <- m
DEBUG.Println(NET, "done putting msg on incomingPubChan")
pr := packets.NewControlPacket(packets.Pubrec).(*packets.PubrecPacket)
pr.MessageID = m.MessageID
DEBUG.Println(NET, "putting pubrec msg on obound")
c.oboundP <- &PacketAndToken{p: pr, t: nil}
DEBUG.Println(NET, "done putting pubrec msg on obound")
case 1:
c.incomingPubChan <- m
DEBUG.Println(NET, "done putting msg on incomingPubChan")
pa := packets.NewControlPacket(packets.Puback).(*packets.PubackPacket)
pa.MessageID = m.MessageID
DEBUG.Println(NET, "putting puback msg on obound")
c.oboundP <- &PacketAndToken{p: pa, t: nil}
DEBUG.Println(NET, "done putting puback msg on obound")
case 0:
c.incomingPubChan <- m
select {
case c.incomingPubChan <- m:
case <-c.stop:
}
DEBUG.Println(NET, "done putting msg on incomingPubChan")
}
case *packets.PubackPacket:
@@ -250,15 +290,16 @@ func alllogic(c *client) {
prel.MessageID = m.MessageID
select {
case c.oboundP <- &PacketAndToken{p: prel, t: nil}:
case <-time.After(time.Second):
case <-c.stop:
}
case *packets.PubrelPacket:
DEBUG.Println(NET, "received pubrel, id:", m.MessageID)
pc := packets.NewControlPacket(packets.Pubcomp).(*packets.PubcompPacket)
pc.MessageID = m.MessageID
persistOutbound(c.persist, pc)
select {
case c.oboundP <- &PacketAndToken{p: pc, t: nil}:
case <-time.After(time.Second):
case <-c.stop:
}
case *packets.PubcompPacket:
DEBUG.Println(NET, "received pubcomp, id:", m.MessageID)
@@ -272,14 +313,43 @@ func alllogic(c *client) {
}
}
func (c *client) ackFunc(packet *packets.PublishPacket) func() {
return func() {
switch packet.Qos {
case 2:
pr := packets.NewControlPacket(packets.Pubrec).(*packets.PubrecPacket)
pr.MessageID = packet.MessageID
DEBUG.Println(NET, "putting pubrec msg on obound")
select {
case c.oboundP <- &PacketAndToken{p: pr, t: nil}:
case <-c.stop:
}
DEBUG.Println(NET, "done putting pubrec msg on obound")
case 1:
pa := packets.NewControlPacket(packets.Puback).(*packets.PubackPacket)
pa.MessageID = packet.MessageID
DEBUG.Println(NET, "putting puback msg on obound")
persistOutbound(c.persist, pa)
select {
case c.oboundP <- &PacketAndToken{p: pa, t: nil}:
case <-c.stop:
}
DEBUG.Println(NET, "done putting puback msg on obound")
case 0:
// do nothing, since there is no need to send an ack packet back
}
}
}
func errorWatch(c *client) {
defer c.workers.Done()
select {
case <-c.stop:
WARN.Println(NET, "errorWatch stopped")
return
case err := <-c.errors:
ERROR.Println(NET, "error triggered, stopping")
c.internalConnLost(err)
go c.internalConnLost(err)
return
}
}