Skip to content

Commit

Permalink
refactor: adjust context pool
Browse files Browse the repository at this point in the history
  • Loading branch information
vicanso committed Dec 12, 2018
1 parent 48e9b6a commit 1857bff
Show file tree
Hide file tree
Showing 11 changed files with 202 additions and 102 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ language: go
sudo: required

go:
- 1.x
- "1.10.x"
- master

install:
- go get -u github.com/golang/dep/cmd/dep
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ test:
go test -race -cover ./...

test-cover:
go test -race -coverprofile=test.out ./... && go tool cover --html=test.out
go test -race -coverprofile=test.out ./... && go tool cover --html=test.out

bench:
go test -bench=. ./
19 changes: 19 additions & 0 deletions bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cod

import (
"net/http/httptest"
"testing"
)

func BenchmarkRoutes(b *testing.B) {
d := NewWithoutServer()
d.GET("/", func(c *Context) error {
return nil
})
b.ReportAllocs()
req := httptest.NewRequest("GET", "/", nil)
resp := httptest.NewRecorder()
for i := 0; i < b.N; i++ {
d.ServeHTTP(resp, req)
}
}
187 changes: 115 additions & 72 deletions cod.go
Original file line number Diff line number Diff line change
@@ -1,52 +1,75 @@
package cod

import (
"errors"
"net/http"
"sync"

"github.com/julienschmidt/httprouter"
)

var (
// ErrOutOfHandlerRange out of handler range (call next over handler's size)
ErrOutOfHandlerRange = errors.New("out of handler range")
)

type (
// Cod web framework instance
Cod struct {
Server *http.Server
Router *httprouter.Router
Middlewares []Handle
Server *http.Server
Router *httprouter.Router
// Middlewares middleware function
Middlewares []Handler
errorLinsteners []ErrorLinstener
ErrorHandle ErrorHandle
ErrorHandler ErrorHandler
// NotFoundHandler not found handler
NotFoundHandler http.HandlerFunc
GenerateID GenerateID
ctxPool sync.Pool
}
// Group group router
Group struct {
Path string
HandleList []Handle
Cod *Cod
Path string
HandlerList []Handler
Cod *Cod
}
// ErrorHandle error handle function
ErrorHandle func(error, *Context)
// GenerateID generate id
// ErrorHandler error handle function
ErrorHandler func(*Context, error)
// GenerateID generate context id
GenerateID func() string
// Handle cod handle function
Handle func(*Context) error
// Handler cod handle function
Handler func(*Context) error
// ErrorLinstener error listener function
ErrorLinstener func(*Context, error)
)

// New create a cod instance
func New() *Cod {
d := &Cod{
Router: httprouter.New(),
Middlewares: make([]Handle, 0),
}
d := NewWithoutServer()
s := &http.Server{
Handler: d,
}
d.Server = s
return d
}

// NewWithoutServer create a cod instance without server
func NewWithoutServer() *Cod {
d := &Cod{
Router: httprouter.New(),
Middlewares: make([]Handler, 0),
}
d.ctxPool.New = func() interface{} {
return &Context{}
}
return d
}

// ListenAndServe listen and serve for http server
func (d *Cod) ListenAndServe(addr string) error {
if d.Server == nil {
panic("server is not inited")
}
d.Server.Addr = addr
return d.Server.ListenAndServe()
}
Expand All @@ -67,11 +90,21 @@ func (d *Cod) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
d.NotFound(resp, req)
}

// fillContext fill the context
func (d *Cod) fillContext(c *Context, resp http.ResponseWriter, req *http.Request) {
c.Reset()
c.Request = req
c.Response = resp
if resp != nil {
c.Headers = resp.Header()
}
}

