upgrade
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1 +1,5 @@
|
||||
/.vscode
|
||||
.vscode
|
||||
/.idea
|
||||
.idea
|
||||
mfmt
|
||||
|
||||
42
README.md
42
README.md
@@ -1,4 +1,11 @@
|
||||

|
||||
```
|
||||
██████╗ ██████╗ ██████╗ ██╗███╗ ██╗ █████╗ ██████╗ ██╗
|
||||
██╔════╝ ██╔═══██╗ ██╔════╝ ██║████╗ ██║ ██╔══██╗██╔══██╗██║
|
||||
██║ ███╗██║ ██║█████╗██║ ███╗██║██╔██╗ ██║█████╗███████║██████╔╝██║
|
||||
██║ ██║██║ ██║╚════╝██║ ██║██║██║╚██╗██║╚════╝██╔══██║██╔═══╝ ██║
|
||||
╚██████╔╝╚██████╔╝ ╚██████╔╝██║██║ ╚████║ ██║ ██║██║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝
|
||||
```
|
||||
|
||||
## go-gin-api
|
||||
|
||||
@@ -37,12 +44,6 @@
|
||||
- [ ] gRPC
|
||||
- [ ] ...
|
||||
|
||||
## Download
|
||||
|
||||
```
|
||||
git clone https://github.com/xinliangnote/go-gin-api.git
|
||||
```
|
||||
|
||||
## Quick start
|
||||
|
||||
#### Requirements
|
||||
@@ -61,20 +62,12 @@ export GOPROXY=https://goproxy.io
|
||||
cd go-gin-api
|
||||
|
||||
go run main.go
|
||||
|
||||
输出如下,表示 Http Server 启动成功。
|
||||
|-----------------------------------|
|
||||
| go-gin-api |
|
||||
|-----------------------------------|
|
||||
| Go Http Server Start Successful |
|
||||
| Port:9999 Pid:xxxxx |
|
||||
|-----------------------------------|
|
||||
```
|
||||
|
||||
#### HTTP Demo
|
||||
|
||||
```
|
||||
curl -X POST http://127.0.0.1:9999/product
|
||||
curl -X POST http://127.0.0.1:9999/demo/user
|
||||
```
|
||||
|
||||
#### Jaeger Demo
|
||||
@@ -138,22 +131,9 @@ pprof -http=:9998 xxx.cpu.prof
|
||||
http://127.0.0.1:9998/ui/
|
||||
```
|
||||
|
||||
## Dependence
|
||||
## Special Thanks
|
||||
|
||||
- WEB 框架:github.com/gin-gonic/gin
|
||||
- 链路追踪:github.com/jaegertracing/jaeger-client-go
|
||||
- 限流:golang.org/x/time/rate
|
||||
- 工具包:github.com/xinliangnote/go-util
|
||||
|
||||
## Document
|
||||
|
||||
- [1. 使用 go modules 初始化项目](https://mp.weixin.qq.com/s/1XNTEgZ0XGZZdxFOfR5f_A)
|
||||
- [2. 规划项目目录和参数验证](https://mp.weixin.qq.com/s/11AuXptWGmL5QfiJArNLnA)
|
||||
- [3. 路由中间件 - 日志记录](https://mp.weixin.qq.com/s/eTygPXnrYM2xfrRQyfn8Tg)
|
||||
- [4. 路由中间件 - 捕获异常](https://mp.weixin.qq.com/s/SconDXB_x7Gan6T0Awdh9A)
|
||||
- [5. 路由中间件 - Jaeger 链路追踪(理论篇)](https://mp.weixin.qq.com/s/28UBEsLOAHDv530ePilKQA)
|
||||
- [6. 路由中间件 - Jaeger 链路追踪(实战篇)](https://mp.weixin.qq.com/s/Ea28475_UTNaM9RNfgPqJA)
|
||||
- [7. 路由中间件 - 签名验证](https://mp.weixin.qq.com/s/0cozELotcpX3Gd6WPJiBbQ)
|
||||
[@koketama](https://github.com/koketama)
|
||||
|
||||
## Learning together
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package param_bind
|
||||
|
||||
type ProductAdd struct {
|
||||
Name string `form:"name" json:"name" validate:"required,NameValid"`
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package param_verify
|
||||
|
||||
import (
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
)
|
||||
|
||||
func NameValid(fl validator.FieldLevel) bool {
|
||||
val := fl.Field().String()
|
||||
if val == "admin" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/controller/param_bind"
|
||||
"go-gin-api/app/controller/param_verify"
|
||||
"go-gin-api/app/util/bind"
|
||||
"go-gin-api/app/util/response"
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
)
|
||||
|
||||
// 新增
|
||||
func Add(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
|
||||
// 参数绑定
|
||||
s, e := bind.Bind(¶m_bind.ProductAdd{}, c)
|
||||
if e != nil {
|
||||
utilGin.Response(-1, e.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 参数验证
|
||||
validate := validator.New()
|
||||
|
||||
// 注册自定义验证
|
||||
_ = validate.RegisterValidation("NameValid", param_verify.NameValid)
|
||||
|
||||
if err := validate.Struct(s); err != nil {
|
||||
utilGin.Response(-1, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 业务处理...
|
||||
|
||||
utilGin.Response(1, "success", nil)
|
||||
}
|
||||
|
||||
// 编辑
|
||||
func Edit(c *gin.Context) {
|
||||
fmt.Println(c.Request.RequestURI)
|
||||
}
|
||||
|
||||
// 删除
|
||||
func Delete(c *gin.Context) {
|
||||
fmt.Println(c.Request.RequestURI)
|
||||
}
|
||||
|
||||
// 详情
|
||||
|
||||
func Detail(c *gin.Context) {
|
||||
fmt.Println(c.Request.RequestURI)
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
jsonUtil "github.com/xinliangnote/go-util/json"
|
||||
"github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type bodyLogWriter struct {
|
||||
gin.ResponseWriter
|
||||
body *bytes.Buffer
|
||||
}
|
||||
|
||||
var accessChannel = make(chan string, 100)
|
||||
|
||||
func (w bodyLogWriter) Write(b []byte) (int, error) {
|
||||
w.body.Write(b)
|
||||
return w.ResponseWriter.Write(b)
|
||||
}
|
||||
|
||||
func (w bodyLogWriter) WriteString(s string) (int, error) {
|
||||
w.body.WriteString(s)
|
||||
return w.ResponseWriter.WriteString(s)
|
||||
}
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
go handleAccessChannel()
|
||||
|
||||
return func(c *gin.Context) {
|
||||
bodyLogWriter := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
|
||||
c.Writer = bodyLogWriter
|
||||
|
||||
// 开始时间
|
||||
startTime := time.GetCurrentMilliUnix()
|
||||
|
||||
// 处理请求
|
||||
c.Next()
|
||||
|
||||
responseBody := bodyLogWriter.body.String()
|
||||
|
||||
var responseCode int
|
||||
var responseMsg string
|
||||
var responseData interface{}
|
||||
|
||||
if responseBody != "" {
|
||||
res := response.Response{}
|
||||
err := json.Unmarshal([]byte(responseBody), &res)
|
||||
if err == nil {
|
||||
responseCode = res.Code
|
||||
responseMsg = res.Message
|
||||
responseData = res.Data
|
||||
}
|
||||
}
|
||||
|
||||
// 结束时间
|
||||
endTime := time.GetCurrentMilliUnix()
|
||||
|
||||
if c.Request.Method == "POST" {
|
||||
_ = c.Request.ParseForm()
|
||||
}
|
||||
|
||||
// 日志格式
|
||||
accessLogMap := make(map[string]interface{})
|
||||
|
||||
accessLogMap["request_time"] = startTime
|
||||
accessLogMap["request_method"] = c.Request.Method
|
||||
accessLogMap["request_uri"] = c.Request.RequestURI
|
||||
accessLogMap["request_proto"] = c.Request.Proto
|
||||
accessLogMap["request_ua"] = c.Request.UserAgent()
|
||||
accessLogMap["request_referer"] = c.Request.Referer()
|
||||
accessLogMap["request_post_data"] = c.Request.PostForm.Encode()
|
||||
accessLogMap["request_client_ip"] = c.ClientIP()
|
||||
|
||||
accessLogMap["response_time"] = endTime
|
||||
accessLogMap["response_code"] = responseCode
|
||||
accessLogMap["response_msg"] = responseMsg
|
||||
accessLogMap["response_data"] = responseData
|
||||
|
||||
accessLogMap["cost_time"] = fmt.Sprintf("%vms", endTime-startTime)
|
||||
|
||||
accessLogJson, _ := jsonUtil.Encode(accessLogMap)
|
||||
accessChannel <- accessLogJson
|
||||
}
|
||||
}
|
||||
|
||||
func handleAccessChannel() {
|
||||
if f, err := os.OpenFile(config.AppAccessLogName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666); err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
for accessLog := range accessChannel {
|
||||
_, _ = f.WriteString(accessLog + "\n")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/controller/jaeger_conn"
|
||||
"go-gin-api/app/controller/product"
|
||||
"go-gin-api/app/controller/test"
|
||||
"go-gin-api/app/route/middleware/exception"
|
||||
"go-gin-api/app/route/middleware/jaeger"
|
||||
"go-gin-api/app/route/middleware/logger"
|
||||
"go-gin-api/app/util/response"
|
||||
)
|
||||
|
||||
func SetupRouter(engine *gin.Engine) {
|
||||
|
||||
//设置路由中间件
|
||||
engine.Use(logger.SetUp(), exception.SetUp(), jaeger.SetUp())
|
||||
|
||||
//404
|
||||
engine.NoRoute(func(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(404,"请求方法不存在", nil)
|
||||
})
|
||||
|
||||
engine.GET("/ping", func(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1,"pong", nil)
|
||||
})
|
||||
|
||||
// 测试链路追踪
|
||||
engine.GET("/jaeger_test", jaeger_conn.JaegerTest)
|
||||
|
||||
//@todo 记录请求超时的路由
|
||||
|
||||
ProductRouter := engine.Group("/product")
|
||||
{
|
||||
// 新增产品
|
||||
ProductRouter.POST("", product.Add)
|
||||
|
||||
// 更新产品
|
||||
ProductRouter.PUT("/:id", product.Edit)
|
||||
|
||||
// 删除产品
|
||||
ProductRouter.DELETE("/:id", product.Delete)
|
||||
|
||||
// 获取产品详情
|
||||
ProductRouter.GET("/:id", product.Detail)
|
||||
}
|
||||
|
||||
// 测试加密性能
|
||||
TestRouter := engine.Group("/test")
|
||||
{
|
||||
// 测试 MD5 组合 的性能
|
||||
TestRouter.GET("/md5", test.Md5Test)
|
||||
|
||||
// 测试 AES 的性能
|
||||
TestRouter.GET("/aes", test.AesTest)
|
||||
|
||||
// 测试 RSA 的性能
|
||||
TestRouter.GET("/rsa", test.RsaTest)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package bind
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
func Bind(s interface{}, c *gin.Context) (interface{}, error) {
|
||||
b := binding.Default(c.Request.Method, c.ContentType())
|
||||
if err := c.ShouldBindWith(s, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package error
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/xinliangnote/go-util/json"
|
||||
"github.com/xinliangnote/go-util/mail"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/route/middleware/exception"
|
||||
"log"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type errorString struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (e *errorString) Error() string {
|
||||
return e.s
|
||||
}
|
||||
|
||||
func ErrorNew (text string) error {
|
||||
alarm("INFO", text)
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// 发邮件
|
||||
func ErrorMail (text string) error {
|
||||
alarm("MAIL",text)
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// 发短信
|
||||
func ErrorSms (text string) error {
|
||||
alarm("SMS", text)
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// 发微信
|
||||
func ErrorWeChat (text string) error {
|
||||
alarm("WX", text)
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// 告警方法
|
||||
func alarm(level string, str string) {
|
||||
if level == "MAIL" {
|
||||
DebugStack := ""
|
||||
for _, v := range strings.Split(string(debug.Stack()), "\n") {
|
||||
DebugStack += v + "<br>"
|
||||
}
|
||||
|
||||
subject := fmt.Sprintf("【系统告警】%s 项目出错了!", config.AppName)
|
||||
|
||||
body := strings.ReplaceAll(exception.MailTemplate, "{ErrorMsg}", fmt.Sprintf("%s", str))
|
||||
body = strings.ReplaceAll(body, "{RequestTime}", timeUtil.GetCurrentDate())
|
||||
body = strings.ReplaceAll(body, "{RequestURL}", "--")
|
||||
body = strings.ReplaceAll(body, "{RequestUA}", "--")
|
||||
body = strings.ReplaceAll(body, "{RequestIP}", "--")
|
||||
body = strings.ReplaceAll(body, "{DebugStack}", DebugStack)
|
||||
|
||||
// 执行发邮件
|
||||
options := &mail.Options{
|
||||
MailHost : config.SystemEmailHost,
|
||||
MailPort : config.SystemEmailPort,
|
||||
MailUser : config.SystemEmailUser,
|
||||
MailPass : config.SystemEmailPass,
|
||||
MailTo : config.ErrorNotifyUser,
|
||||
Subject : subject,
|
||||
Body : body,
|
||||
}
|
||||
_ = mail.Send(options)
|
||||
|
||||
} else if level == "SMS" {
|
||||
// 执行发短信
|
||||
|
||||
} else if level == "WX" {
|
||||
// 执行发微信
|
||||
|
||||
} else if level == "INFO" {
|
||||
// 执行记日志
|
||||
|
||||
if f, err := os.OpenFile(config.AppErrorLogName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666); err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
errorLogMap := make(map[string]interface{})
|
||||
errorLogMap["time"] = time.Now().Format("2006/01/02 - 15:04:05")
|
||||
errorLogMap["info"] = str
|
||||
|
||||
errorLogJson, _ := json.Encode(errorLogMap)
|
||||
_, _ = f.WriteString(errorLogJson + "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package response
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
type Gin struct {
|
||||
Ctx *gin.Context
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"msg"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func (g *Gin)Response(code int, msg string, data interface{}) {
|
||||
g.Ctx.JSON(200, Response{
|
||||
Code : code,
|
||||
Message : msg,
|
||||
Data : data,
|
||||
})
|
||||
return
|
||||
}
|
||||
3
configs/dev.configs.toml
Normal file
3
configs/dev.configs.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[db]
|
||||
host = '127.0.0.1'
|
||||
port = 3306
|
||||
4
configs/fat_configs.toml
Normal file
4
configs/fat_configs.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[db]
|
||||
host = '127.0.0.1'
|
||||
port = 3306
|
||||
|
||||
4
configs/pro.configs.toml
Normal file
4
configs/pro.configs.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[db]
|
||||
host = '127.0.0.1'
|
||||
port = 3306
|
||||
|
||||
4
configs/uat_configs.toml
Normal file
4
configs/uat_configs.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[db]
|
||||
host = '127.0.0.1'
|
||||
port = 3306
|
||||
|
||||
BIN
favicon.ico
BIN
favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
12
go.mod
12
go.mod
@@ -1,4 +1,4 @@
|
||||
module go-gin-api
|
||||
module github.com/xinliangnote/go-gin-api
|
||||
|
||||
go 1.12
|
||||
|
||||
@@ -6,20 +6,22 @@ require (
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
||||
github.com/gin-contrib/pprof v1.2.1
|
||||
github.com/gin-gonic/gin v1.4.0
|
||||
github.com/go-playground/locales v0.12.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
|
||||
github.com/leodido/go-urn v1.1.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/tidwall/gjson v1.6.6
|
||||
github.com/uber-go/atomic v1.4.0 // indirect
|
||||
github.com/uber/jaeger-client-go v2.18.1+incompatible
|
||||
github.com/uber/jaeger-lib v2.1.1+incompatible // indirect
|
||||
github.com/xinliangnote/go-util v0.0.0-20191115235314-e7d1576d41db
|
||||
go.uber.org/zap v1.16.0
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0
|
||||
google.golang.org/grpc v1.23.1
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
)
|
||||
|
||||
287
go.sum
287
go.sum
@@ -1,63 +1,205 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/pprof v1.2.1 h1:p6mY/FsE3tDx2+Wp3ksrMe1QL5egQ7p+lsZ7WbQLT1U=
|
||||
github.com/gin-contrib/pprof v1.2.1/go.mod h1:u2l4P4YNkLXYz+xBbrl7Pxu1Btng6VCD7j3O3pUPP2w=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
|
||||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tidwall/gjson v1.6.6 h1:Gh0D/kZV+L9rcuE2hE8Hn2dTYe2L6j6SKwcPlKpXAcs=
|
||||
github.com/tidwall/gjson v1.6.6/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
|
||||
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
|
||||
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/uber-go/atomic v1.4.0 h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o=
|
||||
github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
|
||||
github.com/uber/jaeger-client-go v2.18.1+incompatible h1:bI1w1jRSWBswo6LhGdqA2SbFQX/TSVleZhMty4IJ78A=
|
||||
@@ -66,64 +208,167 @@ github.com/uber/jaeger-lib v2.1.1+incompatible h1:VY/6p2WopO09BPnw787RbaCIlfKbCR
|
||||
github.com/uber/jaeger-lib v2.1.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xinliangnote/go-util v0.0.0-20191115235314-e7d1576d41db h1:yReVDmqk6oBUOcSRUofahYHJlIwr7wrJ8yx1Ymkz84E=
|
||||
github.com/xinliangnote/go-util v0.0.0-20191115235314-e7d1576d41db/go.mod h1:3ZornrplU9tYj9ar9jchik1XPQ10ZbSXkbgxXR5PVaU=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
|
||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
package config
|
||||
|
||||
var (
|
||||
ApiAuthConfig = map[string] map[string]string {
|
||||
ApiAuthConfig = map[string]map[string]string{
|
||||
|
||||
// 调用方
|
||||
"DEMO" : {
|
||||
"md5" : "IgkibX71IEf382PT",
|
||||
"aes" : "IgkibX71IEf382PT",
|
||||
"rsa" : "rsa/public.pem",
|
||||
"DEMO": {
|
||||
"md5": "IgkibX71IEf382PT",
|
||||
"aes": "IgkibX71IEf382PT",
|
||||
"rsa": "rsa/public.pem",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
AppMode = "release" //debug or release
|
||||
AppPort = ":9999"
|
||||
AppName = "go-gin-api"
|
||||
|
||||
// 签名超时时间
|
||||
@@ -23,14 +21,9 @@ const (
|
||||
// RSA Private File
|
||||
AppRsaPrivateFile = "rsa/private.pem"
|
||||
|
||||
// 超时时间
|
||||
AppReadTimeout = 120
|
||||
AppWriteTimeout = 120
|
||||
|
||||
// 日志文件
|
||||
AppAccessLogName = "log/" + AppName + "-access.log"
|
||||
AppErrorLogName = "log/" + AppName + "-error.log"
|
||||
AppGrpcLogName = "log/" + AppName + "-grpc.log"
|
||||
AppErrorLogName = "log/" + AppName + "-error.log"
|
||||
AppGrpcLogName = "log/" + AppName + "-grpc.log"
|
||||
|
||||
// 系统告警邮箱信息
|
||||
SystemEmailUser = "xinliangnote@163.com"
|
||||
@@ -45,7 +38,7 @@ const (
|
||||
ErrorNotifyOpen = -1
|
||||
|
||||
// Jaeger 配置信息
|
||||
JaegerHostPort = "127.0.0.1:6831"
|
||||
JaegerHostPort = "172.20.2.212:6831"
|
||||
|
||||
// Jaeger 配置开关 1=开通 -1=关闭
|
||||
JaegerOpen = 1
|
||||
118
internal/api/controller/demo/demo.go
Normal file
118
internal/api/controller/demo/demo.go
Normal file
@@ -0,0 +1,118 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/jsonparse"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Demo struct {
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func NewDemo(logger *zap.Logger) *Demo {
|
||||
return &Demo{
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Demo) Get() core.HandlerFunc {
|
||||
type request struct {
|
||||
Name string `uri:"name"`
|
||||
}
|
||||
|
||||
type response struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Job string `json:"job"`
|
||||
}
|
||||
|
||||
return func(c core.Context) {
|
||||
req := new(request)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.SetPayload(errno.ErrParam)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "Tom" {
|
||||
c.SetPayload(errno.ErrUser)
|
||||
return
|
||||
}
|
||||
|
||||
c.SetPayload(errno.OK.WithData(&response{
|
||||
Name: "Tom",
|
||||
Job: "Student",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Demo) Post() core.HandlerFunc {
|
||||
type request struct {
|
||||
Name string `form:"name"`
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Name string `json:"name"`
|
||||
Job string `json:"job"`
|
||||
}
|
||||
|
||||
return func(c core.Context) {
|
||||
req := new(request)
|
||||
if err := c.ShouldBindPostForm(req); err != nil {
|
||||
c.SetPayload(errno.ErrParam)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "Jack" {
|
||||
c.SetPayload(errno.ErrUser)
|
||||
return
|
||||
}
|
||||
|
||||
c.SetPayload(errno.OK.WithData(&response{
|
||||
Name: "Jack",
|
||||
Job: "Teacher",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Demo) User() core.HandlerFunc {
|
||||
|
||||
type response []struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
return func(c core.Context) {
|
||||
body1, err1 := httpclient.Get("http://127.0.0.1:9999/demo/get/Tom", nil,
|
||||
httpclient.WithTTL(time.Second*2),
|
||||
httpclient.WithJournal(c.Journal()),
|
||||
httpclient.WithLogger(c.Logger()),
|
||||
)
|
||||
if err1 != nil {
|
||||
d.logger.Error("get [demo/get] err", zap.Error(err1))
|
||||
}
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("name", "Jack")
|
||||
body2, err2 := httpclient.PostForm("http://127.0.0.1:9999/demo/post", params,
|
||||
httpclient.WithTTL(time.Second*2),
|
||||
httpclient.WithJournal(c.Journal()),
|
||||
httpclient.WithLogger(c.Logger()),
|
||||
)
|
||||
if err2 != nil {
|
||||
d.logger.Error("post [demo/post] err", zap.Error(err2))
|
||||
}
|
||||
|
||||
data := &response{
|
||||
{Name: jsonparse.Get(string(body1), "data.name").(string)},
|
||||
{Name: jsonparse.Get(string(body2), "data.name").(string)},
|
||||
}
|
||||
|
||||
c.SetPayload(errno.OK.WithData(data))
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,16 @@ package jaeger_conn
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/model/proto/listen"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/model/proto/read"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/model/proto/speak"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/model/proto/write"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/grpc_client"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/request"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/model/proto/listen"
|
||||
"go-gin-api/app/model/proto/read"
|
||||
"go-gin-api/app/model/proto/speak"
|
||||
"go-gin-api/app/model/proto/write"
|
||||
"go-gin-api/app/util/grpc_client"
|
||||
"go-gin-api/app/util/request"
|
||||
"go-gin-api/app/util/response"
|
||||
)
|
||||
|
||||
func JaegerTest(c *gin.Context) {
|
||||
@@ -46,12 +48,11 @@ func JaegerTest(c *gin.Context) {
|
||||
// 业务处理...
|
||||
|
||||
msg := resListen.Message + "-" +
|
||||
resSpeak.Message + "-" +
|
||||
resRead.Message + "-" +
|
||||
resWrite.Message + "-" +
|
||||
resHttpGet
|
||||
resSpeak.Message + "-" +
|
||||
resRead.Message + "-" +
|
||||
resWrite.Message + "-" +
|
||||
resHttpGet
|
||||
|
||||
|
||||
utilGin := response.Gin{Ctx:c}
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1, msg, nil)
|
||||
}
|
||||
@@ -2,19 +2,21 @@ package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/errno"
|
||||
|
||||
"github.com/xinliangnote/go-util/aes"
|
||||
"github.com/xinliangnote/go-util/md5"
|
||||
"github.com/xinliangnote/go-util/rsa"
|
||||
"go-gin-api/app/util/response"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Md5Test(c *gin.Context) {
|
||||
startTime := time.Now()
|
||||
appSecret := "IgkibX71IEf382PT"
|
||||
func Md5Test(c core.Context) {
|
||||
startTime := time.Now()
|
||||
appSecret := "IgkibX71IEf382PT"
|
||||
encryptStr := "param_1=xxx¶m_2=xxx&ak=xxx&ts=1111111111"
|
||||
count := 1000000
|
||||
count := 1000000
|
||||
for i := 0; i < count; i++ {
|
||||
// 生成签名
|
||||
md5.MD5(appSecret + encryptStr + appSecret)
|
||||
@@ -22,15 +24,14 @@ func Md5Test(c *gin.Context) {
|
||||
// 验证签名
|
||||
md5.MD5(appSecret + encryptStr + appSecret)
|
||||
}
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1, fmt.Sprintf("%v次 - %v", count, time.Since(startTime)), nil)
|
||||
c.SetPayload(errno.OK.WithData(fmt.Sprintf("%v次 - %v", count, time.Since(startTime))))
|
||||
}
|
||||
|
||||
func AesTest(c *gin.Context) {
|
||||
startTime := time.Now()
|
||||
appSecret := "IgkibX71IEf382PT"
|
||||
func AesTest(c core.Context) {
|
||||
startTime := time.Now()
|
||||
appSecret := "IgkibX71IEf382PT"
|
||||
encryptStr := "param_1=xxx¶m_2=xxx&ak=xxx&ts=1111111111"
|
||||
count := 1000000
|
||||
count := 1000000
|
||||
for i := 0; i < count; i++ {
|
||||
// 生成签名
|
||||
sn, _ := aes.Encrypt(encryptStr, []byte(appSecret), appSecret)
|
||||
@@ -38,14 +39,13 @@ func AesTest(c *gin.Context) {
|
||||
// 验证签名
|
||||
aes.Decrypt(sn, []byte(appSecret), appSecret)
|
||||
}
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1, fmt.Sprintf("%v次 - %v", count, time.Since(startTime)), nil)
|
||||
c.SetPayload(errno.OK.WithData(fmt.Sprintf("%v次 - %v", count, time.Since(startTime))))
|
||||
}
|
||||
|
||||
func RsaTest(c *gin.Context) {
|
||||
startTime := time.Now()
|
||||
func RsaTest(c core.Context) {
|
||||
startTime := time.Now()
|
||||
encryptStr := "param_1=xxx¶m_2=xxx&ak=xxx&ts=1111111111"
|
||||
count := 500
|
||||
count := 500
|
||||
for i := 0; i < count; i++ {
|
||||
// 生成签名
|
||||
sn, _ := rsa.PublicEncrypt(encryptStr, "rsa/public.pem")
|
||||
@@ -53,6 +53,5 @@ func RsaTest(c *gin.Context) {
|
||||
// 验证签名
|
||||
rsa.PrivateDecrypt(sn, "rsa/private.pem")
|
||||
}
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1, fmt.Sprintf("%v次 - %v", count, time.Since(startTime)), nil)
|
||||
c.SetPayload(errno.OK.WithData(fmt.Sprintf("%v次 - %v", count, time.Since(startTime))))
|
||||
}
|
||||
@@ -6,11 +6,12 @@ package listen
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -6,11 +6,12 @@ package read
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -6,11 +6,12 @@ package speak
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -6,11 +6,12 @@ package write
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -2,13 +2,15 @@ package exception
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/mail"
|
||||
"github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
@@ -25,20 +27,20 @@ func SetUp() gin.HandlerFunc {
|
||||
subject := fmt.Sprintf("【重要错误】%s 项目出错了!", config.AppName)
|
||||
|
||||
body := strings.ReplaceAll(MailTemplate, "{ErrorMsg}", fmt.Sprintf("%s", err))
|
||||
body = strings.ReplaceAll(body, "{RequestTime}", time.GetCurrentDate())
|
||||
body = strings.ReplaceAll(body, "{RequestURL}", c.Request.Method + " " + c.Request.Host + c.Request.RequestURI)
|
||||
body = strings.ReplaceAll(body, "{RequestUA}", c.Request.UserAgent())
|
||||
body = strings.ReplaceAll(body, "{RequestIP}", c.ClientIP())
|
||||
body = strings.ReplaceAll(body, "{DebugStack}", DebugStack)
|
||||
body = strings.ReplaceAll(body, "{RequestTime}", time.GetCurrentDate())
|
||||
body = strings.ReplaceAll(body, "{RequestURL}", c.Request.Method+" "+c.Request.Host+c.Request.RequestURI)
|
||||
body = strings.ReplaceAll(body, "{RequestUA}", c.Request.UserAgent())
|
||||
body = strings.ReplaceAll(body, "{RequestIP}", c.ClientIP())
|
||||
body = strings.ReplaceAll(body, "{DebugStack}", DebugStack)
|
||||
|
||||
options := &mail.Options{
|
||||
MailHost : config.SystemEmailHost,
|
||||
MailPort : config.SystemEmailPort,
|
||||
MailUser : config.SystemEmailUser,
|
||||
MailPass : config.SystemEmailPass,
|
||||
MailTo : config.ErrorNotifyUser,
|
||||
Subject : subject,
|
||||
Body : body,
|
||||
MailHost: config.SystemEmailHost,
|
||||
MailPort: config.SystemEmailPort,
|
||||
MailUser: config.SystemEmailUser,
|
||||
MailPass: config.SystemEmailPass,
|
||||
MailTo: config.ErrorNotifyUser,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
}
|
||||
_ = mail.Send(options)
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package jaeger
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/jaeger_trace"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/jaeger_trace"
|
||||
)
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
@@ -15,7 +16,7 @@ func SetUp() gin.HandlerFunc {
|
||||
|
||||
var parentSpan opentracing.Span
|
||||
|
||||
tracer, closer := jaeger_trace.NewJaegerTracer(config.AppName, config.JaegerHostPort)
|
||||
tracer, closer := jaeger_trace.NewJaegerTracer("LXL-TEST", config.JaegerHostPort)
|
||||
defer closer.Close()
|
||||
|
||||
spCtx, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(c.Request.Header))
|
||||
@@ -1,14 +1,16 @@
|
||||
package limiter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/util/response"
|
||||
"golang.org/x/time/rate"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/errno"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
func SetUp (maxBurstSize int) gin.HandlerFunc {
|
||||
func SetUp(maxBurstSize int) gin.HandlerFunc {
|
||||
|
||||
limiter := rate.NewLimiter(rate.Every(time.Second*1), maxBurstSize)
|
||||
return func(c *gin.Context) {
|
||||
@@ -16,9 +18,7 @@ func SetUp (maxBurstSize int) gin.HandlerFunc {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
fmt.Println("Too many requests")
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(-1, "Too many requests", nil)
|
||||
c.JSON(http.StatusOK, errno.ErrManyRequest)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
@@ -3,16 +3,18 @@ package sign_aes
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/aes"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/aes"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
)
|
||||
|
||||
var AppSecret string
|
||||
@@ -44,11 +46,11 @@ func SetUp() gin.HandlerFunc {
|
||||
// 验证签名
|
||||
func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
_ = c.Request.ParseForm()
|
||||
req := c.Request.Form
|
||||
req := c.Request.Form
|
||||
debug := strings.Join(c.Request.Form["debug"], "")
|
||||
ak := strings.Join(c.Request.Form["ak"], "")
|
||||
sn := strings.Join(c.Request.Form["sn"], "")
|
||||
ts := strings.Join(c.Request.Form["ts"], "")
|
||||
ak := strings.Join(c.Request.Form["ak"], "")
|
||||
sn := strings.Join(c.Request.Form["sn"], "")
|
||||
ts := strings.Join(c.Request.Form["ts"], "")
|
||||
|
||||
// 验证来源
|
||||
value, ok := config.ApiAuthConfig[ak]
|
||||
@@ -76,9 +78,9 @@ func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
|
||||
// 验证过期时间
|
||||
timestamp := time.Now().Unix()
|
||||
exp, _ := strconv.ParseInt(config.AppSignExpiry, 10, 64)
|
||||
tsInt, _ := strconv.ParseInt(ts, 10, 64)
|
||||
if tsInt > timestamp || timestamp - tsInt >= exp {
|
||||
exp, _ := strconv.ParseInt(config.AppSignExpiry, 10, 64)
|
||||
tsInt, _ := strconv.ParseInt(ts, 10, 64)
|
||||
if tsInt > timestamp || timestamp-tsInt >= exp {
|
||||
return nil, errors.New("ts Error")
|
||||
}
|
||||
|
||||
@@ -3,16 +3,18 @@ package sign_md5
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/md5"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/md5"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
)
|
||||
|
||||
var AppSecret string
|
||||
@@ -44,11 +46,11 @@ func SetUp() gin.HandlerFunc {
|
||||
// 验证签名
|
||||
func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
_ = c.Request.ParseForm()
|
||||
req := c.Request.Form
|
||||
req := c.Request.Form
|
||||
debug := strings.Join(c.Request.Form["debug"], "")
|
||||
ak := strings.Join(c.Request.Form["ak"], "")
|
||||
sn := strings.Join(c.Request.Form["sn"], "")
|
||||
ts := strings.Join(c.Request.Form["ts"], "")
|
||||
ak := strings.Join(c.Request.Form["ak"], "")
|
||||
sn := strings.Join(c.Request.Form["sn"], "")
|
||||
ts := strings.Join(c.Request.Form["ts"], "")
|
||||
|
||||
// 验证来源
|
||||
value, ok := config.ApiAuthConfig[ak]
|
||||
@@ -70,9 +72,9 @@ func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
|
||||
// 验证过期时间
|
||||
timestamp := time.Now().Unix()
|
||||
exp, _ := strconv.ParseInt(config.AppSignExpiry, 10, 64)
|
||||
tsInt, _ := strconv.ParseInt(ts, 10, 64)
|
||||
if tsInt > timestamp || timestamp - tsInt >= exp {
|
||||
exp, _ := strconv.ParseInt(config.AppSignExpiry, 10, 64)
|
||||
tsInt, _ := strconv.ParseInt(ts, 10, 64)
|
||||
if tsInt > timestamp || timestamp-tsInt >= exp {
|
||||
return nil, errors.New("ts Error")
|
||||
}
|
||||
|
||||
@@ -3,16 +3,18 @@ package sign_rsa
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/rsa"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/rsa"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
)
|
||||
|
||||
var AppSecret string
|
||||
@@ -44,11 +46,11 @@ func SetUp() gin.HandlerFunc {
|
||||
// 验证签名
|
||||
func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
_ = c.Request.ParseForm()
|
||||
req := c.Request.Form
|
||||
req := c.Request.Form
|
||||
debug := strings.Join(c.Request.Form["debug"], "")
|
||||
ak := strings.Join(c.Request.Form["ak"], "")
|
||||
sn := strings.Join(c.Request.Form["sn"], "")
|
||||
ts := strings.Join(c.Request.Form["ts"], "")
|
||||
ak := strings.Join(c.Request.Form["ak"], "")
|
||||
sn := strings.Join(c.Request.Form["sn"], "")
|
||||
ts := strings.Join(c.Request.Form["ts"], "")
|
||||
|
||||
// 验证来源
|
||||
value, ok := config.ApiAuthConfig[ak]
|
||||
@@ -76,9 +78,9 @@ func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
|
||||
// 验证过期时间
|
||||
timestamp := time.Now().Unix()
|
||||
exp, _ := strconv.ParseInt(config.AppSignExpiry, 10, 64)
|
||||
tsInt, _ := strconv.ParseInt(ts, 10, 64)
|
||||
if tsInt > timestamp || timestamp - tsInt >= exp {
|
||||
exp, _ := strconv.ParseInt(config.AppSignExpiry, 10, 64)
|
||||
tsInt, _ := strconv.ParseInt(ts, 10, 64)
|
||||
if tsInt > timestamp || timestamp-tsInt >= exp {
|
||||
return nil, errors.New("ts Error")
|
||||
}
|
||||
|
||||
60
internal/api/router/router.go
Normal file
60
internal/api/router/router.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/demo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func NewHTTPMux(logger *zap.Logger) (core.Mux, error) {
|
||||
|
||||
if logger == nil {
|
||||
return nil, errors.New("logger required")
|
||||
}
|
||||
|
||||
mux, err := core.New(logger,
|
||||
core.WithEnableCors(),
|
||||
core.WithDisablePProf(),
|
||||
core.WithPanicNotify(notify.Email),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//设置路由中间件
|
||||
//engine.Use(exception.SetUp(), jaeger.SetUp())
|
||||
|
||||
demoHandler := demo.NewDemo(logger)
|
||||
|
||||
d := mux.Group("/demo")
|
||||
{
|
||||
d.GET("user", demoHandler.User())
|
||||
|
||||
// 模拟数据
|
||||
d.GET("get/:name", demoHandler.Get(), core.DisableJournal)
|
||||
d.POST("post", demoHandler.Post(), core.DisableJournal)
|
||||
|
||||
}
|
||||
|
||||
// 测试链路追踪
|
||||
//mux.GET("/jaeger_test", jaeger_conn.JaegerTest)
|
||||
|
||||
// 测试加密性能
|
||||
//TestRouter := mux.Group("/test")
|
||||
//{
|
||||
// // 测试 MD5 组合 的性能
|
||||
// TestRouter.GET("/md5", core.Handle(test.Md5Test))
|
||||
//
|
||||
// // 测试 AES 的性能
|
||||
// TestRouter.GET("/aes", core.Handle(test.AesTest))
|
||||
//
|
||||
// // 测试 RSA 的性能
|
||||
// TestRouter.GET("/rsa", core.Handle(test.RsaTest))
|
||||
//}
|
||||
|
||||
return mux, nil
|
||||
}
|
||||
@@ -3,14 +3,16 @@ package grpc_client
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/grpc_log"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/util/jaeger_trace"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
grpc_middeware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/grpc_log"
|
||||
"go-gin-api/app/util/jaeger_trace"
|
||||
"google.golang.org/grpc"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CreateServiceListenConn(c *gin.Context) *grpc.ClientConn {
|
||||
@@ -34,12 +36,12 @@ func createGrpcConn(serviceAddress string, c *gin.Context) *grpc.ClientConn {
|
||||
var conn *grpc.ClientConn
|
||||
var err error
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond * 500)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*500)
|
||||
defer cancel()
|
||||
|
||||
if config.JaegerOpen == 1 {
|
||||
|
||||
tracer, _ := c.Get("Tracer")
|
||||
tracer, _ := c.Get("Tracer")
|
||||
parentSpanContext, _ := c.Get("ParentSpanContext")
|
||||
|
||||
conn, err = grpc.DialContext(
|
||||
@@ -3,12 +3,14 @@ package grpc_log
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/xinliangnote/go-util/json"
|
||||
"github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"google.golang.org/grpc"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
|
||||
"github.com/xinliangnote/go-util/json"
|
||||
"github.com/xinliangnote/go-util/time"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var grpcChannel = make(chan string, 100)
|
||||
@@ -32,11 +34,11 @@ func ClientInterceptor() grpc.UnaryClientInterceptor {
|
||||
// 日志格式
|
||||
grpcLogMap := make(map[string]interface{})
|
||||
|
||||
grpcLogMap["request_time"] = startTime
|
||||
grpcLogMap["request_data"] = req
|
||||
grpcLogMap["request_time"] = startTime
|
||||
grpcLogMap["request_data"] = req
|
||||
grpcLogMap["request_method"] = method
|
||||
|
||||
grpcLogMap["response_data"] = reply
|
||||
grpcLogMap["response_data"] = reply
|
||||
grpcLogMap["response_error"] = err
|
||||
|
||||
grpcLogMap["cost_time"] = fmt.Sprintf("%vms", endTime-startTime)
|
||||
@@ -3,6 +3,9 @@ package jaeger_trace
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"github.com/opentracing/opentracing-go/log"
|
||||
@@ -10,21 +13,19 @@ import (
|
||||
jaegerConfig "github.com/uber/jaeger-client-go/config"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewJaegerTracer(serviceName string, jaegerHostPort string) (opentracing.Tracer, io.Closer) {
|
||||
|
||||
cfg := &jaegerConfig.Configuration {
|
||||
cfg := &jaegerConfig.Configuration{
|
||||
Sampler: &jaegerConfig.SamplerConfig{
|
||||
Type : "const", //固定采样
|
||||
Param : 1, //1=全采样、0=不采样
|
||||
Type: "const", //固定采样
|
||||
Param: 1, //1=全采样、0=不采样
|
||||
},
|
||||
|
||||
Reporter: &jaegerConfig.ReporterConfig{
|
||||
LogSpans : true,
|
||||
LocalAgentHostPort : jaegerHostPort,
|
||||
LogSpans: true,
|
||||
LocalAgentHostPort: jaegerHostPort,
|
||||
},
|
||||
|
||||
ServiceName: serviceName,
|
||||
@@ -2,35 +2,37 @@ package request
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"go-gin-api/app/config"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/config"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
)
|
||||
|
||||
func HttpGet(url string, c *gin.Context) (string, error) {
|
||||
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig : &tls.Config{InsecureSkipVerify: true},
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Timeout : time.Second * 5, //默认5秒超时时间
|
||||
Transport : tr,
|
||||
Timeout: time.Second * 5, //默认5秒超时时间
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url,nil)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if config.JaegerOpen == 1 {
|
||||
|
||||
tracer, _ := c.Get("Tracer")
|
||||
tracer, _ := c.Get("Tracer")
|
||||
parentSpanContext, _ := c.Get("ParentSpanContext")
|
||||
|
||||
span := opentracing.StartSpan(
|
||||
@@ -48,7 +50,7 @@ func HttpGet(url string, c *gin.Context) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
resp ,err := client.Do(req)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
22
internal/api/util/response/response.go
Normal file
22
internal/api/util/response/response.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package response
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
type Gin struct {
|
||||
Ctx *gin.Context
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"msg"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func (g *Gin) Response(code int, msg string, data interface{}) {
|
||||
g.Ctx.JSON(200, Response{
|
||||
Code: code,
|
||||
Message: msg,
|
||||
Data: data,
|
||||
})
|
||||
return
|
||||
}
|
||||
43
internal/pkg/configs/configs.go
Normal file
43
internal/pkg/configs/configs.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var config = new(Config)
|
||||
|
||||
type Config struct {
|
||||
DB struct {
|
||||
Host string `mapstructure:"host"`
|
||||
Port int `mapstructure:"port"`
|
||||
} `mapstructure:"db"`
|
||||
|
||||
Signature struct {
|
||||
Secrets map[string]string `mapstructure:"secrets"`
|
||||
} `mapstructure:"signature"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
viper.SetConfigName(env.Active().Value() + "_configs")
|
||||
viper.SetConfigType("toml")
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("./configs")
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := viper.Unmarshal(config); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Get() Config {
|
||||
return *config
|
||||
}
|
||||
|
||||
func ProjectName() string {
|
||||
return "go-gin-api"
|
||||
}
|
||||
240
internal/pkg/core/context.go
Normal file
240
internal/pkg/core/context.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/journal"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type HandlerFunc func(c Context)
|
||||
|
||||
type Journal = journal.T
|
||||
|
||||
const (
|
||||
_JournalName = "_journal_"
|
||||
_LoggerName = "_logger_"
|
||||
_BodyName = "_body_"
|
||||
_PayloadName = "_payload_"
|
||||
)
|
||||
|
||||
var contextPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(context)
|
||||
},
|
||||
}
|
||||
|
||||
func newContext(ctx *gin.Context) Context {
|
||||
context := contextPool.Get().(*context)
|
||||
context.ctx = ctx
|
||||
return context
|
||||
}
|
||||
|
||||
func releaseContext(ctx Context) {
|
||||
c := ctx.(*context)
|
||||
c.ctx = nil
|
||||
contextPool.Put(c)
|
||||
}
|
||||
|
||||
var _ Context = (*context)(nil)
|
||||
|
||||
type Context interface {
|
||||
init()
|
||||
|
||||
// ShouldBindQuery 反序列化querystring
|
||||
// tag: `form:"xxx"` (注:不要写成query)
|
||||
ShouldBindQuery(obj interface{}) error
|
||||
|
||||
// ShouldBindPostForm 反序列化postform(querystring会被忽略)
|
||||
// tag: `form:"xxx"`
|
||||
ShouldBindPostForm(obj interface{}) error
|
||||
|
||||
// ShouldBindForm 同时反序列化querystring和postform;
|
||||
// 当querystring和postform存在相同字段时,postform优先使用。
|
||||
// tag: `form:"xxx"`
|
||||
ShouldBindForm(obj interface{}) error
|
||||
|
||||
// ShouldBindJSON 反序列化postjson
|
||||
// tag: `json:"xxx"`
|
||||
ShouldBindJSON(obj interface{}) error
|
||||
|
||||
// ShouldBindURI 反序列化path参数(如路由路径为 /user/:name)
|
||||
// tag: `uri:"xxx"`
|
||||
ShouldBindURI(obj interface{}) error
|
||||
|
||||
// Redirect 重定向
|
||||
Redirect(code int, location string)
|
||||
|
||||
Journal() Journal
|
||||
setJournal(journal Journal)
|
||||
disableJournal()
|
||||
|
||||
Logger() *zap.Logger
|
||||
setLogger(logger *zap.Logger)
|
||||
|
||||
GetPayload() interface{}
|
||||
SetPayload(payload errno.Error)
|
||||
|
||||
Header() http.Header
|
||||
GetHeader(key string) string
|
||||
SetHeader(key, value string)
|
||||
|
||||
RawData() []byte
|
||||
|
||||
Method() string
|
||||
|
||||
Host() string
|
||||
|
||||
Path() string
|
||||
|
||||
URI() string
|
||||
}
|
||||
|
||||
type context struct {
|
||||
ctx *gin.Context
|
||||
}
|
||||
|
||||
func (c *context) init() {
|
||||
body, err := c.ctx.GetRawData()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.ctx.Set(_BodyName, body) // cache body是为了journal使用
|
||||
c.ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // re-construct req body
|
||||
}
|
||||
|
||||
// ShouldBindQuery 反序列化querystring
|
||||
// tag: `form:"xxx"` (注:不要写成query)
|
||||
func (c *context) ShouldBindQuery(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.Query)
|
||||
}
|
||||
|
||||
// ShouldBindPostForm 反序列化postform(querystring会被忽略)
|
||||
// tag: `form:"xxx"`
|
||||
func (c *context) ShouldBindPostForm(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.FormPost)
|
||||
}
|
||||
|
||||
// ShouldBindForm 同时反序列化querystring和postform;
|
||||
// 当querystring和postform存在相同字段时,postform优先使用。
|
||||
// tag: `form:"xxx"`
|
||||
func (c *context) ShouldBindForm(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.Form)
|
||||
}
|
||||
|
||||
// ShouldBindJSON 反序列化postjson
|
||||
// tag: `json:"xxx"`
|
||||
func (c *context) ShouldBindJSON(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.JSON)
|
||||
}
|
||||
|
||||
// ShouldBindURI 反序列化path参数(如路由路径为 /user/:name)
|
||||
// tag: `uri:"xxx"`
|
||||
func (c *context) ShouldBindURI(obj interface{}) error {
|
||||
return c.ctx.ShouldBindUri(obj)
|
||||
}
|
||||
|
||||
// Redirect 重定向
|
||||
func (c *context) Redirect(code int, location string) {
|
||||
c.ctx.Redirect(code, location)
|
||||
}
|
||||
|
||||
func (c *context) Journal() Journal {
|
||||
j, ok := c.ctx.Get(_JournalName)
|
||||
if !ok || j == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return j.(Journal)
|
||||
}
|
||||
|
||||
func (c *context) setJournal(journal Journal) {
|
||||
c.ctx.Set(_JournalName, journal)
|
||||
}
|
||||
|
||||
func (c *context) disableJournal() {
|
||||
c.setJournal(nil)
|
||||
}
|
||||
|
||||
func (c *context) Logger() *zap.Logger {
|
||||
logger, ok := c.ctx.Get(_LoggerName)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return logger.(*zap.Logger)
|
||||
}
|
||||
|
||||
func (c *context) setLogger(logger *zap.Logger) {
|
||||
c.ctx.Set(_LoggerName, logger)
|
||||
}
|
||||
|
||||
func (c *context) GetPayload() interface{} {
|
||||
payload, _ := c.ctx.Get(_PayloadName)
|
||||
return payload
|
||||
}
|
||||
|
||||
func (c *context) SetPayload(payload errno.Error) {
|
||||
payload.WithID(c.Journal().ID())
|
||||
c.ctx.Set(_PayloadName, payload)
|
||||
}
|
||||
|
||||
func (c *context) Header() http.Header {
|
||||
header := c.ctx.Request.Header
|
||||
|
||||
clone := make(http.Header, len(header))
|
||||
for k, v := range header {
|
||||
value := make([]string, len(v))
|
||||
copy(value, v)
|
||||
|
||||
clone[k] = value
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
func (c *context) GetHeader(key string) string {
|
||||
return c.ctx.GetHeader(key)
|
||||
}
|
||||
|
||||
func (c *context) SetHeader(key, value string) {
|
||||
c.ctx.Header(key, value)
|
||||
}
|
||||
|
||||
func (c *context) RawData() []byte {
|
||||
body, ok := c.ctx.Get(_BodyName)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return body.([]byte)
|
||||
}
|
||||
|
||||
// Method 请求的method
|
||||
func (c *context) Method() string {
|
||||
return c.ctx.Request.Method
|
||||
}
|
||||
|
||||
// Host 请求的host
|
||||
func (c *context) Host() string {
|
||||
return c.ctx.Request.Host
|
||||
}
|
||||
|
||||
// Path 请求的路径(不附带querystring)
|
||||
func (c *context) Path() string {
|
||||
return c.ctx.Request.URL.Path
|
||||
}
|
||||
|
||||
// URI unescape后的uri
|
||||
func (c *context) URI() string {
|
||||
uri, _ := url.QueryUnescape(c.ctx.Request.URL.RequestURI())
|
||||
return uri
|
||||
}
|
||||
332
internal/pkg/core/core.go
Normal file
332
internal/pkg/core/core.go
Normal file
@@ -0,0 +1,332 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/journal"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/color"
|
||||
|
||||
"github.com/gin-contrib/pprof"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pkg/errors"
|
||||
cors "github.com/rs/cors/wrapper/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const _CLI_UI_ = `
|
||||
██████╗ ██████╗ ██████╗ ██╗███╗ ██╗ █████╗ ██████╗ ██╗
|
||||
██╔════╝ ██╔═══██╗ ██╔════╝ ██║████╗ ██║ ██╔══██╗██╔══██╗██║
|
||||
██║ ███╗██║ ██║█████╗██║ ███╗██║██╔██╗ ██║█████╗███████║██████╔╝██║
|
||||
██║ ██║██║ ██║╚════╝██║ ██║██║██║╚██╗██║╚════╝██╔══██║██╔═══╝ ██║
|
||||
╚██████╔╝╚██████╔╝ ╚██████╔╝██║██║ ╚████║ ██║ ██║██║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝
|
||||
`
|
||||
|
||||
type Option func(*option)
|
||||
|
||||
type option struct {
|
||||
disablePProf bool
|
||||
disablePrometheus bool
|
||||
panicNotify OnPanicNotify
|
||||
enableCors bool
|
||||
}
|
||||
|
||||
// OnPanicNotify 发生panic时通知用
|
||||
type OnPanicNotify func(ctx Context, err interface{}, stackInfo string)
|
||||
|
||||
// DisableJournal 标识某些请求不记录journal
|
||||
func DisableJournal(ctx Context) {
|
||||
ctx.disableJournal()
|
||||
}
|
||||
|
||||
// WithPanicNotify 设置panic时的通知回调
|
||||
func WithPanicNotify(notify OnPanicNotify) Option {
|
||||
return func(opt *option) {
|
||||
opt.panicNotify = notify
|
||||
}
|
||||
}
|
||||
|
||||
// WithDisablePProf 禁用 pprof
|
||||
func WithDisablePProf() Option {
|
||||
return func(opt *option) {
|
||||
opt.disablePProf = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableCors 开启CORS
|
||||
func WithEnableCors() Option {
|
||||
return func(opt *option) {
|
||||
opt.enableCors = true
|
||||
}
|
||||
}
|
||||
|
||||
// RouterGroup 包装gin的RouterGroup
|
||||
type RouterGroup interface {
|
||||
Group(string, ...HandlerFunc) RouterGroup
|
||||
IRoutes
|
||||
}
|
||||
|
||||
var _ IRoutes = (*router)(nil)
|
||||
|
||||
// IRoutes 包装gin的IRoutes
|
||||
type IRoutes interface {
|
||||
Any(string, ...HandlerFunc)
|
||||
GET(string, ...HandlerFunc)
|
||||
POST(string, ...HandlerFunc)
|
||||
DELETE(string, ...HandlerFunc)
|
||||
PATCH(string, ...HandlerFunc)
|
||||
PUT(string, ...HandlerFunc)
|
||||
OPTIONS(string, ...HandlerFunc)
|
||||
HEAD(string, ...HandlerFunc)
|
||||
}
|
||||
|
||||
type router struct {
|
||||
group *gin.RouterGroup
|
||||
}
|
||||
|
||||
func (r *router) Group(relativePath string, handlers ...HandlerFunc) RouterGroup {
|
||||
group := r.group.Group(relativePath, wrapHandlers(handlers...)...)
|
||||
return &router{group: group}
|
||||
}
|
||||
|
||||
func (r *router) Any(relativePath string, handlers ...HandlerFunc) {
|
||||
r.group.Any(relativePath, wrapHandlers(handlers...)...)
|
||||
}
|
||||
|
||||
func (r *router) GET(relativePath string, handlers ...HandlerFunc) {
|
||||
r.group.GET(relativePath, wrapHandlers(handlers...)...)
|
||||
}
|
||||
|
||||
func (r *router) POST(relativePath string, handlers ...HandlerFunc) {
|
||||
r.group.POST(relativePath, wrapHandlers(handlers...)...)
|
||||
}
|
||||
|
||||
func (r *router) DELETE(relativePath string, handlers ...HandlerFunc) {
|
||||
r.group.DELETE(relativePath, wrapHandlers(handlers...)...)
|
||||
}
|
||||
|
||||
func (r *router) PATCH(relativePath string, handlers ...HandlerFunc) {
|
||||
r.group.PATCH(relativePath, wrapHandlers(handlers...)...)
|
||||
}
|
||||
|
||||
func (r *router) PUT(relativePath string, handlers ...HandlerFunc) {
|
||||
r.group.PUT(relativePath, wrapHandlers(handlers...)...)
|
||||
}
|
||||
|
||||
func (r *router) OPTIONS(relativePath string, handlers ...HandlerFunc) {
|
||||
r.group.OPTIONS(relativePath, wrapHandlers(handlers...)...)
|
||||
}
|
||||
|
||||
func (r *router) HEAD(relativePath string, handlers ...HandlerFunc) {
|
||||
r.group.HEAD(relativePath, wrapHandlers(handlers...)...)
|
||||
}
|
||||
|
||||
func wrapHandlers(handlers ...HandlerFunc) []gin.HandlerFunc {
|
||||
funcs := make([]gin.HandlerFunc, len(handlers))
|
||||
for i, handler := range handlers {
|
||||
handler := handler
|
||||
funcs[i] = func(c *gin.Context) {
|
||||
ctx := newContext(c)
|
||||
defer releaseContext(ctx)
|
||||
|
||||
handler(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
return funcs
|
||||
}
|
||||
|
||||
var _ Mux = (*mux)(nil)
|
||||
|
||||
// Mux http mux
|
||||
type Mux interface {
|
||||
http.Handler
|
||||
Group(relativePath string, handlers ...HandlerFunc) RouterGroup
|
||||
}
|
||||
|
||||
type mux struct {
|
||||
engine *gin.Engine
|
||||
}
|
||||
|
||||
func (m *mux) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
m.engine.ServeHTTP(w, req)
|
||||
}
|
||||
|
||||
func (m *mux) Group(relativePath string, handlers ...HandlerFunc) RouterGroup {
|
||||
return &router{
|
||||
group: m.engine.Group(relativePath, wrapHandlers(handlers...)...),
|
||||
}
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
if logger == nil {
|
||||
return nil, errors.New("logger required")
|
||||
}
|
||||
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
gin.DisableBindValidation()
|
||||
engine := gin.New()
|
||||
|
||||
mux := &mux{
|
||||
engine: gin.New(),
|
||||
}
|
||||
|
||||
fmt.Println(color.Blue(_CLI_UI_))
|
||||
|
||||
// withoutLogPaths 这些请求,默认不记录日志
|
||||
withoutJournalPaths := map[string]bool{
|
||||
"/metrics": true,
|
||||
|
||||
"/debug/pprof/": true,
|
||||
"/debug/pprof/cmdline": true,
|
||||
"/debug/pprof/profile": true,
|
||||
"/debug/pprof/symbol": true,
|
||||
"/debug/pprof/trace": true,
|
||||
"/debug/pprof/allocs": true,
|
||||
"/debug/pprof/block": true,
|
||||
"/debug/pprof/goroutine": true,
|
||||
"/debug/pprof/heap": true,
|
||||
"/debug/pprof/mutex": true,
|
||||
"/debug/pprof/threadcreate": true,
|
||||
|
||||
"/favicon.ico": true,
|
||||
}
|
||||
|
||||
opt := new(option)
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
if !opt.disablePProf {
|
||||
pprof.Register(engine) // register pprof to gin
|
||||
}
|
||||
|
||||
if opt.enableCors {
|
||||
mux.engine.Use(cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"*"},
|
||||
AllowedMethods: []string{
|
||||
http.MethodHead,
|
||||
http.MethodGet,
|
||||
http.MethodPost,
|
||||
http.MethodPut,
|
||||
http.MethodPatch,
|
||||
http.MethodDelete,
|
||||
},
|
||||
AllowedHeaders: []string{"*"},
|
||||
AllowCredentials: true,
|
||||
OptionsPassthrough: true,
|
||||
}))
|
||||
}
|
||||
|
||||
// recover两次,防止处理时发生panic,尤其是在OnPanicNotify中。
|
||||
mux.engine.Use(func(ctx *gin.Context) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", string(debug.Stack())))
|
||||
}
|
||||
}()
|
||||
|
||||
ctx.Next()
|
||||
})
|
||||
|
||||
mux.engine.Use(func(ctx *gin.Context) {
|
||||
ts := time.Now()
|
||||
|
||||
context := newContext(ctx)
|
||||
defer releaseContext(context)
|
||||
|
||||
context.init()
|
||||
context.setLogger(logger)
|
||||
|
||||
if !withoutJournalPaths[ctx.Request.URL.Path] {
|
||||
if journalID := context.GetHeader(journal.JournalHeader); journalID != "" {
|
||||
context.setJournal(journal.NewJournal(journalID))
|
||||
} else {
|
||||
context.setJournal(journal.NewJournal(""))
|
||||
}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
stackInfo := string(debug.Stack())
|
||||
logger.Error("got panic", zap.String("panic", fmt.Sprintf("%+v", err)), zap.String("stack", stackInfo))
|
||||
ctx.JSON(http.StatusOK, errno.ErrServer)
|
||||
|
||||
if notify := opt.panicNotify; notify != nil {
|
||||
notify(context, err, stackInfo)
|
||||
}
|
||||
}
|
||||
|
||||
if x := context.Journal(); x != nil {
|
||||
context.SetHeader(journal.JournalHeader, x.ID())
|
||||
}
|
||||
|
||||
response := context.GetPayload()
|
||||
if response != nil {
|
||||
ctx.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
if ctx.Writer.Status() == http.StatusNotFound {
|
||||
return
|
||||
}
|
||||
|
||||
var j *journal.Journal
|
||||
if x := context.Journal(); x != nil {
|
||||
j = x.(*journal.Journal)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
decodedURL, _ := url.QueryUnescape(ctx.Request.URL.RequestURI())
|
||||
j.WithRequest(&journal.Request{
|
||||
TTL: "un-limit",
|
||||
Method: ctx.Request.Method,
|
||||
DecodedURL: decodedURL,
|
||||
Header: ctx.Request.Header,
|
||||
Body: string(context.RawData()),
|
||||
})
|
||||
|
||||
j.WithResponse(&journal.Response{
|
||||
Header: ctx.Writer.Header(),
|
||||
StatusCode: ctx.Writer.Status(),
|
||||
Status: http.StatusText(ctx.Writer.Status()),
|
||||
Body: response,
|
||||
})
|
||||
|
||||
j.Success = !ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK
|
||||
j.CostSeconds = time.Since(ts).Seconds()
|
||||
|
||||
logger.Info("interceptor", zap.Any("journal", j))
|
||||
}()
|
||||
|
||||
ctx.Next()
|
||||
})
|
||||
|
||||
mux.engine.NoMethod(wrapHandlers(DisableJournal)...)
|
||||
mux.engine.NoRoute(wrapHandlers(DisableJournal)...)
|
||||
|
||||
h := mux.Group("/h", DisableJournal)
|
||||
{
|
||||
h.GET("/ping", func(ctx Context) {
|
||||
ctx.SetPayload(errno.OK.WithData("pong"))
|
||||
})
|
||||
|
||||
h.GET("/info", func(ctx Context) {
|
||||
resp := &struct {
|
||||
Header interface{} `json:"header"`
|
||||
Ts time.Time `json:"ts"`
|
||||
}{
|
||||
Header: ctx.Header(),
|
||||
Ts: time.Now(),
|
||||
}
|
||||
ctx.SetPayload(errno.OK.WithData(resp))
|
||||
})
|
||||
}
|
||||
|
||||
return mux, nil
|
||||
}
|
||||
14
internal/pkg/errno/README.md
Normal file
14
internal/pkg/errno/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
## 错误码规则
|
||||
|
||||
- 错误码需在 `code.go` 文件中定义。
|
||||
- 错误码需为 > 0 的数,反之表示正确。
|
||||
|
||||
#### 错误码为 5 位数
|
||||
|
||||
| 1 | 01 | 01 |
|
||||
| :------ | :------ | :------ |
|
||||
| 服务级错误码 | 模块级错误码 | 具体错误码 |
|
||||
|
||||
- 服务级别错误码:1 位数进行表示,比如 1 为系统级错误;2 为普通错误,通常是由用户非法操作引起。
|
||||
- 模块级错误码:2 位数进行表示,比如 01 为用户模块;02 为订单模块。
|
||||
- 具体错误码:2 位数进行表示,比如 01 为手机号不合法;02 为验证码输入错误。
|
||||
22
internal/pkg/errno/code.go
Normal file
22
internal/pkg/errno/code.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package errno
|
||||
|
||||
import "net/http"
|
||||
|
||||
var (
|
||||
// OK
|
||||
OK = NewError(0, "OK")
|
||||
|
||||
// 服务级错误码
|
||||
ErrServer = NewError(10101, http.StatusText(http.StatusInternalServerError))
|
||||
Err404 = NewError(10102, http.StatusText(http.StatusNotFound))
|
||||
ErrManyRequest = NewError(10103, "Too many requests")
|
||||
|
||||
ErrParam = NewError(10002, "参数有误")
|
||||
ErrSignParam = NewError(10003, "签名参数有误")
|
||||
|
||||
// 模块级错误码 - 用户模块
|
||||
ErrUser = NewError(20101, "非法用户")
|
||||
ErrUserCaptcha = NewError(20102, "用户验证码有误")
|
||||
|
||||
// ...
|
||||
)
|
||||
63
internal/pkg/errno/errno.go
Normal file
63
internal/pkg/errno/errno.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package errno
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var _ Error = (*err)(nil)
|
||||
|
||||
type Error interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
// WithData 设置成功时返回的数据
|
||||
WithData(data interface{}) Error
|
||||
// WithID 设置当前请求的唯一ID
|
||||
WithID(id string) Error
|
||||
// ToString 返回 JSON 格式的错误详情
|
||||
ToString() string
|
||||
}
|
||||
|
||||
type err struct {
|
||||
Code int `json:"code"` // 业务编码
|
||||
Msg string `json:"msg"` // 错误描述
|
||||
Data interface{} `json:"data"` // 成功时返回的数据
|
||||
ID string `json:"id,omitempty"` // 当前请求的唯一ID,便于问题定位,忽略也可以
|
||||
}
|
||||
|
||||
func NewError(code int, msg string) Error {
|
||||
return &err{
|
||||
Code: code,
|
||||
Msg: msg,
|
||||
Data: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *err) i() {}
|
||||
|
||||
func (e *err) WithData(data interface{}) Error {
|
||||
e.Data = data
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *err) WithID(id string) Error {
|
||||
e.ID = id
|
||||
return e
|
||||
}
|
||||
|
||||
// ToString 返回 JSON 格式的错误详情
|
||||
func (e *err) ToString() string {
|
||||
err := &struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data interface{} `json:"data"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}{
|
||||
Code: e.Code,
|
||||
Msg: e.Msg,
|
||||
Data: e.Data,
|
||||
ID: e.ID,
|
||||
}
|
||||
|
||||
raw, _ := json.Marshal(err)
|
||||
return string(raw)
|
||||
}
|
||||
121
internal/pkg/journal/journal.go
Normal file
121
internal/pkg/journal/journal.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package journal
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// JournalHeader http/rpc header中的名字
|
||||
const JournalHeader = "Journal-ID"
|
||||
|
||||
var _ T = (*Journal)(nil)
|
||||
var _ T = (*Dialog)(nil)
|
||||
|
||||
// T 约束
|
||||
type T interface {
|
||||
ID() string
|
||||
t()
|
||||
}
|
||||
|
||||
// Journal 包含一次rpc请求的全部参数和内部调用其它方接口的过程
|
||||
type Journal struct {
|
||||
mux sync.Mutex
|
||||
Identifier string `json:"id"`
|
||||
Request *Request `json:"request"`
|
||||
Response *Response `json:"response"`
|
||||
Dialogs []*Dialog `json:"dialogs"`
|
||||
Success bool `json:"success"`
|
||||
CostSeconds float64 `json:"cost_seconds"`
|
||||
}
|
||||
|
||||
// NewJournal 创建Journal
|
||||
func NewJournal(id string) *Journal {
|
||||
if id == "" {
|
||||
buf := make([]byte, 10)
|
||||
io.ReadFull(rand.Reader, buf)
|
||||
id = string(hex.EncodeToString(buf))
|
||||
}
|
||||
|
||||
return &Journal{
|
||||
Identifier: id,
|
||||
}
|
||||
}
|
||||
|
||||
// ID 唯一标识符
|
||||
func (j *Journal) ID() string {
|
||||
return j.Identifier
|
||||
}
|
||||
|
||||
// WithRequest 设置request
|
||||
func (j *Journal) WithRequest(req *Request) *Journal {
|
||||
j.Request = req
|
||||
return j
|
||||
}
|
||||
|
||||
// WithResponse 设置response
|
||||
func (j *Journal) WithResponse(resp *Response) *Journal {
|
||||
j.Response = resp
|
||||
return j
|
||||
}
|
||||
|
||||
// AppendDialog 安全的追加内部调用过程dialog
|
||||
func (j *Journal) AppendDialog(dialog *Dialog) *Journal {
|
||||
if dialog == nil {
|
||||
return j
|
||||
}
|
||||
|
||||
j.mux.Lock()
|
||||
defer j.mux.Unlock()
|
||||
|
||||
j.Dialogs = append(j.Dialogs, dialog)
|
||||
return j
|
||||
}
|
||||
|
||||
func (j *Journal) t() {}
|
||||
|
||||
// Request 请求信息
|
||||
type Request struct {
|
||||
TTL string `json:"ttl"`
|
||||
Method string `json:"method"`
|
||||
DecodedURL string `json:"decoded_url"`
|
||||
Header interface{} `json:"header"`
|
||||
Body interface{} `json:"body"`
|
||||
}
|
||||
|
||||
// Response 响应信息
|
||||
type Response struct {
|
||||
Header interface{} `json:"header"`
|
||||
StatusCode int `json:"status_code"`
|
||||
Status string `json:"status"`
|
||||
Body interface{} `json:"body"`
|
||||
CostSeconds float64 `json:"cost_seconds"`
|
||||
}
|
||||
|
||||
// Dialog 内部调用其它方接口的会话信息;失败时会有retry操作,所以response会有多次。
|
||||
type Dialog struct {
|
||||
mux sync.Mutex
|
||||
Request *Request `json:"request"`
|
||||
Responses []*Response `json:"responses"`
|
||||
Success bool `json:"success"`
|
||||
CostSeconds float64 `json:"cost_seconds"`
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (d *Dialog) ID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// AppendResponse 按转的追加response信息
|
||||
func (d *Dialog) AppendResponse(resp *Response) {
|
||||
if resp == nil {
|
||||
return
|
||||
}
|
||||
|
||||
d.mux.Lock()
|
||||
d.Responses = append(d.Responses, resp)
|
||||
d.mux.Unlock()
|
||||
}
|
||||
|
||||
func (d *Dialog) t() {}
|
||||
7
internal/pkg/jsonparse/jsonparse.go
Normal file
7
internal/pkg/jsonparse/jsonparse.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package jsonparse
|
||||
|
||||
import "github.com/tidwall/gjson"
|
||||
|
||||
func Get(json, path string) interface{} {
|
||||
return gjson.Get(json, path).Value()
|
||||
}
|
||||
29
internal/pkg/notify/email.go
Normal file
29
internal/pkg/notify/email.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/color"
|
||||
)
|
||||
|
||||
// Email
|
||||
func Email(ctx core.Context, err interface{}, stackInfo string) {
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
buf.WriteString(fmt.Sprintf("URI: %s %s%s <br/>", ctx.Method(), ctx.Host(), ctx.URI()))
|
||||
buf.WriteString(fmt.Sprintf("JournalID: %s <br/>", ctx.Journal().ID()))
|
||||
buf.WriteString(fmt.Sprintf("ErrorInfo: %+v <br/>", err))
|
||||
buf.WriteString(fmt.Sprintf("StackInfo: <br/>"))
|
||||
|
||||
for _, v := range strings.Split(stackInfo, "\n") {
|
||||
buf.WriteString(v)
|
||||
buf.WriteString(" <br/>")
|
||||
}
|
||||
|
||||
content := buf.String()
|
||||
|
||||
fmt.Println(color.Red(content))
|
||||
}
|
||||
0
vendor/github.com/modern-go/reflect2/reflect2_amd64.s → logs/go-gin-api.log
Normal file → Executable file
0
vendor/github.com/modern-go/reflect2/reflect2_amd64.s → logs/go-gin-api.log
Normal file → Executable file
74
main.go
74
main.go
@@ -3,59 +3,51 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gin-contrib/pprof"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/route"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/router"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/configs"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/logger"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/shutdown"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gin.SetMode(config.AppMode)
|
||||
engine := gin.New()
|
||||
|
||||
// 性能分析 - 正式环境不要使用!!!
|
||||
pprof.Register(engine)
|
||||
|
||||
// 设置路由
|
||||
route.SetupRouter(engine)
|
||||
|
||||
server := &http.Server{
|
||||
Addr : config.AppPort,
|
||||
Handler : engine,
|
||||
ReadTimeout : config.AppReadTimeout * time.Second,
|
||||
WriteTimeout : config.AppWriteTimeout * time.Second,
|
||||
loggers, err := logger.NewJSONLogger(
|
||||
logger.WithField("domain", configs.ProjectName()),
|
||||
logger.WithTimeLayout("2006-01-02 15:04:05"),
|
||||
logger.WithFileP(fmt.Sprintf("./logs/%s.log", configs.ProjectName())),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("|-----------------------------------|")
|
||||
fmt.Println("| go-gin-api |")
|
||||
fmt.Println("|-----------------------------------|")
|
||||
fmt.Println("| Go Http Server Start Successful |")
|
||||
fmt.Println("| Port" + config.AppPort + " Pid:" + fmt.Sprintf("%d", os.Getpid()) + " |")
|
||||
fmt.Println("|-----------------------------------|")
|
||||
fmt.Println("")
|
||||
mux, err := router.NewHTTPMux(loggers)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
server := &http.Server{
|
||||
Addr: ":9999",
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatalf("HTTP server listen: %s\n", err)
|
||||
loggers.Fatal("http server startup err", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
|
||||
// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
|
||||
signalChan := make(chan os.Signal)
|
||||
signal.Notify(signalChan, os.Interrupt)
|
||||
sig := <-signalChan
|
||||
log.Println("Get Signal:", sig)
|
||||
log.Println("Shutdown Server ...")
|
||||
shutdown.NewHook().Close(func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5 * time.Second)
|
||||
defer cancel()
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
log.Fatal("Server Shutdown:", err)
|
||||
}
|
||||
log.Println("Server exiting")
|
||||
if err := server.Shutdown(ctx); err != nil {
|
||||
loggers.Fatal("shutdown err", zap.Error(err))
|
||||
} else {
|
||||
loggers.Info("shutdown success")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
46
pkg/color/string_darwin.go
Normal file
46
pkg/color/string_darwin.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// +build darwin
|
||||
|
||||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var _ = RandomColor()
|
||||
|
||||
// RandomColor generates a random color.
|
||||
func RandomColor() string {
|
||||
return fmt.Sprintf("#%s", strconv.FormatInt(int64(rand.Intn(16777216)), 16))
|
||||
}
|
||||
|
||||
// Yellow ...
|
||||
func Yellow(msg string) string {
|
||||
return fmt.Sprintf("\x1b[33m%s\x1b[0m", msg)
|
||||
}
|
||||
|
||||
// Red ...
|
||||
func Red(msg string) string {
|
||||
return fmt.Sprintf("\x1b[31m%s\x1b[0m", msg)
|
||||
}
|
||||
|
||||
// Redf ...
|
||||
func Redf(msg string, arg interface{}) string {
|
||||
return fmt.Sprintf("\x1b[31m%s\x1b[0m %+v\n", msg, arg)
|
||||
}
|
||||
|
||||
// Blue ...
|
||||
func Blue(msg string) string {
|
||||
return fmt.Sprintf("\x1b[34m%s\x1b[0m", msg)
|
||||
}
|
||||
|
||||
// Green ...
|
||||
func Green(msg string) string {
|
||||
return fmt.Sprintf("\x1b[32m%s\x1b[0m", msg)
|
||||
}
|
||||
|
||||
// Greenf ...
|
||||
func Greenf(msg string, arg interface{}) string {
|
||||
return fmt.Sprintf("\x1b[32m%s\x1b[0m %+v\n", msg, arg)
|
||||
}
|
||||
46
pkg/color/string_linux.go
Normal file
46
pkg/color/string_linux.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// +build linux
|
||||
|
||||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var _ = RandomColor()
|
||||
|
||||
// RandomColor generates a random color.
|
||||
func RandomColor() string {
|
||||
return fmt.Sprintf("#%s", strconv.FormatInt(int64(rand.Intn(16777216)), 16))
|
||||
}
|
||||
|
||||
// Yellow ...
|
||||
func Yellow(msg string) string {
|
||||
return fmt.Sprintf("\x1b[33m%s\x1b[0m", msg)
|
||||
}
|
||||
|
||||
// Red ...
|
||||
func Red(msg string) string {
|
||||
return fmt.Sprintf("\x1b[31m%s\x1b[0m", msg)
|
||||
}
|
||||
|
||||
// Redf ...
|
||||
func Redf(msg string, arg interface{}) string {
|
||||
return fmt.Sprintf("\x1b[31m%s\x1b[0m %+v\n", msg, arg)
|
||||
}
|
||||
|
||||
// Blue ...
|
||||
func Blue(msg string) string {
|
||||
return fmt.Sprintf("\x1b[34m%s\x1b[0m", msg)
|
||||
}
|
||||
|
||||
// Green ...
|
||||
func Green(msg string) string {
|
||||
return fmt.Sprintf("\x1b[32m%s\x1b[0m", msg)
|
||||
}
|
||||
|
||||
// Greenf ...
|
||||
func Greenf(msg string, arg interface{}) string {
|
||||
return fmt.Sprintf("\x1b[32m%s\x1b[0m %+v\n", msg, arg)
|
||||
}
|
||||
46
pkg/color/string_windows.go
Normal file
46
pkg/color/string_windows.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// +build windows
|
||||
|
||||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var _ = RandomColor()
|
||||
|
||||
// RandomColor generates a random color.
|
||||
func RandomColor() string {
|
||||
return fmt.Sprintf("#%s", strconv.FormatInt(int64(rand.Intn(16777216)), 16))
|
||||
}
|
||||
|
||||
// Yellow ...
|
||||
func Yellow(msg string) string {
|
||||
return fmt.Sprintf("%s", msg)
|
||||
}
|
||||
|
||||
// Red ...
|
||||
func Red(msg string) string {
|
||||
return fmt.Sprintf("%s", msg)
|
||||
}
|
||||
|
||||
// Redf ...
|
||||
func Redf(msg string, arg interface{}) string {
|
||||
return fmt.Sprintf("%s %+v\n", msg, arg)
|
||||
}
|
||||
|
||||
// Blue ...
|
||||
func Blue(msg string) string {
|
||||
return fmt.Sprintf("%s", msg)
|
||||
}
|
||||
|
||||
// Green ...
|
||||
func Green(msg string) string {
|
||||
return fmt.Sprintf("%s", msg)
|
||||
}
|
||||
|
||||
// Greenf ...
|
||||
func Greenf(msg string, arg interface{}) string {
|
||||
return fmt.Sprintf("%s %+v\n", msg, arg)
|
||||
}
|
||||
75
pkg/env/env.go
vendored
Normal file
75
pkg/env/env.go
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
active Environment
|
||||
dev Environment = &environment{value: "dev"}
|
||||
fat Environment = &environment{value: "fat"}
|
||||
uat Environment = &environment{value: "uat"}
|
||||
pro Environment = &environment{value: "pro"}
|
||||
)
|
||||
|
||||
var _ Environment = (*environment)(nil)
|
||||
|
||||
// Environment 环境配置
|
||||
type Environment interface {
|
||||
Value() string
|
||||
IsDev() bool
|
||||
IsFat() bool
|
||||
IsUat() bool
|
||||
IsPro() bool
|
||||
t()
|
||||
}
|
||||
|
||||
type environment struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func (e *environment) Value() string {
|
||||
return e.value
|
||||
}
|
||||
|
||||
func (e *environment) IsDev() bool {
|
||||
return e.value == "dev"
|
||||
}
|
||||
|
||||
func (e *environment) IsFat() bool {
|
||||
return e.value == "fat"
|
||||
}
|
||||
|
||||
func (e *environment) IsUat() bool {
|
||||
return e.value == "uat"
|
||||
}
|
||||
|
||||
func (e *environment) IsPro() bool {
|
||||
return e.value == "pro"
|
||||
}
|
||||
|
||||
func (e *environment) t() {}
|
||||
|
||||
func init() {
|
||||
env := strings.ToLower(strings.TrimSpace(os.Getenv("ACTIVE")))
|
||||
switch env {
|
||||
case "dev":
|
||||
active = dev
|
||||
case "fat":
|
||||
active = fat
|
||||
case "uat":
|
||||
active = uat
|
||||
case "pro":
|
||||
active = pro
|
||||
default:
|
||||
active = fat
|
||||
fmt.Println("Warning: env'ACTIVE' cannot be found, or it is illegal. The default 'fat' will be used.")
|
||||
}
|
||||
}
|
||||
|
||||
// Active 当前配置的env
|
||||
func Active() Environment {
|
||||
return active
|
||||
}
|
||||
300
pkg/httpclient/client.go
Normal file
300
pkg/httpclient/client.go
Normal file
@@ -0,0 +1,300 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
httpURL "net/url"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/journal"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultTTL 一次http请求最长执行1分钟
|
||||
DefaultTTL = time.Minute
|
||||
// DefaultRetryTimes 如果请求失败,最多重试3次
|
||||
DefaultRetryTimes = 3
|
||||
// DefaultRetryDelay 在重试前,延迟等待100毫秒
|
||||
DefaultRetryDelay = time.Millisecond * 100
|
||||
)
|
||||
|
||||
// TODO retry的code不一定正确,缺失或者多余待实际使用中修改。
|
||||
func shouldRetry(ctx context.Context, httpCode int) bool {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return false
|
||||
default:
|
||||
}
|
||||
|
||||
switch httpCode {
|
||||
case
|
||||
_StatusDoReqErr, // customize
|
||||
_StatusReadRespErr, // customize
|
||||
|
||||
http.StatusRequestTimeout,
|
||||
http.StatusLocked,
|
||||
http.StatusTooEarly,
|
||||
http.StatusTooManyRequests,
|
||||
|
||||
http.StatusServiceUnavailable,
|
||||
http.StatusGatewayTimeout:
|
||||
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Get get 请求
|
||||
func Get(url string, form httpURL.Values, options ...Option) (body []byte, err error) {
|
||||
return withoutBody(http.MethodGet, url, form, options...)
|
||||
}
|
||||
|
||||
// Delete delete 请求
|
||||
func Delete(url string, form httpURL.Values, options ...Option) (body []byte, err error) {
|
||||
return withoutBody(http.MethodDelete, url, form, options...)
|
||||
}
|
||||
|
||||
func withoutBody(method, url string, form httpURL.Values, options ...Option) (body []byte, err error) {
|
||||
if url == "" {
|
||||
return nil, errors.New("url required")
|
||||
}
|
||||
|
||||
if len(form) > 0 {
|
||||
if url, err = addFormValuesIntoURL(url, form); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ts := time.Now()
|
||||
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Journal != nil {
|
||||
opt.Dialog.Success = err == nil
|
||||
opt.Dialog.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Journal.AppendDialog(opt.Dialog)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
opt.Header["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8"
|
||||
if opt.Journal != nil {
|
||||
opt.Header[journal.JournalHeader] = opt.Journal.ID()
|
||||
}
|
||||
|
||||
ttl := opt.TTL
|
||||
if ttl <= 0 {
|
||||
ttl = DefaultTTL
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), ttl)
|
||||
defer cancel()
|
||||
|
||||
if opt.Dialog != nil {
|
||||
decodedURL, _ := httpURL.QueryUnescape(url)
|
||||
opt.Dialog.Request = &journal.Request{
|
||||
TTL: ttl.String(),
|
||||
Method: method,
|
||||
DecodedURL: decodedURL,
|
||||
Header: opt.Header,
|
||||
}
|
||||
}
|
||||
|
||||
retryTimes := opt.RetryTimes
|
||||
if retryTimes <= 0 {
|
||||
retryTimes = DefaultRetryTimes
|
||||
}
|
||||
|
||||
retryDelay := opt.RetryDelay
|
||||
if retryDelay <= 0 {
|
||||
retryDelay = DefaultRetryDelay
|
||||
}
|
||||
|
||||
var httpCode int
|
||||
for k := 0; k < retryTimes; k++ {
|
||||
body, httpCode, err = doHTTP(ctx, method, url, nil, opt)
|
||||
if shouldRetry(ctx, httpCode) {
|
||||
time.Sleep(retryDelay)
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PostForm post form 请求
|
||||
func PostForm(url string, form httpURL.Values, options ...Option) (body []byte, err error) {
|
||||
return withFormBody(http.MethodPost, url, form, options...)
|
||||
}
|
||||
|
||||
// PostJSON post json 请求
|
||||
func PostJSON(url string, raw json.RawMessage, options ...Option) (body []byte, err error) {
|
||||
return withJSONBody(http.MethodPost, url, raw, options...)
|
||||
}
|
||||
|
||||
// PutForm put form 请求
|
||||
func PutForm(url string, form httpURL.Values, options ...Option) (body []byte, err error) {
|
||||
return withFormBody(http.MethodPut, url, form, options...)
|
||||
}
|
||||
|
||||
// PutJSON put json 请求
|
||||
func PutJSON(url string, raw json.RawMessage, options ...Option) (body []byte, err error) {
|
||||
return withJSONBody(http.MethodPut, url, raw, options...)
|
||||
}
|
||||
|
||||
// PatchFrom patch form 请求
|
||||
func PatchFrom(url string, form httpURL.Values, options ...Option) (body []byte, err error) {
|
||||
return withFormBody(http.MethodPatch, url, form, options...)
|
||||
}
|
||||
|
||||
// PatchJSON patch json 请求
|
||||
func PatchJSON(url string, raw json.RawMessage, options ...Option) (body []byte, err error) {
|
||||
return withJSONBody(http.MethodPatch, url, raw, options...)
|
||||
}
|
||||
|
||||
func withFormBody(method, url string, form httpURL.Values, options ...Option) (body []byte, err error) {
|
||||
if url == "" {
|
||||
return nil, errors.New("url required")
|
||||
}
|
||||
if len(form) == 0 {
|
||||
return nil, errors.New("form required")
|
||||
}
|
||||
|
||||
ts := time.Now()
|
||||
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Journal != nil {
|
||||
opt.Dialog.Success = err == nil
|
||||
opt.Dialog.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Journal.AppendDialog(opt.Dialog)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
opt.Header["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8"
|
||||
if opt.Journal != nil {
|
||||
opt.Header[journal.JournalHeader] = opt.Journal.ID()
|
||||
}
|
||||
|
||||
ttl := opt.TTL
|
||||
if ttl <= 0 {
|
||||
ttl = DefaultTTL
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), ttl)
|
||||
defer cancel()
|
||||
|
||||
formValue := form.Encode()
|
||||
if opt.Dialog != nil {
|
||||
decodedURL, _ := httpURL.QueryUnescape(url)
|
||||
opt.Dialog.Request = &journal.Request{
|
||||
TTL: ttl.String(),
|
||||
Method: method,
|
||||
DecodedURL: decodedURL,
|
||||
Header: opt.Header,
|
||||
Body: formValue,
|
||||
}
|
||||
}
|
||||
|
||||
retryTimes := opt.RetryTimes
|
||||
if retryTimes <= 0 {
|
||||
retryTimes = DefaultRetryTimes
|
||||
}
|
||||
|
||||
retryDelay := opt.RetryDelay
|
||||
if retryDelay <= 0 {
|
||||
retryDelay = DefaultRetryDelay
|
||||
}
|
||||
|
||||
var httpCode int
|
||||
for k := 0; k < retryTimes; k++ {
|
||||
body, httpCode, err = doHTTP(ctx, method, url, []byte(formValue), opt)
|
||||
if shouldRetry(ctx, httpCode) {
|
||||
time.Sleep(retryDelay)
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func withJSONBody(method, url string, raw json.RawMessage, options ...Option) (body []byte, err error) {
|
||||
if url == "" {
|
||||
return nil, errors.New("url required")
|
||||
}
|
||||
if len(raw) == 0 {
|
||||
return nil, errors.New("raw required")
|
||||
}
|
||||
|
||||
ts := time.Now()
|
||||
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Journal != nil {
|
||||
opt.Dialog.Success = err == nil
|
||||
opt.Dialog.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Journal.AppendDialog(opt.Dialog)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
opt.Header["Content-Type"] = "application/json; charset=utf-8"
|
||||
if opt.Journal != nil {
|
||||
opt.Header[journal.JournalHeader] = opt.Journal.ID()
|
||||
}
|
||||
|
||||
ttl := opt.TTL
|
||||
if ttl <= 0 {
|
||||
ttl = DefaultTTL
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), ttl)
|
||||
defer cancel()
|
||||
|
||||
if opt.Dialog != nil {
|
||||
decodedURL, _ := httpURL.QueryUnescape(url)
|
||||
opt.Dialog.Request = &journal.Request{
|
||||
TTL: ttl.String(),
|
||||
Method: method,
|
||||
DecodedURL: decodedURL,
|
||||
Header: opt.Header,
|
||||
Body: string(raw), // TODO unsafe
|
||||
}
|
||||
}
|
||||
|
||||
retryTimes := opt.RetryTimes
|
||||
if retryTimes <= 0 {
|
||||
retryTimes = DefaultRetryTimes
|
||||
}
|
||||
|
||||
retryDelay := opt.RetryDelay
|
||||
if retryDelay <= 0 {
|
||||
retryDelay = DefaultRetryDelay
|
||||
}
|
||||
|
||||
var httpCode int
|
||||
for k := 0; k < retryTimes; k++ {
|
||||
body, httpCode, err = doHTTP(ctx, method, url, raw, opt)
|
||||
if shouldRetry(ctx, httpCode) {
|
||||
time.Sleep(retryDelay)
|
||||
continue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
46
pkg/httpclient/error.go
Normal file
46
pkg/httpclient/error.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package httpclient
|
||||
|
||||
var _ ReplyErr = (*replyErr)(nil)
|
||||
|
||||
// ReplyErr 错误响应,当resp.StatusCode != http.StatusOK时用来包装返回的httpcode和body。
|
||||
type ReplyErr interface {
|
||||
error
|
||||
StatusCode() int
|
||||
Body() []byte
|
||||
}
|
||||
|
||||
type replyErr struct {
|
||||
err error
|
||||
statusCode int
|
||||
body []byte
|
||||
}
|
||||
|
||||
func (r *replyErr) Error() string {
|
||||
return r.err.Error()
|
||||
}
|
||||
|
||||
func (r *replyErr) StatusCode() int {
|
||||
return r.statusCode
|
||||
}
|
||||
|
||||
func (r *replyErr) Body() []byte {
|
||||
return r.body
|
||||
}
|
||||
|
||||
func newReplyErr(statusCode int, body []byte, err error) ReplyErr {
|
||||
return &replyErr{
|
||||
statusCode: statusCode,
|
||||
body: body,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// ToReplyErr 尝试将err转换为ReplyErr
|
||||
func ToReplyErr(err error) (ReplyErr, bool) {
|
||||
if err == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
e, ok := err.(ReplyErr)
|
||||
return e, ok
|
||||
}
|
||||
76
pkg/httpclient/option.go
Normal file
76
pkg/httpclient/option.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/journal"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Journal 记录内部流转信息
|
||||
type Journal = journal.T
|
||||
|
||||
// Option 自定义设置http请求
|
||||
type Option func(*option)
|
||||
|
||||
type option struct {
|
||||
TTL time.Duration
|
||||
Header map[string]string
|
||||
Journal *journal.Journal
|
||||
Dialog *journal.Dialog
|
||||
Logger *zap.Logger
|
||||
RetryTimes int
|
||||
RetryDelay time.Duration
|
||||
}
|
||||
|
||||
func newOption() *option {
|
||||
return &option{
|
||||
Header: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// WithTTL 本次http请求最长执行时间
|
||||
func WithTTL(ttl time.Duration) Option {
|
||||
return func(opt *option) {
|
||||
opt.TTL = ttl
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeader 设置http header,可以调用多次设置多对key-value
|
||||
func WithHeader(key, value string) Option {
|
||||
return func(opt *option) {
|
||||
opt.Header[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// WithJournal 设置Journal以便记录内部流转信息
|
||||
func WithJournal(j Journal) Option {
|
||||
return func(opt *option) {
|
||||
if j != nil {
|
||||
opt.Journal = j.(*journal.Journal)
|
||||
opt.Dialog = new(journal.Dialog)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger 设置logger以便打印关键日志
|
||||
func WithLogger(logger *zap.Logger) Option {
|
||||
return func(opt *option) {
|
||||
opt.Logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
// WithRetryTimes 如果请求失败,最多重试N次
|
||||
func WithRetryTimes(retryTimes int) Option {
|
||||
return func(opt *option) {
|
||||
opt.RetryTimes = retryTimes
|
||||
}
|
||||
}
|
||||
|
||||
// WithRetryDelay 在重试前,延迟等待一会
|
||||
func WithRetryDelay(retryDelay time.Duration) Option {
|
||||
return func(opt *option) {
|
||||
opt.RetryDelay = retryDelay
|
||||
}
|
||||
}
|
||||
127
pkg/httpclient/util.go
Normal file
127
pkg/httpclient/util.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package httpclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/journal"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
// _StatusReadRespErr read resp body err, should re-call doHTTP again.
|
||||
_StatusReadRespErr = -204
|
||||
// _StatusDoReqErr do req err, should re-call doHTTP again.
|
||||
_StatusDoReqErr = -500
|
||||
)
|
||||
|
||||
var defaultClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
DisableKeepAlives: true,
|
||||
DisableCompression: true,
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func doHTTP(ctx context.Context, method, url string, payload []byte, opt *option) ([]byte, int, error) {
|
||||
ts := time.Now()
|
||||
|
||||
req, err := http.NewRequest(method, url, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return nil, -1, errors.Wrapf(err, "new request [%s %s] err", method, url)
|
||||
}
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
for key, value := range opt.Header {
|
||||
req.Header.Set(key, value)
|
||||
}
|
||||
|
||||
resp, err := defaultClient.Do(req)
|
||||
if err != nil {
|
||||
err = errors.Wrapf(err, "do request [%s %s] err", method, url)
|
||||
if opt.Dialog != nil {
|
||||
opt.Dialog.AppendResponse(&journal.Response{
|
||||
Body: err.Error(),
|
||||
CostSeconds: time.Since(ts).Seconds(),
|
||||
})
|
||||
}
|
||||
|
||||
if opt.Logger != nil {
|
||||
opt.Logger.Warn("doHTTP got err", zap.Error(err))
|
||||
}
|
||||
return nil, _StatusDoReqErr, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
err = errors.Wrapf(err, "read resp body from [%s %s] err", method, url)
|
||||
if opt.Dialog != nil {
|
||||
opt.Dialog.AppendResponse(&journal.Response{
|
||||
Body: err.Error(),
|
||||
CostSeconds: time.Since(ts).Seconds(),
|
||||
})
|
||||
}
|
||||
|
||||
if opt.Logger != nil {
|
||||
opt.Logger.Warn("doHTTP got err", zap.Error(err))
|
||||
}
|
||||
return nil, _StatusReadRespErr, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if opt.Dialog != nil {
|
||||
opt.Dialog.AppendResponse(&journal.Response{
|
||||
Header: resp.Header,
|
||||
StatusCode: resp.StatusCode,
|
||||
Status: resp.Status,
|
||||
Body: string(body), // unsafe
|
||||
CostSeconds: time.Since(ts).Seconds(),
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, resp.StatusCode, newReplyErr(
|
||||
resp.StatusCode,
|
||||
body,
|
||||
errors.Errorf("do [%s %s] return code: %d message: %s", method, url, resp.StatusCode, string(body)),
|
||||
)
|
||||
}
|
||||
|
||||
return body, http.StatusOK, nil
|
||||
}
|
||||
|
||||
// addFormValuesIntoURL append url.Values into url string
|
||||
func addFormValuesIntoURL(rawURL string, form url.Values) (string, error) {
|
||||
if rawURL == "" {
|
||||
return "", errors.New("rawURL required")
|
||||
}
|
||||
if len(form) == 0 {
|
||||
return "", errors.New("form required")
|
||||
}
|
||||
|
||||
target, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "parse rawURL `%s` err", rawURL)
|
||||
}
|
||||
|
||||
urlValues := target.Query()
|
||||
for key, values := range form {
|
||||
for _, value := range values {
|
||||
urlValues.Add(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
target.RawQuery = urlValues.Encode()
|
||||
return target.String(), nil
|
||||
}
|
||||
232
pkg/logger/logger.go
Normal file
232
pkg/logger/logger.go
Normal file
@@ -0,0 +1,232 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultLevel the default log level
|
||||
DefaultLevel = zapcore.InfoLevel
|
||||
// DefaultTimeLayout the default time layout;
|
||||
DefaultTimeLayout = time.RFC3339
|
||||
)
|
||||
|
||||
// Option custom setup config
|
||||
type Option func(*option)
|
||||
|
||||
type option struct {
|
||||
level zapcore.Level
|
||||
fields map[string]string
|
||||
file io.Writer
|
||||
timeLayout string
|
||||
}
|
||||
|
||||
// WithDebugLevel only greater than 'level' will output
|
||||
func WithDebugLevel() Option {
|
||||
return func(opt *option) {
|
||||
opt.level = zapcore.DebugLevel
|
||||
}
|
||||
}
|
||||
|
||||
// WithInfoLevel only greater than 'level' will output
|
||||
func WithInfoLevel() Option {
|
||||
return func(opt *option) {
|
||||
opt.level = zapcore.InfoLevel
|
||||
}
|
||||
}
|
||||
|
||||
// WithWarnLevel only greater than 'level' will output
|
||||
func WithWarnLevel() Option {
|
||||
return func(opt *option) {
|
||||
opt.level = zapcore.WarnLevel
|
||||
}
|
||||
}
|
||||
|
||||
// WithErrorLevel only greater than 'level' will output
|
||||
func WithErrorLevel() Option {
|
||||
return func(opt *option) {
|
||||
opt.level = zapcore.ErrorLevel
|
||||
}
|
||||
}
|
||||
|
||||
// WithField add some field(s) to log
|
||||
func WithField(key, value string) Option {
|
||||
return func(opt *option) {
|
||||
opt.fields[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
// WithFileP write log to some file
|
||||
func WithFileP(file string) Option {
|
||||
dir := filepath.Dir(file)
|
||||
if err := os.MkdirAll(dir, 0766); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(file, os.O_CREATE|os.O_APPEND|os.O_RDWR, 0766)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return func(opt *option) {
|
||||
opt.file = zapcore.Lock(f)
|
||||
}
|
||||
}
|
||||
|
||||
// WithFileRotationP write log to some file with rotation
|
||||
func WithFileRotationP(file string) Option {
|
||||
dir := filepath.Dir(file)
|
||||
if err := os.MkdirAll(dir, 0766); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return func(opt *option) {
|
||||
opt.file = &lumberjack.Logger{ // concurrent-safed
|
||||
Filename: file,
|
||||
MaxSize: 10, // megabytes
|
||||
MaxBackups: 100,
|
||||
MaxAge: 30, // days
|
||||
LocalTime: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithTimeLayout custom time format
|
||||
func WithTimeLayout(timeLayout string) Option {
|
||||
return func(opt *option) {
|
||||
opt.timeLayout = timeLayout
|
||||
}
|
||||
}
|
||||
|
||||
// NewJSONLogger return a json-encoder zap logger,
|
||||
func NewJSONLogger(opts ...Option) (*zap.Logger, error) {
|
||||
opt := &option{level: DefaultLevel, fields: make(map[string]string)}
|
||||
for _, f := range opts {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
timeLayout := DefaultTimeLayout
|
||||
if opt.timeLayout != "" {
|
||||
timeLayout = opt.timeLayout
|
||||
}
|
||||
|
||||
// similar to zap.NewProductionEncoderConfig()
|
||||
encoderConfig := zapcore.EncoderConfig{
|
||||
TimeKey: "timestamp",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger", // used by logger.Named(key); optional; useless
|
||||
CallerKey: "caller",
|
||||
MessageKey: "msg",
|
||||
StacktraceKey: "stacktrace", // use by zap.AddStacktrace; optional; useless
|
||||
LineEnding: zapcore.DefaultLineEnding,
|
||||
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
||||
EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||||
enc.AppendString(t.Format(timeLayout))
|
||||
},
|
||||
EncodeDuration: zapcore.MillisDurationEncoder,
|
||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||
}
|
||||
|
||||
jsonEncoder := zapcore.NewJSONEncoder(encoderConfig)
|
||||
|
||||
// lowPriority usd by info\debug\warn
|
||||
lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||
return lvl >= opt.level && lvl < zapcore.ErrorLevel
|
||||
})
|
||||
|
||||
// highPriority usd by error\panic\fatal
|
||||
highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||
return lvl >= opt.level && lvl >= zapcore.ErrorLevel
|
||||
})
|
||||
|
||||
stdout := zapcore.Lock(os.Stdout) // lock for concurrent safe
|
||||
stderr := zapcore.Lock(os.Stderr) // lock for concurrent safe
|
||||
|
||||
core := zapcore.NewTee(
|
||||
zapcore.NewCore(jsonEncoder,
|
||||
zapcore.NewMultiWriteSyncer(stdout),
|
||||
lowPriority,
|
||||
),
|
||||
zapcore.NewCore(jsonEncoder,
|
||||
zapcore.NewMultiWriteSyncer(stderr),
|
||||
highPriority,
|
||||
),
|
||||
)
|
||||
|
||||
if opt.file != nil {
|
||||
core = zapcore.NewTee(core,
|
||||
zapcore.NewCore(jsonEncoder,
|
||||
zapcore.AddSync(opt.file),
|
||||
zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||||
return lvl >= opt.level
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
logger := zap.New(core,
|
||||
zap.AddCaller(),
|
||||
zap.ErrorOutput(stderr),
|
||||
)
|
||||
|
||||
for key, value := range opt.fields {
|
||||
logger = logger.WithOptions(zap.Fields(zapcore.Field{Key: key, Type: zapcore.StringType, String: value}))
|
||||
}
|
||||
return logger, nil
|
||||
}
|
||||
|
||||
var _ Meta = (*meta)(nil)
|
||||
|
||||
// Meta key-value
|
||||
type Meta interface {
|
||||
Key() string
|
||||
Value() interface{}
|
||||
meta()
|
||||
}
|
||||
|
||||
type meta struct {
|
||||
key string
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (m *meta) Key() string {
|
||||
return m.key
|
||||
}
|
||||
|
||||
func (m *meta) Value() interface{} {
|
||||
return m.value
|
||||
}
|
||||
|
||||
func (m *meta) meta() {}
|
||||
|
||||
// NewMeta create meat
|
||||
func NewMeta(key string, value interface{}) Meta {
|
||||
return &meta{key: key, value: value}
|
||||
}
|
||||
|
||||
// WrapMeta wrap meta to zap fields
|
||||
func WrapMeta(err error, metas ...Meta) (fields []zap.Field) {
|
||||
capacity := len(metas) + 1 // namespace meta
|
||||
if err != nil {
|
||||
capacity++
|
||||
}
|
||||
|
||||
fields = make([]zap.Field, 0, capacity)
|
||||
if err != nil {
|
||||
fields = append(fields, zap.Error(err))
|
||||
}
|
||||
|
||||
fields = append(fields, zap.Namespace("meta"))
|
||||
for _, meta := range metas {
|
||||
fields = append(fields, zap.Any(meta.Key(), meta.Value()))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
20
pkg/logger/logger_test.go
Normal file
20
pkg/logger/logger_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func TestJSONLogger(t *testing.T) {
|
||||
logger, err := NewJSONLogger(WithField("defined_key", "defined_value"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer logger.Sync()
|
||||
|
||||
err = errors.New("pkg error")
|
||||
logger.Error("err occurs", WrapMeta(nil, NewMeta("para1", "value1"), NewMeta("para2", "value2"))...)
|
||||
logger.Error("err occurs", WrapMeta(err, NewMeta("para1", "value1"), NewMeta("para2", "value2"))...)
|
||||
|
||||
}
|
||||
50
pkg/shutdown/shutdown.go
Normal file
50
pkg/shutdown/shutdown.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package shutdown
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var _ Hook = (*hook)(nil)
|
||||
|
||||
// Hook a graceful shutdown hook, default with signals of SIGINT and SIGTERM
|
||||
type Hook interface {
|
||||
// WithSignals add more signals into hook
|
||||
WithSignals(signals ...syscall.Signal) Hook
|
||||
|
||||
// Close register shutdown handles
|
||||
Close(funcs ...func())
|
||||
}
|
||||
|
||||
type hook struct {
|
||||
ctx chan os.Signal
|
||||
}
|
||||
|
||||
// NewHook create a Hook instance
|
||||
func NewHook() Hook {
|
||||
hook := &hook{
|
||||
ctx: make(chan os.Signal, 1),
|
||||
}
|
||||
|
||||
return hook.WithSignals(syscall.SIGINT, syscall.SIGTERM)
|
||||
}
|
||||
|
||||
func (h *hook) WithSignals(signals ...syscall.Signal) Hook {
|
||||
for _, s := range signals {
|
||||
signal.Notify(h.ctx, s)
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *hook) Close(funcs ...func()) {
|
||||
select {
|
||||
case <-h.ctx:
|
||||
}
|
||||
signal.Stop(h.ctx)
|
||||
|
||||
for _, f := range funcs {
|
||||
f()
|
||||
}
|
||||
}
|
||||
25
vendor/github.com/gin-contrib/pprof/.gitignore
generated
vendored
25
vendor/github.com/gin-contrib/pprof/.gitignore
generated
vendored
@@ -1,25 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
coverage*
|
||||
33
vendor/github.com/gin-contrib/pprof/.travis.yml
generated
vendored
33
vendor/github.com/gin-contrib/pprof/.travis.yml
generated
vendored
@@ -1,33 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- go: 1.10.x
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=on
|
||||
- go: 1.12.x
|
||||
env: GO111MODULE=on
|
||||
- go: master
|
||||
env: GO111MODULE=on
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
||||
install:
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else go get -t -v ./...; fi
|
||||
|
||||
script:
|
||||
- go test -v -covermode=atomic -coverprofile=coverage.out
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/acc2c57482e94b44f557
|
||||
on_success: change
|
||||
on_failure: always
|
||||
on_start: false
|
||||
21
vendor/github.com/gin-contrib/pprof/LICENSE
generated
vendored
21
vendor/github.com/gin-contrib/pprof/LICENSE
generated
vendored
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Gin-Gonic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
81
vendor/github.com/gin-contrib/pprof/README.md
generated
vendored
81
vendor/github.com/gin-contrib/pprof/README.md
generated
vendored
@@ -1,81 +0,0 @@
|
||||
# pprof
|
||||
|
||||
[](https://travis-ci.org/gin-contrib/pprof)
|
||||
[](https://codecov.io/gh/gin-contrib/pprof)
|
||||
[](https://goreportcard.com/report/github.com/gin-contrib/pprof)
|
||||
[](https://godoc.org/github.com/gin-contrib/pprof)
|
||||
[](https://gitter.im/gin-gonic/gin)
|
||||
|
||||
gin pprof middleware
|
||||
|
||||
> Package pprof serves via its HTTP server runtime profiling data in the format expected by the pprof visualization tool.
|
||||
|
||||
## Usage
|
||||
|
||||
### Start using it
|
||||
|
||||
Download and install it:
|
||||
|
||||
```bash
|
||||
go get github.com/gin-contrib/pprof
|
||||
```
|
||||
|
||||
Import it in your code:
|
||||
|
||||
```go
|
||||
import "github.com/gin-contrib/pprof"
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-contrib/pprof"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
pprof.Register(router)
|
||||
router.Run(":8080")
|
||||
}
|
||||
```
|
||||
|
||||
### change default path prefix
|
||||
|
||||
```go
|
||||
func main() {
|
||||
router := gin.Default()
|
||||
// default is "debug/pprof"
|
||||
pprof.Register(router, "dev/pprof")
|
||||
router.Run(":8080")
|
||||
}
|
||||
```
|
||||
|
||||
### Use the pprof tool
|
||||
|
||||
Then use the pprof tool to look at the heap profile:
|
||||
|
||||
```bash
|
||||
go tool pprof http://localhost:8080/debug/pprof/heap
|
||||
```
|
||||
|
||||
Or to look at a 30-second CPU profile:
|
||||
|
||||
```bash
|
||||
go tool pprof http://localhost:8080/debug/pprof/profile
|
||||
```
|
||||
|
||||
Or to look at the goroutine blocking profile, after calling runtime.SetBlockProfileRate in your program:
|
||||
|
||||
```bash
|
||||
go tool pprof http://localhost:8080/debug/pprof/block
|
||||
```
|
||||
|
||||
Or to collect a 5-second execution trace:
|
||||
|
||||
```bash
|
||||
wget http://localhost:8080/debug/pprof/trace?seconds=5
|
||||
```
|
||||
6
vendor/github.com/gin-contrib/pprof/go.mod
generated
vendored
6
vendor/github.com/gin-contrib/pprof/go.mod
generated
vendored
@@ -1,6 +0,0 @@
|
||||
module github.com/gin-contrib/pprof
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/gin-gonic/gin v1.4.0
|
||||
)
|
||||
39
vendor/github.com/gin-contrib/pprof/go.sum
generated
vendored
39
vendor/github.com/gin-contrib/pprof/go.sum
generated
vendored
@@ -1,39 +0,0 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
|
||||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
51
vendor/github.com/gin-contrib/pprof/pprof.go
generated
vendored
51
vendor/github.com/gin-contrib/pprof/pprof.go
generated
vendored
@@ -1,51 +0,0 @@
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultPrefix url prefix of pprof
|
||||
DefaultPrefix = "/debug/pprof"
|
||||
)
|
||||
|
||||
func getPrefix(prefixOptions ...string) string {
|
||||
prefix := DefaultPrefix
|
||||
if len(prefixOptions) > 0 {
|
||||
prefix = prefixOptions[0]
|
||||
}
|
||||
return prefix
|
||||
}
|
||||
|
||||
// Register the standard HandlerFuncs from the net/http/pprof package with
|
||||
// the provided gin.Engine. prefixOptions is a optional. If not prefixOptions,
|
||||
// the default path prefix is used, otherwise first prefixOptions will be path prefix.
|
||||
func Register(r *gin.Engine, prefixOptions ...string) {
|
||||
prefix := getPrefix(prefixOptions...)
|
||||
|
||||
prefixRouter := r.Group(prefix)
|
||||
{
|
||||
prefixRouter.GET("/", pprofHandler(pprof.Index))
|
||||
prefixRouter.GET("/cmdline", pprofHandler(pprof.Cmdline))
|
||||
prefixRouter.GET("/profile", pprofHandler(pprof.Profile))
|
||||
prefixRouter.POST("/symbol", pprofHandler(pprof.Symbol))
|
||||
prefixRouter.GET("/symbol", pprofHandler(pprof.Symbol))
|
||||
prefixRouter.GET("/trace", pprofHandler(pprof.Trace))
|
||||
prefixRouter.GET("/allocs", pprofHandler(pprof.Handler("allocs").ServeHTTP))
|
||||
prefixRouter.GET("/block", pprofHandler(pprof.Handler("block").ServeHTTP))
|
||||
prefixRouter.GET("/goroutine", pprofHandler(pprof.Handler("goroutine").ServeHTTP))
|
||||
prefixRouter.GET("/heap", pprofHandler(pprof.Handler("heap").ServeHTTP))
|
||||
prefixRouter.GET("/mutex", pprofHandler(pprof.Handler("mutex").ServeHTTP))
|
||||
prefixRouter.GET("/threadcreate", pprofHandler(pprof.Handler("threadcreate").ServeHTTP))
|
||||
}
|
||||
}
|
||||
|
||||
func pprofHandler(h http.HandlerFunc) gin.HandlerFunc {
|
||||
handler := http.HandlerFunc(h)
|
||||
return func(c *gin.Context) {
|
||||
handler.ServeHTTP(c.Writer, c.Request)
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/gin-contrib/sse/.travis.yml
generated
vendored
26
vendor/github.com/gin-contrib/sse/.travis.yml
generated
vendored
@@ -1,26 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- master
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=on
|
||||
- go: 1.12.x
|
||||
env: GO111MODULE=on
|
||||
|
||||
script:
|
||||
- go test -v -covermode=count -coverprofile=coverage.out
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
21
vendor/github.com/gin-contrib/sse/LICENSE
generated
vendored
21
vendor/github.com/gin-contrib/sse/LICENSE
generated
vendored
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Manuel Martínez-Almeida
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
58
vendor/github.com/gin-contrib/sse/README.md
generated
vendored
58
vendor/github.com/gin-contrib/sse/README.md
generated
vendored
@@ -1,58 +0,0 @@
|
||||
# Server-Sent Events
|
||||
|
||||
[](https://godoc.org/github.com/gin-contrib/sse)
|
||||
[](https://travis-ci.org/gin-contrib/sse)
|
||||
[](https://codecov.io/gh/gin-contrib/sse)
|
||||
[](https://goreportcard.com/report/github.com/gin-contrib/sse)
|
||||
|
||||
Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is [standardized as part of HTML5[1] by the W3C](http://www.w3.org/TR/2009/WD-eventsource-20091029/).
|
||||
|
||||
- [Read this great SSE introduction by the HTML5Rocks guys](http://www.html5rocks.com/en/tutorials/eventsource/basics/)
|
||||
- [Browser support](http://caniuse.com/#feat=eventsource)
|
||||
|
||||
## Sample code
|
||||
|
||||
```go
|
||||
import "github.com/gin-contrib/sse"
|
||||
|
||||
func httpHandler(w http.ResponseWriter, req *http.Request) {
|
||||
// data can be a primitive like a string, an integer or a float
|
||||
sse.Encode(w, sse.Event{
|
||||
Event: "message",
|
||||
Data: "some data\nmore data",
|
||||
})
|
||||
|
||||
// also a complex type, like a map, a struct or a slice
|
||||
sse.Encode(w, sse.Event{
|
||||
Id: "124",
|
||||
Event: "message",
|
||||
Data: map[string]interface{}{
|
||||
"user": "manu",
|
||||
"date": time.Now().Unix(),
|
||||
"content": "hi!",
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
```
|
||||
event: message
|
||||
data: some data\\nmore data
|
||||
|
||||
id: 124
|
||||
event: message
|
||||
data: {"content":"hi!","date":1431540810,"user":"manu"}
|
||||
|
||||
```
|
||||
|
||||
## Content-Type
|
||||
|
||||
```go
|
||||
fmt.Println(sse.ContentType)
|
||||
```
|
||||
```
|
||||
text/event-stream
|
||||
```
|
||||
|
||||
## Decoding support
|
||||
|
||||
There is a client-side implementation of SSE coming soon.
|
||||
116
vendor/github.com/gin-contrib/sse/sse-decoder.go
generated
vendored
116
vendor/github.com/gin-contrib/sse/sse-decoder.go
generated
vendored
@@ -1,116 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sse
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type decoder struct {
|
||||
events []Event
|
||||
}
|
||||
|
||||
func Decode(r io.Reader) ([]Event, error) {
|
||||
var dec decoder
|
||||
return dec.decode(r)
|
||||
}
|
||||
|
||||
func (d *decoder) dispatchEvent(event Event, data string) {
|
||||
dataLength := len(data)
|
||||
if dataLength > 0 {
|
||||
//If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer.
|
||||
data = data[:dataLength-1]
|
||||
dataLength--
|
||||
}
|
||||
if dataLength == 0 && event.Event == "" {
|
||||
return
|
||||
}
|
||||
if event.Event == "" {
|
||||
event.Event = "message"
|
||||
}
|
||||
event.Data = data
|
||||
d.events = append(d.events, event)
|
||||
}
|
||||
|
||||
func (d *decoder) decode(r io.Reader) ([]Event, error) {
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var currentEvent Event
|
||||
var dataBuffer *bytes.Buffer = new(bytes.Buffer)
|
||||
// TODO (and unit tests)
|
||||
// Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair,
|
||||
// a single U+000A LINE FEED (LF) character,
|
||||
// or a single U+000D CARRIAGE RETURN (CR) character.
|
||||
lines := bytes.Split(buf, []byte{'\n'})
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
// If the line is empty (a blank line). Dispatch the event.
|
||||
d.dispatchEvent(currentEvent, dataBuffer.String())
|
||||
|
||||
// reset current event and data buffer
|
||||
currentEvent = Event{}
|
||||
dataBuffer.Reset()
|
||||
continue
|
||||
}
|
||||
if line[0] == byte(':') {
|
||||
// If the line starts with a U+003A COLON character (:), ignore the line.
|
||||
continue
|
||||
}
|
||||
|
||||
var field, value []byte
|
||||
colonIndex := bytes.IndexRune(line, ':')
|
||||
if colonIndex != -1 {
|
||||
// If the line contains a U+003A COLON character character (:)
|
||||
// Collect the characters on the line before the first U+003A COLON character (:),
|
||||
// and let field be that string.
|
||||
field = line[:colonIndex]
|
||||
// Collect the characters on the line after the first U+003A COLON character (:),
|
||||
// and let value be that string.
|
||||
value = line[colonIndex+1:]
|
||||
// If value starts with a single U+0020 SPACE character, remove it from value.
|
||||
if len(value) > 0 && value[0] == ' ' {
|
||||
value = value[1:]
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the string is not empty but does not contain a U+003A COLON character character (:)
|
||||
// Use the whole line as the field name, and the empty string as the field value.
|
||||
field = line
|
||||
value = []byte{}
|
||||
}
|
||||
// The steps to process the field given a field name and a field value depend on the field name,
|
||||
// as given in the following list. Field names must be compared literally,
|
||||
// with no case folding performed.
|
||||
switch string(field) {
|
||||
case "event":
|
||||
// Set the event name buffer to field value.
|
||||
currentEvent.Event = string(value)
|
||||
case "id":
|
||||
// Set the event stream's last event ID to the field value.
|
||||
currentEvent.Id = string(value)
|
||||
case "retry":
|
||||
// If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9),
|
||||
// then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer.
|
||||
// Otherwise, ignore the field.
|
||||
currentEvent.Id = string(value)
|
||||
case "data":
|
||||
// Append the field value to the data buffer,
|
||||
dataBuffer.Write(value)
|
||||
// then append a single U+000A LINE FEED (LF) character to the data buffer.
|
||||
dataBuffer.WriteString("\n")
|
||||
default:
|
||||
//Otherwise. The field is ignored.
|
||||
continue
|
||||
}
|
||||
}
|
||||
// Once the end of the file is reached, the user agent must dispatch the event one final time.
|
||||
d.dispatchEvent(currentEvent, dataBuffer.String())
|
||||
|
||||
return d.events, nil
|
||||
}
|
||||
110
vendor/github.com/gin-contrib/sse/sse-encoder.go
generated
vendored
110
vendor/github.com/gin-contrib/sse/sse-encoder.go
generated
vendored
@@ -1,110 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sse
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Server-Sent Events
|
||||
// W3C Working Draft 29 October 2009
|
||||
// http://www.w3.org/TR/2009/WD-eventsource-20091029/
|
||||
|
||||
const ContentType = "text/event-stream"
|
||||
|
||||
var contentType = []string{ContentType}
|
||||
var noCache = []string{"no-cache"}
|
||||
|
||||
var fieldReplacer = strings.NewReplacer(
|
||||
"\n", "\\n",
|
||||
"\r", "\\r")
|
||||
|
||||
var dataReplacer = strings.NewReplacer(
|
||||
"\n", "\ndata:",
|
||||
"\r", "\\r")
|
||||
|
||||
type Event struct {
|
||||
Event string
|
||||
Id string
|
||||
Retry uint
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
func Encode(writer io.Writer, event Event) error {
|
||||
w := checkWriter(writer)
|
||||
writeId(w, event.Id)
|
||||
writeEvent(w, event.Event)
|
||||
writeRetry(w, event.Retry)
|
||||
return writeData(w, event.Data)
|
||||
}
|
||||
|
||||
func writeId(w stringWriter, id string) {
|
||||
if len(id) > 0 {
|
||||
w.WriteString("id:")
|
||||
fieldReplacer.WriteString(w, id)
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeEvent(w stringWriter, event string) {
|
||||
if len(event) > 0 {
|
||||
w.WriteString("event:")
|
||||
fieldReplacer.WriteString(w, event)
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeRetry(w stringWriter, retry uint) {
|
||||
if retry > 0 {
|
||||
w.WriteString("retry:")
|
||||
w.WriteString(strconv.FormatUint(uint64(retry), 10))
|
||||
w.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func writeData(w stringWriter, data interface{}) error {
|
||||
w.WriteString("data:")
|
||||
switch kindOfData(data) {
|
||||
case reflect.Struct, reflect.Slice, reflect.Map:
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.WriteString("\n")
|
||||
default:
|
||||
dataReplacer.WriteString(w, fmt.Sprint(data))
|
||||
w.WriteString("\n\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r Event) Render(w http.ResponseWriter) error {
|
||||
r.WriteContentType(w)
|
||||
return Encode(w, r)
|
||||
}
|
||||
|
||||
func (r Event) WriteContentType(w http.ResponseWriter) {
|
||||
header := w.Header()
|
||||
header["Content-Type"] = contentType
|
||||
|
||||
if _, exist := header["Cache-Control"]; !exist {
|
||||
header["Cache-Control"] = noCache
|
||||
}
|
||||
}
|
||||
|
||||
func kindOfData(data interface{}) reflect.Kind {
|
||||
value := reflect.ValueOf(data)
|
||||
valueType := value.Kind()
|
||||
if valueType == reflect.Ptr {
|
||||
valueType = value.Elem().Kind()
|
||||
}
|
||||
return valueType
|
||||
}
|
||||
24
vendor/github.com/gin-contrib/sse/writer.go
generated
vendored
24
vendor/github.com/gin-contrib/sse/writer.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
package sse
|
||||
|
||||
import "io"
|
||||
|
||||
type stringWriter interface {
|
||||
io.Writer
|
||||
WriteString(string) (int, error)
|
||||
}
|
||||
|
||||
type stringWrapper struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (w stringWrapper) WriteString(str string) (int, error) {
|
||||
return w.Writer.Write([]byte(str))
|
||||
}
|
||||
|
||||
func checkWriter(writer io.Writer) stringWriter {
|
||||
if w, ok := writer.(stringWriter); ok {
|
||||
return w
|
||||
} else {
|
||||
return stringWrapper{writer}
|
||||
}
|
||||
}
|
||||
7
vendor/github.com/gin-gonic/gin/.gitignore
generated
vendored
7
vendor/github.com/gin-gonic/gin/.gitignore
generated
vendored
@@ -1,7 +0,0 @@
|
||||
vendor/*
|
||||
!vendor/vendor.json
|
||||
coverage.out
|
||||
count.out
|
||||
test
|
||||
profile.out
|
||||
tmp.out
|
||||
44
vendor/github.com/gin-gonic/gin/.travis.yml
generated
vendored
44
vendor/github.com/gin-gonic/gin/.travis.yml
generated
vendored
@@ -1,44 +0,0 @@
|
||||
language: go
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- go: 1.8.x
|
||||
- go: 1.9.x
|
||||
- go: 1.10.x
|
||||
- go: 1.11.x
|
||||
env: GO111MODULE=on
|
||||
- go: 1.12.x
|
||||
env: GO111MODULE=on
|
||||
- go: master
|
||||
env: GO111MODULE=on
|
||||
|
||||
git:
|
||||
depth: 10
|
||||
|
||||
before_install:
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi
|
||||
|
||||
install:
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make install; fi
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi
|
||||
- if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi
|
||||
|
||||
go_import_path: github.com/gin-gonic/gin
|
||||
|
||||
script:
|
||||
- make vet
|
||||
- make fmt-check
|
||||
- make misspell-check
|
||||
- make test
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/7f95bf605c4d356372f4
|
||||
on_success: change # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
231
vendor/github.com/gin-gonic/gin/AUTHORS.md
generated
vendored
231
vendor/github.com/gin-gonic/gin/AUTHORS.md
generated
vendored
@@ -1,231 +0,0 @@
|
||||
List of all the awesome people working to make Gin the best Web Framework in Go.
|
||||
|
||||
## gin 1.x series authors
|
||||
|
||||
**Gin Core Team:** Bo-Yi Wu (@appleboy), 田欧 (@thinkerou), Javier Provecho (@javierprovecho)
|
||||
|
||||
## gin 0.x series authors
|
||||
|
||||
**Maintainers:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho)
|
||||
|
||||
People and companies, who have contributed, in alphabetical order.
|
||||
|
||||
**@858806258 (杰哥)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@achedeuzot (Klemen Sever)**
|
||||
- Fix newline debug printing
|
||||
|
||||
|
||||
**@adammck (Adam Mckaig)**
|
||||
- Add MIT license
|
||||
|
||||
|
||||
**@AlexanderChen1989 (Alexander)**
|
||||
- Typos in README
|
||||
|
||||
|
||||
**@alexanderdidenko (Aleksandr Didenko)**
|
||||
- Add support multipart/form-data
|
||||
|
||||
|
||||
**@alexandernyquist (Alexander Nyquist)**
|
||||
- Using template.Must to fix multiple return issue
|
||||
- ★ Added support for OPTIONS verb
|
||||
- ★ Setting response headers before calling WriteHeader
|
||||
- Improved documentation for model binding
|
||||
- ★ Added Content.Redirect()
|
||||
- ★ Added tons of Unit tests
|
||||
|
||||
|
||||
**@austinheap (Austin Heap)**
|
||||
- Added travis CI integration
|
||||
|
||||
|
||||
**@andredublin (Andre Dublin)**
|
||||
- Fix typo in comment
|
||||
|
||||
|
||||
**@bredov (Ludwig Valda Vasquez)**
|
||||
- Fix html templating in debug mode
|
||||
|
||||
|
||||
**@bluele (Jun Kimura)**
|
||||
- Fixes code examples in README
|
||||
|
||||
|
||||
**@chad-russell**
|
||||
- ★ Support for serializing gin.H into XML
|
||||
|
||||
|
||||
**@dickeyxxx (Jeff Dickey)**
|
||||
- Typos in README
|
||||
- Add example about serving static files
|
||||
|
||||
|
||||
**@donileo (Adonis)**
|
||||
- Add NoMethod handler
|
||||
|
||||
|
||||
**@dutchcoders (DutchCoders)**
|
||||
- ★ Fix security bug that allows client to spoof ip
|
||||
- Fix typo. r.HTMLTemplates -> SetHTMLTemplate
|
||||
|
||||
|
||||
**@el3ctro- (Joshua Loper)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@ethankan (Ethan Kan)**
|
||||
- Unsigned integers in binding
|
||||
|
||||
|
||||
**(Evgeny Persienko)**
|
||||
- Validate sub structures
|
||||
|
||||
|
||||
**@frankbille (Frank Bille)**
|
||||
- Add support for HTTP Realm Auth
|
||||
|
||||
|
||||
**@fmd (Fareed Dudhia)**
|
||||
- Fix typo. SetHTTPTemplate -> SetHTMLTemplate
|
||||
|
||||
|
||||
**@ironiridis (Christopher Harrington)**
|
||||
- Remove old reference
|
||||
|
||||
|
||||
**@jammie-stackhouse (Jamie Stackhouse)**
|
||||
- Add more shortcuts for router methods
|
||||
|
||||
|
||||
**@jasonrhansen**
|
||||
- Fix spelling and grammar errors in documentation
|
||||
|
||||
|
||||
**@JasonSoft (Jason Lee)**
|
||||
- Fix typo in comment
|
||||
|
||||
|
||||
**@joiggama (Ignacio Galindo)**
|
||||
- Add utf-8 charset header on renders
|
||||
|
||||
|
||||
**@julienschmidt (Julien Schmidt)**
|
||||
- gofmt the code examples
|
||||
|
||||
|
||||
**@kelcecil (Kel Cecil)**
|
||||
- Fix readme typo
|
||||
|
||||
|
||||
**@kyledinh (Kyle Dinh)**
|
||||
- Adds RunTLS()
|
||||
|
||||
|
||||
**@LinusU (Linus Unnebäck)**
|
||||
- Small fixes in README
|
||||
|
||||
|
||||
**@loongmxbt (Saint Asky)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@lucas-clemente (Lucas Clemente)**
|
||||
- ★ work around path.Join removing trailing slashes from routes
|
||||
|
||||
|
||||
**@mattn (Yasuhiro Matsumoto)**
|
||||
- Improve color logger
|
||||
|
||||
|
||||
**@mdigger (Dmitry Sedykh)**
|
||||
- Fixes Form binding when content-type is x-www-form-urlencoded
|
||||
- No repeat call c.Writer.Status() in gin.Logger
|
||||
- Fixes Content-Type for json render
|
||||
|
||||
|
||||
**@mirzac (Mirza Ceric)**
|
||||
- Fix debug printing
|
||||
|
||||
|
||||
**@mopemope (Yutaka Matsubara)**
|
||||
- ★ Adds Godep support (Dependencies Manager)
|
||||
- Fix variadic parameter in the flexible render API
|
||||
- Fix Corrupted plain render
|
||||
- Add Pluggable View Renderer Example
|
||||
|
||||
|
||||
**@msemenistyi (Mykyta Semenistyi)**
|
||||
- update Readme.md. Add code to String method
|
||||
|
||||
|
||||
**@msoedov (Sasha Myasoedov)**
|
||||
- ★ Adds tons of unit tests.
|
||||
|
||||
|
||||
**@ngerakines (Nick Gerakines)**
|
||||
- ★ Improves API, c.GET() doesn't panic
|
||||
- Adds MustGet() method
|
||||
|
||||
|
||||
**@r8k (Rajiv Kilaparti)**
|
||||
- Fix Port usage in README.
|
||||
|
||||
|
||||
**@rayrod2030 (Ray Rodriguez)**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@rns**
|
||||
- Fix typo in example
|
||||
|
||||
|
||||
**@RobAWilkinson (Robert Wilkinson)**
|
||||
- Add example of forms and params
|
||||
|
||||
|
||||
**@rogierlommers (Rogier Lommers)**
|
||||
- Add updated static serve example
|
||||
|
||||
|
||||
**@se77en (Damon Zhao)**
|
||||
- Improve color logging
|
||||
|
||||
|
||||
**@silasb (Silas Baronda)**
|
||||
- Fixing quotes in README
|
||||
|
||||
|
||||
**@SkuliOskarsson (Skuli Oskarsson)**
|
||||
- Fixes some texts in README II
|
||||
|
||||
|
||||
**@slimmy (Jimmy Pettersson)**
|
||||
- Added messages for required bindings
|
||||
|
||||
|
||||
**@smira (Andrey Smirnov)**
|
||||
- Add support for ignored/unexported fields in binding
|
||||
|
||||
|
||||
**@superalsrk (SRK.Lyu)**
|
||||
- Update httprouter godeps
|
||||
|
||||
|
||||
**@tebeka (Miki Tebeka)**
|
||||
- Use net/http constants instead of numeric values
|
||||
|
||||
|
||||
**@techjanitor**
|
||||
- Update context.go reserved IPs
|
||||
|
||||
|
||||
**@yosssi (Keiji Yoshida)**
|
||||
- Fix link in README
|
||||
|
||||
|
||||
**@yuyabee**
|
||||
- Fixed README
|
||||
604
vendor/github.com/gin-gonic/gin/BENCHMARKS.md
generated
vendored
604
vendor/github.com/gin-gonic/gin/BENCHMARKS.md
generated
vendored
@@ -1,604 +0,0 @@
|
||||
|
||||
## Benchmark System
|
||||
|
||||
**VM HOST:** DigitalOcean
|
||||
**Machine:** 4 CPU, 8 GB RAM. Ubuntu 16.04.2 x64
|
||||
**Date:** July 19th, 2017
|
||||
**Go Version:** 1.8.3 linux/amd64
|
||||
**Source:** [Go HTTP Router Benchmark](https://github.com/julienschmidt/go-http-routing-benchmark)
|
||||
|
||||
## Static Routes: 157
|
||||
|
||||
```
|
||||
Gin: 30512 Bytes
|
||||
|
||||
HttpServeMux: 17344 Bytes
|
||||
Ace: 30080 Bytes
|
||||
Bear: 30472 Bytes
|
||||
Beego: 96408 Bytes
|
||||
Bone: 37904 Bytes
|
||||
Denco: 10464 Bytes
|
||||
Echo: 73680 Bytes
|
||||
GocraftWeb: 55720 Bytes
|
||||
Goji: 27200 Bytes
|
||||
Gojiv2: 104464 Bytes
|
||||
GoJsonRest: 136472 Bytes
|
||||
GoRestful: 914904 Bytes
|
||||
GorillaMux: 675568 Bytes
|
||||
HttpRouter: 21128 Bytes
|
||||
HttpTreeMux: 73448 Bytes
|
||||
Kocha: 115072 Bytes
|
||||
LARS: 30120 Bytes
|
||||
Macaron: 37984 Bytes
|
||||
Martini: 310832 Bytes
|
||||
Pat: 20464 Bytes
|
||||
Possum: 91328 Bytes
|
||||
R2router: 23712 Bytes
|
||||
Rivet: 23880 Bytes
|
||||
Tango: 28008 Bytes
|
||||
TigerTonic: 80368 Bytes
|
||||
Traffic: 626480 Bytes
|
||||
Vulcan: 369064 Bytes
|
||||
```
|
||||
|
||||
## GithubAPI Routes: 203
|
||||
|
||||
```
|
||||
Gin: 52672 Bytes
|
||||
|
||||
Ace: 48992 Bytes
|
||||
Bear: 161592 Bytes
|
||||
Beego: 147992 Bytes
|
||||
Bone: 97728 Bytes
|
||||
Denco: 36440 Bytes
|
||||
Echo: 95672 Bytes
|
||||
GocraftWeb: 95640 Bytes
|
||||
Goji: 86088 Bytes
|
||||
Gojiv2: 144392 Bytes
|
||||
GoJsonRest: 134648 Bytes
|
||||
GoRestful: 1410760 Bytes
|
||||
GorillaMux: 1509488 Bytes
|
||||
HttpRouter: 37464 Bytes
|
||||
HttpTreeMux: 78800 Bytes
|
||||
Kocha: 785408 Bytes
|
||||
LARS: 49032 Bytes
|
||||
Macaron: 132712 Bytes
|
||||
Martini: 564352 Bytes
|
||||
Pat: 21200 Bytes
|
||||
Possum: 83888 Bytes
|
||||
R2router: 47104 Bytes
|
||||
Rivet: 42840 Bytes
|
||||
Tango: 54584 Bytes
|
||||
TigerTonic: 96384 Bytes
|
||||
Traffic: 1061920 Bytes
|
||||
Vulcan: 465296 Bytes
|
||||
```
|
||||
|
||||
## GPlusAPI Routes: 13
|
||||
|
||||
```
|
||||
Gin: 3968 Bytes
|
||||
|
||||
Ace: 3600 Bytes
|
||||
Bear: 7112 Bytes
|
||||
Beego: 10048 Bytes
|
||||
Bone: 6480 Bytes
|
||||
Denco: 3256 Bytes
|
||||
Echo: 9000 Bytes
|
||||
GocraftWeb: 7496 Bytes
|
||||
Goji: 2912 Bytes
|
||||
Gojiv2: 7376 Bytes
|
||||
GoJsonRest: 11544 Bytes
|
||||
GoRestful: 88776 Bytes
|
||||
GorillaMux: 71488 Bytes
|
||||
HttpRouter: 2712 Bytes
|
||||
HttpTreeMux: 7440 Bytes
|
||||
Kocha: 128880 Bytes
|
||||
LARS: 3640 Bytes
|
||||
Macaron: 8656 Bytes
|
||||
Martini: 23936 Bytes
|
||||
Pat: 1856 Bytes
|
||||
Possum: 7248 Bytes
|
||||
R2router: 3928 Bytes
|
||||
Rivet: 3064 Bytes
|
||||
Tango: 4912 Bytes
|
||||
TigerTonic: 9408 Bytes
|
||||
Traffic: 49472 Bytes
|
||||
Vulcan: 25496 Bytes
|
||||
```
|
||||
|
||||
## ParseAPI Routes: 26
|
||||
|
||||
```
|
||||
Gin: 6928 Bytes
|
||||
|
||||
Ace: 6592 Bytes
|
||||
Bear: 12320 Bytes
|
||||
Beego: 18960 Bytes
|
||||
Bone: 11024 Bytes
|
||||
Denco: 4184 Bytes
|
||||
Echo: 11168 Bytes
|
||||
GocraftWeb: 12800 Bytes
|
||||
Goji: 5232 Bytes
|
||||
Gojiv2: 14464 Bytes
|
||||
GoJsonRest: 14216 Bytes
|
||||
GoRestful: 127368 Bytes
|
||||
GorillaMux: 123016 Bytes
|
||||
HttpRouter: 4976 Bytes
|
||||
HttpTreeMux: 7848 Bytes
|
||||
Kocha: 181712 Bytes
|
||||
LARS: 6632 Bytes
|
||||
Macaron: 13648 Bytes
|
||||
Martini: 45952 Bytes
|
||||
Pat: 2560 Bytes
|
||||
Possum: 9200 Bytes
|
||||
R2router: 7056 Bytes
|
||||
Rivet: 5680 Bytes
|
||||
Tango: 8664 Bytes
|
||||
TigerTonic: 9840 Bytes
|
||||
Traffic: 93480 Bytes
|
||||
Vulcan: 44504 Bytes
|
||||
```
|
||||
|
||||
## Static Routes
|
||||
|
||||
```
|
||||
BenchmarkGin_StaticAll 50000 34506 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_StaticAll 30000 49657 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpServeMux_StaticAll 2000 1183737 ns/op 96 B/op 8 allocs/op
|
||||
BenchmarkBeego_StaticAll 5000 412621 ns/op 57776 B/op 628 allocs/op
|
||||
BenchmarkBear_StaticAll 10000 149242 ns/op 20336 B/op 461 allocs/op
|
||||
BenchmarkBone_StaticAll 10000 118583 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkDenco_StaticAll 100000 13247 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_StaticAll 20000 79914 ns/op 5024 B/op 157 allocs/op
|
||||
BenchmarkGocraftWeb_StaticAll 10000 211823 ns/op 46440 B/op 785 allocs/op
|
||||
BenchmarkGoji_StaticAll 10000 109390 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGojiv2_StaticAll 3000 415533 ns/op 145696 B/op 1099 allocs/op
|
||||
BenchmarkGoJsonRest_StaticAll 5000 364403 ns/op 51653 B/op 1727 allocs/op
|
||||
BenchmarkGoRestful_StaticAll 500 2578579 ns/op 314936 B/op 3144 allocs/op
|
||||
BenchmarkGorillaMux_StaticAll 500 2704856 ns/op 115648 B/op 1578 allocs/op
|
||||
BenchmarkHttpRouter_StaticAll 100000 18541 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_StaticAll 100000 22332 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_StaticAll 50000 31176 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLARS_StaticAll 50000 40840 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_StaticAll 5000 517656 ns/op 120576 B/op 1413 allocs/op
|
||||
BenchmarkMartini_StaticAll 300 4462289 ns/op 125442 B/op 1717 allocs/op
|
||||
BenchmarkPat_StaticAll 500 2157275 ns/op 533904 B/op 11123 allocs/op
|
||||
BenchmarkPossum_StaticAll 10000 254701 ns/op 65312 B/op 471 allocs/op
|
||||
BenchmarkR2router_StaticAll 10000 133956 ns/op 22608 B/op 628 allocs/op
|
||||
BenchmarkRivet_StaticAll 30000 46812 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkTango_StaticAll 5000 390613 ns/op 39225 B/op 1256 allocs/op
|
||||
BenchmarkTigerTonic_StaticAll 20000 88060 ns/op 7504 B/op 157 allocs/op
|
||||
BenchmarkTraffic_StaticAll 500 2910236 ns/op 729736 B/op 14287 allocs/op
|
||||
BenchmarkVulcan_StaticAll 5000 277366 ns/op 15386 B/op 471 allocs/op
|
||||
```
|
||||
|
||||
## Micro Benchmarks
|
||||
|
||||
```
|
||||
BenchmarkGin_Param 20000000 113 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_Param 5000000 375 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkBear_Param 1000000 1709 ns/op 456 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param 1000000 2484 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_Param 1000000 2391 ns/op 688 B/op 5 allocs/op
|
||||
BenchmarkDenco_Param 10000000 240 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param 5000000 366 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGocraftWeb_Param 1000000 2343 ns/op 648 B/op 8 allocs/op
|
||||
BenchmarkGoji_Param 1000000 1197 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_Param 1000000 2771 ns/op 944 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_Param 1000000 2993 ns/op 649 B/op 13 allocs/op
|
||||
BenchmarkGoRestful_Param 200000 8860 ns/op 2296 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_Param 500000 4461 ns/op 1056 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_Param 10000000 175 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param 1000000 1167 ns/op 352 B/op 3 allocs/op
|
||||
BenchmarkKocha_Param 3000000 429 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkLARS_Param 10000000 134 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_Param 500000 4635 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_Param 200000 9933 ns/op 1072 B/op 10 allocs/op
|
||||
BenchmarkPat_Param 1000000 2929 ns/op 648 B/op 12 allocs/op
|
||||
BenchmarkPossum_Param 1000000 2503 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_Param 1000000 1507 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_Param 5000000 297 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTango_Param 1000000 1862 ns/op 248 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_Param 500000 5660 ns/op 992 B/op 17 allocs/op
|
||||
BenchmarkTraffic_Param 200000 8408 ns/op 1960 B/op 21 allocs/op
|
||||
BenchmarkVulcan_Param 2000000 963 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_Param5 2000000 740 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkBear_Param5 1000000 2777 ns/op 501 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param5 1000000 3740 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_Param5 1000000 2950 ns/op 736 B/op 5 allocs/op
|
||||
BenchmarkDenco_Param5 2000000 644 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param5 3000000 558 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_Param5 10000000 198 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Param5 500000 3870 ns/op 920 B/op 11 allocs/op
|
||||
BenchmarkGoji_Param5 1000000 1746 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_Param5 1000000 3214 ns/op 1008 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_Param5 500000 5509 ns/op 1097 B/op 16 allocs/op
|
||||
BenchmarkGoRestful_Param5 200000 11232 ns/op 2392 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_Param5 300000 7777 ns/op 1184 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_Param5 3000000 631 ns/op 160 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param5 1000000 2800 ns/op 576 B/op 6 allocs/op
|
||||
BenchmarkKocha_Param5 1000000 2053 ns/op 440 B/op 10 allocs/op
|
||||
BenchmarkLARS_Param5 10000000 232 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_Param5 500000 5888 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_Param5 200000 12807 ns/op 1232 B/op 11 allocs/op
|
||||
BenchmarkPat_Param5 300000 7320 ns/op 964 B/op 32 allocs/op
|
||||
BenchmarkPossum_Param5 1000000 2495 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_Param5 1000000 1844 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_Param5 2000000 935 ns/op 240 B/op 1 allocs/op
|
||||
BenchmarkTango_Param5 1000000 2327 ns/op 360 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_Param5 100000 18514 ns/op 2551 B/op 43 allocs/op
|
||||
BenchmarkTraffic_Param5 200000 11997 ns/op 2248 B/op 25 allocs/op
|
||||
BenchmarkVulcan_Param5 1000000 1333 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_Param20 1000000 2031 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkBear_Param20 200000 7285 ns/op 1664 B/op 5 allocs/op
|
||||
BenchmarkBeego_Param20 300000 6224 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_Param20 200000 8023 ns/op 1903 B/op 5 allocs/op
|
||||
BenchmarkDenco_Param20 1000000 2262 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkEcho_Param20 1000000 1387 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_Param20 3000000 503 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Param20 100000 14408 ns/op 3795 B/op 15 allocs/op
|
||||
BenchmarkGoji_Param20 500000 5272 ns/op 1247 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_Param20 1000000 4163 ns/op 1248 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_Param20 100000 17866 ns/op 4485 B/op 20 allocs/op
|
||||
BenchmarkGoRestful_Param20 100000 21022 ns/op 4724 B/op 23 allocs/op
|
||||
BenchmarkGorillaMux_Param20 100000 17055 ns/op 3547 B/op 13 allocs/op
|
||||
BenchmarkHttpRouter_Param20 1000000 1748 ns/op 640 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Param20 200000 12246 ns/op 3196 B/op 10 allocs/op
|
||||
BenchmarkKocha_Param20 300000 6861 ns/op 1808 B/op 27 allocs/op
|
||||
BenchmarkLARS_Param20 3000000 526 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_Param20 100000 13069 ns/op 2906 B/op 12 allocs/op
|
||||
BenchmarkMartini_Param20 100000 23602 ns/op 3597 B/op 13 allocs/op
|
||||
BenchmarkPat_Param20 50000 32143 ns/op 4688 B/op 111 allocs/op
|
||||
BenchmarkPossum_Param20 1000000 2396 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_Param20 200000 8907 ns/op 2283 B/op 7 allocs/op
|
||||
BenchmarkRivet_Param20 1000000 3280 ns/op 1024 B/op 1 allocs/op
|
||||
BenchmarkTango_Param20 500000 4640 ns/op 856 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_Param20 20000 67581 ns/op 10532 B/op 138 allocs/op
|
||||
BenchmarkTraffic_Param20 50000 40313 ns/op 7941 B/op 45 allocs/op
|
||||
BenchmarkVulcan_Param20 1000000 2264 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_ParamWrite 3000000 532 ns/op 40 B/op 2 allocs/op
|
||||
BenchmarkBear_ParamWrite 1000000 1778 ns/op 456 B/op 5 allocs/op
|
||||
BenchmarkBeego_ParamWrite 1000000 2596 ns/op 376 B/op 5 allocs/op
|
||||
BenchmarkBone_ParamWrite 1000000 2519 ns/op 688 B/op 5 allocs/op
|
||||
BenchmarkDenco_ParamWrite 5000000 411 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkEcho_ParamWrite 2000000 718 ns/op 40 B/op 2 allocs/op
|
||||
BenchmarkGin_ParamWrite 5000000 283 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_ParamWrite 1000000 2561 ns/op 656 B/op 9 allocs/op
|
||||
BenchmarkGoji_ParamWrite 1000000 1378 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_ParamWrite 1000000 3128 ns/op 976 B/op 10 allocs/op
|
||||
BenchmarkGoJsonRest_ParamWrite 500000 4446 ns/op 1128 B/op 18 allocs/op
|
||||
BenchmarkGoRestful_ParamWrite 200000 10291 ns/op 2304 B/op 22 allocs/op
|
||||
BenchmarkGorillaMux_ParamWrite 500000 5153 ns/op 1064 B/op 12 allocs/op
|
||||
BenchmarkHttpRouter_ParamWrite 5000000 263 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_ParamWrite 1000000 1351 ns/op 352 B/op 3 allocs/op
|
||||
BenchmarkKocha_ParamWrite 3000000 538 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkLARS_ParamWrite 5000000 316 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_ParamWrite 500000 5756 ns/op 1160 B/op 14 allocs/op
|
||||
BenchmarkMartini_ParamWrite 200000 13097 ns/op 1176 B/op 14 allocs/op
|
||||
BenchmarkPat_ParamWrite 500000 4954 ns/op 1072 B/op 17 allocs/op
|
||||
BenchmarkPossum_ParamWrite 1000000 2499 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_ParamWrite 1000000 1531 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_ParamWrite 3000000 570 ns/op 112 B/op 2 allocs/op
|
||||
BenchmarkTango_ParamWrite 2000000 957 ns/op 136 B/op 4 allocs/op
|
||||
BenchmarkTigerTonic_ParamWrite 200000 7025 ns/op 1424 B/op 23 allocs/op
|
||||
BenchmarkTraffic_ParamWrite 200000 10112 ns/op 2384 B/op 25 allocs/op
|
||||
BenchmarkVulcan_ParamWrite 1000000 1006 ns/op 98 B/op 3 allocs/op
|
||||
```
|
||||
|
||||
## GitHub
|
||||
|
||||
```
|
||||
BenchmarkGin_GithubStatic 10000000 156 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_GithubStatic 5000000 294 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBear_GithubStatic 2000000 893 ns/op 120 B/op 3 allocs/op
|
||||
BenchmarkBeego_GithubStatic 1000000 2491 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GithubStatic 50000 25300 ns/op 2880 B/op 60 allocs/op
|
||||
BenchmarkDenco_GithubStatic 20000000 76.0 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_GithubStatic 2000000 516 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGocraftWeb_GithubStatic 1000000 1448 ns/op 296 B/op 5 allocs/op
|
||||
BenchmarkGoji_GithubStatic 3000000 496 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGojiv2_GithubStatic 1000000 2941 ns/op 928 B/op 7 allocs/op
|
||||
BenchmarkGoRestful_GithubStatic 100000 27256 ns/op 3224 B/op 22 allocs/op
|
||||
BenchmarkGoJsonRest_GithubStatic 1000000 2196 ns/op 329 B/op 11 allocs/op
|
||||
BenchmarkGorillaMux_GithubStatic 50000 31617 ns/op 736 B/op 10 allocs/op
|
||||
BenchmarkHttpRouter_GithubStatic 20000000 88.4 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubStatic 10000000 134 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_GithubStatic 20000000 113 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLARS_GithubStatic 10000000 195 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GithubStatic 500000 3740 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkMartini_GithubStatic 50000 27673 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkPat_GithubStatic 100000 19470 ns/op 3648 B/op 76 allocs/op
|
||||
BenchmarkPossum_GithubStatic 1000000 1729 ns/op 416 B/op 3 allocs/op
|
||||
BenchmarkR2router_GithubStatic 2000000 879 ns/op 144 B/op 4 allocs/op
|
||||
BenchmarkRivet_GithubStatic 10000000 231 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkTango_GithubStatic 1000000 2325 ns/op 248 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GithubStatic 3000000 610 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTraffic_GithubStatic 20000 62973 ns/op 18904 B/op 148 allocs/op
|
||||
BenchmarkVulcan_GithubStatic 1000000 1447 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GithubParam 2000000 686 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkBear_GithubParam 1000000 2155 ns/op 496 B/op 5 allocs/op
|
||||
BenchmarkBeego_GithubParam 1000000 2713 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GithubParam 100000 15088 ns/op 1760 B/op 18 allocs/op
|
||||
BenchmarkDenco_GithubParam 2000000 629 ns/op 128 B/op 1 allocs/op
|
||||
BenchmarkEcho_GithubParam 2000000 653 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_GithubParam 5000000 255 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GithubParam 1000000 3145 ns/op 712 B/op 9 allocs/op
|
||||
BenchmarkGoji_GithubParam 1000000 1916 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_GithubParam 1000000 3975 ns/op 1024 B/op 10 allocs/op
|
||||
BenchmarkGoJsonRest_GithubParam 300000 4134 ns/op 713 B/op 14 allocs/op
|
||||
BenchmarkGoRestful_GithubParam 50000 30782 ns/op 2360 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_GithubParam 100000 17148 ns/op 1088 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_GithubParam 3000000 523 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubParam 1000000 1671 ns/op 384 B/op 4 allocs/op
|
||||
BenchmarkKocha_GithubParam 1000000 1021 ns/op 128 B/op 5 allocs/op
|
||||
BenchmarkLARS_GithubParam 5000000 283 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GithubParam 500000 4270 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_GithubParam 100000 21728 ns/op 1152 B/op 11 allocs/op
|
||||
BenchmarkPat_GithubParam 200000 11208 ns/op 2464 B/op 48 allocs/op
|
||||
BenchmarkPossum_GithubParam 1000000 2334 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_GithubParam 1000000 1487 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_GithubParam 2000000 782 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkTango_GithubParam 1000000 2653 ns/op 344 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GithubParam 300000 14073 ns/op 1440 B/op 24 allocs/op
|
||||
BenchmarkTraffic_GithubParam 50000 29164 ns/op 5992 B/op 52 allocs/op
|
||||
BenchmarkVulcan_GithubParam 1000000 2529 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GithubAll 10000 134059 ns/op 13792 B/op 167 allocs/op
|
||||
BenchmarkBear_GithubAll 5000 534445 ns/op 86448 B/op 943 allocs/op
|
||||
BenchmarkBeego_GithubAll 3000 592444 ns/op 74705 B/op 812 allocs/op
|
||||
BenchmarkBone_GithubAll 200 6957308 ns/op 698784 B/op 8453 allocs/op
|
||||
BenchmarkDenco_GithubAll 10000 158819 ns/op 20224 B/op 167 allocs/op
|
||||
BenchmarkEcho_GithubAll 10000 154700 ns/op 6496 B/op 203 allocs/op
|
||||
BenchmarkGin_GithubAll 30000 48375 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GithubAll 3000 570806 ns/op 131656 B/op 1686 allocs/op
|
||||
BenchmarkGoji_GithubAll 2000 818034 ns/op 56112 B/op 334 allocs/op
|
||||
BenchmarkGojiv2_GithubAll 2000 1213973 ns/op 274768 B/op 3712 allocs/op
|
||||
BenchmarkGoJsonRest_GithubAll 2000 785796 ns/op 134371 B/op 2737 allocs/op
|
||||
BenchmarkGoRestful_GithubAll 300 5238188 ns/op 689672 B/op 4519 allocs/op
|
||||
BenchmarkGorillaMux_GithubAll 100 10257726 ns/op 211840 B/op 2272 allocs/op
|
||||
BenchmarkHttpRouter_GithubAll 20000 105414 ns/op 13792 B/op 167 allocs/op
|
||||
BenchmarkHttpTreeMux_GithubAll 10000 319934 ns/op 65856 B/op 671 allocs/op
|
||||
BenchmarkKocha_GithubAll 10000 209442 ns/op 23304 B/op 843 allocs/op
|
||||
BenchmarkLARS_GithubAll 20000 62565 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GithubAll 2000 1161270 ns/op 204194 B/op 2000 allocs/op
|
||||
BenchmarkMartini_GithubAll 200 9991713 ns/op 226549 B/op 2325 allocs/op
|
||||
BenchmarkPat_GithubAll 200 5590793 ns/op 1499568 B/op 27435 allocs/op
|
||||
BenchmarkPossum_GithubAll 10000 319768 ns/op 84448 B/op 609 allocs/op
|
||||
BenchmarkR2router_GithubAll 10000 305134 ns/op 77328 B/op 979 allocs/op
|
||||
BenchmarkRivet_GithubAll 10000 132134 ns/op 16272 B/op 167 allocs/op
|
||||
BenchmarkTango_GithubAll 3000 552754 ns/op 63826 B/op 1618 allocs/op
|
||||
BenchmarkTigerTonic_GithubAll 1000 1439483 ns/op 239104 B/op 5374 allocs/op
|
||||
BenchmarkTraffic_GithubAll 100 11383067 ns/op 2659329 B/op 21848 allocs/op
|
||||
BenchmarkVulcan_GithubAll 5000 394253 ns/op 19894 B/op 609 allocs/op
|
||||
```
|
||||
|
||||
## Google+
|
||||
|
||||
```
|
||||
BenchmarkGin_GPlusStatic 10000000 183 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_GPlusStatic 5000000 276 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBear_GPlusStatic 2000000 652 ns/op 104 B/op 3 allocs/op
|
||||
BenchmarkBeego_GPlusStatic 1000000 2239 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GPlusStatic 5000000 380 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkDenco_GPlusStatic 30000000 45.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_GPlusStatic 5000000 338 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusStatic 1000000 1158 ns/op 280 B/op 5 allocs/op
|
||||
BenchmarkGoji_GPlusStatic 5000000 331 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGojiv2_GPlusStatic 1000000 2106 ns/op 928 B/op 7 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusStatic 1000000 1626 ns/op 329 B/op 11 allocs/op
|
||||
BenchmarkGoRestful_GPlusStatic 300000 7598 ns/op 1976 B/op 20 allocs/op
|
||||
BenchmarkGorillaMux_GPlusStatic 1000000 2629 ns/op 736 B/op 10 allocs/op
|
||||
BenchmarkHttpRouter_GPlusStatic 30000000 52.5 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusStatic 20000000 85.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_GPlusStatic 20000000 89.2 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLARS_GPlusStatic 10000000 162 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlusStatic 500000 3479 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkMartini_GPlusStatic 200000 9092 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkPat_GPlusStatic 3000000 493 ns/op 96 B/op 2 allocs/op
|
||||
BenchmarkPossum_GPlusStatic 1000000 1467 ns/op 416 B/op 3 allocs/op
|
||||
BenchmarkR2router_GPlusStatic 2000000 788 ns/op 144 B/op 4 allocs/op
|
||||
BenchmarkRivet_GPlusStatic 20000000 114 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkTango_GPlusStatic 1000000 1534 ns/op 200 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GPlusStatic 5000000 282 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkTraffic_GPlusStatic 500000 3798 ns/op 1192 B/op 15 allocs/op
|
||||
BenchmarkVulcan_GPlusStatic 2000000 1125 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GPlusParam 3000000 528 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_GPlusParam 1000000 1570 ns/op 480 B/op 5 allocs/op
|
||||
BenchmarkBeego_GPlusParam 1000000 2369 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GPlusParam 1000000 2028 ns/op 688 B/op 5 allocs/op
|
||||
BenchmarkDenco_GPlusParam 5000000 385 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_GPlusParam 3000000 441 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_GPlusParam 10000000 174 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusParam 1000000 2033 ns/op 648 B/op 8 allocs/op
|
||||
BenchmarkGoji_GPlusParam 1000000 1399 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_GPlusParam 1000000 2641 ns/op 944 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusParam 1000000 2824 ns/op 649 B/op 13 allocs/op
|
||||
BenchmarkGoRestful_GPlusParam 200000 8875 ns/op 2296 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_GPlusParam 200000 6291 ns/op 1056 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_GPlusParam 5000000 316 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusParam 1000000 1129 ns/op 352 B/op 3 allocs/op
|
||||
BenchmarkKocha_GPlusParam 3000000 538 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkLARS_GPlusParam 10000000 198 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlusParam 500000 3554 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_GPlusParam 200000 9831 ns/op 1072 B/op 10 allocs/op
|
||||
BenchmarkPat_GPlusParam 1000000 2706 ns/op 688 B/op 12 allocs/op
|
||||
BenchmarkPossum_GPlusParam 1000000 2297 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_GPlusParam 1000000 1318 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_GPlusParam 5000000 399 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTango_GPlusParam 1000000 2070 ns/op 264 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GPlusParam 500000 4853 ns/op 1056 B/op 17 allocs/op
|
||||
BenchmarkTraffic_GPlusParam 200000 8278 ns/op 1976 B/op 21 allocs/op
|
||||
BenchmarkVulcan_GPlusParam 1000000 1243 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GPlus2Params 3000000 549 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_GPlus2Params 1000000 2112 ns/op 496 B/op 5 allocs/op
|
||||
BenchmarkBeego_GPlus2Params 500000 2750 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_GPlus2Params 300000 7032 ns/op 1040 B/op 9 allocs/op
|
||||
BenchmarkDenco_GPlus2Params 3000000 502 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_GPlus2Params 3000000 641 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_GPlus2Params 5000000 250 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlus2Params 1000000 2681 ns/op 712 B/op 9 allocs/op
|
||||
BenchmarkGoji_GPlus2Params 1000000 1926 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_GPlus2Params 500000 3996 ns/op 1024 B/op 11 allocs/op
|
||||
BenchmarkGoJsonRest_GPlus2Params 500000 3886 ns/op 713 B/op 14 allocs/op
|
||||
BenchmarkGoRestful_GPlus2Params 200000 10376 ns/op 2360 B/op 21 allocs/op
|
||||
BenchmarkGorillaMux_GPlus2Params 100000 14162 ns/op 1088 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_GPlus2Params 5000000 336 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlus2Params 1000000 1523 ns/op 384 B/op 4 allocs/op
|
||||
BenchmarkKocha_GPlus2Params 2000000 970 ns/op 128 B/op 5 allocs/op
|
||||
BenchmarkLARS_GPlus2Params 5000000 238 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlus2Params 500000 4016 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_GPlus2Params 100000 21253 ns/op 1200 B/op 13 allocs/op
|
||||
BenchmarkPat_GPlus2Params 200000 8632 ns/op 2256 B/op 34 allocs/op
|
||||
BenchmarkPossum_GPlus2Params 1000000 2171 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_GPlus2Params 1000000 1340 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_GPlus2Params 3000000 557 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkTango_GPlus2Params 1000000 2186 ns/op 344 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_GPlus2Params 200000 9060 ns/op 1488 B/op 24 allocs/op
|
||||
BenchmarkTraffic_GPlus2Params 100000 20324 ns/op 3272 B/op 31 allocs/op
|
||||
BenchmarkVulcan_GPlus2Params 1000000 2039 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_GPlusAll 300000 6603 ns/op 640 B/op 11 allocs/op
|
||||
BenchmarkBear_GPlusAll 100000 22363 ns/op 5488 B/op 61 allocs/op
|
||||
BenchmarkBeego_GPlusAll 50000 38757 ns/op 4784 B/op 52 allocs/op
|
||||
BenchmarkBone_GPlusAll 20000 54916 ns/op 10336 B/op 98 allocs/op
|
||||
BenchmarkDenco_GPlusAll 300000 4959 ns/op 672 B/op 11 allocs/op
|
||||
BenchmarkEcho_GPlusAll 200000 6558 ns/op 416 B/op 13 allocs/op
|
||||
BenchmarkGin_GPlusAll 500000 2757 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_GPlusAll 50000 34615 ns/op 8040 B/op 103 allocs/op
|
||||
BenchmarkGoji_GPlusAll 100000 16002 ns/op 3696 B/op 22 allocs/op
|
||||
BenchmarkGojiv2_GPlusAll 50000 35060 ns/op 12624 B/op 115 allocs/op
|
||||
BenchmarkGoJsonRest_GPlusAll 50000 41479 ns/op 8117 B/op 170 allocs/op
|
||||
BenchmarkGoRestful_GPlusAll 10000 131653 ns/op 32024 B/op 275 allocs/op
|
||||
BenchmarkGorillaMux_GPlusAll 10000 101380 ns/op 13296 B/op 142 allocs/op
|
||||
BenchmarkHttpRouter_GPlusAll 500000 3711 ns/op 640 B/op 11 allocs/op
|
||||
BenchmarkHttpTreeMux_GPlusAll 100000 14438 ns/op 4032 B/op 38 allocs/op
|
||||
BenchmarkKocha_GPlusAll 200000 8039 ns/op 976 B/op 43 allocs/op
|
||||
BenchmarkLARS_GPlusAll 500000 2630 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_GPlusAll 30000 51123 ns/op 13152 B/op 128 allocs/op
|
||||
BenchmarkMartini_GPlusAll 10000 176157 ns/op 14016 B/op 145 allocs/op
|
||||
BenchmarkPat_GPlusAll 20000 69911 ns/op 16576 B/op 298 allocs/op
|
||||
BenchmarkPossum_GPlusAll 100000 20716 ns/op 5408 B/op 39 allocs/op
|
||||
BenchmarkR2router_GPlusAll 100000 17463 ns/op 5040 B/op 63 allocs/op
|
||||
BenchmarkRivet_GPlusAll 300000 5142 ns/op 768 B/op 11 allocs/op
|
||||
BenchmarkTango_GPlusAll 50000 27321 ns/op 3656 B/op 104 allocs/op
|
||||
BenchmarkTigerTonic_GPlusAll 20000 77597 ns/op 14512 B/op 288 allocs/op
|
||||
BenchmarkTraffic_GPlusAll 10000 151406 ns/op 37360 B/op 392 allocs/op
|
||||
BenchmarkVulcan_GPlusAll 100000 18555 ns/op 1274 B/op 39 allocs/op
|
||||
```
|
||||
|
||||
## Parse.com
|
||||
|
||||
```
|
||||
BenchmarkGin_ParseStatic 10000000 133 ns/op 0 B/op 0 allocs/op
|
||||
|
||||
BenchmarkAce_ParseStatic 5000000 241 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkBear_ParseStatic 2000000 728 ns/op 120 B/op 3 allocs/op
|
||||
BenchmarkBeego_ParseStatic 1000000 2623 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_ParseStatic 1000000 1285 ns/op 144 B/op 3 allocs/op
|
||||
BenchmarkDenco_ParseStatic 30000000 57.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkEcho_ParseStatic 5000000 342 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGocraftWeb_ParseStatic 1000000 1478 ns/op 296 B/op 5 allocs/op
|
||||
BenchmarkGoji_ParseStatic 3000000 415 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGojiv2_ParseStatic 1000000 2087 ns/op 928 B/op 7 allocs/op
|
||||
BenchmarkGoJsonRest_ParseStatic 1000000 1712 ns/op 329 B/op 11 allocs/op
|
||||
BenchmarkGoRestful_ParseStatic 200000 11072 ns/op 3224 B/op 22 allocs/op
|
||||
BenchmarkGorillaMux_ParseStatic 500000 4129 ns/op 752 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_ParseStatic 30000000 52.4 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkHttpTreeMux_ParseStatic 20000000 109 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkKocha_ParseStatic 20000000 81.8 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkLARS_ParseStatic 10000000 150 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_ParseStatic 1000000 3288 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkMartini_ParseStatic 200000 9110 ns/op 768 B/op 9 allocs/op
|
||||
BenchmarkPat_ParseStatic 1000000 1135 ns/op 240 B/op 5 allocs/op
|
||||
BenchmarkPossum_ParseStatic 1000000 1557 ns/op 416 B/op 3 allocs/op
|
||||
BenchmarkR2router_ParseStatic 2000000 730 ns/op 144 B/op 4 allocs/op
|
||||
BenchmarkRivet_ParseStatic 10000000 121 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkTango_ParseStatic 1000000 1688 ns/op 248 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_ParseStatic 3000000 427 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTraffic_ParseStatic 500000 5962 ns/op 1816 B/op 20 allocs/op
|
||||
BenchmarkVulcan_ParseStatic 2000000 969 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_ParseParam 3000000 497 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_ParseParam 1000000 1473 ns/op 467 B/op 5 allocs/op
|
||||
BenchmarkBeego_ParseParam 1000000 2384 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_ParseParam 1000000 2513 ns/op 768 B/op 6 allocs/op
|
||||
BenchmarkDenco_ParseParam 5000000 364 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_ParseParam 5000000 418 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_ParseParam 10000000 163 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_ParseParam 1000000 2361 ns/op 664 B/op 8 allocs/op
|
||||
BenchmarkGoji_ParseParam 1000000 1590 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_ParseParam 1000000 2851 ns/op 976 B/op 9 allocs/op
|
||||
BenchmarkGoJsonRest_ParseParam 1000000 2965 ns/op 649 B/op 13 allocs/op
|
||||
BenchmarkGoRestful_ParseParam 200000 12207 ns/op 3544 B/op 23 allocs/op
|
||||
BenchmarkGorillaMux_ParseParam 500000 5187 ns/op 1088 B/op 12 allocs/op
|
||||
BenchmarkHttpRouter_ParseParam 5000000 275 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_ParseParam 1000000 1108 ns/op 352 B/op 3 allocs/op
|
||||
BenchmarkKocha_ParseParam 3000000 495 ns/op 56 B/op 3 allocs/op
|
||||
BenchmarkLARS_ParseParam 10000000 192 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_ParseParam 500000 4103 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_ParseParam 200000 9878 ns/op 1072 B/op 10 allocs/op
|
||||
BenchmarkPat_ParseParam 500000 3657 ns/op 1120 B/op 17 allocs/op
|
||||
BenchmarkPossum_ParseParam 1000000 2084 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_ParseParam 1000000 1251 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_ParseParam 5000000 335 ns/op 48 B/op 1 allocs/op
|
||||
BenchmarkTango_ParseParam 1000000 1854 ns/op 280 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_ParseParam 500000 4582 ns/op 1008 B/op 17 allocs/op
|
||||
BenchmarkTraffic_ParseParam 200000 8125 ns/op 2248 B/op 23 allocs/op
|
||||
BenchmarkVulcan_ParseParam 1000000 1148 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_Parse2Params 3000000 539 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkBear_Parse2Params 1000000 1778 ns/op 496 B/op 5 allocs/op
|
||||
BenchmarkBeego_Parse2Params 1000000 2519 ns/op 368 B/op 4 allocs/op
|
||||
BenchmarkBone_Parse2Params 1000000 2596 ns/op 720 B/op 5 allocs/op
|
||||
BenchmarkDenco_Parse2Params 3000000 492 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkEcho_Parse2Params 3000000 484 ns/op 32 B/op 1 allocs/op
|
||||
BenchmarkGin_Parse2Params 10000000 193 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_Parse2Params 1000000 2575 ns/op 712 B/op 9 allocs/op
|
||||
BenchmarkGoji_Parse2Params 1000000 1373 ns/op 336 B/op 2 allocs/op
|
||||
BenchmarkGojiv2_Parse2Params 500000 2416 ns/op 960 B/op 8 allocs/op
|
||||
BenchmarkGoJsonRest_Parse2Params 300000 3452 ns/op 713 B/op 14 allocs/op
|
||||
BenchmarkGoRestful_Parse2Params 100000 17719 ns/op 6008 B/op 25 allocs/op
|
||||
BenchmarkGorillaMux_Parse2Params 300000 5102 ns/op 1088 B/op 11 allocs/op
|
||||
BenchmarkHttpRouter_Parse2Params 5000000 303 ns/op 64 B/op 1 allocs/op
|
||||
BenchmarkHttpTreeMux_Parse2Params 1000000 1372 ns/op 384 B/op 4 allocs/op
|
||||
BenchmarkKocha_Parse2Params 2000000 874 ns/op 128 B/op 5 allocs/op
|
||||
BenchmarkLARS_Parse2Params 10000000 192 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_Parse2Params 500000 3871 ns/op 1056 B/op 10 allocs/op
|
||||
BenchmarkMartini_Parse2Params 200000 9954 ns/op 1152 B/op 11 allocs/op
|
||||
BenchmarkPat_Parse2Params 500000 4194 ns/op 832 B/op 17 allocs/op
|
||||
BenchmarkPossum_Parse2Params 1000000 2121 ns/op 560 B/op 6 allocs/op
|
||||
BenchmarkR2router_Parse2Params 1000000 1415 ns/op 432 B/op 5 allocs/op
|
||||
BenchmarkRivet_Parse2Params 3000000 457 ns/op 96 B/op 1 allocs/op
|
||||
BenchmarkTango_Parse2Params 1000000 1914 ns/op 312 B/op 8 allocs/op
|
||||
BenchmarkTigerTonic_Parse2Params 300000 6895 ns/op 1408 B/op 24 allocs/op
|
||||
BenchmarkTraffic_Parse2Params 200000 8317 ns/op 2040 B/op 22 allocs/op
|
||||
BenchmarkVulcan_Parse2Params 1000000 1274 ns/op 98 B/op 3 allocs/op
|
||||
BenchmarkAce_ParseAll 200000 10401 ns/op 640 B/op 16 allocs/op
|
||||
BenchmarkBear_ParseAll 50000 37743 ns/op 8928 B/op 110 allocs/op
|
||||
BenchmarkBeego_ParseAll 20000 63193 ns/op 9568 B/op 104 allocs/op
|
||||
BenchmarkBone_ParseAll 20000 61767 ns/op 14160 B/op 131 allocs/op
|
||||
BenchmarkDenco_ParseAll 300000 7036 ns/op 928 B/op 16 allocs/op
|
||||
BenchmarkEcho_ParseAll 200000 11824 ns/op 832 B/op 26 allocs/op
|
||||
BenchmarkGin_ParseAll 300000 4199 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkGocraftWeb_ParseAll 30000 51758 ns/op 13728 B/op 181 allocs/op
|
||||
BenchmarkGoji_ParseAll 50000 29614 ns/op 5376 B/op 32 allocs/op
|
||||
BenchmarkGojiv2_ParseAll 20000 68676 ns/op 24464 B/op 199 allocs/op
|
||||
BenchmarkGoJsonRest_ParseAll 20000 76135 ns/op 13866 B/op 321 allocs/op
|
||||
BenchmarkGoRestful_ParseAll 5000 389487 ns/op 110928 B/op 600 allocs/op
|
||||
BenchmarkGorillaMux_ParseAll 10000 221250 ns/op 24864 B/op 292 allocs/op
|
||||
BenchmarkHttpRouter_ParseAll 200000 6444 ns/op 640 B/op 16 allocs/op
|
||||
BenchmarkHttpTreeMux_ParseAll 50000 30702 ns/op 5728 B/op 51 allocs/op
|
||||
BenchmarkKocha_ParseAll 200000 13712 ns/op 1112 B/op 54 allocs/op
|
||||
BenchmarkLARS_ParseAll 300000 6925 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkMacaron_ParseAll 20000 96278 ns/op 24576 B/op 250 allocs/op
|
||||
BenchmarkMartini_ParseAll 5000 271352 ns/op 25072 B/op 253 allocs/op
|
||||
BenchmarkPat_ParseAll 20000 74941 ns/op 17264 B/op 343 allocs/op
|
||||
BenchmarkPossum_ParseAll 50000 39947 ns/op 10816 B/op 78 allocs/op
|
||||
BenchmarkR2router_ParseAll 50000 42479 ns/op 8352 B/op 120 allocs/op
|
||||
BenchmarkRivet_ParseAll 200000 7726 ns/op 912 B/op 16 allocs/op
|
||||
BenchmarkTango_ParseAll 30000 50014 ns/op 7168 B/op 208 allocs/op
|
||||
BenchmarkTigerTonic_ParseAll 10000 106550 ns/op 19728 B/op 379 allocs/op
|
||||
BenchmarkTraffic_ParseAll 10000 216037 ns/op 57776 B/op 642 allocs/op
|
||||
BenchmarkVulcan_ParseAll 50000 34379 ns/op 2548 B/op 78 allocs/op
|
||||
```
|
||||
269
vendor/github.com/gin-gonic/gin/CHANGELOG.md
generated
vendored
269
vendor/github.com/gin-gonic/gin/CHANGELOG.md
generated
vendored
@@ -1,269 +0,0 @@
|
||||
|
||||
### Gin 1.4.0
|
||||
|
||||
- [NEW] Support for [Go Modules](https://github.com/golang/go/wiki/Modules) [#1569](https://github.com/gin-gonic/gin/pull/1569)
|
||||
- [NEW] Refactor of form mapping multipart requesta [#1829](https://github.com/gin-gonic/gin/pull/1829)
|
||||
- [FIX] Truncate Latency precision in long running request [#1830](https://github.com/gin-gonic/gin/pull/1830)
|
||||
- [FIX] IsTerm flag should not be affected by DisableConsoleColor method. [#1802](https://github.com/gin-gonic/gin/pull/1802)
|
||||
- [NEW] Supporting file binding [#1264](https://github.com/gin-gonic/gin/pull/1264)
|
||||
- [NEW] Add support for mapping arrays [#1797](https://github.com/gin-gonic/gin/pull/1797)
|
||||
- [FIX] Readme updates [#1793](https://github.com/gin-gonic/gin/pull/1793) [#1788](https://github.com/gin-gonic/gin/pull/1788) [1789](https://github.com/gin-gonic/gin/pull/1789)
|
||||
- [FIX] StaticFS: Fixed Logging two log lines on 404. [#1805](https://github.com/gin-gonic/gin/pull/1805), [#1804](https://github.com/gin-gonic/gin/pull/1804)
|
||||
- [NEW] Make context.Keys available as LogFormatterParams [#1779](https://github.com/gin-gonic/gin/pull/1779)
|
||||
- [NEW] Use internal/json for Marshal/Unmarshal [#1791](https://github.com/gin-gonic/gin/pull/1791)
|
||||
- [NEW] Support mapping time.Duration [#1794](https://github.com/gin-gonic/gin/pull/1794)
|
||||
- [NEW] Refactor form mappings [#1749](https://github.com/gin-gonic/gin/pull/1749)
|
||||
- [NEW] Added flag to context.Stream indicates if client disconnected in middle of stream [#1252](https://github.com/gin-gonic/gin/pull/1252)
|
||||
- [FIX] Moved [examples](https://github.com/gin-gonic/examples) to stand alone Repo [#1775](https://github.com/gin-gonic/gin/pull/1775)
|
||||
- [NEW] Extend context.File to allow for the content-dispositon attachments via a new method context.Attachment [#1260](https://github.com/gin-gonic/gin/pull/1260)
|
||||
- [FIX] Support HTTP content negotiation wildcards [#1112](https://github.com/gin-gonic/gin/pull/1112)
|
||||
- [NEW] Add prefix from X-Forwarded-Prefix in redirectTrailingSlash [#1238](https://github.com/gin-gonic/gin/pull/1238)
|
||||
- [FIX] context.Copy() race condition [#1020](https://github.com/gin-gonic/gin/pull/1020)
|
||||
- [NEW] Add context.HandlerNames() [#1729](https://github.com/gin-gonic/gin/pull/1729)
|
||||
- [FIX] Change color methods to public in the defaultLogger. [#1771](https://github.com/gin-gonic/gin/pull/1771)
|
||||
- [FIX] Update writeHeaders method to use http.Header.Set [#1722](https://github.com/gin-gonic/gin/pull/1722)
|
||||
- [NEW] Add response size to LogFormatterParams [#1752](https://github.com/gin-gonic/gin/pull/1752)
|
||||
- [NEW] Allow ignoring field on form mapping [#1733](https://github.com/gin-gonic/gin/pull/1733)
|
||||
- [NEW] Add a function to force color in console output. [#1724](https://github.com/gin-gonic/gin/pull/1724)
|
||||
- [FIX] Context.Next() - recheck len of handlers on every iteration. [#1745](https://github.com/gin-gonic/gin/pull/1745)
|
||||
- [FIX] Fix all errcheck warnings [#1739](https://github.com/gin-gonic/gin/pull/1739) [#1653](https://github.com/gin-gonic/gin/pull/1653)
|
||||
- [NEW] context: inherits context cancellation and deadline from http.Request context for Go>=1.7 [#1690](https://github.com/gin-gonic/gin/pull/1690)
|
||||
- [NEW] Binding for URL Params [#1694](https://github.com/gin-gonic/gin/pull/1694)
|
||||
- [NEW] Add LoggerWithFormatter method [#1677](https://github.com/gin-gonic/gin/pull/1677)
|
||||
- [FIX] CI testing updates [#1671](https://github.com/gin-gonic/gin/pull/1671) [#1670](https://github.com/gin-gonic/gin/pull/1670) [#1682](https://github.com/gin-gonic/gin/pull/1682) [#1669](https://github.com/gin-gonic/gin/pull/1669)
|
||||
- [FIX] StaticFS(): Send 404 when path does not exist [#1663](https://github.com/gin-gonic/gin/pull/1663)
|
||||
- [FIX] Handle nil body for JSON binding [#1638](https://github.com/gin-gonic/gin/pull/1638)
|
||||
- [FIX] Support bind uri param [#1612](https://github.com/gin-gonic/gin/pull/1612)
|
||||
- [FIX] recovery: fix issue with syscall import on google app engine [#1640](https://github.com/gin-gonic/gin/pull/1640)
|
||||
- [FIX] Make sure the debug log contains line breaks [#1650](https://github.com/gin-gonic/gin/pull/1650)
|
||||
- [FIX] Panic stack trace being printed during recovery of broken pipe [#1089](https://github.com/gin-gonic/gin/pull/1089) [#1259](https://github.com/gin-gonic/gin/pull/1259)
|
||||
- [NEW] RunFd method to run http.Server through a file descriptor [#1609](https://github.com/gin-gonic/gin/pull/1609)
|
||||
- [NEW] Yaml binding support [#1618](https://github.com/gin-gonic/gin/pull/1618)
|
||||
- [FIX] Pass MaxMultipartMemory when FormFile is called [#1600](https://github.com/gin-gonic/gin/pull/1600)
|
||||
- [FIX] LoadHTML* tests [#1559](https://github.com/gin-gonic/gin/pull/1559)
|
||||
- [FIX] Removed use of sync.pool from HandleContext [#1565](https://github.com/gin-gonic/gin/pull/1565)
|
||||
- [FIX] Format output log to os.Stderr [#1571](https://github.com/gin-gonic/gin/pull/1571)
|
||||
- [FIX] Make logger use a yellow background and a darkgray text for legibility [#1570](https://github.com/gin-gonic/gin/pull/1570)
|
||||
- [FIX] Remove sensitive request information from panic log. [#1370](https://github.com/gin-gonic/gin/pull/1370)
|
||||
- [FIX] log.Println() does not print timestamp [#829](https://github.com/gin-gonic/gin/pull/829) [#1560](https://github.com/gin-gonic/gin/pull/1560)
|
||||
- [NEW] Add PureJSON renderer [#694](https://github.com/gin-gonic/gin/pull/694)
|
||||
- [FIX] Add missing copyright and update if/else [#1497](https://github.com/gin-gonic/gin/pull/1497)
|
||||
- [FIX] Update msgpack usage [#1498](https://github.com/gin-gonic/gin/pull/1498)
|
||||
- [FIX] Use protobuf on render [#1496](https://github.com/gin-gonic/gin/pull/1496)
|
||||
- [FIX] Add support for Protobuf format response [#1479](https://github.com/gin-gonic/gin/pull/1479)
|
||||
- [NEW] Set default time format in form binding [#1487](https://github.com/gin-gonic/gin/pull/1487)
|
||||
- [FIX] Add BindXML and ShouldBindXML [#1485](https://github.com/gin-gonic/gin/pull/1485)
|
||||
- [NEW] Upgrade dependency libraries [#1491](https://github.com/gin-gonic/gin/pull/1491)
|
||||
|
||||
|
||||
### Gin 1.3.0
|
||||
|
||||
- [NEW] Add [`func (*Context) QueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.QueryMap), [`func (*Context) GetQueryMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetQueryMap), [`func (*Context) PostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.PostFormMap) and [`func (*Context) GetPostFormMap`](https://godoc.org/github.com/gin-gonic/gin#Context.GetPostFormMap) to support `type map[string]string` as query string or form parameters, see [#1383](https://github.com/gin-gonic/gin/pull/1383)
|
||||
- [NEW] Add [`func (*Context) AsciiJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.AsciiJSON), see [#1358](https://github.com/gin-gonic/gin/pull/1358)
|
||||
- [NEW] Add `Pusher()` in [`type ResponseWriter`](https://godoc.org/github.com/gin-gonic/gin#ResponseWriter) for supporting http2 push, see [#1273](https://github.com/gin-gonic/gin/pull/1273)
|
||||
- [NEW] Add [`func (*Context) DataFromReader`](https://godoc.org/github.com/gin-gonic/gin#Context.DataFromReader) for serving dynamic data, see [#1304](https://github.com/gin-gonic/gin/pull/1304)
|
||||
- [NEW] Add [`func (*Context) ShouldBindBodyWith`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith) allowing to call binding multiple times, see [#1341](https://github.com/gin-gonic/gin/pull/1341)
|
||||
- [NEW] Support pointers in form binding, see [#1336](https://github.com/gin-gonic/gin/pull/1336)
|
||||
- [NEW] Add [`func (*Context) JSONP`](https://godoc.org/github.com/gin-gonic/gin#Context.JSONP), see [#1333](https://github.com/gin-gonic/gin/pull/1333)
|
||||
- [NEW] Support default value in form binding, see [#1138](https://github.com/gin-gonic/gin/pull/1138)
|
||||
- [NEW] Expose validator engine in [`type StructValidator`](https://godoc.org/github.com/gin-gonic/gin/binding#StructValidator), see [#1277](https://github.com/gin-gonic/gin/pull/1277)
|
||||
- [NEW] Add [`func (*Context) ShouldBind`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBind), [`func (*Context) ShouldBindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindQuery) and [`func (*Context) ShouldBindJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindJSON), see [#1047](https://github.com/gin-gonic/gin/pull/1047)
|
||||
- [NEW] Add support for `time.Time` location in form binding, see [#1117](https://github.com/gin-gonic/gin/pull/1117)
|
||||
- [NEW] Add [`func (*Context) BindQuery`](https://godoc.org/github.com/gin-gonic/gin#Context.BindQuery), see [#1029](https://github.com/gin-gonic/gin/pull/1029)
|
||||
- [NEW] Make [jsonite](https://github.com/json-iterator/go) optional with build tags, see [#1026](https://github.com/gin-gonic/gin/pull/1026)
|
||||
- [NEW] Show query string in logger, see [#999](https://github.com/gin-gonic/gin/pull/999)
|
||||
- [NEW] Add [`func (*Context) SecureJSON`](https://godoc.org/github.com/gin-gonic/gin#Context.SecureJSON), see [#987](https://github.com/gin-gonic/gin/pull/987) and [#993](https://github.com/gin-gonic/gin/pull/993)
|
||||
- [DEPRECATE] `func (*Context) GetCookie` for [`func (*Context) Cookie`](https://godoc.org/github.com/gin-gonic/gin#Context.Cookie)
|
||||
- [FIX] Don't display color tags if [`func DisableConsoleColor`](https://godoc.org/github.com/gin-gonic/gin#DisableConsoleColor) called, see [#1072](https://github.com/gin-gonic/gin/pull/1072)
|
||||
- [FIX] Gin Mode `""` when calling [`func Mode`](https://godoc.org/github.com/gin-gonic/gin#Mode) now returns `const DebugMode`, see [#1250](https://github.com/gin-gonic/gin/pull/1250)
|
||||
- [FIX] `Flush()` now doesn't overwrite `responseWriter` status code, see [#1460](https://github.com/gin-gonic/gin/pull/1460)
|
||||
|
||||
### Gin 1.2.0
|
||||
|
||||
- [NEW] Switch from godeps to govendor
|
||||
- [NEW] Add support for Let's Encrypt via gin-gonic/autotls
|
||||
- [NEW] Improve README examples and add extra at examples folder
|
||||
- [NEW] Improved support with App Engine
|
||||
- [NEW] Add custom template delimiters, see #860
|
||||
- [NEW] Add Template Func Maps, see #962
|
||||
- [NEW] Add \*context.Handler(), see #928
|
||||
- [NEW] Add \*context.GetRawData()
|
||||
- [NEW] Add \*context.GetHeader() (request)
|
||||
- [NEW] Add \*context.AbortWithStatusJSON() (JSON content type)
|
||||
- [NEW] Add \*context.Keys type cast helpers
|
||||
- [NEW] Add \*context.ShouldBindWith()
|
||||
- [NEW] Add \*context.MustBindWith()
|
||||
- [NEW] Add \*engine.SetFuncMap()
|
||||
- [DEPRECATE] On next release: \*context.BindWith(), see #855
|
||||
- [FIX] Refactor render
|
||||
- [FIX] Reworked tests
|
||||
- [FIX] logger now supports cygwin
|
||||
- [FIX] Use X-Forwarded-For before X-Real-Ip
|
||||
- [FIX] time.Time binding (#904)
|
||||
|
||||
### Gin 1.1.4
|
||||
|
||||
- [NEW] Support google appengine for IsTerminal func
|
||||
|
||||
### Gin 1.1.3
|
||||
|
||||
- [FIX] Reverted Logger: skip ANSI color commands
|
||||
|
||||
### Gin 1.1
|
||||
|
||||
- [NEW] Implement QueryArray and PostArray methods
|
||||
- [NEW] Refactor GetQuery and GetPostForm
|
||||
- [NEW] Add contribution guide
|
||||
- [FIX] Corrected typos in README
|
||||
- [FIX] Removed additional Iota
|
||||
- [FIX] Changed imports to gopkg instead of github in README (#733)
|
||||
- [FIX] Logger: skip ANSI color commands if output is not a tty
|
||||
|
||||
### Gin 1.0rc2 (...)
|
||||
|
||||
- [PERFORMANCE] Fast path for writing Content-Type.
|
||||
- [PERFORMANCE] Much faster 404 routing
|
||||
- [PERFORMANCE] Allocation optimizations
|
||||
- [PERFORMANCE] Faster root tree lookup
|
||||
- [PERFORMANCE] Zero overhead, String() and JSON() rendering.
|
||||
- [PERFORMANCE] Faster ClientIP parsing
|
||||
- [PERFORMANCE] Much faster SSE implementation
|
||||
- [NEW] Benchmarks suite
|
||||
- [NEW] Bind validation can be disabled and replaced with custom validators.
|
||||
- [NEW] More flexible HTML render
|
||||
- [NEW] Multipart and PostForm bindings
|
||||
- [NEW] Adds method to return all the registered routes
|
||||
- [NEW] Context.HandlerName() returns the main handler's name
|
||||
- [NEW] Adds Error.IsType() helper
|
||||
- [FIX] Binding multipart form
|
||||
- [FIX] Integration tests
|
||||
- [FIX] Crash when binding non struct object in Context.
|
||||
- [FIX] RunTLS() implementation
|
||||
- [FIX] Logger() unit tests
|
||||
- [FIX] Adds SetHTMLTemplate() warning
|
||||
- [FIX] Context.IsAborted()
|
||||
- [FIX] More unit tests
|
||||
- [FIX] JSON, XML, HTML renders accept custom content-types
|
||||
- [FIX] gin.AbortIndex is unexported
|
||||
- [FIX] Better approach to avoid directory listing in StaticFS()
|
||||
- [FIX] Context.ClientIP() always returns the IP with trimmed spaces.
|
||||
- [FIX] Better warning when running in debug mode.
|
||||
- [FIX] Google App Engine integration. debugPrint does not use os.Stdout
|
||||
- [FIX] Fixes integer overflow in error type
|
||||
- [FIX] Error implements the json.Marshaller interface
|
||||
- [FIX] MIT license in every file
|
||||
|
||||
|
||||
### Gin 1.0rc1 (May 22, 2015)
|
||||
|
||||
- [PERFORMANCE] Zero allocation router
|
||||
- [PERFORMANCE] Faster JSON, XML and text rendering
|
||||
- [PERFORMANCE] Custom hand optimized HttpRouter for Gin
|
||||
- [PERFORMANCE] Misc code optimizations. Inlining, tail call optimizations
|
||||
- [NEW] Built-in support for golang.org/x/net/context
|
||||
- [NEW] Any(path, handler). Create a route that matches any path
|
||||
- [NEW] Refactored rendering pipeline (faster and static typeded)
|
||||
- [NEW] Refactored errors API
|
||||
- [NEW] IndentedJSON() prints pretty JSON
|
||||
- [NEW] Added gin.DefaultWriter
|
||||
- [NEW] UNIX socket support
|
||||
- [NEW] RouterGroup.BasePath is exposed
|
||||
- [NEW] JSON validation using go-validate-yourself (very powerful options)
|
||||
- [NEW] Completed suite of unit tests
|
||||
- [NEW] HTTP streaming with c.Stream()
|
||||
- [NEW] StaticFile() creates a router for serving just one file.
|
||||
- [NEW] StaticFS() has an option to disable directory listing.
|
||||
- [NEW] StaticFS() for serving static files through virtual filesystems
|
||||
- [NEW] Server-Sent Events native support
|
||||
- [NEW] WrapF() and WrapH() helpers for wrapping http.HandlerFunc and http.Handler
|
||||
- [NEW] Added LoggerWithWriter() middleware
|
||||
- [NEW] Added RecoveryWithWriter() middleware
|
||||
- [NEW] Added DefaultPostFormValue()
|
||||
- [NEW] Added DefaultFormValue()
|
||||
- [NEW] Added DefaultParamValue()
|
||||
- [FIX] BasicAuth() when using custom realm
|
||||
- [FIX] Bug when serving static files in nested routing group
|
||||
- [FIX] Redirect using built-in http.Redirect()
|
||||
- [FIX] Logger when printing the requested path
|
||||
- [FIX] Documentation typos
|
||||
- [FIX] Context.Engine renamed to Context.engine
|
||||
- [FIX] Better debugging messages
|
||||
- [FIX] ErrorLogger
|
||||
- [FIX] Debug HTTP render
|
||||
- [FIX] Refactored binding and render modules
|
||||
- [FIX] Refactored Context initialization
|
||||
- [FIX] Refactored BasicAuth()
|
||||
- [FIX] NoMethod/NoRoute handlers
|
||||
- [FIX] Hijacking http
|
||||
- [FIX] Better support for Google App Engine (using log instead of fmt)
|
||||
|
||||
|
||||
### Gin 0.6 (Mar 9, 2015)
|
||||
|
||||
- [NEW] Support multipart/form-data
|
||||
- [NEW] NoMethod handler
|
||||
- [NEW] Validate sub structures
|
||||
- [NEW] Support for HTTP Realm Auth
|
||||
- [FIX] Unsigned integers in binding
|
||||
- [FIX] Improve color logger
|
||||
|
||||
|
||||
### Gin 0.5 (Feb 7, 2015)
|
||||
|
||||
- [NEW] Content Negotiation
|
||||
- [FIX] Solved security bug that allow a client to spoof ip
|
||||
- [FIX] Fix unexported/ignored fields in binding
|
||||
|
||||
|
||||
### Gin 0.4 (Aug 21, 2014)
|
||||
|
||||
- [NEW] Development mode
|
||||
- [NEW] Unit tests
|
||||
- [NEW] Add Content.Redirect()
|
||||
- [FIX] Deferring WriteHeader()
|
||||
- [FIX] Improved documentation for model binding
|
||||
|
||||
|
||||
### Gin 0.3 (Jul 18, 2014)
|
||||
|
||||
- [PERFORMANCE] Normal log and error log are printed in the same call.
|
||||
- [PERFORMANCE] Improve performance of NoRouter()
|
||||
- [PERFORMANCE] Improve context's memory locality, reduce CPU cache faults.
|
||||
- [NEW] Flexible rendering API
|
||||
- [NEW] Add Context.File()
|
||||
- [NEW] Add shorcut RunTLS() for http.ListenAndServeTLS
|
||||
- [FIX] Rename NotFound404() to NoRoute()
|
||||
- [FIX] Errors in context are purged
|
||||
- [FIX] Adds HEAD method in Static file serving
|
||||
- [FIX] Refactors Static() file serving
|
||||
- [FIX] Using keyed initialization to fix app-engine integration
|
||||
- [FIX] Can't unmarshal JSON array, #63
|
||||
- [FIX] Renaming Context.Req to Context.Request
|
||||
- [FIX] Check application/x-www-form-urlencoded when parsing form
|
||||
|
||||
|
||||
### Gin 0.2b (Jul 08, 2014)
|
||||
- [PERFORMANCE] Using sync.Pool to allocatio/gc overhead
|
||||
- [NEW] Travis CI integration
|
||||
- [NEW] Completely new logger
|
||||
- [NEW] New API for serving static files. gin.Static()
|
||||
- [NEW] gin.H() can be serialized into XML
|
||||
- [NEW] Typed errors. Errors can be typed. Internet/external/custom.
|
||||
- [NEW] Support for Godeps
|
||||
- [NEW] Travis/Godocs badges in README
|
||||
- [NEW] New Bind() and BindWith() methods for parsing request body.
|
||||
- [NEW] Add Content.Copy()
|
||||
- [NEW] Add context.LastError()
|
||||
- [NEW] Add shorcut for OPTIONS HTTP method
|
||||
- [FIX] Tons of README fixes
|
||||
- [FIX] Header is written before body
|
||||
- [FIX] BasicAuth() and changes API a little bit
|
||||
- [FIX] Recovery() middleware only prints panics
|
||||
- [FIX] Context.Get() does not panic anymore. Use MustGet() instead.
|
||||
- [FIX] Multiple http.WriteHeader() in NotFound handlers
|
||||
- [FIX] Engine.Run() panics if http server can't be setted up
|
||||
- [FIX] Crash when route path doesn't start with '/'
|
||||
- [FIX] Do not update header when status code is negative
|
||||
- [FIX] Setting response headers before calling WriteHeader in context.String()
|
||||
- [FIX] Add MIT license
|
||||
- [FIX] Changes behaviour of ErrorLogger() and Logger()
|
||||
46
vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md
generated
vendored
46
vendor/github.com/gin-gonic/gin/CODE_OF_CONDUCT.md
generated
vendored
@@ -1,46 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at teamgingonic@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
13
vendor/github.com/gin-gonic/gin/CONTRIBUTING.md
generated
vendored
13
vendor/github.com/gin-gonic/gin/CONTRIBUTING.md
generated
vendored
@@ -1,13 +0,0 @@
|
||||
## Contributing
|
||||
|
||||
- With issues:
|
||||
- Use the search tool before opening a new issue.
|
||||
- Please provide source code and commit sha if you found a bug.
|
||||
- Review existing issues and provide feedback or react to them.
|
||||
|
||||
- With pull requests:
|
||||
- Open your pull request against `master`
|
||||
- Your pull request should have no more than two commits, if not you should squash them.
|
||||
- It should pass all tests in the available continuous integrations systems such as TravisCI.
|
||||
- You should add/modify tests to cover your proposed code changes.
|
||||
- If your pull request contains a new feature, please document it on the README.
|
||||
21
vendor/github.com/gin-gonic/gin/LICENSE
generated
vendored
21
vendor/github.com/gin-gonic/gin/LICENSE
generated
vendored
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Manuel Martínez-Almeida
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
80
vendor/github.com/gin-gonic/gin/Makefile
generated
vendored
80
vendor/github.com/gin-gonic/gin/Makefile
generated
vendored
@@ -1,80 +0,0 @@
|
||||
GO ?= go
|
||||
GOFMT ?= gofmt "-s"
|
||||
PACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/)
|
||||
VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/ | grep -v /examples/)
|
||||
GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*")
|
||||
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'gin$$|binding$$|render$$' | grep -v examples)
|
||||
|
||||
all: install
|
||||
|
||||
install: deps
|
||||
govendor sync
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
echo "mode: count" > coverage.out
|
||||
for d in $(TESTFOLDER); do \
|
||||
$(GO) test -v -covermode=count -coverprofile=profile.out $$d > tmp.out; \
|
||||
cat tmp.out; \
|
||||
if grep -q "^--- FAIL" tmp.out; then \
|
||||
rm tmp.out; \
|
||||
exit 1; \
|
||||
elif grep -q "build failed" tmp.out; then \
|
||||
rm tmp.out; \
|
||||
exit 1; \
|
||||
elif grep -q "setup failed" tmp.out; then \
|
||||
rm tmp.out; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
if [ -f profile.out ]; then \
|
||||
cat profile.out | grep -v "mode:" >> coverage.out; \
|
||||
rm profile.out; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
$(GOFMT) -w $(GOFILES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
@diff=$$($(GOFMT) -d $(GOFILES)); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make fmt' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
exit 1; \
|
||||
fi;
|
||||
|
||||
vet:
|
||||
$(GO) vet $(VETPACKAGES)
|
||||
|
||||
deps:
|
||||
@hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/kardianos/govendor; \
|
||||
fi
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u golang.org/x/lint/golint; \
|
||||
fi
|
||||
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
|
||||
|
||||
.PHONY: misspell-check
|
||||
misspell-check:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -error $(GOFILES)
|
||||
|
||||
.PHONY: misspell
|
||||
misspell:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -w $(GOFILES)
|
||||
|
||||
.PHONY: tools
|
||||
tools:
|
||||
go install golang.org/x/lint/golint; \
|
||||
go install github.com/client9/misspell/cmd/misspell;
|
||||
2070
vendor/github.com/gin-gonic/gin/README.md
generated
vendored
2070
vendor/github.com/gin-gonic/gin/README.md
generated
vendored
File diff suppressed because it is too large
Load Diff
96
vendor/github.com/gin-gonic/gin/auth.go
generated
vendored
96
vendor/github.com/gin-gonic/gin/auth.go
generated
vendored
@@ -1,96 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// AuthUserKey is the cookie name for user credential in basic auth.
|
||||
const AuthUserKey = "user"
|
||||
|
||||
// Accounts defines a key/value for user/pass list of authorized logins.
|
||||
type Accounts map[string]string
|
||||
|
||||
type authPair struct {
|
||||
value string
|
||||
user string
|
||||
}
|
||||
|
||||
type authPairs []authPair
|
||||
|
||||
func (a authPairs) searchCredential(authValue string) (string, bool) {
|
||||
if authValue == "" {
|
||||
return "", false
|
||||
}
|
||||
for _, pair := range a {
|
||||
if pair.value == authValue {
|
||||
return pair.user, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
|
||||
// BasicAuthForRealm returns a Basic HTTP Authorization middleware. It takes as arguments a map[string]string where
|
||||
// the key is the user name and the value is the password, as well as the name of the Realm.
|
||||
// If the realm is empty, "Authorization Required" will be used by default.
|
||||
// (see http://tools.ietf.org/html/rfc2617#section-1.2)
|
||||
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc {
|
||||
if realm == "" {
|
||||
realm = "Authorization Required"
|
||||
}
|
||||
realm = "Basic realm=" + strconv.Quote(realm)
|
||||
pairs := processAccounts(accounts)
|
||||
return func(c *Context) {
|
||||
// Search user in the slice of allowed credentials
|
||||
user, found := pairs.searchCredential(c.requestHeader("Authorization"))
|
||||
if !found {
|
||||
// Credentials doesn't match, we return 401 and abort handlers chain.
|
||||
c.Header("WWW-Authenticate", realm)
|
||||
c.AbortWithStatus(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// The user credentials was found, set user's id to key AuthUserKey in this context, the user's id can be read later using
|
||||
// c.MustGet(gin.AuthUserKey).
|
||||
c.Set(AuthUserKey, user)
|
||||
}
|
||||
}
|
||||
|
||||
// BasicAuth returns a Basic HTTP Authorization middleware. It takes as argument a map[string]string where
|
||||
// the key is the user name and the value is the password.
|
||||
func BasicAuth(accounts Accounts) HandlerFunc {
|
||||
return BasicAuthForRealm(accounts, "")
|
||||
}
|
||||
|
||||
func processAccounts(accounts Accounts) authPairs {
|
||||
assert1(len(accounts) > 0, "Empty list of authorized credentials")
|
||||
pairs := make(authPairs, 0, len(accounts))
|
||||
for user, password := range accounts {
|
||||
assert1(user != "", "User can not be empty")
|
||||
value := authorizationHeader(user, password)
|
||||
pairs = append(pairs, authPair{
|
||||
value: value,
|
||||
user: user,
|
||||
})
|
||||
}
|
||||
return pairs
|
||||
}
|
||||
|
||||
func authorizationHeader(user, password string) string {
|
||||
base := user + ":" + password
|
||||
return "Basic " + base64.StdEncoding.EncodeToString([]byte(base))
|
||||
}
|
||||
|
||||
func secureCompare(given, actual string) bool {
|
||||
if subtle.ConstantTimeEq(int32(len(given)), int32(len(actual))) == 1 {
|
||||
return subtle.ConstantTimeCompare([]byte(given), []byte(actual)) == 1
|
||||
}
|
||||
// Securely compare actual to itself to keep constant time, but always return false.
|
||||
return subtle.ConstantTimeCompare([]byte(actual), []byte(actual)) == 1 && false
|
||||
}
|
||||
113
vendor/github.com/gin-gonic/gin/binding/binding.go
generated
vendored
113
vendor/github.com/gin-gonic/gin/binding/binding.go
generated
vendored
@@ -1,113 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Content-Type MIME of the most common data formats.
|
||||
const (
|
||||
MIMEJSON = "application/json"
|
||||
MIMEHTML = "text/html"
|
||||
MIMEXML = "application/xml"
|
||||
MIMEXML2 = "text/xml"
|
||||
MIMEPlain = "text/plain"
|
||||
MIMEPOSTForm = "application/x-www-form-urlencoded"
|
||||
MIMEMultipartPOSTForm = "multipart/form-data"
|
||||
MIMEPROTOBUF = "application/x-protobuf"
|
||||
MIMEMSGPACK = "application/x-msgpack"
|
||||
MIMEMSGPACK2 = "application/msgpack"
|
||||
MIMEYAML = "application/x-yaml"
|
||||
)
|
||||
|
||||
// Binding describes the interface which needs to be implemented for binding the
|
||||
// data present in the request such as JSON request body, query parameters or
|
||||
// the form POST.
|
||||
type Binding interface {
|
||||
Name() string
|
||||
Bind(*http.Request, interface{}) error
|
||||
}
|
||||
|
||||
// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
|
||||
// but it reads the body from supplied bytes instead of req.Body.
|
||||
type BindingBody interface {
|
||||
Binding
|
||||
BindBody([]byte, interface{}) error
|
||||
}
|
||||
|
||||
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
||||
// but it read the Params.
|
||||
type BindingUri interface {
|
||||
Name() string
|
||||
BindUri(map[string][]string, interface{}) error
|
||||
}
|
||||
|
||||
// StructValidator is the minimal interface which needs to be implemented in
|
||||
// order for it to be used as the validator engine for ensuring the correctness
|
||||
// of the request. Gin provides a default implementation for this using
|
||||
// https://github.com/go-playground/validator/tree/v8.18.2.
|
||||
type StructValidator interface {
|
||||
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
|
||||
// If the received type is not a struct, any validation should be skipped and nil must be returned.
|
||||
// If the received type is a struct or pointer to a struct, the validation should be performed.
|
||||
// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
|
||||
// Otherwise nil must be returned.
|
||||
ValidateStruct(interface{}) error
|
||||
|
||||
// Engine returns the underlying validator engine which powers the
|
||||
// StructValidator implementation.
|
||||
Engine() interface{}
|
||||
}
|
||||
|
||||
// Validator is the default validator which implements the StructValidator
|
||||
// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2
|
||||
// under the hood.
|
||||
var Validator StructValidator = &defaultValidator{}
|
||||
|
||||
// These implement the Binding interface and can be used to bind the data
|
||||
// present in the request to struct instances.
|
||||
var (
|
||||
JSON = jsonBinding{}
|
||||
XML = xmlBinding{}
|
||||
Form = formBinding{}
|
||||
Query = queryBinding{}
|
||||
FormPost = formPostBinding{}
|
||||
FormMultipart = formMultipartBinding{}
|
||||
ProtoBuf = protobufBinding{}
|
||||
MsgPack = msgpackBinding{}
|
||||
YAML = yamlBinding{}
|
||||
Uri = uriBinding{}
|
||||
)
|
||||
|
||||
// Default returns the appropriate Binding instance based on the HTTP method
|
||||
// and the content type.
|
||||
func Default(method, contentType string) Binding {
|
||||
if method == "GET" {
|
||||
return Form
|
||||
}
|
||||
|
||||
switch contentType {
|
||||
case MIMEJSON:
|
||||
return JSON
|
||||
case MIMEXML, MIMEXML2:
|
||||
return XML
|
||||
case MIMEPROTOBUF:
|
||||
return ProtoBuf
|
||||
case MIMEMSGPACK, MIMEMSGPACK2:
|
||||
return MsgPack
|
||||
case MIMEYAML:
|
||||
return YAML
|
||||
case MIMEMultipartPOSTForm:
|
||||
return FormMultipart
|
||||
default: // case MIMEPOSTForm:
|
||||
return Form
|
||||
}
|
||||
}
|
||||
|
||||
func validate(obj interface{}) error {
|
||||
if Validator == nil {
|
||||
return nil
|
||||
}
|
||||
return Validator.ValidateStruct(obj)
|
||||
}
|
||||
51
vendor/github.com/gin-gonic/gin/binding/default_validator.go
generated
vendored
51
vendor/github.com/gin-gonic/gin/binding/default_validator.go
generated
vendored
@@ -1,51 +0,0 @@
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"gopkg.in/go-playground/validator.v8"
|
||||
)
|
||||
|
||||
type defaultValidator struct {
|
||||
once sync.Once
|
||||
validate *validator.Validate
|
||||
}
|
||||
|
||||
var _ StructValidator = &defaultValidator{}
|
||||
|
||||
// ValidateStruct receives any kind of type, but only performed struct or pointer to struct type.
|
||||
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
|
||||
value := reflect.ValueOf(obj)
|
||||
valueType := value.Kind()
|
||||
if valueType == reflect.Ptr {
|
||||
valueType = value.Elem().Kind()
|
||||
}
|
||||
if valueType == reflect.Struct {
|
||||
v.lazyinit()
|
||||
if err := v.validate.Struct(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Engine returns the underlying validator engine which powers the default
|
||||
// Validator instance. This is useful if you want to register custom validations
|
||||
// or struct level validations. See validator GoDoc for more info -
|
||||
// https://godoc.org/gopkg.in/go-playground/validator.v8
|
||||
func (v *defaultValidator) Engine() interface{} {
|
||||
v.lazyinit()
|
||||
return v.validate
|
||||
}
|
||||
|
||||
func (v *defaultValidator) lazyinit() {
|
||||
v.once.Do(func() {
|
||||
config := &validator.Config{TagName: "binding"}
|
||||
v.validate = validator.New(config)
|
||||
})
|
||||
}
|
||||
89
vendor/github.com/gin-gonic/gin/binding/form.go
generated
vendored
89
vendor/github.com/gin-gonic/gin/binding/form.go
generated
vendored
@@ -1,89 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const defaultMemory = 32 * 1024 * 1024
|
||||
|
||||
type formBinding struct{}
|
||||
type formPostBinding struct{}
|
||||
type formMultipartBinding struct{}
|
||||
|
||||
func (formBinding) Name() string {
|
||||
return "form"
|
||||
}
|
||||
|
||||
func (formBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := req.ParseMultipartForm(defaultMemory); err != nil {
|
||||
if err != http.ErrNotMultipart {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := mapForm(obj, req.Form); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (formPostBinding) Name() string {
|
||||
return "form-urlencoded"
|
||||
}
|
||||
|
||||
func (formPostBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mapForm(obj, req.PostForm); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
func (formMultipartBinding) Name() string {
|
||||
return "multipart/form-data"
|
||||
}
|
||||
|
||||
func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if err := req.ParseMultipartForm(defaultMemory); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mappingByPtr(obj, (*multipartRequest)(req), "form"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validate(obj)
|
||||
}
|
||||
|
||||
type multipartRequest http.Request
|
||||
|
||||
var _ setter = (*multipartRequest)(nil)
|
||||
|
||||
var (
|
||||
multipartFileHeaderStructType = reflect.TypeOf(multipart.FileHeader{})
|
||||
)
|
||||
|
||||
// TrySet tries to set a value by the multipart request with the binding a form file
|
||||
func (r *multipartRequest) TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) {
|
||||
if value.Type() == multipartFileHeaderStructType {
|
||||
_, file, err := (*http.Request)(r).FormFile(key)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if file != nil {
|
||||
value.Set(reflect.ValueOf(*file))
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return setByForm(value, field, r.MultipartForm.Value, key, opt)
|
||||
}
|
||||
330
vendor/github.com/gin-gonic/gin/binding/form_mapping.go
generated
vendored
330
vendor/github.com/gin-gonic/gin/binding/form_mapping.go
generated
vendored
@@ -1,330 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin/internal/json"
|
||||
)
|
||||
|
||||
var errUnknownType = errors.New("Unknown type")
|
||||
|
||||
func mapUri(ptr interface{}, m map[string][]string) error {
|
||||
return mapFormByTag(ptr, m, "uri")
|
||||
}
|
||||
|
||||
func mapForm(ptr interface{}, form map[string][]string) error {
|
||||
return mapFormByTag(ptr, form, "form")
|
||||
}
|
||||
|
||||
var emptyField = reflect.StructField{}
|
||||
|
||||
func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
|
||||
return mappingByPtr(ptr, formSource(form), tag)
|
||||
}
|
||||
|
||||
// setter tries to set value on a walking by fields of a struct
|
||||
type setter interface {
|
||||
TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error)
|
||||
}
|
||||
|
||||
type formSource map[string][]string
|
||||
|
||||
var _ setter = formSource(nil)
|
||||
|
||||
// TrySet tries to set a value by request's form source (like map[string][]string)
|
||||
func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) {
|
||||
return setByForm(value, field, form, tagValue, opt)
|
||||
}
|
||||
|
||||
func mappingByPtr(ptr interface{}, setter setter, tag string) error {
|
||||
_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
|
||||
return err
|
||||
}
|
||||
|
||||
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||
var vKind = value.Kind()
|
||||
|
||||
if vKind == reflect.Ptr {
|
||||
var isNew bool
|
||||
vPtr := value
|
||||
if value.IsNil() {
|
||||
isNew = true
|
||||
vPtr = reflect.New(value.Type().Elem())
|
||||
}
|
||||
isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if isNew && isSetted {
|
||||
value.Set(vPtr)
|
||||
}
|
||||
return isSetted, nil
|
||||
}
|
||||
|
||||
ok, err := tryToSetValue(value, field, setter, tag)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if ok {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if vKind == reflect.Struct {
|
||||
tValue := value.Type()
|
||||
|
||||
var isSetted bool
|
||||
for i := 0; i < value.NumField(); i++ {
|
||||
if !value.Field(i).CanSet() {
|
||||
continue
|
||||
}
|
||||
ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
isSetted = isSetted || ok
|
||||
}
|
||||
return isSetted, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
type setOptions struct {
|
||||
isDefaultExists bool
|
||||
defaultValue string
|
||||
}
|
||||
|
||||
func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||
var tagValue string
|
||||
var setOpt setOptions
|
||||
|
||||
tagValue = field.Tag.Get(tag)
|
||||
tagValue, opts := head(tagValue, ",")
|
||||
|
||||
if tagValue == "-" { // just ignoring this field
|
||||
return false, nil
|
||||
}
|
||||
if tagValue == "" { // default value is FieldName
|
||||
tagValue = field.Name
|
||||
}
|
||||
if tagValue == "" { // when field is "emptyField" variable
|
||||
return false, nil
|
||||
}
|
||||
|
||||
var opt string
|
||||
for len(opts) > 0 {
|
||||
opt, opts = head(opts, ",")
|
||||
|
||||
k, v := head(opt, "=")
|
||||
switch k {
|
||||
case "default":
|
||||
setOpt.isDefaultExists = true
|
||||
setOpt.defaultValue = v
|
||||
}
|
||||
}
|
||||
|
||||
return setter.TrySet(value, field, tagValue, setOpt)
|
||||
}
|
||||
|
||||
func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) {
|
||||
vs, ok := form[tagValue]
|
||||
if !ok && !opt.isDefaultExists {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
switch value.Kind() {
|
||||
case reflect.Slice:
|
||||
if !ok {
|
||||
vs = []string{opt.defaultValue}
|
||||
}
|
||||
return true, setSlice(vs, value, field)
|
||||
case reflect.Array:
|
||||
if !ok {
|
||||
vs = []string{opt.defaultValue}
|
||||
}
|
||||
if len(vs) != value.Len() {
|
||||
return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
|
||||
}
|
||||
return true, setArray(vs, value, field)
|
||||
default:
|
||||
var val string
|
||||
if !ok {
|
||||
val = opt.defaultValue
|
||||
}
|
||||
|
||||
if len(vs) > 0 {
|
||||
val = vs[0]
|
||||
}
|
||||
return true, setWithProperType(val, value, field)
|
||||
}
|
||||
}
|
||||
|
||||
func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
|
||||
switch value.Kind() {
|
||||
case reflect.Int:
|
||||
return setIntField(val, 0, value)
|
||||
case reflect.Int8:
|
||||
return setIntField(val, 8, value)
|
||||
case reflect.Int16:
|
||||
return setIntField(val, 16, value)
|
||||
case reflect.Int32:
|
||||
return setIntField(val, 32, value)
|
||||
case reflect.Int64:
|
||||
switch value.Interface().(type) {
|
||||
case time.Duration:
|
||||
return setTimeDuration(val, value, field)
|
||||
}
|
||||
return setIntField(val, 64, value)
|
||||
case reflect.Uint:
|
||||
return setUintField(val, 0, value)
|
||||
case reflect.Uint8:
|
||||
return setUintField(val, 8, value)
|
||||
case reflect.Uint16:
|
||||
return setUintField(val, 16, value)
|
||||
case reflect.Uint32:
|
||||
return setUintField(val, 32, value)
|
||||
case reflect.Uint64:
|
||||
return setUintField(val, 64, value)
|
||||
case reflect.Bool:
|
||||
return setBoolField(val, value)
|
||||
case reflect.Float32:
|
||||
return setFloatField(val, 32, value)
|
||||
case reflect.Float64:
|
||||
return setFloatField(val, 64, value)
|
||||
case reflect.String:
|
||||
value.SetString(val)
|
||||
case reflect.Struct:
|
||||
switch value.Interface().(type) {
|
||||
case time.Time:
|
||||
return setTimeField(val, field, value)
|
||||
}
|
||||
return json.Unmarshal([]byte(val), value.Addr().Interface())
|
||||
case reflect.Map:
|
||||
return json.Unmarshal([]byte(val), value.Addr().Interface())
|
||||
default:
|
||||
return errUnknownType
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setIntField(val string, bitSize int, field reflect.Value) error {
|
||||
if val == "" {
|
||||
val = "0"
|
||||
}
|
||||
intVal, err := strconv.ParseInt(val, 10, bitSize)
|
||||
if err == nil {
|
||||
field.SetInt(intVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setUintField(val string, bitSize int, field reflect.Value) error {
|
||||
if val == "" {
|
||||
val = "0"
|
||||
}
|
||||
uintVal, err := strconv.ParseUint(val, 10, bitSize)
|
||||
if err == nil {
|
||||
field.SetUint(uintVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setBoolField(val string, field reflect.Value) error {
|
||||
if val == "" {
|
||||
val = "false"
|
||||
}
|
||||
boolVal, err := strconv.ParseBool(val)
|
||||
if err == nil {
|
||||
field.SetBool(boolVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setFloatField(val string, bitSize int, field reflect.Value) error {
|
||||
if val == "" {
|
||||
val = "0.0"
|
||||
}
|
||||
floatVal, err := strconv.ParseFloat(val, bitSize)
|
||||
if err == nil {
|
||||
field.SetFloat(floatVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
|
||||
timeFormat := structField.Tag.Get("time_format")
|
||||
if timeFormat == "" {
|
||||
timeFormat = time.RFC3339
|
||||
}
|
||||
|
||||
if val == "" {
|
||||
value.Set(reflect.ValueOf(time.Time{}))
|
||||
return nil
|
||||
}
|
||||
|
||||
l := time.Local
|
||||
if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
|
||||
l = time.UTC
|
||||
}
|
||||
|
||||
if locTag := structField.Tag.Get("time_location"); locTag != "" {
|
||||
loc, err := time.LoadLocation(locTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l = loc
|
||||
}
|
||||
|
||||
t, err := time.ParseInLocation(timeFormat, val, l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
value.Set(reflect.ValueOf(t))
|
||||
return nil
|
||||
}
|
||||
|
||||
func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
|
||||
for i, s := range vals {
|
||||
err := setWithProperType(s, value.Index(i), field)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
|
||||
slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
|
||||
err := setArray(vals, slice, field)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value.Set(slice)
|
||||
return nil
|
||||
}
|
||||
|
||||
func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
|
||||
d, err := time.ParseDuration(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value.Set(reflect.ValueOf(d))
|
||||
return nil
|
||||
}
|
||||
|
||||
func head(str, sep string) (head string, tail string) {
|
||||
idx := strings.Index(str, sep)
|
||||
if idx < 0 {
|
||||
return str, ""
|
||||
}
|
||||
return str[:idx], str[idx+len(sep):]
|
||||
}
|
||||
47
vendor/github.com/gin-gonic/gin/binding/json.go
generated
vendored
47
vendor/github.com/gin-gonic/gin/binding/json.go
generated
vendored
@@ -1,47 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin/internal/json"
|
||||
)
|
||||
|
||||
// EnableDecoderUseNumber is used to call the UseNumber method on the JSON
|
||||
// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an
|
||||
// interface{} as a Number instead of as a float64.
|
||||
var EnableDecoderUseNumber = false
|
||||
|
||||
type jsonBinding struct{}
|
||||
|
||||
func (jsonBinding) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if req == nil || req.Body == nil {
|
||||
return fmt.Errorf("invalid request")
|
||||
}
|
||||
return decodeJSON(req.Body, obj)
|
||||
}
|
||||
|
||||
func (jsonBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return decodeJSON(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeJSON(r io.Reader, obj interface{}) error {
|
||||
decoder := json.NewDecoder(r)
|
||||
if EnableDecoderUseNumber {
|
||||
decoder.UseNumber()
|
||||
}
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
35
vendor/github.com/gin-gonic/gin/binding/msgpack.go
generated
vendored
35
vendor/github.com/gin-gonic/gin/binding/msgpack.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/ugorji/go/codec"
|
||||
)
|
||||
|
||||
type msgpackBinding struct{}
|
||||
|
||||
func (msgpackBinding) Name() string {
|
||||
return "msgpack"
|
||||
}
|
||||
|
||||
func (msgpackBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
return decodeMsgPack(req.Body, obj)
|
||||
}
|
||||
|
||||
func (msgpackBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return decodeMsgPack(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeMsgPack(r io.Reader, obj interface{}) error {
|
||||
cdc := new(codec.MsgpackHandle)
|
||||
if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
36
vendor/github.com/gin-gonic/gin/binding/protobuf.go
generated
vendored
36
vendor/github.com/gin-gonic/gin/binding/protobuf.go
generated
vendored
@@ -1,36 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type protobufBinding struct{}
|
||||
|
||||
func (protobufBinding) Name() string {
|
||||
return "protobuf"
|
||||
}
|
||||
|
||||
func (b protobufBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
buf, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.BindBody(buf, obj)
|
||||
}
|
||||
|
||||
func (protobufBinding) BindBody(body []byte, obj interface{}) error {
|
||||
if err := proto.Unmarshal(body, obj.(proto.Message)); err != nil {
|
||||
return err
|
||||
}
|
||||
// Here it's same to return validate(obj), but util now we can't add
|
||||
// `binding:""` to the struct which automatically generate by gen-proto
|
||||
return nil
|
||||
// return validate(obj)
|
||||
}
|
||||
21
vendor/github.com/gin-gonic/gin/binding/query.go
generated
vendored
21
vendor/github.com/gin-gonic/gin/binding/query.go
generated
vendored
@@ -1,21 +0,0 @@
|
||||
// Copyright 2017 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import "net/http"
|
||||
|
||||
type queryBinding struct{}
|
||||
|
||||
func (queryBinding) Name() string {
|
||||
return "query"
|
||||
}
|
||||
|
||||
func (queryBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
values := req.URL.Query()
|
||||
if err := mapForm(obj, values); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
18
vendor/github.com/gin-gonic/gin/binding/uri.go
generated
vendored
18
vendor/github.com/gin-gonic/gin/binding/uri.go
generated
vendored
@@ -1,18 +0,0 @@
|
||||
// Copyright 2018 Gin Core Team. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
type uriBinding struct{}
|
||||
|
||||
func (uriBinding) Name() string {
|
||||
return "uri"
|
||||
}
|
||||
|
||||
func (uriBinding) BindUri(m map[string][]string, obj interface{}) error {
|
||||
if err := mapUri(obj, m); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
33
vendor/github.com/gin-gonic/gin/binding/xml.go
generated
vendored
33
vendor/github.com/gin-gonic/gin/binding/xml.go
generated
vendored
@@ -1,33 +0,0 @@
|
||||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type xmlBinding struct{}
|
||||
|
||||
func (xmlBinding) Name() string {
|
||||
return "xml"
|
||||
}
|
||||
|
||||
func (xmlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
return decodeXML(req.Body, obj)
|
||||
}
|
||||
|
||||
func (xmlBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return decodeXML(bytes.NewReader(body), obj)
|
||||
}
|
||||
func decodeXML(r io.Reader, obj interface{}) error {
|
||||
decoder := xml.NewDecoder(r)
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
35
vendor/github.com/gin-gonic/gin/binding/yaml.go
generated
vendored
35
vendor/github.com/gin-gonic/gin/binding/yaml.go
generated
vendored
@@ -1,35 +0,0 @@
|
||||
// Copyright 2018 Gin Core Team. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type yamlBinding struct{}
|
||||
|
||||
func (yamlBinding) Name() string {
|
||||
return "yaml"
|
||||
}
|
||||
|
||||
func (yamlBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
return decodeYAML(req.Body, obj)
|
||||
}
|
||||
|
||||
func (yamlBinding) BindBody(body []byte, obj interface{}) error {
|
||||
return decodeYAML(bytes.NewReader(body), obj)
|
||||
}
|
||||
|
||||
func decodeYAML(r io.Reader, obj interface{}) error {
|
||||
decoder := yaml.NewDecoder(r)
|
||||
if err := decoder.Decode(obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return validate(obj)
|
||||
}
|
||||
5
vendor/github.com/gin-gonic/gin/codecov.yml
generated
vendored
5
vendor/github.com/gin-gonic/gin/codecov.yml
generated
vendored
@@ -1,5 +0,0 @@
|
||||
coverage:
|
||||
notify:
|
||||
gitter:
|
||||
default:
|
||||
url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user