func (s *Server) MatchingRoute(path string) (*Route, map[string]string) {
	if s.IgnoreTrailingSlash && path != "/" {
		path = strings.TrimRight(path, "/")
	}
	parts := strings.Split(path, "/")
	for _, route := range s.routes {
		if route.matchParts(parts) {
			parameters := route.parametersFor(parts)
			return &route, parameters
		}
	}
	return nil, nil
}
TODO this should probably be a tree structure for faster lookups
package viewproxy
import (
	"context"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
	"time"
	"github.com/blakewilliams/viewproxy/internal/tracing"
	"github.com/blakewilliams/viewproxy/pkg/fragment"
	"github.com/blakewilliams/viewproxy/pkg/multiplexer"
	"github.com/blakewilliams/viewproxy/pkg/secretfilter"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/trace"
)
const (
	HeaderViewProxyOriginalPath = "X-Viewproxy-Original-Path"
)
type ResultError = multiplexer.ResultError
type logger interface {
	Fatal(v ...interface{})
	Fatalf(format string, v ...interface{})
	Fatalln(v ...interface{})
	Panic(v ...interface{})
	Panicf(format string, v ...interface{})
	Panicln(v ...interface{})
	Print(v ...interface{})
	Printf(format string, v ...interface{})
	Println(v ...interface{})
}
type Server struct {
	Addr string
	ProxyTimeout time.Duration
	ReadTimeout time.Duration
	WriteTimeout time.Duration
	IgnoreTrailingSlash bool
	routes              []Route
	target              string
	targetURL           *url.URL
	httpServer          *http.Server
	reverseProxy        *httputil.ReverseProxy
	Logger              logger
	passThrough         bool
	SecretFilter        secretfilter.Filter
	HmacSecret string
	MultiplexerTripper multiplexer.Tripper
	AroundRequest func(http.Handler) http.Handler
	AroundResponse func(http.Handler) http.Handler
	tracingConfig  tracing.TracingConfig
}
type ServerOption = func(*Server) error
type routeContextKey struct{}
type parametersContextKey struct{}
type startTimeKey struct{}
const defaultTimeout = 10 * time.Second
func emptyMiddleware(h http.Handler) http.Handler { return h }
func NewServer(target string, opts ...ServerOption) (*Server, error) {
	targetURL, err := url.Parse(target)
	if err != nil {
		return nil, err
	}
	server := &Server{
		MultiplexerTripper:  multiplexer.NewStandardTripper(&http.Client{}),
		Logger:              log.Default(),
		SecretFilter:        secretfilter.New(),
		Addr:                "localhost:3005",
		ProxyTimeout:        defaultTimeout,
		ReadTimeout:         defaultTimeout,
		WriteTimeout:        defaultTimeout,
		passThrough:         false,
		AroundRequest:       emptyMiddleware,
		AroundResponse:      emptyMiddleware,
		IgnoreTrailingSlash: true,
		target:              target,
		targetURL:           targetURL,
		routes:              make([]Route, 0),
		tracingConfig:       tracing.TracingConfig{Enabled: false},
	}
	for _, fn := range opts {
		err := fn(server)
		if err != nil {
			return nil, fmt.Errorf("viewproxy.ServerOption error: %w", err)
		}
	}
	return server, nil
}
func WithPassThrough(passthroughTarget string) ServerOption {
	return func(server *Server) error {
		targetURL, err := url.Parse(passthroughTarget)
		if err != nil {
			return fmt.Errorf("WithPassThrough error: %w", err)
		}
		server.passThrough = true
		server.reverseProxy = httputil.NewSingleHostReverseProxy(targetURL)
		return nil
	}
}
func (s *Server) PassThroughEnabled() bool {
	return s.passThrough
}
type GetOption = func(*Route)
func WithRouteMetadata(metadata map[string]string) GetOption {
	return func(route *Route) {
		route.Metadata = metadata
	}
}
func (s *Server) Get(path string, root *fragment.Definition, opts ...GetOption) error {
	route := newRoute(path, map[string]string{}, root)
	for _, opt := range opts {
		opt(route)
	}
	err := route.Validate()
	if err != nil {
		return err
	}
	s.routes = append(s.routes, *route)
	return nil
}
func (s *Server) Target() string {
	return s.target
}
func (s *Server) Routes() []Route {
	return s.routes
}
func (s *Server) ConfigureTracing(endpoint string, serviceName string, serviceVersion string, insecure bool) {
	s.tracingConfig.Enabled = true
	s.tracingConfig.Endpoint = endpoint
	s.tracingConfig.ServiceName = serviceName
	s.tracingConfig.ServiceVersion = serviceVersion
	s.tracingConfig.Insecure = insecure
}
func (s *Server) Shutdown(ctx context.Context) error {
	return s.httpServer.Shutdown(ctx)
}
func (s *Server) Close() {
	s.httpServer.Close()
}