forked from luraproject/lura
-
Notifications
You must be signed in to change notification settings - Fork 0
/
router.go
146 lines (123 loc) · 4.11 KB
/
router.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package chi
import (
"context"
"net/http"
"strings"
"github.com/devopsfaith/krakend/config"
"github.com/devopsfaith/krakend/logging"
"github.com/devopsfaith/krakend/proxy"
"github.com/devopsfaith/krakend/router"
"github.com/devopsfaith/krakend/router/mux"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
)
// ChiDefaultDebugPattern is the default pattern used to define the debug endpoint
const ChiDefaultDebugPattern = "/__debug/"
// RunServerFunc is a func that will run the http Server with the given params.
type RunServerFunc func(context.Context, config.ServiceConfig, http.Handler) error
// Config is the struct that collects the parts the router should be builded from
type Config struct {
Engine chi.Router
Middlewares chi.Middlewares
HandlerFactory HandlerFactory
ProxyFactory proxy.Factory
Logger logging.Logger
DebugPattern string
RunServer RunServerFunc
}
// DefaultFactory returns a chi router factory with the injected proxy factory and logger.
// It also uses a default chi router and the default HandlerFactory
func DefaultFactory(proxyFactory proxy.Factory, logger logging.Logger) router.Factory {
return NewFactory(
Config{
Engine: chi.NewRouter(),
Middlewares: chi.Middlewares{middleware.Logger},
HandlerFactory: NewEndpointHandler,
ProxyFactory: proxyFactory,
Logger: logger,
DebugPattern: ChiDefaultDebugPattern,
RunServer: router.RunServer,
},
)
}
// NewFactory returns a chi router factory with the injected configuration
func NewFactory(cfg Config) router.Factory {
if cfg.DebugPattern == "" {
cfg.DebugPattern = ChiDefaultDebugPattern
}
return factory{cfg}
}
type factory struct {
cfg Config
}
// New implements the factory interface
func (rf factory) New() router.Router {
return rf.NewWithContext(context.Background())
}
// NewWithContext implements the factory interface
func (rf factory) NewWithContext(ctx context.Context) router.Router {
return chiRouter{rf.cfg, ctx, rf.cfg.RunServer}
}
type chiRouter struct {
cfg Config
ctx context.Context
RunServer RunServerFunc
}
// Run implements the router interface
func (r chiRouter) Run(cfg config.ServiceConfig) {
r.cfg.Engine.Use(r.cfg.Middlewares...)
if cfg.Debug {
r.registerDebugEndpoints()
}
router.InitHTTPDefaultTransport(cfg)
r.registerKrakendEndpoints(cfg.Endpoints)
r.cfg.Engine.NotFound(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set(router.CompleteResponseHeaderName, router.HeaderIncompleteResponseValue)
http.NotFound(w, r)
})
if err := r.RunServer(r.ctx, cfg, r.cfg.Engine); err != nil {
r.cfg.Logger.Error(err.Error())
}
r.cfg.Logger.Info("Router execution ended")
}
func (r chiRouter) registerDebugEndpoints() {
debugHandler := mux.DebugHandler(r.cfg.Logger)
r.cfg.Engine.Get(r.cfg.DebugPattern, debugHandler)
r.cfg.Engine.Post(r.cfg.DebugPattern, debugHandler)
r.cfg.Engine.Put(r.cfg.DebugPattern, debugHandler)
r.cfg.Engine.Patch(r.cfg.DebugPattern, debugHandler)
r.cfg.Engine.Delete(r.cfg.DebugPattern, debugHandler)
}
func (r chiRouter) registerKrakendEndpoints(endpoints []*config.EndpointConfig) {
for _, c := range endpoints {
proxyStack, err := r.cfg.ProxyFactory.New(c)
if err != nil {
r.cfg.Logger.Error("calling the ProxyFactory", err.Error())
continue
}
r.registerKrakendEndpoint(c.Method, c.Endpoint, r.cfg.HandlerFactory(c, proxyStack), len(c.Backend))
}
}
func (r chiRouter) registerKrakendEndpoint(method, path string, handler http.HandlerFunc, totBackends int) {
method = strings.ToTitle(method)
if method != http.MethodGet && totBackends > 1 {
r.cfg.Logger.Error(method, "endpoints must have a single backend! Ignoring", path)
return
}
switch method {
case http.MethodGet:
r.cfg.Engine.Get(path, handler)
case http.MethodPost:
r.cfg.Engine.Post(path, handler)
case http.MethodPut:
r.cfg.Engine.Put(path, handler)
case http.MethodPatch:
r.cfg.Engine.Patch(path, handler)
case http.MethodDelete:
r.cfg.Engine.Delete(path, handler)
default:
r.cfg.Logger.Error("Unsupported method", method)
return
}
r.cfg.Logger.Debug("registering the endpoint", method, path)
}