forked from NETCRACKER-P2P-Streaming/krakend
-
Notifications
You must be signed in to change notification settings - Fork 0
/
router.go
151 lines (127 loc) · 4.31 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
147
148
149
150
151
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()
}
r.cfg.Engine.Get("/__health", mux.HealthHandler)
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, r.cfg.HandlerFactory(c, proxyStack), len(c.Backend))
}
}
func (r chiRouter) registerKrakendEndpoint(method string, endpoint *config.EndpointConfig, handler http.HandlerFunc, totBackends int) {
method = strings.ToTitle(method)
path := endpoint.Endpoint
if method != http.MethodGet && totBackends > 1 {
if !router.IsValidSequentialEndpoint(endpoint) {
r.cfg.Logger.Error(method, " endpoints with sequential enabled is only the last one is allowed to be non GET! 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)
}