macaron.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // Copyright 2014 Unknwon
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. // Package macaron is a high productive and modular design web framework in Go.
  15. package macaron
  16. import (
  17. "io"
  18. "log"
  19. "net/http"
  20. "os"
  21. "reflect"
  22. "strings"
  23. "github.com/Unknwon/com"
  24. "gopkg.in/ini.v1"
  25. "github.com/Unknwon/macaron/inject"
  26. )
  27. const _VERSION = "0.4.9.1229"
  28. func Version() string {
  29. return _VERSION
  30. }
  31. // Handler can be any callable function.
  32. // Macaron attempts to inject services into the handler's argument list,
  33. // and panics if an argument could not be fullfilled via dependency injection.
  34. type Handler interface{}
  35. // validateHandler makes sure a handler is a callable function,
  36. // and panics if it is not.
  37. func validateHandler(h Handler) {
  38. if reflect.TypeOf(h).Kind() != reflect.Func {
  39. panic("Macaron handler must be a callable function")
  40. }
  41. }
  42. // validateHandlers makes sure handlers are callable functions,
  43. // and panics if any of them is not.
  44. func validateHandlers(handlers []Handler) {
  45. for _, h := range handlers {
  46. validateHandler(h)
  47. }
  48. }
  49. // Macaron represents the top level web application.
  50. // inject.Injector methods can be invoked to map services on a global level.
  51. type Macaron struct {
  52. inject.Injector
  53. befores []BeforeHandler
  54. handlers []Handler
  55. action Handler
  56. urlPrefix string // For suburl support.
  57. *Router
  58. logger *log.Logger
  59. }
  60. // NewWithLogger creates a bare bones Macaron instance.
  61. // Use this method if you want to have full control over the middleware that is used.
  62. // You can specify logger output writer with this function.
  63. func NewWithLogger(out io.Writer) *Macaron {
  64. m := &Macaron{
  65. Injector: inject.New(),
  66. action: func() {},
  67. Router: NewRouter(),
  68. logger: log.New(out, "[Macaron] ", 0),
  69. }
  70. m.Router.m = m
  71. m.Map(m.logger)
  72. m.Map(defaultReturnHandler())
  73. m.notFound = func(resp http.ResponseWriter, req *http.Request) {
  74. c := m.createContext(resp, req)
  75. c.handlers = append(c.handlers, http.NotFound)
  76. c.run()
  77. }
  78. return m
  79. }
  80. // New creates a bare bones Macaron instance.
  81. // Use this method if you want to have full control over the middleware that is used.
  82. func New() *Macaron {
  83. return NewWithLogger(os.Stdout)
  84. }
  85. // Classic creates a classic Macaron with some basic default middleware:
  86. // mocaron.Logger, mocaron.Recovery and mocaron.Static.
  87. func Classic() *Macaron {
  88. m := New()
  89. m.Use(Logger())
  90. m.Use(Recovery())
  91. m.Use(Static("public"))
  92. return m
  93. }
  94. // Handlers sets the entire middleware stack with the given Handlers.
  95. // This will clear any current middleware handlers,
  96. // and panics if any of the handlers is not a callable function
  97. func (m *Macaron) Handlers(handlers ...Handler) {
  98. m.handlers = make([]Handler, 0)
  99. for _, handler := range handlers {
  100. m.Use(handler)
  101. }
  102. }
  103. // Action sets the handler that will be called after all the middleware has been invoked.
  104. // This is set to macaron.Router in a macaron.Classic().
  105. func (m *Macaron) Action(handler Handler) {
  106. validateHandler(handler)
  107. m.action = handler
  108. }
  109. // BeforeHandler represents a handler executes at beginning of every request.
  110. // Macaron stops future process when it returns true.
  111. type BeforeHandler func(rw http.ResponseWriter, req *http.Request) bool
  112. func (m *Macaron) Before(handler BeforeHandler) {
  113. m.befores = append(m.befores, handler)
  114. }
  115. // Use adds a middleware Handler to the stack,
  116. // and panics if the handler is not a callable func.
  117. // Middleware Handlers are invoked in the order that they are added.
  118. func (m *Macaron) Use(handler Handler) {
  119. validateHandler(handler)
  120. m.handlers = append(m.handlers, handler)
  121. }
  122. func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Context {
  123. c := &Context{
  124. Injector: inject.New(),
  125. handlers: m.handlers,
  126. action: m.action,
  127. index: 0,
  128. Router: m.Router,
  129. Req: Request{req},
  130. Resp: NewResponseWriter(rw),
  131. Data: make(map[string]interface{}),
  132. }
  133. c.SetParent(m)
  134. c.Map(c)
  135. c.MapTo(c.Resp, (*http.ResponseWriter)(nil))
  136. c.Map(req)
  137. return c
  138. }
  139. // ServeHTTP is the HTTP Entry point for a Macaron instance.
  140. // Useful if you want to control your own HTTP server.
  141. // Be aware that none of middleware will run without registering any router.
  142. func (m *Macaron) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
  143. req.URL.Path = strings.TrimPrefix(req.URL.Path, m.urlPrefix)
  144. for _, h := range m.befores {
  145. if h(rw, req) {
  146. return
  147. }
  148. }
  149. m.Router.ServeHTTP(rw, req)
  150. }
  151. func GetDefaultListenInfo() (string, int) {
  152. host := os.Getenv("HOST")
  153. if len(host) == 0 {
  154. host = "0.0.0.0"
  155. }
  156. port := com.StrTo(os.Getenv("PORT")).MustInt()
  157. if port == 0 {
  158. port = 4000
  159. }
  160. return host, port
  161. }
  162. // Run the http server. Listening on os.GetEnv("PORT") or 4000 by default.
  163. func (m *Macaron) Run(args ...interface{}) {
  164. host, port := GetDefaultListenInfo()
  165. if len(args) == 1 {
  166. switch arg := args[0].(type) {
  167. case string:
  168. host = arg
  169. case int:
  170. port = arg
  171. }
  172. } else if len(args) >= 2 {
  173. if arg, ok := args[0].(string); ok {
  174. host = arg
  175. }
  176. if arg, ok := args[1].(int); ok {
  177. port = arg
  178. }
  179. }
  180. addr := host + ":" + com.ToStr(port)
  181. logger := m.Injector.GetVal(reflect.TypeOf(m.logger)).Interface().(*log.Logger)
  182. logger.Printf("listening on %s (%s)\n", addr, Env)
  183. logger.Fatalln(http.ListenAndServe(addr, m))
  184. }
  185. // SetURLPrefix sets URL prefix of router layer, so that it support suburl.
  186. func (m *Macaron) SetURLPrefix(prefix string) {
  187. m.urlPrefix = prefix
  188. }
  189. // ____ ____ .__ ___. .__
  190. // \ \ / /____ _______|__|____ \_ |__ | | ____ ______
  191. // \ Y /\__ \\_ __ \ \__ \ | __ \| | _/ __ \ / ___/
  192. // \ / / __ \| | \/ |/ __ \| \_\ \ |_\ ___/ \___ \
  193. // \___/ (____ /__| |__(____ /___ /____/\___ >____ >
  194. // \/ \/ \/ \/ \/
  195. const (
  196. DEV = "development"
  197. PROD = "production"
  198. TEST = "test"
  199. )
  200. var (
  201. // Env is the environment that Macaron is executing in.
  202. // The MACARON_ENV is read on initialization to set this variable.
  203. Env = DEV
  204. // Path of work directory.
  205. Root string
  206. // Flash applies to current request.
  207. FlashNow bool
  208. // Configuration convention object.
  209. cfg *ini.File
  210. )
  211. func setENV(e string) {
  212. if len(e) > 0 {
  213. Env = e
  214. }
  215. }
  216. func init() {
  217. setENV(os.Getenv("MACARON_ENV"))
  218. var err error
  219. Root, err = os.Getwd()
  220. if err != nil {
  221. panic("error getting work directory: " + err.Error())
  222. }
  223. }
  224. // SetConfig sets data sources for configuration.
  225. func SetConfig(source interface{}, others ...interface{}) (err error) {
  226. cfg, err = ini.Load(source, others...)
  227. return err
  228. }
  229. // Config returns configuration convention object.
  230. // It returns an empty object if there is no one available.
  231. func Config() *ini.File {
  232. if cfg == nil {
  233. return &ini.File{}
  234. }
  235. return cfg
  236. }