6c8a7f13 by astaxie

beego: router change to method Tree

1 parent e00eab7f
...@@ -35,9 +35,16 @@ const ( ...@@ -35,9 +35,16 @@ const (
35 var ( 35 var (
36 // custom error when user stop request handler manually. 36 // custom error when user stop request handler manually.
37 USERSTOPRUN = errors.New("User stop run") 37 USERSTOPRUN = errors.New("User stop run")
38 GlobalControllerRouter map[string]map[string]*Tree //pkgpath+controller:method:routertree 38 GlobalControllerRouter map[string]*ControllerComments //pkgpath+controller:comments
39 ) 39 )
40 40
41 // store the comment for the controller method
42 type ControllerComments struct {
43 method string
44 router string
45 allowHTTPMethods []string
46 }
47
41 // Controller defines some basic http request handler operations, such as 48 // Controller defines some basic http request handler operations, such as
42 // http context, template and view, session and xsrf. 49 // http context, template and view, session and xsrf.
43 type Controller struct { 50 type Controller struct {
...@@ -56,7 +63,7 @@ type Controller struct { ...@@ -56,7 +63,7 @@ type Controller struct {
56 AppController interface{} 63 AppController interface{}
57 EnableRender bool 64 EnableRender bool
58 EnableXSRF bool 65 EnableXSRF bool
59 Routers map[string]*Tree //method:routertree 66 methodMapping map[string]func() //method:routertree
60 } 67 }
61 68
62 // ControllerInterface is an interface to uniform all controller handler. 69 // ControllerInterface is an interface to uniform all controller handler.
...@@ -74,7 +81,7 @@ type ControllerInterface interface { ...@@ -74,7 +81,7 @@ type ControllerInterface interface {
74 Render() error 81 Render() error
75 XsrfToken() string 82 XsrfToken() string
76 CheckXsrfCookie() bool 83 CheckXsrfCookie() bool
77 HandlerFunc(fn interface{}) 84 HandlerFunc(fn string)
78 URLMapping() 85 URLMapping()
79 } 86 }
80 87
...@@ -90,7 +97,7 @@ func (c *Controller) Init(ctx *context.Context, controllerName, actionName strin ...@@ -90,7 +97,7 @@ func (c *Controller) Init(ctx *context.Context, controllerName, actionName strin
90 c.EnableRender = true 97 c.EnableRender = true
91 c.EnableXSRF = true 98 c.EnableXSRF = true
92 c.Data = ctx.Input.Data 99 c.Data = ctx.Input.Data
93 c.Routers = make(map[string]*Tree) 100 c.methodMapping = make(map[string]func())
94 } 101 }
95 102
96 // Prepare runs after Init before request function execution. 103 // Prepare runs after Init before request function execution.
...@@ -139,9 +146,11 @@ func (c *Controller) Options() { ...@@ -139,9 +146,11 @@ func (c *Controller) Options() {
139 } 146 }
140 147
141 // call function fn 148 // call function fn
142 func (c *Controller) HandlerFunc(fn interface{}) { 149 func (c *Controller) HandlerFunc(fnname string) {
143 if v, ok := fn.(func()); ok { 150 if v, ok := c.methodMapping[fnname]; ok {
144 v() 151 v()
152 } else {
153 Error("call funcname not exist in the methodMapping: " + fnname)
145 } 154 }
146 } 155 }
147 156
...@@ -149,19 +158,8 @@ func (c *Controller) HandlerFunc(fn interface{}) { ...@@ -149,19 +158,8 @@ func (c *Controller) HandlerFunc(fn interface{}) {
149 func (c *Controller) URLMapping() { 158 func (c *Controller) URLMapping() {
150 } 159 }
151 160
152 func (c *Controller) Mapping(method, pattern string, fn func()) { 161 func (c *Controller) Mapping(method string, fn func()) {
153 method = strings.ToLower(method) 162 c.methodMapping[method] = fn
154 if !utils.InSlice(method, HTTPMETHOD) && method != "*" {
155 Critical("add mapping method:" + method + " is a valid method")
156 return
157 }
158 if t, ok := c.Routers[method]; ok {
159 t.AddRouter(pattern, fn)
160 } else {
161 t = NewTree()
162 t.AddRouter(pattern, fn)
163 c.Routers[method] = t
164 }
165 } 163 }
166 164
167 // Render sends the response with rendered template bytes as text/html type. 165 // Render sends the response with rendered template bytes as text/html type.
......
...@@ -182,7 +182,15 @@ func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace { ...@@ -182,7 +182,15 @@ func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace {
182 //) 182 //)
183 func (n *Namespace) Namespace(ns ...*Namespace) *Namespace { 183 func (n *Namespace) Namespace(ns ...*Namespace) *Namespace {
184 for _, ni := range ns { 184 for _, ni := range ns {
185 n.handlers.routers.AddTree(ni.prefix, ni.handlers.routers) 185 for k, v := range ni.handlers.routers {
186 if t, ok := n.handlers.routers[k]; ok {
187 n.handlers.routers[k].AddTree(ni.prefix, v)
188 } else {
189 t = NewTree()
190 t.AddTree(ni.prefix, v)
191 n.handlers.routers[k] = t
192 }
193 }
186 if n.handlers.enableFilter { 194 if n.handlers.enableFilter {
187 for pos, filterList := range ni.handlers.filters { 195 for pos, filterList := range ni.handlers.filters {
188 for _, mr := range filterList { 196 for _, mr := range filterList {
...@@ -201,7 +209,15 @@ func (n *Namespace) Namespace(ns ...*Namespace) *Namespace { ...@@ -201,7 +209,15 @@ func (n *Namespace) Namespace(ns ...*Namespace) *Namespace {
201 // support multi Namespace 209 // support multi Namespace
202 func AddNamespace(nl ...*Namespace) { 210 func AddNamespace(nl ...*Namespace) {
203 for _, n := range nl { 211 for _, n := range nl {
204 BeeApp.Handlers.routers.AddTree(n.prefix, n.handlers.routers) 212 for k, v := range n.handlers.routers {
213 if t, ok := BeeApp.Handlers.routers[k]; ok {
214 BeeApp.Handlers.routers[k].AddTree(n.prefix, v)
215 } else {
216 t = NewTree()
217 t.AddTree(n.prefix, v)
218 BeeApp.Handlers.routers[k] = t
219 }
220 }
205 if n.handlers.enableFilter { 221 if n.handlers.enableFilter {
206 for pos, filterList := range n.handlers.filters { 222 for pos, filterList := range n.handlers.filters {
207 for _, mr := range filterList { 223 for _, mr := range filterList {
......
...@@ -4,3 +4,43 @@ ...@@ -4,3 +4,43 @@
4 // @license http://github.com/astaxie/beego/blob/master/LICENSE 4 // @license http://github.com/astaxie/beego/blob/master/LICENSE
5 // @authors astaxie 5 // @authors astaxie
6 package beego 6 package beego
7
8 import (
9 "os"
10 "path/filepath"
11 )
12
13 var globalControllerRouter = `package routers
14
15 import (
16 "github.com/astaxie/beego"
17 )
18
19 func init() {
20 {{.globalinfo}}
21 }
22 `
23
24 func parserPkg(pkgpath string) error {
25 err := filepath.Walk(pkgpath, func(path string, info os.FileInfo, err error) error {
26 if err != nil {
27 Error("error scan app Controller source:", err)
28 return err
29 }
30 //if is normal file or name is temp skip
31 //directory is needed
32 if !info.IsDir() || info.Name() == "tmp" {
33 return nil
34 }
35
36 //fileSet := token.NewFileSet()
37 //astPkgs, err := parser.ParseDir(fileSet, path, func(info os.FileInfo) bool {
38 // name := info.Name()
39 // return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
40 //}, parser.ParseComments)
41
42 return nil
43 })
44
45 return err
46 }
......
...@@ -12,7 +12,9 @@ import ( ...@@ -12,7 +12,9 @@ import (
12 "fmt" 12 "fmt"
13 "net" 13 "net"
14 "net/http" 14 "net/http"
15 "os"
15 "path" 16 "path"
17 "path/filepath"
16 "reflect" 18 "reflect"
17 "runtime" 19 "runtime"
18 "strconv" 20 "strconv"
...@@ -67,7 +69,7 @@ type controllerInfo struct { ...@@ -67,7 +69,7 @@ type controllerInfo struct {
67 69
68 // ControllerRegistor containers registered router rules, controller handlers and filters. 70 // ControllerRegistor containers registered router rules, controller handlers and filters.
69 type ControllerRegistor struct { 71 type ControllerRegistor struct {
70 routers *Tree 72 routers map[string]*Tree
71 enableFilter bool 73 enableFilter bool
72 filters map[int][]*FilterRouter 74 filters map[int][]*FilterRouter
73 } 75 }
...@@ -75,7 +77,7 @@ type ControllerRegistor struct { ...@@ -75,7 +77,7 @@ type ControllerRegistor struct {
75 // NewControllerRegistor returns a new ControllerRegistor. 77 // NewControllerRegistor returns a new ControllerRegistor.
76 func NewControllerRegistor() *ControllerRegistor { 78 func NewControllerRegistor() *ControllerRegistor {
77 return &ControllerRegistor{ 79 return &ControllerRegistor{
78 routers: NewTree(), 80 routers: make(map[string]*Tree),
79 filters: make(map[int][]*FilterRouter), 81 filters: make(map[int][]*FilterRouter),
80 } 82 }
81 } 83 }
...@@ -120,17 +122,69 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM ...@@ -120,17 +122,69 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
120 route.methods = methods 122 route.methods = methods
121 route.routerType = routerTypeBeego 123 route.routerType = routerTypeBeego
122 route.controllerType = t 124 route.controllerType = t
123 p.routers.AddRouter(pattern, route) 125 if len(methods) == 0 {
126 for _, m := range HTTPMETHOD {
127 p.addToRouter(m, pattern, route)
128 }
129 } else {
130 for k, _ := range methods {
131 if k == "*" {
132 for _, m := range HTTPMETHOD {
133 p.addToRouter(m, pattern, route)
134 }
135 } else {
136 p.addToRouter(k, pattern, route)
137 }
138 }
139 }
140 }
141
142 func (p *ControllerRegistor) addToRouter(method, pattern string, r *controllerInfo) {
143 if t, ok := p.routers[method]; ok {
144 t.AddRouter(pattern, r)
145 } else {
146 t := NewTree()
147 t.AddRouter(pattern, r)
148 p.routers[method] = t
149 }
124 } 150 }
125 151
126 // only when the Runmode is dev will generate router file in the router/auto.go from the controller 152 // only when the Runmode is dev will generate router file in the router/auto.go from the controller
127 // Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{}) 153 // Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
128 func (p *ControllerRegistor) Include(cList ...ControllerInterface) { 154 func (p *ControllerRegistor) Include(cList ...ControllerInterface) {
129 if RunMode == "dev" { 155 if RunMode == "dev" {
156 skip := make(map[string]bool, 10)
130 for _, c := range cList { 157 for _, c := range cList {
131 reflectVal := reflect.ValueOf(c) 158 reflectVal := reflect.ValueOf(c)
132 t := reflect.Indirect(reflectVal).Type() 159 t := reflect.Indirect(reflectVal).Type()
133 t.PkgPath() 160 gopath := os.Getenv("GOPATH")
161 if gopath == "" {
162 panic("you are in dev mode. So please set gopath")
163 }
164 pkgpath := ""
165
166 wgopath := filepath.SplitList(gopath)
167 for _, wg := range wgopath {
168 wg, _ = filepath.EvalSymlinks(filepath.Join(wg, "src", t.PkgPath()))
169 if utils.FileExists(wg) {
170 pkgpath = wg
171 break
172 }
173 }
174 if pkgpath != "" {
175 if _, ok := skip[pkgpath]; !ok {
176 skip[pkgpath] = true
177 parserPkg(pkgpath)
178 }
179 }
180 }
181 }
182 for _, c := range cList {
183 reflectVal := reflect.ValueOf(c)
184 t := reflect.Indirect(reflectVal).Type()
185 key := t.PkgPath() + ":" + t.Name()
186 if comm, ok := GlobalControllerRouter[key]; ok {
187 p.Add(comm.router, c, strings.Join(comm.allowHTTPMethods, ",")+":"+comm.method)
134 } 188 }
135 } 189 }
136 } 190 }
...@@ -228,7 +282,15 @@ func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) { ...@@ -228,7 +282,15 @@ func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
228 methods[method] = method 282 methods[method] = method
229 } 283 }
230 route.methods = methods 284 route.methods = methods
231 p.routers.AddRouter(pattern, route) 285 for k, _ := range methods {
286 if k == "*" {
287 for _, m := range HTTPMETHOD {
288 p.addToRouter(m, pattern, route)
289 }
290 } else {
291 p.addToRouter(k, pattern, route)
292 }
293 }
232 } 294 }
233 295
234 // add user defined Handler 296 // add user defined Handler
...@@ -241,7 +303,9 @@ func (p *ControllerRegistor) Handler(pattern string, h http.Handler, options ... ...@@ -241,7 +303,9 @@ func (p *ControllerRegistor) Handler(pattern string, h http.Handler, options ...
241 pattern = path.Join(pattern, "?:all") 303 pattern = path.Join(pattern, "?:all")
242 } 304 }
243 } 305 }
244 p.routers.AddRouter(pattern, route) 306 for _, m := range HTTPMETHOD {
307 p.addToRouter(m, pattern, route)
308 }
245 } 309 }
246 310
247 // Add auto router to ControllerRegistor. 311 // Add auto router to ControllerRegistor.
...@@ -270,7 +334,9 @@ func (p *ControllerRegistor) AddAutoPrefix(prefix string, c ControllerInterface) ...@@ -270,7 +334,9 @@ func (p *ControllerRegistor) AddAutoPrefix(prefix string, c ControllerInterface)
270 route.methods = map[string]string{"*": rt.Method(i).Name} 334 route.methods = map[string]string{"*": rt.Method(i).Name}
271 route.controllerType = ct 335 route.controllerType = ct
272 pattern := path.Join(prefix, controllerName, strings.ToLower(rt.Method(i).Name), "*") 336 pattern := path.Join(prefix, controllerName, strings.ToLower(rt.Method(i).Name), "*")
273 p.routers.AddRouter(pattern, route) 337 for _, m := range HTTPMETHOD {
338 p.addToRouter(m, pattern, route)
339 }
274 } 340 }
275 } 341 }
276 } 342 }
...@@ -317,12 +383,13 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { ...@@ -317,12 +383,13 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string {
317 } 383 }
318 controllName := strings.Join(paths[:len(paths)-1], ".") 384 controllName := strings.Join(paths[:len(paths)-1], ".")
319 methodName := paths[len(paths)-1] 385 methodName := paths[len(paths)-1]
320 ok, url := p.geturl(p.routers, "/", controllName, methodName, params) 386 for _, t := range p.routers {
321 if ok { 387 ok, url := p.geturl(t, "/", controllName, methodName, params)
322 return url 388 if ok {
323 } else { 389 return url
324 return "" 390 }
325 } 391 }
392 return ""
326 } 393 }
327 394
328 func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName string, params map[string]string) (bool, string) { 395 func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName string, params map[string]string) (bool, string) {
...@@ -436,6 +503,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -436,6 +503,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
436 503
437 starttime := time.Now() 504 starttime := time.Now()
438 requestPath := r.URL.Path 505 requestPath := r.URL.Path
506 method := strings.ToLower(r.Method)
439 var runrouter reflect.Type 507 var runrouter reflect.Type
440 var findrouter bool 508 var findrouter bool
441 var runMethod string 509 var runMethod string
...@@ -485,7 +553,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -485,7 +553,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
485 }() 553 }()
486 } 554 }
487 555
488 if !utils.InSlice(strings.ToLower(r.Method), HTTPMETHOD) { 556 if !utils.InSlice(method, HTTPMETHOD) {
489 http.Error(w, "Method Not Allowed", 405) 557 http.Error(w, "Method Not Allowed", 405)
490 goto Admin 558 goto Admin
491 } 559 }
...@@ -512,18 +580,21 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -512,18 +580,21 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
512 } 580 }
513 581
514 if !findrouter { 582 if !findrouter {
515 runObject, p := p.routers.Match(requestPath) 583 if t, ok := p.routers[method]; ok {
516 if r, ok := runObject.(*controllerInfo); ok { 584 runObject, p := t.Match(requestPath)
517 routerInfo = r 585 if r, ok := runObject.(*controllerInfo); ok {
518 findrouter = true 586 routerInfo = r
519 if splat, ok := p[":splat"]; ok { 587 findrouter = true
520 splatlist := strings.Split(splat, "/") 588 if splat, ok := p[":splat"]; ok {
521 for k, v := range splatlist { 589 splatlist := strings.Split(splat, "/")
522 p[strconv.Itoa(k)] = v 590 for k, v := range splatlist {
591 p[strconv.Itoa(k)] = v
592 }
523 } 593 }
594 context.Input.Params = p
524 } 595 }
525 context.Input.Params = p
526 } 596 }
597
527 } 598 }
528 599
529 //if no matches to url, throw a not found exception 600 //if no matches to url, throw a not found exception
......
...@@ -291,6 +291,17 @@ func (a *AdminController) Get() { ...@@ -291,6 +291,17 @@ func (a *AdminController) Get() {
291 a.Ctx.WriteString("hello") 291 a.Ctx.WriteString("hello")
292 } 292 }
293 293
294 func TestRouterFunc(t *testing.T) {
295 mux := NewControllerRegistor()
296 mux.Get("/action", beegoFilterFunc)
297 mux.Post("/action", beegoFilterFunc)
298 rw, r := testRequest("GET", "/action")
299 mux.ServeHTTP(rw, r)
300 if rw.Body.String() != "hello" {
301 t.Errorf("TestRouterFunc can't run")
302 }
303 }
304
294 func BenchmarkFunc(b *testing.B) { 305 func BenchmarkFunc(b *testing.B) {
295 mux := NewControllerRegistor() 306 mux := NewControllerRegistor()
296 mux.Get("/action", beegoFilterFunc) 307 mux.Get("/action", beegoFilterFunc)
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!