language: go | |||||
install: | |||||
- go get github.com/smartystreets/goconvey | |||||
go: | |||||
- 1.4 | |||||
- tip |
/* ---------------------------------------------------------------------- | |||||
* ______ ___ __ | |||||
* / ____/___ / | ____ __ ___ __/ /_ ___ ________ | |||||
* / / __/ __ \/ /| | / __ \/ / / / | /| / / __ \/ _ \/ ___/ _ \ | |||||
* / /_/ / /_/ / ___ |/ / / / /_/ /| |/ |/ / / / / __/ / / __/ | |||||
* \____/\____/_/ |_/_/ /_/\__. / |__/|__/_/ /_/\___/_/ \___/ | |||||
* /____/ | |||||
* | |||||
* (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" |
/* ---------------------------------------------------------------------- | |||||
* ______ ___ __ | |||||
* / ____/___ / | ____ __ ___ __/ /_ ___ ________ | |||||
* / / __/ __ \/ /| | / __ \/ / / / | /| / / __ \/ _ \/ ___/ _ \ | |||||
* / /_/ / /_/ / ___ |/ / / / /_/ /| |/ |/ / / / / __/ / / __/ | |||||
* \____/\____/_/ |_/_/ /_/\__. / |__/|__/_/ /_/\___/_/ \___/ | |||||
* /____/ | |||||
* | |||||
* (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) | |||||
} |
import "net/http" | 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) | |||||
} | } |
"path/filepath" | "path/filepath" | ||||
"runtime" | "runtime" | ||||
"github.com/goanywhere/rex/internal" | |||||
"github.com/goanywhere/rex/modules" | "github.com/goanywhere/rex/modules" | ||||
"github.com/goanywhere/x/env" | "github.com/goanywhere/x/env" | ||||
"github.com/goanywhere/x/fs" | "github.com/goanywhere/x/fs" | ||||
// FileServer registers a handler to serve HTTP requests | // FileServer registers a handler to serve HTTP requests | ||||
// with the contents of the file system rooted at root. | // with the contents of the file system rooted at root. | ||||
/* | |||||
func FileServer(prefix, dir string) { | func FileServer(prefix, dir string) { | ||||
DefaultMux.FileServer(prefix, dir) | DefaultMux.FileServer(prefix, dir) | ||||
} | } | ||||
*/ | |||||
// Use appends middleware module into the serving list, modules will be served in FIFO order. | // Use appends middleware module into the serving list, modules will be served in FIFO order. | ||||
func Use(module func(http.Handler) http.Handler) { | func Use(module func(http.Handler) http.Handler) { | ||||
} | } | ||||
func init() { | func init() { | ||||
// ---------------------------------------- | |||||
// Project Root | |||||
// ---------------------------------------- | |||||
// setup project root | |||||
var root = fs.Getcd(2) | var root = fs.Getcd(2) | ||||
env.Set(internal.Root, root) | |||||
env.Set("rex.root", fs.Getcd(2)) | |||||
env.Load(filepath.Join(root, ".env")) | env.Load(filepath.Join(root, ".env")) | ||||
// cmd arguments | // cmd arguments |
import ( | import ( | ||||
"fmt" | "fmt" | ||||
"net/http" | "net/http" | ||||
"path/filepath" | |||||
"reflect" | "reflect" | ||||
"runtime" | "runtime" | ||||
"time" | "time" | ||||
"github.com/goanywhere/rex/internal" | |||||
"github.com/gorilla/mux" | "github.com/gorilla/mux" | ||||
) | ) | ||||
type Router struct { | type Router struct { | ||||
mod *internal.Module | |||||
module *module | |||||
mux *mux.Router | mux *mux.Router | ||||
ready bool | ready bool | ||||
subrouters []*Router | subrouters []*Router | ||||
func New() *Router { | func New() *Router { | ||||
return &Router{ | return &Router{ | ||||
mod: new(internal.Module), | |||||
mux: mux.NewRouter().StrictSlash(true), | |||||
module: new(module), | |||||
mux: mux.NewRouter().StrictSlash(true), | |||||
} | } | ||||
} | } | ||||
if !self.ready { | if !self.ready { | ||||
self.ready = true | self.ready = true | ||||
// * activate router's middleware modules. | // * 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. | // * activate subrouters's middleware modules. | ||||
for index := 0; index < len(self.subrouters); index++ { | for index := 0; index < len(self.subrouters); index++ { | ||||
sr := 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. | // register adds the http.Handler/http.HandleFunc into Gorilla mux. | ||||
// Group creates a new application group under the given path prefix. | // Group creates a new application group under the given path prefix. | ||||
func (self *Router) Group(prefix string) *Router { | 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() | 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) | self.subrouters = append(self.subrouters, router) | ||||
return 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. | // Name returns route name for the given request, if any. | ||||
func (self *Router) Name(r *http.Request) (name string) { | func (self *Router) Name(r *http.Request) (name string) { | ||||
var match mux.RouteMatch | var match mux.RouteMatch | ||||
return name | 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 | // ServeHTTP dispatches the request to the handler whose |