123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- // Package martini is a powerful package for quickly writing modular web applications/services in Golang.
- //
- // For a full guide visit http://github.com/go-martini/martini
- //
- // package main
- //
- // import "github.com/go-martini/martini"
- //
- // func main() {
- // m := martini.Classic()
- //
- // m.Get("/", func() string {
- // return "Hello world!"
- // })
- //
- // m.Run()
- // }
- package martini
- import (
- "log"
- "net/http"
- "os"
- "reflect"
- "github.com/codegangsta/inject"
- )
- // Martini represents the top level web application. inject.Injector methods can be invoked to map services on a global level.
- type Martini struct {
- inject.Injector
- handlers []Handler
- action Handler
- logger *log.Logger
- }
- // New creates a bare bones Martini instance. Use this method if you want to have full control over the middleware that is used.
- func New() *Martini {
- m := &Martini{Injector: inject.New(), action: func() {}, logger: log.New(os.Stdout, "[martini] ", 0)}
- m.Map(m.logger)
- m.Map(defaultReturnHandler())
- return m
- }
- // Handlers sets the entire middleware stack with the given Handlers. This will clear any current middleware handlers.
- // Will panic if any of the handlers is not a callable function
- func (m *Martini) Handlers(handlers ...Handler) {
- m.handlers = make([]Handler, 0)
- for _, handler := range handlers {
- m.Use(handler)
- }
- }
- // 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().
- func (m *Martini) Action(handler Handler) {
- validateHandler(handler)
- m.action = handler
- }
- // 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.
- func (m *Martini) Use(handler Handler) {
- validateHandler(handler)
- m.handlers = append(m.handlers, handler)
- }
- // ServeHTTP is the HTTP Entry point for a Martini instance. Useful if you want to control your own HTTP server.
- func (m *Martini) ServeHTTP(res http.ResponseWriter, req *http.Request) {
- m.createContext(res, req).run()
- }
- // Run the http server on a given host and port.
- func (m *Martini) RunOnAddr(addr string) {
- // TODO: Should probably be implemented using a new instance of http.Server in place of
- // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use.
- // This would also allow to improve testing when a custom host and port are passed.
- logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger)
- logger.Printf("listening on %s (%s)\n", addr, Env)
- logger.Fatalln(http.ListenAndServe(addr, m))
- }
- // Run the http server. Listening on os.GetEnv("PORT") or 3000 by default.
- func (m *Martini) Run() {
- port := os.Getenv("PORT")
- if len(port) == 0 {
- port = "3000"
- }
- host := os.Getenv("HOST")
- m.RunOnAddr(host + ":" + port)
- }
- func (m *Martini) createContext(res http.ResponseWriter, req *http.Request) *context {
- c := &context{inject.New(), m.handlers, m.action, NewResponseWriter(res), 0}
- c.SetParent(m)
- c.MapTo(c, (*Context)(nil))
- c.MapTo(c.rw, (*http.ResponseWriter)(nil))
- c.Map(req)
- return c
- }
- // ClassicMartini represents a Martini with some reasonable defaults. Embeds the router functions for convenience.
- type ClassicMartini struct {
- *Martini
- Router
- }
- // Classic creates a classic Martini with some basic default middleware - martini.Logger, martini.Recovery and martini.Static.
- // Classic also maps martini.Routes as a service.
- func Classic() *ClassicMartini {
- r := NewRouter()
- m := New()
- m.Use(Logger())
- m.Use(Recovery())
- m.Use(Static("public"))
- m.MapTo(r, (*Routes)(nil))
- m.Action(r.Handle)
- return &ClassicMartini{m, r}
- }
- // Handler can be any callable function. Martini attempts to inject services into the handler's argument list.
- // Martini will panic if an argument could not be fullfilled via dependency injection.
- type Handler interface{}
- func validateHandler(handler Handler) {
- if reflect.TypeOf(handler).Kind() != reflect.Func {
- panic("martini handler must be a callable func")
- }
- }
- // Context represents a request context. Services can be mapped on the request level from this interface.
- type Context interface {
- inject.Injector
- // Next is an optional function that Middleware Handlers can call to yield the until after
- // the other Handlers have been executed. This works really well for any operations that must
- // happen after an http request
- Next()
- // Written returns whether or not the response for this context has been written.
- Written() bool
- }
- type context struct {
- inject.Injector
- handlers []Handler
- action Handler
- rw ResponseWriter
- index int
- }
- func (c *context) handler() Handler {
- if c.index < len(c.handlers) {
- return c.handlers[c.index]
- }
- if c.index == len(c.handlers) {
- return c.action
- }
- panic("invalid index for context handler")
- }
- func (c *context) Next() {
- c.index += 1
- c.run()
- }
- func (c *context) Written() bool {
- return c.rw.Written()
- }
- func (c *context) run() {
- for c.index <= len(c.handlers) {
- _, err := c.Invoke(c.handler())
- if err != nil {
- panic(err)
- }
- c.index += 1
- if c.Written() {
- return
- }
- }
- }
|