This repository has been archived by the owner on Oct 12, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenlight.go
273 lines (233 loc) · 7.29 KB
/
enlight.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
package enlight
import (
"fmt"
"io"
"net/url"
"path"
"path/filepath"
"sync"
"github.com/valyala/fasthttp"
)
// Enlight is a http.Handler which can be
// used to dispatch requests to different handler
// functions via configurable routes
type Enlight struct {
common
Debug bool
Router *Router
Server *fasthttp.Server
TLSServer *fasthttp.Server
premiddleware []MiddlewareFunc
aftermiddleware []MiddlewareFunc
middleware []MiddlewareFunc
HTTPErrorHandler HTTPErrorHandler
pool sync.Pool
Renderer Renderer
}
// Common struct for Echo & Group.
type common struct{}
// Renderer is the interface that wraps the Render function.
type Renderer interface {
Render(io.Writer, string, interface{}, Context) error
}
// Map defines a generic map of type `map[string]interface{}`.
type Map map[string]interface{}
// New returns a new initialized Enlight instance
func New() (e *Enlight) {
e = &Enlight{
Server: new(fasthttp.Server),
TLSServer: new(fasthttp.Server),
Router: NewRouter(),
HTTPErrorHandler: e.DefaultHTTPErrorHandler,
Debug: false,
}
e.Server.Handler = e.ServeHTTP
e.pool.New = func() interface{} {
return e.NewContext()
}
return
}
// NewContext returns a Context instance.
func (e *Enlight) NewContext() Context {
return &context{
enlight: e,
handler: NotFoundHandler,
}
}
// Before adds middleware to the chain which is run before router.
func (e *Enlight) Before(middleware ...MiddlewareFunc) {
e.premiddleware = append(e.premiddleware, middleware...)
}
// After adds middleware to the chain which is run after router.
func (e *Enlight) After(middleware ...MiddlewareFunc) {
e.aftermiddleware = append(e.aftermiddleware, middleware...)
}
// Use adds middleware to the chain which is run after router
func (e *Enlight) Use(middleware ...MiddlewareFunc) {
e.middleware = append(e.middleware, middleware...)
}
// CONNECT registers a new CONNECT route for a path with matching handler
func (e *Enlight) CONNECT(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodConnect, path, handle, m...)
}
// DELETE registers a new DELETE route for a path with matching handler
func (e *Enlight) DELETE(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodDelete, path, handle, m...)
}
// GET registers a new GET route for a path withh matching handler
func (e *Enlight) GET(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodGet, path, handle, m...)
}
// HEAD registers a new HEAD route for a path withh matching handler
func (e *Enlight) HEAD(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodHead, path, handle, m...)
}
// OPTIONS registers a new OPTIONS route for a path withh matching handler
func (e *Enlight) OPTIONS(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodOptions, path, handle, m...)
}
// PATCH registers a new PATCH route for a path with matching handler
func (e *Enlight) PATCH(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodPatch, path, handle, m...)
}
// POST registers a new POST route for a path with matching handler
func (e *Enlight) POST(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodPost, path, handle, m...)
}
// PUT registers a new PUT route for a path with matching handler
func (e *Enlight) PUT(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodPut, path, handle, m...)
}
// TRACE registers a new TRACE route for a path with matching handler
func (e *Enlight) TRACE(path string, handle HandleFunc, m ...MiddlewareFunc) {
e.Add(fasthttp.MethodTrace, path, handle, m...)
}
var (
methods = [...]string{
fasthttp.MethodConnect,
fasthttp.MethodDelete,
fasthttp.MethodGet,
fasthttp.MethodHead,
fasthttp.MethodOptions,
fasthttp.MethodPatch,
fasthttp.MethodPost,
PROPFIND,
fasthttp.MethodPut,
fasthttp.MethodTrace,
REPORT,
}
)
// Any registers a new route for all HTTP methods and path with matching handler
func (e *Enlight) Any(path string, handle HandleFunc, middleware ...MiddlewareFunc) {
for _, m := range methods {
e.Add(m, path, handle, middleware...)
}
}
// Match registers a new route for all given HTTP methods and path with matching handler
func (e *Enlight) Match(methods []string, path string, handle HandleFunc, middleware ...MiddlewareFunc) {
for _, m := range methods {
e.Add(m, path, handle, middleware...)
}
}
// Drop removes a route from router-tree
func (e *Enlight) Drop(method, path string) {
e.Router.Drop(method, path)
}
// Static serves static files
func (e *Enlight) Static(prefix, root string) {
if root == "" {
root = "."
}
e.static(prefix, root, e.GET)
}
// Add registers a new route for an HTTP method and path with matching handler
// in the router with optional route-level middleware.
func (e *Enlight) Add(method, path string, handle HandleFunc, middleware ...MiddlewareFunc) {
e.add(method, path, handle, middleware...)
}
func (e *Enlight) add(method, path string, handle HandleFunc, middleware ...MiddlewareFunc) {
e.Router.Handle(method, path, func(c Context) error {
h := handle
// Chain middleware
for i := len(middleware) - 1; i >= 0; i-- {
h = middleware[i](h)
}
return h(c)
}, false)
}
func (common) static(prefix, root string, get func(string, HandleFunc, ...MiddlewareFunc)) {
h := func(c Context) error {
p, err := url.PathUnescape(c.Param("filepath"))
if err != nil {
return err
}
name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
return c.File(name)
}
if prefix == "/" {
get(prefix+"*filepath", h)
return
}
get(prefix+"/*filepath", h)
return
}
// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
//func (e *Enlight) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (e *Enlight) ServeHTTP(ctx *fasthttp.RequestCtx) {
// Acquire context
c := e.pool.Get().(*context)
c.Reset(ctx)
h := NotFoundHandler
if e.premiddleware == nil {
e.Router.Find(c)
h = c.Handler()
h = applyMiddleware(h, e.middleware...)
} else {
h = func(c Context) error {
e.Router.Find(c)
h := c.Handler()
h = applyMiddleware(h, e.middleware...)
return h(c)
}
h = applyMiddleware(h, e.premiddleware...)
}
if err := h(c); err != nil {
fmt.Println(err)
e.HTTPErrorHandler(err, c)
}
// the last handleFunc is usually returning nil
//
if e.aftermiddleware != nil {
after := func(c Context) error {
// middlewares are calling next(c)
// it's not always clear if it's the last in chain
return nil
}
after = applyMiddleware(after, e.aftermiddleware...)
if err := after(c); err != nil {
fmt.Println(err)
e.HTTPErrorHandler(err, c)
}
}
// Clearing ref to fasthttp
c.RequestCtx = nil
e.pool.Put(c)
}
// Start starts an HTTP server.
func (e *Enlight) Start(address string) error {
return e.StartServer(address)
}
// StartServer starts a custom http server.
func (e *Enlight) StartServer(address string) (err error) {
e.Server = &fasthttp.Server{
Name: "Enlight",
Handler: e.ServeHTTP,
}
fmt.Printf("⇨ http server started on %s\n", address)
return e.Server.ListenAndServe(address)
}
// Shutdown stops the server gracefully.
func (e *Enlight) Shutdown() error {
fmt.Print("⇨ Server is shutting down...")
return e.Server.Shutdown()
}