Browse Source

license & small optimization

tags/v0.4.6
Lunny Xiao 4 years ago
parent
commit
92f09e5ad9
33 changed files with 282 additions and 122 deletions
  1. +1
    -1
      LICENSE
  2. +11
    -4
      compress.go
  3. +13
    -9
      compress_test.go
  4. +20
    -1
      context.go
  5. +4
    -0
      context_test.go
  6. +4
    -0
      cookie.go
  7. +4
    -0
      cookie_test.go
  8. +2
    -4
      doc.go
  9. +4
    -0
      error.go
  10. +4
    -0
      error_test.go
  11. +4
    -0
      file.go
  12. +4
    -0
      file_test.go
  13. +11
    -7
      group.go
  14. +4
    -0
      group_test.go
  15. +4
    -0
      logger.go
  16. +4
    -0
      logger_test.go
  17. +4
    -0
      param.go
  18. +4
    -0
      param_test.go
  19. +10
    -6
      pool.go
  20. +8
    -4
      pool_test.go
  21. +4
    -0
      prefix.go
  22. +7
    -4
      prefix_test.go
  23. +5
    -1
      recovery.go
  24. +6
    -2
      recovery_test.go
  25. +5
    -1
      response.go
  26. +59
    -53
      return.go
  27. +24
    -20
      return_test.go
  28. +6
    -4
      router.go
  29. +25
    -0
      router_test.go
  30. +4
    -0
      static.go
  31. +4
    -0
      static_test.go
  32. +5
    -1
      tan.go
  33. +4
    -0
      tan_test.go

+ 1
- 1
LICENSE View File

@@ -1,4 +1,4 @@
Copyright (c) 2014 lunny xiaolunwen@gmail.com
Copyright (c) 2014 - 2015 The Tango Authors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal


+ 11
- 4
compress.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
@@ -24,22 +28,25 @@ type Compresser interface {
CompressType() string
}

type GZip struct {}
type GZip struct{}

func (GZip) CompressType() string {
return "gzip"
}

type Deflate struct {}
type Deflate struct{}

func (Deflate) CompressType() string {
return "deflate"
}

type Compress struct {}
type Compress struct{}

func (Compress) CompressType() string {
return "auto"
}

