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.

175 lines
5.8KB

  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(),
  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. // FileRouter 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. fs := http.StripPrefix(prefix, http.FileServer(http.Dir(abs)))
  118. self.mux.PathPrefix(prefix).Handler(fs)
  119. } else {
  120. Fatalf("Failed to setup file server: %v", err)
  121. }
  122. }
  123. // Name returns route name for the given request, if any.
  124. func (self *Router) Name(r *http.Request) (name string) {
  125. var match mux.RouteMatch
  126. if self.mux.Match(r, &match) {
  127. name = match.Route.GetName()
  128. }
  129. return name
  130. }
  131. func (self *Router) Use(module interface{}) {
  132. self.mod.Use(module)
  133. }
  134. // ServeHTTP dispatches the request to the handler whose
  135. // pattern most closely matches the request URL.
  136. func (self *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  137. self.build().ServeHTTP(w, r)
  138. }
  139. // Run starts the application server to serve incoming requests at the given address.
  140. func (self *Router) Run() {
  141. runtime.GOMAXPROCS(options.maxprocs)
  142. go func() {
  143. time.Sleep(500 * time.Millisecond)
  144. Infof("Application server is listening at %d", options.port)
  145. }()
  146. if err := http.ListenAndServe(fmt.Sprintf(":%d", options.port), self); err != nil {
  147. Fatalf("Failed to start the server: %v", err)
  148. }
  149. }