You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

router.go 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /* ----------------------------------------------------------------------
  2. * ______ ___ __
  3. * / ____/___ / | ____ __ ___ __/ /_ ___ ________
  4. * / / __/ __ \/ /| | / __ \/ / / / | /| / / __ \/ _ \/ ___/ _ \
  5. * / /_/ / /_/ / ___ |/ / / / /_/ /| |/ |/ / / / / __/ / / __/
  6. * \____/\____/_/ |_/_/ /_/\__. / |__/|__/_/ /_/\___/_/ \___/
  7. * /____/
  8. *
  9. * (C) Copyright 2015 GoAnywhere (http://goanywhere.io).
  10. * ----------------------------------------------------------------------
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. * ----------------------------------------------------------------------*/
  23. package rex
  24. import (
  25. "fmt"
  26. "net/http"
  27. "path/filepath"
  28. "reflect"
  29. "runtime"
  30. "time"
  31. "github.com/goanywhere/rex/internal"
  32. "github.com/gorilla/mux"
  33. )
  34. type Router struct {
  35. mod *internal.Module
  36. mux *mux.Router
  37. ready bool
  38. subrouters []*Router
  39. }
  40. func New() *Router {
  41. return &Router{
  42. mod: new(internal.Module),
  43. mux: mux.NewRouter().StrictSlash(true),
  44. }
  45. }
  46. // build constructs all router/subrouters along with their middleware modules chain.
  47. func (self *Router) build() http.Handler {
  48. if !self.ready {
  49. self.ready = true
  50. // * activate router's middleware modules.
  51. self.mod.Use(self.mux)
  52. // * activate subrouters's middleware modules.
  53. for index := 0; index < len(self.subrouters); index++ {
  54. sr := self.subrouters[index]
  55. sr.mod.Use(sr.mux)
  56. }
  57. }
  58. return self.mod
  59. }
  60. // register adds the http.Handler/http.HandleFunc into Gorilla mux.
  61. func (self *Router) register(method string, pattern string, handler interface{}) {
  62. // finds the full function name (with package) as its mappings.
  63. var name = runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name()
  64. switch H := handler.(type) {
  65. case http.Handler:
  66. self.mux.Handle(pattern, H).Methods(method).Name(name)
  67. case func(http.ResponseWriter, *http.Request):
  68. self.mux.HandleFunc(pattern, H).Methods(method).Name(name)
  69. default:
  70. Fatalf("Unsupported handler (%s) passed in.", name)
  71. }
  72. }
  73. // Get is a shortcut for mux.HandleFunc(pattern, handler).Methods("GET"),
  74. // it also fetch the full function name of the handler (with package) to name the route.
  75. func (self *Router) Get(pattern string, handler interface{}) {
  76. self.register("GET", pattern, handler)
  77. }
  78. // Head is a shortcut for mux.HandleFunc(pattern, handler).Methods("HEAD")
  79. // it also fetch the full function name of the handler (with package) to name the route.
  80. func (self *Router) Head(pattern string, handler interface{}) {
  81. self.register("HEAD", pattern, handler)
  82. }
  83. // Options is a shortcut for mux.HandleFunc(pattern, handler).Methods("OPTIONS")
  84. // it also fetch the full function name of the handler (with package) to name the route.
  85. // NOTE method OPTIONS is **NOT** cachable, beware of what you are going to do.
  86. func (self *Router) Options(pattern string, handler interface{}) {
  87. self.register("OPTIONS", pattern, handler)
  88. }
  89. // Post is a shortcut for mux.HandleFunc(pattern, handler).Methods("POST")
  90. // it also fetch the full function name of the handler (with package) to name the route.
  91. func (self *Router) Post(pattern string, handler interface{}) {
  92. self.register("POST", pattern, handler)
  93. }
  94. // Put is a shortcut for mux.HandleFunc(pattern, handler).Methods("PUT")
  95. // it also fetch the full function name of the handler (with package) to name the route.
  96. func (self *Router) Put(pattern string, handler interface{}) {
  97. self.register("PUT", pattern, handler)
  98. }
  99. // Delete is a shortcut for mux.HandleFunc(pattern, handler).Methods("DELETE")
  100. // it also fetch the full function name of the handler (with package) to name the route.
  101. func (self *Router) Delete(pattern string, handler interface{}) {
  102. self.register("Delete", pattern, handler)
  103. }
  104. // Group creates a new application group under the given path prefix.
  105. func (self *Router) Group(prefix string) *Router {
  106. var mod = new(internal.Module)
  107. self.mux.PathPrefix(prefix).Handler(mod)
  108. var mux = self.mux.PathPrefix(prefix).Subrouter()
  109. router := &Router{mod: mod, mux: mux}
  110. self.subrouters = append(self.subrouters, router)
  111. return router
  112. }
  113. // FileServer registers a handler to serve HTTP requests
  114. // with the contents of the file system rooted at root.
  115. func (self *Router) FileServer(prefix, dir string) {
  116. if abs, err := filepath.Abs(dir); err == nil {
  117. Infof("FS: %s", abs)
  118. fs := http.StripPrefix(prefix, http.FileServer(http.Dir(abs)))
  119. self.mux.PathPrefix(prefix).Handler(fs)
  120. } else {
  121. Fatalf("Failed to setup file server: %v", err)
  122. }
  123. }
  124. // Name returns route name for the given request, if any.
  125. func (self *Router) Name(r *http.Request) (name string) {
  126. var match mux.RouteMatch
  127. if self.mux.Match(r, &match) {
  128. name = match.Route.GetName()
  129. }
  130. return name
  131. }
  132. func (self *Router) Use(module interface{}) {
  133. self.mod.Use(module)
  134. }
  135. // ServeHTTP dispatches the request to the handler whose
  136. // pattern most closely matches the request URL.
  137. func (self *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  138. self.build().ServeHTTP(w, r)
  139. }
  140. // Run starts the application server to serve incoming requests at the given address.
  141. func (self *Router) Run() {
  142. runtime.GOMAXPROCS(config.maxprocs)
  143. go func() {
  144. time.Sleep(500 * time.Millisecond)
  145. Infof("Application server is listening at %d", config.port)
  146. }()
  147. if err := http.ListenAndServe(fmt.Sprintf(":%d", config.port), self); err != nil {
  148. Fatalf("Failed to start the server: %v", err)
  149. }
  150. }