github.com/argoproj/argo-events@v1.9.1/eventsources/sources/nats/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 nats 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "time" 24 25 natslib "github.com/nats-io/nats.go" 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 nats event source 39 type EventListener struct { 40 EventSourceName string 41 EventName string 42 NATSEventSource v1alpha1.NATSEventsSource 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.NATSEvent 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 natsEventSource := &el.NATSEventSource 68 69 var opt []natslib.Option 70 if natsEventSource.TLS != nil { 71 tlsConfig, err := common.GetTLSConfig(natsEventSource.TLS) 72 if err != nil { 73 return fmt.Errorf("failed to get the tls configuration, %w", err) 74 } 75 opt = append(opt, natslib.Secure(tlsConfig)) 76 } 77 78 if natsEventSource.Auth != nil { 79 switch { 80 case natsEventSource.Auth.Basic != nil: 81 username, err := common.GetSecretFromVolume(natsEventSource.Auth.Basic.Username) 82 if err != nil { 83 return err 84 } 85 password, err := common.GetSecretFromVolume(natsEventSource.Auth.Basic.Password) 86 if err != nil { 87 return err 88 } 89 opt = append(opt, natslib.UserInfo(username, password)) 90 case natsEventSource.Auth.Token != nil: 91 token, err := common.GetSecretFromVolume(natsEventSource.Auth.Token) 92 if err != nil { 93 return err 94 } 95 opt = append(opt, natslib.Token(token)) 96 case natsEventSource.Auth.NKey != nil: 97 nkeyFile, err := common.GetSecretVolumePath(natsEventSource.Auth.NKey) 98 if err != nil { 99 return err 100 } 101 o, err := natslib.NkeyOptionFromSeed(nkeyFile) 102 if err != nil { 103 return fmt.Errorf("failed to get NKey, %w", err) 104 } 105 opt = append(opt, o) 106 case natsEventSource.Auth.Credential != nil: 107 cFile, err := common.GetSecretVolumePath(natsEventSource.Auth.Credential) 108 if err != nil { 109 return err 110 } 111 opt = append(opt, natslib.UserCredentials(cFile)) 112 } 113 } 114 115 var conn *natslib.Conn 116 log.Info("connecting to nats cluster...") 117 if err := common.DoWithRetry(natsEventSource.ConnectionBackoff, func() error { 118 var err error 119 if conn, err = natslib.Connect(natsEventSource.URL, opt...); err != nil { 120 return err 121 } 122 return nil 123 }); err != nil { 124 return fmt.Errorf("failed to connect to the nats server for event source %s, %w", el.GetEventName(), err) 125 } 126 defer conn.Close() 127 128 if natsEventSource.JSONBody { 129 log.Info("assuming all events have a json body...") 130 } 131 132 log.Info("subscribing to messages on the queue...") 133 _, err := conn.Subscribe(natsEventSource.Subject, func(msg *natslib.Msg) { 134 defer func(start time.Time) { 135 el.Metrics.EventProcessingDuration(el.GetEventSourceName(), el.GetEventName(), float64(time.Since(start)/time.Millisecond)) 136 }(time.Now()) 137 138 eventData := &events.NATSEventData{ 139 Subject: msg.Subject, 140 Header: msg.Header, 141 Metadata: natsEventSource.Metadata, 142 } 143 if natsEventSource.JSONBody { 144 eventData.Body = (*json.RawMessage)(&msg.Data) 145 } else { 146 eventData.Body = msg.Data 147 } 148 149 eventBody, err := json.Marshal(eventData) 150 if err != nil { 151 log.Errorw("failed to marshal the event data, rejecting the event...", zap.Error(err)) 152 el.Metrics.EventProcessingFailed(el.GetEventSourceName(), el.GetEventName()) 153 return 154 } 155 log.Info("dispatching the event on data channel...") 156 if err = dispatch(eventBody); err != nil { 157 log.Errorw("failed to dispatch a NATS event", zap.Error(err)) 158 el.Metrics.EventProcessingFailed(el.GetEventSourceName(), el.GetEventName()) 159 } 160 }) 161 if err != nil { 162 return fmt.Errorf("failed to subscribe to the subject %s for event source %s, %w", natsEventSource.Subject, el.GetEventName(), err) 163 } 164 165 conn.Flush() 166 if err := conn.LastError(); err != nil { 167 return fmt.Errorf("connection failure for event source %s, %w", el.GetEventName(), err) 168 } 169 170 <-ctx.Done() 171 log.Info("event source is stopped") 172 return nil 173 }