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.

macaron.go 7.3KB

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