|
@@ -30,6 +30,7 @@ import (
|
|
|
|
|
|
type MQTTSource struct {
|
|
|
srv string
|
|
|
+ qos int
|
|
|
format string
|
|
|
tpc string
|
|
|
clientid string
|
|
@@ -38,6 +39,8 @@ type MQTTSource struct {
|
|
|
password string
|
|
|
certPath string
|
|
|
pkeyPath string
|
|
|
+ conSel string
|
|
|
+ InSecure bool
|
|
|
|
|
|
model modelVersion
|
|
|
schema map[string]interface{}
|
|
@@ -45,17 +48,19 @@ type MQTTSource struct {
|
|
|
}
|
|
|
|
|
|
type MQTTConfig struct {
|
|
|
- Format string `json:"format"`
|
|
|
- Qos int `json:"qos"`
|
|
|
- Servers []string `json:"servers"`
|
|
|
- Clientid string `json:"clientid"`
|
|
|
- PVersion string `json:"protocolVersion"`
|
|
|
- Uname string `json:"username"`
|
|
|
- Password string `json:"password"`
|
|
|
- Certification string `json:"certificationPath"`
|
|
|
- PrivateKPath string `json:"privateKeyPath"`
|
|
|
- KubeedgeModelFile string `json:"kubeedgeModelFile"`
|
|
|
- KubeedgeVersion string `json:"kubeedgeVersion"`
|
|
|
+ Format string `json:"format"`
|
|
|
+ Qos int `json:"qos"`
|
|
|
+ Servers []string `json:"servers"`
|
|
|
+ Clientid string `json:"clientid"`
|
|
|
+ PVersion string `json:"protocolVersion"`
|
|
|
+ Uname string `json:"username"`
|
|
|
+ Password string `json:"password"`
|
|
|
+ Certification string `json:"certificationPath"`
|
|
|
+ PrivateKPath string `json:"privateKeyPath"`
|
|
|
+ InsecureSkipVerify bool `json:"insecureSkipVerify"`
|
|
|
+ KubeedgeModelFile string `json:"kubeedgeModelFile"`
|
|
|
+ KubeedgeVersion string `json:"kubeedgeVersion"`
|
|
|
+ ConnectionSelector string `json:"connectionSelector"`
|
|
|
}
|
|
|
|
|
|
func (ms *MQTTSource) WithSchema(_ string) *MQTTSource {
|
|
@@ -69,14 +74,17 @@ func (ms *MQTTSource) Configure(topic string, props map[string]interface{}) erro
|
|
|
return fmt.Errorf("read properties %v fail with error: %v", props, err)
|
|
|
}
|
|
|
ms.tpc = topic
|
|
|
- if srvs := cfg.Servers; srvs != nil && len(srvs) > 0 {
|
|
|
- ms.srv = srvs[0]
|
|
|
- } else {
|
|
|
- return fmt.Errorf("missing server property")
|
|
|
+ if cfg.ConnectionSelector == "" {
|
|
|
+ if srvs := cfg.Servers; srvs != nil && len(srvs) > 0 {
|
|
|
+ ms.srv = srvs[0]
|
|
|
+ } else {
|
|
|
+ return fmt.Errorf("missing server property")
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
+ ms.conSel = cfg.ConnectionSelector
|
|
|
ms.format = cfg.Format
|
|
|
ms.clientid = cfg.Clientid
|
|
|
+ ms.qos = cfg.Qos
|
|
|
|
|
|
ms.pVersion = 3
|
|
|
if cfg.PVersion == "3.1.1" {
|
|
@@ -100,89 +108,102 @@ func (ms *MQTTSource) Configure(topic string, props map[string]interface{}) erro
|
|
|
}
|
|
|
|
|
|
func (ms *MQTTSource) Open(ctx api.StreamContext, consumer chan<- api.SourceTuple, errCh chan<- error) {
|
|
|
+ var client MQTT.Client
|
|
|
log := ctx.GetLogger()
|
|
|
|
|
|
- opts := MQTT.NewClientOptions().AddBroker(ms.srv).SetProtocolVersion(ms.pVersion)
|
|
|
- if ms.clientid == "" {
|
|
|
- if newUUID, err := uuid.NewUUID(); err != nil {
|
|
|
- errCh <- fmt.Errorf("failed to get uuid, the error is %s", err)
|
|
|
+ if ms.conSel != "" {
|
|
|
+ con, err := ctx.GetConnection(ms.conSel)
|
|
|
+ if err != nil {
|
|
|
+ log.Errorf("The mqtt client for connection selector %s get fail with error: %s", ms.conSel, err)
|
|
|
+ errCh <- err
|
|
|
return
|
|
|
- } else {
|
|
|
- ms.clientid = newUUID.String()
|
|
|
- opts.SetClientID(newUUID.String())
|
|
|
}
|
|
|
+ client = con.(MQTT.Client)
|
|
|
+ log.Infof("The mqtt client for connection selector %s get successfully", ms.conSel)
|
|
|
} else {
|
|
|
- opts.SetClientID(ms.clientid)
|
|
|
- }
|
|
|
+ opts := MQTT.NewClientOptions().AddBroker(ms.srv).SetProtocolVersion(ms.pVersion)
|
|
|
+ if ms.clientid == "" {
|
|
|
+ if newUUID, err := uuid.NewUUID(); err != nil {
|
|
|
+ errCh <- fmt.Errorf("failed to get uuid, the error is %s", err)
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ ms.clientid = newUUID.String()
|
|
|
+ opts = opts.SetClientID(newUUID.String())
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ opts = opts.SetClientID(ms.clientid)
|
|
|
+ }
|
|
|
|
|
|
- if ms.certPath != "" || ms.pkeyPath != "" {
|
|
|
- log.Infof("Connect MQTT broker with certification and keys.")
|
|
|
- if cp, err := conf.ProcessPath(ms.certPath); err == nil {
|
|
|
- log.Infof("The certification file is %s.", cp)
|
|
|
- if kp, err1 := conf.ProcessPath(ms.pkeyPath); err1 == nil {
|
|
|
- log.Infof("The private key file is %s.", kp)
|
|
|
- if cer, err2 := tls.LoadX509KeyPair(cp, kp); err2 != nil {
|
|
|
- errCh <- err2
|
|
|
- return
|
|
|
+ if ms.certPath != "" || ms.pkeyPath != "" {
|
|
|
+ log.Infof("Connect MQTT broker with certification and keys.")
|
|
|
+ if cp, err := conf.ProcessPath(ms.certPath); err == nil {
|
|
|
+ log.Infof("The certification file is %s.", cp)
|
|
|
+ if kp, err1 := conf.ProcessPath(ms.pkeyPath); err1 == nil {
|
|
|
+ log.Infof("The private key file is %s.", kp)
|
|
|
+ if cer, err2 := tls.LoadX509KeyPair(cp, kp); err2 != nil {
|
|
|
+ errCh <- err2
|
|
|
+ return
|
|
|
+ } else {
|
|
|
+ opts.SetTLSConfig(&tls.Config{Certificates: []tls.Certificate{cer}, InsecureSkipVerify: ms.InSecure})
|
|
|
+ }
|
|
|
} else {
|
|
|
- opts.SetTLSConfig(&tls.Config{Certificates: []tls.Certificate{cer}})
|
|
|
+ errCh <- err1
|
|
|
+ return
|
|
|
}
|
|
|
} else {
|
|
|
- errCh <- err1
|
|
|
+ errCh <- err
|
|
|
return
|
|
|
}
|
|
|
} else {
|
|
|
- errCh <- err
|
|
|
- return
|
|
|
- }
|
|
|
- } else {
|
|
|
- log.Infof("Connect MQTT broker with username and password.")
|
|
|
- if ms.uName != "" {
|
|
|
- opts = opts.SetUsername(ms.uName)
|
|
|
- } else {
|
|
|
- log.Infof("The username is empty.")
|
|
|
+ log.Infof("Connect MQTT broker with username and password.")
|
|
|
+ if ms.uName != "" {
|
|
|
+ opts = opts.SetUsername(ms.uName)
|
|
|
+ } else {
|
|
|
+ log.Infof("The username is empty.")
|
|
|
+ }
|
|
|
+
|
|
|
+ if ms.password != "" {
|
|
|
+ opts = opts.SetPassword(ms.password)
|
|
|
+ } else {
|
|
|
+ log.Infof("The password is empty.")
|
|
|
+ }
|
|
|
}
|
|
|
+ opts.SetAutoReconnect(true)
|
|
|
+ var reconn = false
|
|
|
+ opts.SetConnectionLostHandler(func(client MQTT.Client, e error) {
|
|
|
+ log.Errorf("The connection %s is disconnected due to error %s, will try to re-connect later.", ms.srv+": "+ms.clientid, e)
|
|
|
+ reconn = true
|
|
|
+ subscribe(ms, client, ctx, consumer)
|
|
|
+ })
|
|
|
+
|
|
|
+ opts.SetOnConnectHandler(func(client MQTT.Client) {
|
|
|
+ if reconn {
|
|
|
+ log.Infof("The connection is %s re-established successfully.", ms.srv+": "+ms.clientid)
|
|
|
+ subscribe(ms, client, ctx, consumer)
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
- if ms.password != "" {
|
|
|
- opts = opts.SetPassword(ms.password)
|
|
|
- } else {
|
|
|
- log.Infof("The password is empty.")
|
|
|
+ client = MQTT.NewClient(opts)
|
|
|
+
|
|
|
+ if token := client.Connect(); token.Wait() && token.Error() != nil {
|
|
|
+ errCh <- fmt.Errorf("found error when connecting to %s: %s", ms.srv, token.Error())
|
|
|
+ return
|
|
|
}
|
|
|
+ log.Infof("The connection to server %s:%s was established successfully", ms.srv, ms.clientid)
|
|
|
}
|
|
|
- opts.SetAutoReconnect(true)
|
|
|
- var reconn = false
|
|
|
- opts.SetConnectionLostHandler(func(client MQTT.Client, e error) {
|
|
|
- log.Errorf("The connection %s is disconnected due to error %s, will try to re-connect later.", ms.srv+": "+ms.clientid, e)
|
|
|
- reconn = true
|
|
|
- subscribe(ms.tpc, client, ctx, consumer, ms.model, ms.format)
|
|
|
- })
|
|
|
-
|
|
|
- opts.SetOnConnectHandler(func(client MQTT.Client) {
|
|
|
- if reconn {
|
|
|
- log.Infof("The connection is %s re-established successfully.", ms.srv+": "+ms.clientid)
|
|
|
- subscribe(ms.tpc, client, ctx, consumer, ms.model, ms.format)
|
|
|
- }
|
|
|
- })
|
|
|
|
|
|
- c := MQTT.NewClient(opts)
|
|
|
- if token := c.Connect(); token.Wait() && token.Error() != nil {
|
|
|
- errCh <- fmt.Errorf("found error when connecting to %s: %s", ms.srv, token.Error())
|
|
|
- return
|
|
|
- }
|
|
|
- log.Infof("The connection to server %s was established successfully", ms.srv)
|
|
|
- ms.conn = c
|
|
|
- subscribe(ms.tpc, c, ctx, consumer, ms.model, ms.format)
|
|
|
- log.Infof("Successfully subscribe to topic %s", ms.srv+": "+ms.clientid)
|
|
|
+ ms.conn = client
|
|
|
+ subscribe(ms, client, ctx, consumer)
|
|
|
}
|
|
|
|
|
|
-func subscribe(topic string, client MQTT.Client, ctx api.StreamContext, consumer chan<- api.SourceTuple, model modelVersion, format string) {
|
|
|
+func subscribe(ms *MQTTSource, client MQTT.Client, ctx api.StreamContext, consumer chan<- api.SourceTuple) {
|
|
|
log := ctx.GetLogger()
|
|
|
h := func(client MQTT.Client, msg MQTT.Message) {
|
|
|
log.Debugf("instance %d received %s", ctx.GetInstanceId(), msg.Payload())
|
|
|
- result, e := message.Decode(msg.Payload(), format)
|
|
|
+ result, e := message.Decode(msg.Payload(), ms.format)
|
|
|
//The unmarshal type can only be bool, float64, string, []interface{}, map[string]interface{}, nil
|
|
|
if e != nil {
|
|
|
- log.Errorf("Invalid data format, cannot decode %s to %s format with error %s", string(msg.Payload()), format, e)
|
|
|
+ log.Errorf("Invalid data format, cannot decode %s to %s format with error %s", string(msg.Payload()), ms.format, e)
|
|
|
return
|
|
|
}
|
|
|
|
|
@@ -190,8 +211,8 @@ func subscribe(topic string, client MQTT.Client, ctx api.StreamContext, consumer
|
|
|
meta["topic"] = msg.Topic()
|
|
|
meta["messageid"] = strconv.Itoa(int(msg.MessageID()))
|
|
|
|
|
|
- if nil != model {
|
|
|
- sliErr := model.checkType(result, msg.Topic())
|
|
|
+ if nil != ms.model {
|
|
|
+ sliErr := ms.model.checkType(result, msg.Topic())
|
|
|
for _, v := range sliErr {
|
|
|
log.Errorf(v)
|
|
|
}
|
|
@@ -205,17 +226,20 @@ func subscribe(topic string, client MQTT.Client, ctx api.StreamContext, consumer
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if token := client.Subscribe(topic, 0, h); token.Wait() && token.Error() != nil {
|
|
|
+ if token := client.Subscribe(ms.tpc, byte(ms.qos), h); token.Wait() && token.Error() != nil {
|
|
|
log.Errorf("Found error: %s", token.Error())
|
|
|
} else {
|
|
|
- log.Infof("Successfully subscribe to topic %s", topic)
|
|
|
+ log.Infof("Successfully subscribe to topic %s", ms.tpc)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (ms *MQTTSource) Close(ctx api.StreamContext) error {
|
|
|
ctx.GetLogger().Infof("Mqtt Source instance %d Done", ctx.GetInstanceId())
|
|
|
- if ms.conn != nil && ms.conn.IsConnected() {
|
|
|
+ if ms.conn != nil && ms.conn.IsConnected() && ms.conSel == "" {
|
|
|
ms.conn.Disconnect(5000)
|
|
|
}
|
|
|
+ if ms.conSel != "" {
|
|
|
+ ctx.ReleaseConnection(ms.conSel)
|
|
|
+ }
|
|
|
return nil
|
|
|
}
|