// Handle add http handle function
func (d *Cod) Handle(method, path string, handleList ...Handle) {
func (d *Cod) Handle(method, path string, handlerList ...Handler) {
d.Router.Handle(method, path, func(resp http.ResponseWriter, req *http.Request, params httprouter.Params) {
c := NewContext(resp, req)
defer ReleaseContext(c)
c := d.ctxPool.Get().(*Context)
d.fillContext(c, resp, req)
c.Params = make(map[string]string)
for _, item := range params {
c.Params[item.Key] = item.Value
Expand All @@ -83,96 +116,106 @@ func (d *Cod) Handle(method, path string, handleList ...Handle) {
c.cod = d
mids := d.Middlewares
maxMid := len(mids)
maxNext := maxMid + len(handlerList)
index := -1
c.Next = func() error {
index++
// 如果已到最后,执行handle list
// 如果调用过多的next,则会导致panic
if index >= maxNext {
panic(ErrOutOfHandlerRange)
}
// 如果已执行完公共添加的中间件,执行handler list
if index >= maxMid {
return handleList[index-maxMid](c)
return handlerList[index-maxMid](c)
}
return mids[index](c)
}
err := c.Next()
if err != nil {
d.EmitError(c, err)
fn := d.ErrorHandle
if fn == nil {
fn = d.Error
}
fn(err, c)
d.Error(c, err)
}
d.ctxPool.Put(c)
})
}

// GET add http get method handle
func (d *Cod) GET(path string, handleList ...Handle) {
d.Handle(http.MethodGet, path, handleList...)
func (d *Cod) GET(path string, handlerList ...Handler) {
d.Handle(http.MethodGet, path, handlerList...)
}

// POST add http post method handle
func (d *Cod) POST(path string, handleList ...Handle) {
d.Handle(http.MethodPost, path, handleList...)
func (d *Cod) POST(path string, handlerList ...Handler) {
d.Handle(http.MethodPost, path, handlerList...)
}

// PUT add http put method handle
func (d *Cod) PUT(path string, handleList ...Handle) {
d.Handle(http.MethodPut, path, handleList...)
func (d *Cod) PUT(path string, handlerList ...Handler) {
d.Handle(http.MethodPut, path, handlerList...)
}

// PATCH add http patch method handle
func (d *Cod) PATCH(path string, handleList ...Handle) {
d.Handle(http.MethodPatch, path, handleList...)
func (d *Cod) PATCH(path string, handlerList ...Handler) {
d.Handle(http.MethodPatch, path, handlerList...)
}

// DELETE add http delete method handle
func (d *Cod) DELETE(path string, handleList ...Handle) {
d.Handle(http.MethodDelete, path, handleList...)
func (d *Cod) DELETE(path string, handlerList ...Handler) {
d.Handle(http.MethodDelete, path, handlerList...)
}

// HEAD add http head method handle
func (d *Cod) HEAD(path string, handleList ...Handle) {
d.Handle(http.MethodHead, path, handleList...)
func (d *Cod) HEAD(path string, handlerList ...Handler) {
d.Handle(http.MethodHead, path, handlerList...)
}

// OPTIONS add http options method handle
func (d *Cod) OPTIONS(path string, handleList ...Handle) {
d.Handle(http.MethodOptions, path, handleList...)
func (d *Cod) OPTIONS(path string, handlerList ...Handler) {
d.Handle(http.MethodOptions, path, handlerList...)
}

// TRACE add http trace method handle
func (d *Cod) TRACE(path string, handleList ...Handle) {
d.Handle(http.MethodTrace, path, handleList...)
func (d *Cod) TRACE(path string, handlerList ...Handler) {
d.Handle(http.MethodTrace, path, handlerList...)
}

// ALL add http all method handle
func (d *Cod) ALL(path string, handleList ...Handle) {
func (d *Cod) ALL(path string, handlerList ...Handler) {
for _, method := range methods {
d.Handle(method, path, handleList...)
d.Handle(method, path, handlerList...)
}
}

// Group create a http handle group
func (d *Cod) Group(path string, handleList ...Handle) (g *Group) {
func (d *Cod) Group(path string, handlerList ...Handler) (g *Group) {
return &Group{
Cod: d,
Path: path,
HandleList: handleList,
Cod: d,
Path: path,
HandlerList: handlerList,
}
}

// Use add middleware function handle
func (d *Cod) Use(handleList ...Handle) {
d.Middlewares = append(d.Middlewares, handleList...)
func (d *Cod) Use(handlerList ...Handler) {
d.Middlewares = append(d.Middlewares, handlerList...)
}

// NotFound not found handle
func (d *Cod) NotFound(resp http.ResponseWriter, req *http.Request) {
if d.NotFoundHandler != nil {
d.NotFoundHandler(resp, req)
return
}
resp.WriteHeader(http.StatusNotFound)
resp.Write([]byte("Not found"))
}

// Error error handle
func (d *Cod) Error(err error, c *Context) {
func (d *Cod) Error(c *Context, err error) {
if d.ErrorHandler != nil {
d.ErrorHandler(c, err)
return
}
resp := c.Response
he, ok := err.(*HTTPError)
if ok {
Expand Down Expand Up @@ -200,73 +243,73 @@ func (d *Cod) OnError(ln ErrorLinstener) {
d.errorLinsteners = append(d.errorLinsteners, ln)
}

func (g *Group) merge(s2 []Handle) []Handle {
s1 := g.HandleList
fns := make([]Handle, len(s1)+len(s2))
func (g *Group) merge(s2 []Handler) []Handler {
s1 := g.HandlerList
fns := make([]Handler, len(s1)+len(s2))
copy(fns, s1)
copy(fns[len(s1):], s2)
return fns
}

// GET add group http get method handl
func (g *Group) GET(path string, handleList ...Handle) {
func (g *Group) GET(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.GET(p, fns...)
}

// POST add group http post method handl
func (g *Group) POST(path string, handleList ...Handle) {
func (g *Group) POST(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.POST(p, fns...)
}

// PUT add group http put method handl
func (g *Group) PUT(path string, handleList ...Handle) {
func (g *Group) PUT(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.PUT(p, fns...)
}

// PATCH add group http patch method handl
func (g *Group) PATCH(path string, handleList ...Handle) {
func (g *Group) PATCH(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.PATCH(p, fns...)
}

// DELETE add group http delete method handl
func (g *Group) DELETE(path string, handleList ...Handle) {
func (g *Group) DELETE(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.DELETE(p, fns...)
}

// HEAD add group http head method handl
func (g *Group) HEAD(path string, handleList ...Handle) {
func (g *Group) HEAD(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.HEAD(p, fns...)
}

// OPTIONS add group http options method handl
func (g *Group) OPTIONS(path string, handleList ...Handle) {
func (g *Group) OPTIONS(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.OPTIONS(p, fns...)
}

// TRACE add group http trace method handl
func (g *Group) TRACE(path string, handleList ...Handle) {
func (g *Group) TRACE(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.TRACE(p, fns...)
}

// ALL add group http all method handl
func (g *Group) ALL(path string, handleList ...Handle) {
func (g *Group) ALL(path string, handlerList ...Handler) {
p := g.Path + path
fns := g.merge(handleList)
fns := g.merge(handlerList)
g.Cod.ALL(p, fns...)
}
Loading

0 comments on commit 1857bff

Please sign in to comment.