mirror of
https://github.com/pgsty/minio.git
synced 2026-08-10 08:13:28 +03:00
Persist offline mqtt events in the queueDir and replay (#7037)
This commit is contained in:
committed by
Harshavardhana
parent
8757c963ba
commit
6571641735
+102
-32
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user