github.com/argoproj/argo-events@v1.9.1/eventsources/sources/mqtt/start.go (about) 1 /* 2 Copyright 2018 BlackRock, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package mqtt 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "time" 24 25 mqttlib "github.com/eclipse/paho.mqtt.golang" 26 "go.uber.org/zap" 27 28 "github.com/argoproj/argo-events/common" 29 "github.com/argoproj/argo-events/common/logging" 30 eventsourcecommon "github.com/argoproj/argo-events/eventsources/common" 31 "github.com/argoproj/argo-events/eventsources/sources" 32 metrics "github.com/argoproj/argo-events/metrics" 33 apicommon "github.com/argoproj/argo-events/pkg/apis/common" 34 "github.com/argoproj/argo-events/pkg/apis/events" 35 "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1" 36 ) 37 38 // EventListener implements Eventing for mqtt event source 39 type EventListener struct { 40 EventSourceName string 41 EventName string 42 MQTTEventSource v1alpha1.MQTTEventSource 43 Metrics *metrics.Metrics 44 } 45 46 // GetEventSourceName returns name of event source 47 func (el *EventListener) GetEventSourceName() string { 48 return el.EventSourceName 49 } 50 51 // GetEventName returns name of event 52 func (el *EventListener) GetEventName() string { 53 return el.EventName 54 } 55 56 // GetEventSourceType return type of event server 57 func (el *EventListener) GetEventSourceType() apicommon.EventSourceType { 58 return apicommon.MQTTEvent 59 } 60 61 // StartListening starts listening events 62 func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byte, ...eventsourcecommon.Option) error) error { 63 log := logging.FromContext(ctx). 64 With(logging.LabelEventSourceType, el.GetEventSourceType(), logging.LabelEventName, el.GetEventName()) 65 defer sources.Recover(el.GetEventName()) 66 67 log.Info("starting MQTT event source...") 68 mqttEventSource := &el.MQTTEventSource 69 70 if mqttEventSource.JSONBody { 71 log.Info("assuming all events have a json body...") 72 } 73 74 log.Info("setting up the message handler...") 75 handler := func(c mqttlib.Client, msg mqttlib.Message) { 76 defer func(start time.Time) { 77 el.Metrics.EventProcessingDuration(el.GetEventSourceName(), el.GetEventName(), float64(time.Since(start)/time.Millisecond)) 78 }(time.Now()) 79 80 eventData := &events.MQTTEventData{ 81 Topic: msg.Topic(), 82 MessageID: int(msg.MessageID()), 83 Body: msg.Payload(), 84 Metadata: mqttEventSource.Metadata, 85 } 86 if mqttEventSource.JSONBody { 87 body := msg.Payload() 88 eventData.Body = (*json.RawMessage)(&body) 89 } else { 90 eventData.Body = msg.Payload() 91 } 92 93 eventBody, err := json.Marshal(eventData) 94 if err != nil { 95 log.Errorw("failed to marshal the event data, rejecting the event...", zap.Error(err)) 96 el.Metrics.EventProcessingFailed(el.GetEventSourceName(), el.GetEventName()) 97 return 98 } 99 log.Info("dispatching event on the data channel...") 100 if err = dispatch(eventBody); err != nil { 101 log.Errorw("failed to dispatch MQTT event...", zap.Error(err)) 102 el.Metrics.EventProcessingFailed(el.GetEventSourceName(), el.GetEventName()) 103 } 104 } 105 106 log.Info("setting up the mqtt broker client...") 107 opts := mqttlib.NewClientOptions().AddBroker(mqttEventSource.URL).SetClientID(mqttEventSource.ClientID) 108 if mqttEventSource.TLS != nil { 109 tlsConfig, err := common.GetTLSConfig(mqttEventSource.TLS) 110 if err != nil { 111 return fmt.Errorf("failed to get the tls configuration, %w", err) 112 } 113 opts.TLSConfig = tlsConfig 114 } 115 116 if mqttEventSource.Auth != nil { 117 username, err := common.GetSecretFromVolume(mqttEventSource.Auth.Username) 118 if err != nil { 119 return fmt.Errorf("username not found, %w", err) 120 } 121 password, err := common.GetSecretFromVolume(mqttEventSource.Auth.Password) 122 if err != nil { 123 return fmt.Errorf("password not found, %w", err) 124 } 125 opts.SetUsername(username) 126 opts.SetPassword(password) 127 } 128 129 var client mqttlib.Client 130 131 log.Info("connecting to mqtt broker...") 132 if err := common.DoWithRetry(mqttEventSource.ConnectionBackoff, func() error { 133 client = mqttlib.NewClient(opts) 134 if token := client.Connect(); token.Wait() && token.Error() != nil { 135 return token.Error() 136 } 137 return nil 138 }); err != nil { 139 return fmt.Errorf("failed to connect to the mqtt broker for event source %s, %w", el.GetEventName(), err) 140 } 141 142 log.Info("subscribing to the topic...") 143 if token := client.Subscribe(mqttEventSource.Topic, 0, handler); token.Wait() && token.Error() != nil { 144 return fmt.Errorf("failed to subscribe to the topic %s for event source %s, %w", mqttEventSource.Topic, el.GetEventName(), token.Error()) 145 } 146 147 <-ctx.Done() 148 log.Info("event source is stopped, unsubscribing the client...") 149 150 token := client.Unsubscribe(mqttEventSource.Topic) 151 if token.Error() != nil { 152 log.Errorw("failed to unsubscribe client", zap.Error(token.Error())) 153 } 154 155 return nil 156 }