| @@ -0,0 +1,8 @@ | |||
| language: go | |||
| install: | |||
| - go get github.com/smartystreets/goconvey | |||
| go: | |||
| - 1.4 | |||
| - tip | |||
| @@ -1,25 +0,0 @@ | |||
| /* ---------------------------------------------------------------------- | |||
| * ______ ___ __ | |||
| * / ____/___ / | ____ __ ___ __/ /_ ___ ________ | |||
| * / / __/ __ \/ /| | / __ \/ / / / | /| / / __ \/ _ \/ ___/ _ \ | |||
| * / /_/ / /_/ / ___ |/ / / / /_/ /| |/ |/ / / / / __/ / / __/ | |||
| * \____/\____/_/ |_/_/ /_/\__. / |__/|__/_/ /_/\___/_/ \___/ | |||
| * /____/ | |||
| * | |||
| * (C) Copyright 2015 GoAnywhere (http://goanywhere.io). | |||
| * ---------------------------------------------------------------------- | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ----------------------------------------------------------------------*/ | |||
| package internal | |||
| const Root = "rex.root" | |||
| @@ -1,74 +0,0 @@ | |||
| /* ---------------------------------------------------------------------- | |||
| * ______ ___ __ | |||
| * / ____/___ / | ____ __ ___ __/ /_ ___ ________ | |||
| * / / __/ __ \/ /| | / __ \/ / / / | /| / / __ \/ _ \/ ___/ _ \ | |||
| * / /_/ / /_/ / ___ |/ / / / /_/ /| |/ |/ / / / / __/ / / __/ | |||
| * \____/\____/_/ |_/_/ /_/\__. / |__/|__/_/ /_/\___/_/ \___/ | |||
| * /____/ | |||
| * | |||
| * (C) Copyright 2015 GoAnywhere (http://goanywhere.io). | |||
| * ---------------------------------------------------------------------- | |||
| * Licensed under the Apache License, Version 2.0 (the "License"); | |||
| * you may not use this file except in compliance with the License. | |||
| * You may obtain a copy of the License at | |||
| * | |||
| * http://www.apache.org/licenses/LICENSE-2.0 | |||
| * | |||
| * Unless required by applicable law or agreed to in writing, software | |||
| * distributed under the License is distributed on an "AS IS" BASIS, | |||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| * See the License for the specific language governing permissions and | |||
| * limitations under the License. | |||
| * ----------------------------------------------------------------------*/ | |||
| package internal | |||
| import ( | |||
| "net/http" | |||
| "github.com/Sirupsen/logrus" | |||
| ) | |||
| type Module struct { | |||
| cache http.Handler | |||
| stack []func(http.Handler) http.Handler | |||
| } | |||
| func (self *Module) build() http.Handler { | |||
| if self.cache == nil { | |||
| next := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {})) | |||
| // Activate modules in FIFO order. | |||
| for index := len(self.stack) - 1; index >= 0; index-- { | |||
| next = self.stack[index](next) | |||
| } | |||
| self.cache = next | |||
| } | |||
| return self.cache | |||
| } | |||
| // Use add the middleware module into the stack chain. | |||
| // Supported middleware modules: | |||
| // - http.Handler | |||
| // - func(http.Handler) http.Handler | |||
| func (self *Module) Use(mod interface{}) { | |||
| switch H := mod.(type) { | |||
| case http.Handler: | |||
| handler := func(next http.Handler) http.Handler { | |||
| return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { | |||
| H.ServeHTTP(w, req) | |||
| next.ServeHTTP(w, req) | |||
| }) | |||
| } | |||
| self.stack = append(self.stack, handler) | |||
| case func(http.Handler) http.Handler: | |||
| self.stack = append(self.stack, H) | |||
| default: | |||
| logrus.Fatal("Unsupported middleware module passed in.") | |||
| } | |||
| } | |||
| // Implements the net/http Handler interface and calls the middleware stack. | |||
| func (self *Module) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||
| self.build().ServeHTTP(w, r) | |||
| } | |||
| @@ -24,10 +24,26 @@ package rex | |||
| import "net/http" | |||
| type response interface { | |||
| SetStatus(code int) | |||
| SetContentType(contentType string) | |||
| type module struct { | |||
| stack []func(http.Handler) http.Handler | |||
| } | |||
| func Render(w http.ResponseWriter) { | |||
| // build sets up the whole middleware modules in a FIFO chain. | |||
| func (self *module) build() http.Handler { | |||
| var next http.Handler = http.DefaultServeMux | |||
| // Activate modules in FIFO order. | |||
| for index := len(self.stack) - 1; index >= 0; index-- { | |||
| next = self.stack[index](next) | |||
| } | |||
| return next | |||
| } | |||
| // Use add the middleware module into the stack chain. | |||
| func (self *module) Use(modules ...func(http.Handler) http.Handler) { | |||
| self.stack = append(self.stack, modules...) | |||
| } | |||
| // Implements the net/http Handler interface and calls the middleware stack. | |||
| func (self *module) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||
| self.build().ServeHTTP(w, r) | |||
| } | |||
| @@ -28,7 +28,6 @@ import ( | |||
| "path/filepath" | |||
| "runtime" | |||
| "github.com/goanywhere/rex/internal" | |||
| "github.com/goanywhere/rex/modules" | |||
| "github.com/goanywhere/x/env" | |||
| "github.com/goanywhere/x/fs" | |||
| @@ -88,9 +87,11 @@ func Group(path string) *Router { | |||
| // FileServer registers a handler to serve HTTP requests | |||
| // with the contents of the file system rooted at root. | |||
| /* | |||
| func FileServer(prefix, dir string) { | |||
| DefaultMux.FileServer(prefix, dir) | |||
| } | |||
| */ | |||
| // Use appends middleware module into the serving list, modules will be served in FIFO order. | |||
| func Use(module func(http.Handler) http.Handler) { | |||
| @@ -103,11 +104,9 @@ func Run() { | |||
| } | |||
| func init() { | |||
| // ---------------------------------------- | |||
| // Project Root | |||
| // ---------------------------------------- | |||
| // setup project root | |||
| var root = fs.Getcd(2) | |||
| env.Set(internal.Root, root) | |||
| env.Set("rex.root", fs.Getcd(2)) | |||
| env.Load(filepath.Join(root, ".env")) | |||
| // cmd arguments | |||
| @@ -25,17 +25,15 @@ package rex | |||
| import ( | |||
| "fmt" | |||
| "net/http" | |||
| "path/filepath" | |||
| "reflect" | |||
| "runtime" | |||
| "time" | |||
| "github.com/goanywhere/rex/internal" | |||
| "github.com/gorilla/mux" | |||
| ) | |||
| type Router struct { | |||
| mod *internal.Module | |||
| module *module | |||
| mux *mux.Router | |||
| ready bool | |||
| subrouters []*Router | |||
| @@ -43,8 +41,8 @@ type Router struct { | |||
| func New() *Router { | |||
| return &Router{ | |||
| mod: new(internal.Module), | |||
| mux: mux.NewRouter().StrictSlash(true), | |||
| module: new(module), | |||
| mux: mux.NewRouter().StrictSlash(true), | |||
| } | |||
| } | |||
| @@ -53,15 +51,18 @@ func (self *Router) build() http.Handler { | |||
| if !self.ready { | |||
| self.ready = true | |||
| // * activate router's middleware modules. | |||
| self.mod.Use(self.mux) | |||
| self.module.Use(func(http.Handler) http.Handler { | |||
| return self.mux | |||
| }) | |||
| // * activate subrouters's middleware modules. | |||
| for index := 0; index < len(self.subrouters); index++ { | |||
| sr := self.subrouters[index] | |||
| sr.mod.Use(sr.mux) | |||
| sr.module.Use(func(http.Handler) http.Handler { | |||
| return sr.mux | |||
| }) | |||
| } | |||
| } | |||
| return self.mod | |||
| return self.module | |||
| } | |||
| // register adds the http.Handler/http.HandleFunc into Gorilla mux. | |||
| @@ -120,27 +121,15 @@ func (self *Router) Delete(pattern string, handler interface{}) { | |||
| // Group creates a new application group under the given path prefix. | |||
| func (self *Router) Group(prefix string) *Router { | |||
| var mod = new(internal.Module) | |||
| self.mux.PathPrefix(prefix).Handler(mod) | |||
| var module = new(module) | |||
| self.mux.PathPrefix(prefix).Handler(module) | |||
| var mux = self.mux.PathPrefix(prefix).Subrouter() | |||
| router := &Router{mod: mod, mux: mux} | |||
| router := &Router{module: module, mux: mux} | |||
| self.subrouters = append(self.subrouters, router) | |||
| return router | |||
| } | |||
| // FileServer registers a handler to serve HTTP requests | |||
| // with the contents of the file system rooted at root. | |||
| func (self *Router) FileServer(prefix, dir string) { | |||
| if abs, err := filepath.Abs(dir); err == nil { | |||
| Infof("FS: %s", abs) | |||
| fs := http.StripPrefix(prefix, http.FileServer(http.Dir(abs))) | |||
| self.mux.PathPrefix(prefix).Handler(fs) | |||
| } else { | |||
| Fatalf("Failed to setup file server: %v", err) | |||
| } | |||
| } | |||
| // Name returns route name for the given request, if any. | |||
| func (self *Router) Name(r *http.Request) (name string) { | |||
| var match mux.RouteMatch | |||
| @@ -150,8 +139,9 @@ func (self *Router) Name(r *http.Request) (name string) { | |||
| return name | |||
| } | |||
| func (self *Router) Use(module interface{}) { | |||
| self.mod.Use(module) | |||
| // Use add the middleware module into the stack chain. | |||
| func (self *Router) Use(module func(http.Handler) http.Handler) { | |||
| self.module.Use(module) | |||
| } | |||
| // ServeHTTP dispatches the request to the handler whose | |||