func Compresses(exts []string) HandlerFunc{
func Compresses(exts []string) HandlerFunc {
extsmap := make(map[string]bool)
for _, ext := range exts {
extsmap[strings.ToLower(ext)] = true


+ 13
- 9
compress_test.go View File

@@ -1,14 +1,18 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
"fmt"
"testing"
"bytes"
"compress/gzip"
"compress/flate"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)

type CompressExample struct {
@@ -45,28 +49,28 @@ func (NoCompress) Get() string {
func TestCompressAuto(t *testing.T) {
o := Classic()
o.Get("/", new(CompressExample))
testCompress(t, o, "http://localhost:8000/",
testCompress(t, o, "http://localhost:8000/",
"This is a auto compress text", "gzip")
}

func TestCompressGzip(t *testing.T) {
o := Classic()
o.Get("/", new(GZipExample))
testCompress(t, o, "http://localhost:8000/",
testCompress(t, o, "http://localhost:8000/",
"This is a gzip compress text", "gzip")
}

func TestCompressDeflate(t *testing.T) {
o := Classic()
o.Get("/", new(DeflateExample))
testCompress(t, o, "http://localhost:8000/",
testCompress(t, o, "http://localhost:8000/",
"This is a deflate compress text", "deflate")
}

func TestCompressNon(t *testing.T) {
o := Classic()
o.Get("/", new(NoCompress))
testCompress(t, o, "http://localhost:8000/",
testCompress(t, o, "http://localhost:8000/",
"This is a non-compress text", "")
}

@@ -74,7 +78,7 @@ func TestCompressStatic(t *testing.T) {
o := New()
o.Use(Compresses([]string{".html"}))
o.Use(ClassicHandlers...)
testCompress(t, o, "http://localhost:8000/public/test.html",
testCompress(t, o, "http://localhost:8000/public/test.html",
"hello tango", "gzip")
}

@@ -119,4 +123,4 @@ func testCompress(t *testing.T, o *Tango, url, content, enc string) {
expect(t, buff.String(), content)
}
expect(t, enc, ce)
}
}

+ 20
- 1
context.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
@@ -128,7 +132,22 @@ func (ctx *Context) Invoke() {
ctx.newAction()
// route is matched
if ctx.action != nil {
ret := ctx.route.method.Call(ctx.callArgs)
var ret []reflect.Value
switch fn := ctx.route.raw.(type) {
case func(*Context):
fn(ctx)
case func(*http.Request, http.ResponseWriter):
fn(ctx.req, ctx.ResponseWriter)
case func():
fn()
case func(*http.Request):
fn(ctx.req)
case func(http.ResponseWriter):
fn(ctx.ResponseWriter)
default:
ret = ctx.route.method.Call(ctx.callArgs)
}

if len(ret) > 0 {
ctx.Result = ret[0].Interface()
}


+ 4
- 0
context_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 4
- 0
cookie.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 4
- 0
cookie_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 2
- 4
doc.go View File

@@ -1,7 +1,5 @@
// package nodb is a high performance embedded NoSQL.
//
// Copyright 2014 lunny. All rights reserved.
// Use of this source code is governed by a BSD
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Tango is a micro & pluggable web framework for Go language.


+ 4
- 0
error.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 4
- 0
error_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 4
- 0
file.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import "path/filepath"


+ 4
- 0
file_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 11
- 7
group.go View File

@@ -1,24 +1,28 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
"reflect"
"path"
"reflect"
)

type groupRouter struct {
methods []string
url string
c interface{}
url string
c interface{}
}

type Group struct {
routers []groupRouter
routers []groupRouter
handlers []Handler
}

func NewGroup() *Group {
return &Group{
routers : make([]groupRouter, 0),
routers: make([]groupRouter, 0),
handlers: make([]Handler, 0),
}
}
@@ -80,7 +84,7 @@ func getGroup(o interface{}) *Group {
var g *Group
if tp == gt {
g = o.(*Group)
} else if tp.Kind() == reflect.Func &&
} else if tp.Kind() == reflect.Func &&
tp.NumIn() == 1 && tp.In(0) == gt {
g = NewGroup()
vc.Call([]reflect.Value{reflect.ValueOf(g)})
@@ -105,4 +109,4 @@ var (

func (t *Tango) Group(p string, o interface{}) {
t.addGroup(p, getGroup(o))
}
}

+ 4
- 0
group_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 4
- 0
logger.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 4
- 0
logger_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 4
- 0
param.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

type (


+ 4
- 0
param_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 10
- 6
pool.go View File

@@ -1,24 +1,28 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
"sync"
"reflect"
"sync"
)

type pool struct {
size int
tp reflect.Type
tp reflect.Type
pool reflect.Value
cur int
cur int
lock sync.Mutex
}

func newPool(size int, tp reflect.Type) *pool {
return &pool{
size: size,
cur: 0,
cur: 0,
pool: reflect.MakeSlice(reflect.SliceOf(tp), size, size),
tp: reflect.SliceOf(tp),
tp: reflect.SliceOf(tp),
}
}

@@ -34,4 +38,4 @@ func (p *pool) New() reflect.Value {
p.cur = 0
}
return p.pool.Index(p.cur).Addr()
}
}

+ 8
- 4
pool_test.go View File

@@ -1,11 +1,15 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

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

type PoolAction struct {
@@ -18,12 +22,12 @@ func (PoolAction) Get() string {
func TestPool(t *testing.T) {
o := Classic()
o.Get("/", new(PoolAction))
var wg sync.WaitGroup
// default pool size is 800
for i:=0; i< 1000; i++ {
for i := 0; i < 1000; i++ {
wg.Add(1)
go func(){
go func() {
buff := bytes.NewBufferString("")
recorder := httptest.NewRecorder()
recorder.Body = buff


+ 4
- 0
prefix.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 7
- 4
prefix_test.go View File

@@ -1,20 +1,24 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

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

type PrefixAction struct{
type PrefixAction struct {
}

func (PrefixAction) Get() string {
return "Prefix"
}

type NoPrefixAction struct{
type NoPrefixAction struct {
}

func (NoPrefixAction) Get() string {
@@ -61,4 +65,3 @@ func TestPrefix(t *testing.T) {
expect(t, buff.String(), "NoPrefix")
expect(t, isPrefix, false)
}


+ 5
- 1
recovery.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
@@ -11,7 +15,7 @@ func Recovery(debug bool) HandlerFunc {
defer func() {
if e := recover(); e != nil {
content := fmt.Sprintf("Handler crashed with error: %v", e)
for i := 1; ;i += 1 {
for i := 1; ; i += 1 {
_, file, line, ok := runtime.Caller(i)
if !ok {
break


+ 6
- 2
recovery_test.go View File

@@ -1,11 +1,15 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

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

func TestRecovery(t *testing.T) {
@@ -28,4 +32,4 @@ func TestRecovery(t *testing.T) {
expect(t, recorder.Code, http.StatusInternalServerError)
refute(t, recorder.Body.Len(), 0)
refute(t, len(buff.String()), 0)
}
}

+ 5
- 1
response.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
@@ -77,4 +81,4 @@ func (rw *responseWriter) Flush() {
if ok {
flusher.Flush()
}
}
}

+ 59
- 53
return.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
@@ -17,12 +21,14 @@ type ResponseTyper interface {
ResponseType() int
}

type Json struct {}
type Json struct{}

func (Json) ResponseType() int {
return JsonResponse
}

type Xml struct {}
type Xml struct{}

func (Xml) ResponseType() int {
return XmlResponse
}
@@ -36,13 +42,13 @@ func isNil(a interface{}) bool {
}

type XmlError struct {
XMLName xml.Name `xml:"err"`
Content string `xml:"content"`
XMLName xml.Name `xml:"err"`
Content string `xml:"content"`
}

type XmlString struct {
XMLName xml.Name `xml:"string"`
Content string `xml:"content"`
XMLName xml.Name `xml:"string"`
Content string `xml:"content"`
}

func Return() HandlerFunc {
@@ -72,31 +78,31 @@ func Return() HandlerFunc {
encoder := json.NewEncoder(ctx)
ctx.Header().Set("Content-Type", "application/json")
switch res := ctx.Result.(type) {
case AbortError:
ctx.WriteHeader(res.Code())
encoder.Encode(map[string]string{
"err": res.Error(),
})
case error:
encoder.Encode(map[string]string{
"err": res.Error(),
})
case string:
case AbortError:
ctx.WriteHeader(res.Code())
encoder.Encode(map[string]string{
"err": res.Error(),
})
case error:
encoder.Encode(map[string]string{
"err": res.Error(),
})
case string:
encoder.Encode(map[string]string{
"content": res,
})
case []byte:
encoder.Encode(map[string]string{
"content": string(res),
})
default:
err := encoder.Encode(ctx.Result)
if err != nil {
ctx.Result = err
encoder.Encode(map[string]string{
"content": res,
"err": err.Error(),
})
case []byte:
encoder.Encode(map[string]string{
"content": string(res),
})
default:
err := encoder.Encode(ctx.Result)
if err != nil {
ctx.Result = err
encoder.Encode(map[string]string{
"err": err.Error(),
})
}
}
}

return
@@ -104,31 +110,31 @@ func Return() HandlerFunc {
encoder := xml.NewEncoder(ctx)
ctx.Header().Set("Content-Type", "application/xml")
switch res := ctx.Result.(type) {
case AbortError:
ctx.WriteHeader(res.Code())
encoder.Encode(XmlError{
Content: res.Error(),
})
case error:
case AbortError:
ctx.WriteHeader(res.Code())
encoder.Encode(XmlError{
Content: res.Error(),
})
case error:
encoder.Encode(XmlError{
Content: res.Error(),
})
case string:
encoder.Encode(XmlString{
Content: res,
})
case []byte:
encoder.Encode(XmlString{
Content: string(res),
})
default:
err := encoder.Encode(ctx.Result)
if err != nil {
ctx.Result = err
encoder.Encode(XmlError{
Content: res.Error(),
Content: err.Error(),
})
case string:
encoder.Encode(XmlString{
Content: res,
})
case []byte:
encoder.Encode(XmlString{
Content: string(res),
})
default:
err := encoder.Encode(ctx.Result)
if err != nil {
ctx.Result = err
encoder.Encode(XmlError{
Content: err.Error(),
})
}
}
}
return
}
@@ -144,4 +150,4 @@ func Return() HandlerFunc {
ctx.Write([]byte(res))
}
}
}
}

+ 24
- 20
return_test.go View File

@@ -1,13 +1,17 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
"bytes"
"encoding/xml"
"errors"
"net/http"
"net/http/httptest"
"testing"
"errors"
"strings"
"encoding/xml"
"testing"
)

type MyReturn struct {
@@ -93,7 +97,7 @@ func TestReturnJson1(t *testing.T) {

o := Classic()
o.Get("/", new(JsonReturn))
req, err := http.NewRequest("GET", "http://localhost:8000/", nil)
if err != nil {
t.Error(err)
@@ -120,7 +124,7 @@ func TestReturnJsonError(t *testing.T) {

o := Classic()
o.Get("/", new(JsonErrReturn))
req, err := http.NewRequest("GET", "http://localhost:8000/", nil)
if err != nil {
t.Error(err)
@@ -147,7 +151,7 @@ func TestReturnJsonError2(t *testing.T) {

o := Classic()
o.Get("/", new(JsonErrReturn2))
req, err := http.NewRequest("GET", "http://localhost:8000/", nil)
if err != nil {
t.Error(err)
@@ -174,7 +178,7 @@ func TestReturnJson2(t *testing.T) {

o := Classic()
o.Get("/", new(JsonReturn1))
req, err := http.NewRequest("GET", "http://localhost:8000/", nil)
if err != nil {
t.Error(err)
@@ -201,7 +205,7 @@ func TestReturnJson3(t *testing.T) {

o := Classic()
o.Get("/", new(JsonReturn2))
req, err := http.NewRequest("GET", "http://localhost:8000/", nil)
if err != nil {
t.Error(err)
@@ -218,18 +222,18 @@ type XmlReturn struct {
}

type Address struct {
City, State string
City, State string
}
type Person struct {
XMLName xml.Name `xml:"person"`
Id int `xml:"id,attr"`
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"`
Age int `xml:"age"`
Height float32 `xml:"height,omitempty"`
Married bool
Address
Comment string `xml:",comment"`
XMLName xml.Name `xml:"person"`
Id int `xml:"id,attr"`
FirstName string `xml:"name>first"`
LastName string `xml:"name>last"`
Age int `xml:"age"`
Height float32 `xml:"height,omitempty"`
Married bool
Address
Comment string `xml:",comment"`
}

func (XmlReturn) Get() interface{} {
@@ -246,7 +250,7 @@ func TestReturnXml(t *testing.T) {

o := Classic()
o.Get("/", new(XmlReturn))
req, err := http.NewRequest("GET", "http://localhost:8000/", nil)
if err != nil {
t.Error(err)
@@ -273,7 +277,7 @@ func TestReturnXmlError(t *testing.T) {

o := Classic()
o.Get("/", new(XmlErrReturn))
req, err := http.NewRequest("GET", "http://localhost:8000/", nil)
if err != nil {
t.Error(err)


+ 6
- 4
router.go View File

@@ -39,18 +39,20 @@ var (

// Route
type Route struct {
raw interface{}
method reflect.Value
routeType RouteType
pool *pool
}

func NewRoute(t reflect.Type,
func NewRoute(v interface{}, t reflect.Type,
method reflect.Value, tp RouteType) *Route {
var pool *pool
if tp == StructRoute || tp == StructPtrRoute {
pool = newPool(PoolSize, t)
}
return &Route{
raw: v,
routeType: tp,
method: method,
pool: pool,
@@ -505,7 +507,7 @@ func (router *router) addFunc(methods []string, url string, c interface{}) {
panic("no support function type")
}

var r = NewRoute(t, vc, rt)
var r = NewRoute(c, t, vc, rt)
url = removeStick(url)
for _, m := range methods {
router.addRoute(m, url, r)
@@ -519,9 +521,9 @@ func (router *router) addStruct(methods map[string]string, url string, c interfa
// added a default method Get, Post
for name, method := range methods {
if m, ok := t.MethodByName(method); ok {
router.addRoute(name, removeStick(url), NewRoute(t, m.Func, StructPtrRoute))
router.addRoute(name, removeStick(url), NewRoute(c, t, m.Func, StructPtrRoute))
} else if m, ok := vc.Type().MethodByName(method); ok {
router.addRoute(name, removeStick(url), NewRoute(t, m.Func, StructRoute))
router.addRoute(name, removeStick(url), NewRoute(c, t, m.Func, StructRoute))
}
}
}

+ 25
- 0
router_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
@@ -710,3 +714,24 @@ func TestRouterMultiple(t *testing.T) {
}
}
}

func TestRouter10(t *testing.T) {
buff := bytes.NewBufferString("")
recorder := httptest.NewRecorder()
recorder.Body = buff

r := New()
r.Get("/", func(ctx *Context) {
ctx.Write([]byte("test"))
})

req, err := http.NewRequest("GET", "http://localhost:8000/", nil)
if err != nil {
t.Error(err)
}

r.ServeHTTP(recorder, req)
expect(t, recorder.Code, http.StatusOK)
expect(t, buff.String(), "test")
refute(t, len(buff.String()), 0)
}

+ 4
- 0
static.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 4
- 0
static_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


+ 5
- 1
tan.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (
@@ -7,7 +11,7 @@ import (
)

func Version() string {
return "0.4.5.0421"
return "0.4.5.0428"
}

type Tango struct {


+ 4
- 0
tan_test.go View File

@@ -1,3 +1,7 @@
// Copyright 2015 The Tango Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tango

import (


Loading…
Cancel
Save