Skip to content

Commit

Permalink
router
Browse files Browse the repository at this point in the history
  • Loading branch information
chonglou committed May 11, 2017
1 parent c6027d4 commit 40df762
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Go
/vendor/*/

# Editor
.*.swp
.*.un~
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
# h2o
A web application framework for the golang.


## Thanks
- [mux](https://github.com/gorilla/mux)
- [negroni](https://github.com/urfave/negroni)
- [logrus](https://github.com/Sirupsen/logrus)
86 changes: 86 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package h2o

import (
"context"
"encoding/json"
"encoding/xml"
"net"
"net/http"
"strings"
)

// K key type
type K string

// H hash
type H map[string]interface{}

// Context context
type Context struct {
Writer http.ResponseWriter
Request *http.Request

vars map[string]string
}

// Set set
func (p *Context) Set(k string, v interface{}) {
p.Request = p.Request.WithContext(
context.WithValue(p.Request.Context(), K(k), v),
)
}

// Get get
func (p *Context) Get(k string) interface{} {
return p.Request.Context().Value(K(k))
}

// Redirect redirect
func (p *Context) Redirect(code int, url string) {
http.Redirect(p.Writer, p.Request, url, code)
}

// Header get header
func (p *Context) Header(k string) string {
return p.Request.Header.Get(k)
}

// Param the value of the URL param.
func (p *Context) Param(k string) string {
return p.vars[k]
}

// ClientIP client ip
func (p *Context) ClientIP() string {
// -------------
if ip := strings.TrimSpace(p.Header("X-Real-Ip")); ip != "" {
return ip
}
// -------------
ip := p.Header("X-Forwarded-For")
if idx := strings.IndexByte(ip, ','); idx >= 0 {
ip = ip[0:idx]
}
ip = strings.TrimSpace(ip)
if ip != "" {
return ip
}
// -------------
if ip, _, err := net.SplitHostPort(strings.TrimSpace(p.Request.RemoteAddr)); err == nil {
return ip
}
// -----------
return ""
}

// JSON write json
func (p *Context) JSON(s int, v interface{}) error {
enc := json.NewEncoder(p.Writer)
return enc.Encode(v)
}

// XML write xml
func (p *Context) XML(s int, v interface{}) error {
enc := xml.NewEncoder(p.Writer)
return enc.Encode(v)
}
11 changes: 11 additions & 0 deletions error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package h2o

// HTTPError http error
type HTTPError struct {
Message string
Status int
}

func (p *HTTPError) Error() string {
return p.Message
}
7 changes: 7 additions & 0 deletions route.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package h2o

type route struct {
path string
methods []string
handlers []HandlerFunc
}
107 changes: 107 additions & 0 deletions router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package h2o

import (
"net/http"
"reflect"
"runtime"
"time"

log "github.com/Sirupsen/logrus"
"github.com/gorilla/mux"
)

// HandlerFunc an adapter to allow the use of ordinary functions as HTTP handler
type HandlerFunc func(*Context) error

// New new blank Engine instance without any middleware attached.
func New() *Router {
return &Router{
handlers: make([]HandlerFunc, 0),
routes: make([]*route, 0),
}
}

// Router associated with a prefix and an array of handlers
type Router struct {
path string
handlers []HandlerFunc
routes []*route
}

// Group creates a new router group
func (p *Router) Group(group func(*Router), path string, handlers ...HandlerFunc) {
rt := &Router{
path: p.path + path,
handlers: append(p.handlers, handlers...),
routes: make([]*route, 0),
}
group(rt)
p.routes = append(p.routes, rt.routes...)
}

// GET http get
func (p *Router) GET(path string, handlers ...HandlerFunc) {
p.Handle([]string{http.MethodGet}, path, handlers...)
}

// POST http post
func (p *Router) POST(path string, handlers ...HandlerFunc) {
p.Handle([]string{http.MethodPost}, path, handlers...)
}

// PUT http put
func (p *Router) PUT(path string, handlers ...HandlerFunc) {
p.Handle([]string{http.MethodPut}, path, handlers...)
}

// PATCH http patch
func (p *Router) PATCH(path string, handlers ...HandlerFunc) {
p.Handle([]string{http.MethodPatch}, path, handlers...)
}

// DELETE http delete
func (p *Router) DELETE(path string, handlers ...HandlerFunc) {
p.Handle([]string{http.MethodDelete}, path, handlers...)
}

// Handle registers a new request handle and middleware with the given path and method.
func (p *Router) Handle(methods []string, path string, handlers ...HandlerFunc) {
p.routes = append(
p.routes,
&route{
methods: methods,
path: p.path + path,
handlers: append(p.handlers, handlers...),
},
)
}

// Run attaches the router to a http.Server and starts listening and serving HTTP requests.
func (p *Router) Run(port int, grace bool) error {
rt := mux.NewRouter()
for _, r := range p.routes {
rt.HandleFunc(r.path, func(w http.ResponseWriter, r *http.Request) {
begin := time.Now()
ctx := Context{
Request: r,
Writer: w,
vars: mux.Vars(r),
}
log.Infof("%s %s %s %s", r.Proto, r.Method, r.RequestURI, ctx.ClientIP())
for _, h := range p.handlers {
log.Debugf("call %s", runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name())
if e := h(&ctx); e != nil {
log.Error(e)
s := http.StatusInternalServerError
if he, ok := e.(*HTTPError); ok {
s = he.Status
}
http.Error(w, e.Error(), s)
}
}
log.Infof("done %s", time.Now().Sub(begin))
}).Methods(r.methods...)
}

return nil
}
37 changes: 37 additions & 0 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"comment": "",
"ignore": "test",
"package": [
{
"checksumSHA1": "m+iiamnbukzE8kFPfBche6D0FmQ=",
"path": "github.com/Sirupsen/logrus",
"revision": "5b60b3d3ee017ed00bcd0225fcca7acab767844b",
"revisionTime": "2017-05-04T07:10:19Z"
},
{
"checksumSHA1": "g/V4qrXjUGG9B+e3hB+4NAYJ5Gs=",
"path": "github.com/gorilla/context",
"revision": "08b5f424b9271eedf6f9f0ce86cb9396ed337a42",
"revisionTime": "2016-08-17T18:46:32Z"
},
{
"checksumSHA1": "zmCk+lgIeiOf0Ng9aFP9aFy8ksE=",
"path": "github.com/gorilla/mux",
"revision": "4c1c3952b7d9d0a061a3fa7b36fd373ba0398ebc",
"revisionTime": "2017-04-27T04:12:50Z"
},
{
"checksumSHA1": "x1AhvSvgDWiTnAc57jsoFKeKLsI=",
"path": "github.com/urfave/negroni",
"revision": "1d8981a52d6bda4467a9faacf3fdddd38222dfc4",
"revisionTime": "2017-05-06T02:27:41Z"
},
{
"checksumSHA1": "oS0UZOGWVVsVciOQ8nZJ582mFF8=",
"path": "golang.org/x/sys/unix",
"revision": "9ccfe848b9db8435a24c424abbc07a921adf1df5",
"revisionTime": "2017-04-27T03:54:25Z"
}
],
"rootPath": "github.com/kapmahc/h2o"
}

0 comments on commit 40df762

Please sign in to comment.