-
Notifications
You must be signed in to change notification settings - Fork 2
/
router.go
134 lines (121 loc) · 3.41 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
package router
import (
"fmt"
"net/http"
"path"
)
const (
// ErrNotFound is not found error.
ErrNotFound = "not found page"
// ErrMethodUnsupported is method upsupported error.
ErrMethodUnsupported = "http method unsupported"
// RouterKey is route key format.
RouterKey = "%s-%s"
)
type (
// Router is a http.Handler. store all routes.
Router struct {
// store parent all HandlerFunc.
globalHandlers []HandlerFunc
// store parent path.
basePath string
// store all routes.
routers map[string]*route
}
// route is storage http method and handle function.
route struct {
// http method.
method string
// handle function.
handlers []HandlerFunc
}
// Context is storage request response information.
Context struct {
Request *http.Request
Writer http.ResponseWriter
// handle function.
handlers []HandlerFunc
// The current handle function index is executed.
index int8
}
// HandlerFunc is a function that can be registered to a route to handle HTTP requests.
HandlerFunc func(*Context)
)
// New is returns an initialized Router.
func New() *Router {
return &Router{
routers: make(map[string]*route),
basePath: "/",
}
}
// Use is add global handle function.
func (r *Router) Use(handlers ...HandlerFunc) {
r.globalHandlers = append(r.globalHandlers, handlers...)
}
// Group is add route group.
func (r *Router) Group(partPath string, fn func(), handlers ...HandlerFunc) {
rootBasePath := r.basePath
rootHandlers := r.globalHandlers
r.basePath = path.Join(r.basePath, partPath)
r.globalHandlers = r.combineHandlers(handlers)
fn()
r.basePath = rootBasePath
r.globalHandlers = rootHandlers
}
// GET is register GET method HandlerFunc to Router.
func (r *Router) GET(partPath string, handlers ...HandlerFunc) {
path := path.Join(r.basePath, partPath)
handlers = r.combineHandlers(handlers)
r.addRoute(http.MethodGet, path, handlers)
}
// POST is register POST method HandlerFunc to Router.
func (r *Router) POST(partPath string, handlers ...HandlerFunc) {
path := path.Join(r.basePath, partPath)
handlers = r.combineHandlers(handlers)
r.addRoute(http.MethodPost, path, handlers)
}
// Run listens on the TCP network address addr.
func (r *Router) Run(addr string) error {
return http.ListenAndServe(addr, r)
}
// combineHandlers is merge multiple HnalderFunc slice into one HandlerFunc slice.
func (r *Router) combineHandlers(handlers []HandlerFunc) []HandlerFunc {
finallyLen := len(r.globalHandlers) + len(handlers)
finallyHandlers := make([]HandlerFunc, finallyLen)
copy(finallyHandlers, r.globalHandlers)
copy(finallyHandlers[len(r.globalHandlers):], handlers)
return finallyHandlers
}
// addRoute is add to routes.
func (r *Router) addRoute(method, path string, handlers []HandlerFunc) {
route := &route{
method: method,
handlers: handlers,
}
r.routers[fmt.Sprintf(RouterKey, path, method)] = route
}
// ServeHTTP is implement the http.Handler interface.
func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
httpMethod := req.Method
path := req.URL.Path
route, ok := r.routers[fmt.Sprintf(RouterKey, path, httpMethod)]
if !ok {
w.WriteHeader(http.StatusNotFound)
fmt.Fprintf(w, ErrNotFound)
return
}
c := &Context{
Request: req,
Writer: w,
handlers: route.handlers,
index: -1,
}
c.Next()
}
// Next is call the next handler function.
func (c *Context) Next() {
c.index++
if n := int8(len(c.handlers)); c.index < n {
c.handlers[c.index](c)
}
}