macaron.go 7.1 KB

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