martini.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // Package martini is a powerful package for quickly writing modular web applications/services in Golang.
  2. //
  3. // For a full guide visit http://github.com/go-martini/martini
  4. //
  5. // package main
  6. //
  7. // import "github.com/go-martini/martini"
  8. //
  9. // func main() {
  10. // m := martini.Classic()
  11. //
  12. // m.Get("/", func() string {
  13. // return "Hello world!"
  14. // })
  15. //
  16. // m.Run()
  17. // }
  18. package martini
  19. import (
  20. "log"
  21. "net/http"
  22. "os"
  23. "reflect"
  24. "github.com/codegangsta/inject"
  25. )
  26. // Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level.
  27. type Martini struct {
  28. inject.Injector
  29. handlers []Handler
  30. action Handler
  31. logger *log.Logger
  32. }
  33. // New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used.
  34. func New() *Martini {
  35. m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(os.Stdout, "[martini] ", 0)}
  36. m.Map(m.logger)
  37. m.Map(defaultReturnHandler())
  38. return m
  39. }
  40. // Handlers sets the entire middleware stack with the given Handlers. This will clear any current middleware handlers.
  41. // Will panic if any of the handlers is not a callable function
  42. func (m *Martini) Handlers(handlers ...Handler) {
  43. m.handlers = make([]Handler, 0)
  44. for _, handler := range handlers {
  45. m.Use(handler)
  46. }
  47. }
  48. // Action sets the handler that will be called after all the middleware has been invoked. This is set to martini.Router in a martini.Classic().
  49. func (m *Martini) Action(handler Handler) {
  50. validateHandler(handler)
  51. m.action = handler
  52. }
  53. // Use adds a middleware Handler to the stack. Will panic if the handler is not a callable func. Middleware Handlers are invoked in the order that they are added.
  54. func (m *Martini) Use(handler Handler) {
  55. validateHandler(handler)
  56. m.handlers = append(m.handlers, handler)
  57. }
  58. // ServeHTTP is the HTTP Entry point for a Martini instance. Useful if you want to control your own HTTP server.
  59. func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request) {
  60. m.createContext(res, req).run()
  61. }
  62. // Run the http server on a given host and port.
  63. func (m *Martini) RunOnAddr(addr string) {
  64. // TODO: Should probably be implemented using a new instance of http.Server in place of
  65. // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use.
  66. // This would also allow to improve testing when a custom host and port are passed.
  67. logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger)
  68. logger.Printf("listening on %s (%s)\n", addr, Env)
  69. logger.Fatalln(http.ListenAndServe(addr, m))
  70. }
  71. // Run the http server. Listening on os.GetEnv("PORT") or 3000 by default.
  72. func (m *Martini) Run() {
  73. port := os.Getenv("PORT")
  74. if len(port) == 0 {
  75. port = "3000"
  76. }
  77. host := os.Getenv("HOST")
  78. m.RunOnAddr(host + ":" + port)
  79. }
  80. func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context {
  81. c := &context{inject.New(), m.handlers, m.action, NewResponseWriter(res), 0}
  82. c.SetParent(m)
  83. c.MapTo(c, (*Context)(nil))
  84. c.MapTo(c.rw, (*http.ResponseWriter)(nil))
  85. c.Map(req)
  86. return c
  87. }
  88. // ClassicMartini represents a Martini with some reasonable defaults. Embeds the router functions for convenience.
  89. type ClassicMartini struct {
  90. *Martini
  91. Router
  92. }
  93. // Classic creates a classic Martini with some basic default middleware - martini.Logger, martini.Recovery and martini.Static.
  94. // Classic also maps martini.Routes as a service.
  95. func Classic() *ClassicMartini {
  96. r := NewRouter()
  97. m := New()
  98. m.Use(Logger())
  99. m.Use(Recovery())
  100. m.Use(Static("public"))
  101. m.MapTo(r, (*Routes)(nil))
  102. m.Action(r.Handle)
  103. return &ClassicMartini{m, r}
  104. }
  105. // Handler can be any callable function. Martini attempts to inject services into the handler's argument list.
  106. // Martini will panic if an argument could not be fullfilled via dependency injection.
  107. type Handler interface{}
  108. func validateHandler(handler Handler) {
  109. if reflect.TypeOf(handler).Kind() != reflect.Func {
  110. panic("martini handler must be a callable func")
  111. }
  112. }
  113. // Context represents a request context. Services can be mapped on the request level from this interface.
  114. type Context interface {
  115. inject.Injector
  116. // Next is an optional function that Middleware Handlers can call to yield the until after
  117. // the other Handlers have been executed. This works really well for any operations that must
  118. // happen after an http request
  119. Next()
  120. // Written returns whether or not the response for this context has been written.
  121. Written() bool
  122. }
  123. type context struct {
  124. inject.Injector
  125. handlers []Handler
  126. action Handler
  127. rw ResponseWriter
  128. index int
  129. }
  130. func (c *context) handler() Handler {
  131. if c.index < len(c.handlers) {
  132. return c.handlers[c.index]
  133. }
  134. if c.index == len(c.handlers) {
  135. return c.action
  136. }
  137. panic("invalid index for context handler")
  138. }
  139. func (c *context) Next() {
  140. c.index += 1
  141. c.run()
  142. }
  143. func (c *context) Written() bool {
  144. return c.rw.Written()
  145. }
  146. func (c *context) run() {
  147. for c.index <= len(c.handlers) {
  148. _, err := c.Invoke(c.handler())
  149. if err != nil {
  150. panic(err)
  151. }
  152. c.index += 1
  153. if c.Written() {
  154. return
  155. }
  156. }
  157. }