github.com/hellofresh/janus@v0.0.0-20230925145208-ce8de8183c67/pkg/proxy/register.go (about)

     1  package proxy
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/hellofresh/stats-go/client"
    10  	log "github.com/sirupsen/logrus"
    11  	"go.opencensus.io/plugin/ochttp"
    12  
    13  	"github.com/hellofresh/janus/pkg/proxy/balancer"
    14  	"github.com/hellofresh/janus/pkg/proxy/transport"
    15  	"github.com/hellofresh/janus/pkg/router"
    16  )
    17  
    18  const (
    19  	methodAll = "ALL"
    20  )
    21  
    22  // Register handles the register of proxies into the chosen router.
    23  // It also handles the conversion from a proxy to an http.HandlerFunc
    24  type Register struct {
    25  	router                 router.Router
    26  	idleConnectionsPerHost int
    27  	idleConnTimeout        time.Duration
    28  	idleConnPurgeTicker    *time.Ticker
    29  	flushInterval          time.Duration
    30  	statsClient            client.Client
    31  	matcher                *router.ListenPathMatcher
    32  	isPublicEndpoint       bool
    33  }
    34  
    35  // NewRegister creates a new instance of Register
    36  func NewRegister(opts ...RegisterOption) *Register {
    37  	r := Register{
    38  		matcher: router.NewListenPathMatcher(),
    39  	}
    40  
    41  	for _, opt := range opts {
    42  		opt(&r)
    43  	}
    44  
    45  	return &r
    46  }
    47  
    48  // UpdateRouter updates the reference to the router. This is useful to reload the mux
    49  func (p *Register) UpdateRouter(router router.Router) {
    50  	p.router = router
    51  }
    52  
    53  // Add register a new route
    54  func (p *Register) Add(definition *RouterDefinition) error {
    55  	log.WithField("balancing_alg", definition.Upstreams.Balancing).Debug("Using a load balancing algorithm")
    56  	balancerInstance, err := balancer.New(definition.Upstreams.Balancing)
    57  	if err != nil {
    58  		log.WithError(err).Error("Could not create a balancer")
    59  		return fmt.Errorf("could not create a balancer: %w", err)
    60  	}
    61  
    62  	handler := NewBalancedReverseProxy(definition.Definition, balancerInstance, p.statsClient)
    63  	handler.FlushInterval = p.flushInterval
    64  	handler.Transport = &ochttp.Transport{
    65  		Base: transport.New(
    66  			transport.WithIdleConnTimeout(p.idleConnTimeout),
    67  			transport.WithIdleConnPurgeTicker(p.idleConnPurgeTicker),
    68  			transport.WithInsecureSkipVerify(definition.InsecureSkipVerify),
    69  			transport.WithDialTimeout(time.Duration(definition.ForwardingTimeouts.DialTimeout)),
    70  			transport.WithResponseHeaderTimeout(time.Duration(definition.ForwardingTimeouts.ResponseHeaderTimeout)),
    71  		),
    72  	}
    73  
    74  	if p.matcher.Match(definition.ListenPath) {
    75  		p.doRegister(p.matcher.Extract(definition.ListenPath), definition, &ochttp.Handler{Handler: handler, IsPublicEndpoint: p.isPublicEndpoint})
    76  	}
    77  
    78  	p.doRegister(definition.ListenPath, definition, &ochttp.Handler{Handler: handler, IsPublicEndpoint: p.isPublicEndpoint})
    79  	return nil
    80  }
    81  
    82  func (p *Register) doRegister(listenPath string, def *RouterDefinition, handler http.Handler) {
    83  	log.WithFields(log.Fields{
    84  		"listen_path": listenPath,
    85  	}).Debug("Registering a route")
    86  
    87  	if strings.Index(listenPath, "/") != 0 {
    88  		log.WithField("listen_path", listenPath).
    89  			Error("Route listen path must begin with '/'. Skipping invalid route.")
    90  	} else {
    91  		for _, method := range def.Methods {
    92  			if strings.ToUpper(method) == methodAll {
    93  				p.router.Any(listenPath, handler.ServeHTTP, def.middleware...)
    94  			} else {
    95  				p.router.Handle(strings.ToUpper(method), listenPath, handler.ServeHTTP, def.middleware...)
    96  			}
    97  		}
    98  	}
    99  }