github.com/argoproj/argo-events@v1.9.1/eventsources/sources/stripe/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 stripe 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "io" 24 "net/http" 25 "time" 26 27 "github.com/stripe/stripe-go" 28 "github.com/stripe/stripe-go/webhookendpoint" 29 "go.uber.org/zap" 30 31 "github.com/argoproj/argo-events/common" 32 "github.com/argoproj/argo-events/common/logging" 33 eventsourcecommon "github.com/argoproj/argo-events/eventsources/common" 34 "github.com/argoproj/argo-events/eventsources/common/webhook" 35 "github.com/argoproj/argo-events/eventsources/sources" 36 apicommon "github.com/argoproj/argo-events/pkg/apis/common" 37 "github.com/argoproj/argo-events/pkg/apis/events" 38 ) 39 40 // controller controls the webhook operations 41 var ( 42 controller = webhook.NewController() 43 ) 44 45 // set up the activation and inactivation channels to control the state of routes. 46 func init() { 47 go webhook.ProcessRouteStatus(controller) 48 } 49 50 // GetEventSourceName returns name of event source 51 func (el *EventListener) GetEventSourceName() string { 52 return el.EventSourceName 53 } 54 55 // GetEventName returns name of event 56 func (el *EventListener) GetEventName() string { 57 return el.EventName 58 } 59 60 // GetEventSourceType return type of event server 61 func (el *EventListener) GetEventSourceType() apicommon.EventSourceType { 62 return apicommon.StripeEvent 63 } 64 65 // Implement Router 66 // 1. GetRoute 67 // 2. HandleRoute 68 // 3. PostActivate 69 // 4. PostDeactivate 70 71 // GetRoute returns the route 72 func (rc *Router) GetRoute() *webhook.Route { 73 return rc.route 74 } 75 76 // HandleRoute handles incoming requests on the route 77 func (rc *Router) HandleRoute(writer http.ResponseWriter, request *http.Request) { 78 route := rc.route 79 80 logger := route.Logger.With( 81 logging.LabelEndpoint, route.Context.Endpoint, 82 logging.LabelPort, route.Context.Port, 83 logging.LabelHTTPMethod, route.Context.Method, 84 ) 85 86 logger.Info("request a received, processing it...") 87 88 if !route.Active { 89 logger.Warn("endpoint is not active, won't process it") 90 common.SendErrorResponse(writer, "endpoint is inactive") 91 return 92 } 93 94 defer func(start time.Time) { 95 route.Metrics.EventProcessingDuration(route.EventSourceName, route.EventName, float64(time.Since(start)/time.Millisecond)) 96 }(time.Now()) 97 98 request.Body = http.MaxBytesReader(writer, request.Body, route.Context.GetMaxPayloadSize()) 99 payload, err := io.ReadAll(request.Body) 100 if err != nil { 101 logger.Errorw("error reading request body", zap.Error(err)) 102 writer.WriteHeader(http.StatusServiceUnavailable) 103 route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) 104 return 105 } 106 107 var event *stripe.Event 108 if err := json.Unmarshal(payload, &event); err != nil { 109 logger.Errorw("failed to parse request body", zap.Error(err)) 110 common.SendErrorResponse(writer, "failed to parse the event") 111 route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) 112 return 113 } 114 115 if ok := filterEvent(event, rc.stripeEventSource.EventFilter); !ok { 116 logger.Errorw("failed to pass the filters", zap.Any("event-type", event.Type), zap.Error(err)) 117 common.SendErrorResponse(writer, "invalid event") 118 route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) 119 return 120 } 121 122 eventData := &events.StripeEventData{ 123 Event: event, 124 Metadata: rc.stripeEventSource.Metadata, 125 } 126 127 data, err := json.Marshal(eventData) 128 if err != nil { 129 logger.Errorw("failed to marshal event data", zap.Any("event-id", event.ID), zap.Error(err)) 130 common.SendErrorResponse(writer, "invalid event") 131 route.Metrics.EventProcessingFailed(route.EventSourceName, route.EventName) 132 return 133 } 134 135 logger.Info("dispatching event on route's data channel...") 136 route.DataCh <- data 137 logger.Info("request successfully processed") 138 common.SendSuccessResponse(writer, "success") 139 } 140 141 // PostActivate performs operations once the route is activated and ready to consume requests 142 func (rc *Router) PostActivate() error { 143 if rc.stripeEventSource.CreateWebhook { 144 route := rc.route 145 stripeEventSource := rc.stripeEventSource 146 logger := route.Logger.With( 147 logging.LabelEndpoint, route.Context.Endpoint, 148 logging.LabelHTTPMethod, route.Context.Method, 149 ) 150 logger.Info("registering a new webhook") 151 152 apiKey, err := common.GetSecretFromVolume(stripeEventSource.APIKey) 153 if err != nil { 154 return fmt.Errorf("APIKey not found, %w", err) 155 } 156 157 stripe.Key = apiKey 158 159 params := &stripe.WebhookEndpointParams{ 160 URL: stripe.String(common.FormattedURL(stripeEventSource.Webhook.URL, stripeEventSource.Webhook.Endpoint)), 161 } 162 if stripeEventSource.EventFilter != nil { 163 params.EnabledEvents = stripe.StringSlice(stripeEventSource.EventFilter) 164 } 165 166 endpoint, err := webhookendpoint.New(params) 167 if err != nil { 168 return err 169 } 170 logger.With("endpoint-id", endpoint.ID).Info("new stripe webhook endpoint created") 171 } 172 return nil 173 } 174 175 // PostInactivate performs operations after the route is inactivated 176 func (rc *Router) PostInactivate() error { 177 return nil 178 } 179 180 func filterEvent(event *stripe.Event, filters []string) bool { 181 if filters == nil { 182 return true 183 } 184 for _, filter := range filters { 185 if event.Type == filter { 186 return true 187 } 188 } 189 return false 190 } 191 192 // StartListening starts an event source 193 func (el *EventListener) StartListening(ctx context.Context, dispatch func([]byte, ...eventsourcecommon.Option) error) error { 194 log := logging.FromContext(ctx). 195 With(logging.LabelEventSourceType, el.GetEventSourceType(), logging.LabelEventName, el.GetEventName()) 196 log.Info("started processing the Stripe event source...") 197 defer sources.Recover(el.GetEventName()) 198 199 stripeEventSource := &el.StripeEventSource 200 route := webhook.NewRoute(stripeEventSource.Webhook, log, el.GetEventSourceName(), el.GetEventName(), el.Metrics) 201 202 return webhook.ManageRoute(ctx, &Router{ 203 route: route, 204 stripeEventSource: stripeEventSource, 205 }, controller, dispatch) 206 }