mirror of
https://github.com/xinliangnote/go-gin-api.git
synced 2024-04-21 12:31:46 +00:00
upgrade
This commit is contained in:
@@ -5,38 +5,41 @@
|
||||
██║ ██║██║ ██║╚════╝██║ ██║██║██║╚██╗██║╚════╝██╔══██║██╔═══╝ ██║
|
||||
╚██████╔╝╚██████╔╝ ╚██████╔╝██║██║ ╚████║ ██║ ██║██║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝
|
||||
|
||||
* [register cors]
|
||||
* [register rate]
|
||||
* [register panic notify]
|
||||
* [register pprof]
|
||||
* [register swagger]
|
||||
* [register prometheus]
|
||||
```
|
||||
|
||||
## go-gin-api
|
||||
|
||||
基于 [Gin](https://github.com/gin-gonic/gin) 进行模块化设计的 API 框架,封装了常用的功能,使用简单,致力于进行快速的业务研发。
|
||||
基于 [Gin](https://github.com/gin-gonic/gin) 进行模块化设计的 API 框架,封装了常用的功能,使用简单,致力于进行快速的业务研发,同时增加了更多限制,以约束项目组开发成员、规避混乱无序和自由随意。
|
||||
|
||||
供参考学习,线上使用请谨慎!
|
||||
|
||||
**查看 Jaeger 链路追踪代码,请查看 [v1.0版](https://github.com/xinliangnote/go-gin-api/releases/tag/v1.0),文档 [jaeger.md](https://github.com/xinliangnote/go-gin-api/blob/master/docs/jaeger.md) 点这里**。
|
||||
|
||||
持续更新...
|
||||
|
||||
## Features
|
||||
|
||||
- [x] 使用 go modules 初始化项目
|
||||
- [x] 安装 Gin 框架
|
||||
- [x] 性能分析工具(pprof)
|
||||
- [x] 支持优雅地重启或停止
|
||||
- [x] 规划项目目录
|
||||
- [x] 参数验证(validator.v9)
|
||||
- [x] 模型绑定和验证
|
||||
- [x] 自定义验证器
|
||||
- [x] 路由中间件
|
||||
- [x] 签名验证
|
||||
- [x] MD5 组合加密
|
||||
- [x] AES 对称加密
|
||||
- [x] RSA 非对称加密
|
||||
- [x] 日志记录
|
||||
- [x] 异常捕获
|
||||
- [x] 链路追踪(Jaeger)
|
||||
- [x] 限流
|
||||
- [x] 自定义告警
|
||||
- [x] 邮件(gomail)
|
||||
- [ ] 微信
|
||||
- [ ] 短信
|
||||
- [ ] 钉钉
|
||||
- [x] 包管理工具 [Go Modules](https://github.com/golang/go/wiki/Modules)
|
||||
- [x] [Gin](https://github.com/gin-gonic/gin) 支持优雅关闭
|
||||
- [x] 配置文件解析库 [Viper](https://github.com/spf13/viper)
|
||||
- [x] 文档使用 [Swagger](https://swagger.io/) 生成
|
||||
- [x] 性能分析使用 [pprof](github.com/gin-contrib/pprof)
|
||||
- [x] 集成
|
||||
- [x] [JWT](https://jwt.io/) 身份认证
|
||||
- [x] [zap](go.uber.org/zap) 日志记录
|
||||
- [x] [rate](golang.org/x/time/rate) 限流
|
||||
- [x] 异常捕获并邮件告警
|
||||
- [x] 每个请求具备链路ID
|
||||
- [x] 统一定义错误码
|
||||
- [x] 支持 FAT、UAT、PRO 环境
|
||||
- [x] MD5、AES 对称加密、RSA 非对称加密
|
||||
- [ ] 存储
|
||||
- [ ] MySQL
|
||||
- [ ] Redis
|
||||
@@ -64,27 +67,15 @@ cd go-gin-api
|
||||
go run main.go
|
||||
```
|
||||
|
||||
#### HTTP Demo
|
||||
#### swagger
|
||||
|
||||
```go
|
||||
http://127.0.0.1:9999/swagger/index.html
|
||||
|
||||
// 生成文档
|
||||
$ go get -u github.com/swaggo/swag/cmd/swag
|
||||
$ swag init
|
||||
```
|
||||
curl -X POST http://127.0.0.1:9999/demo/user
|
||||
```
|
||||
|
||||
#### Jaeger Demo
|
||||
|
||||
访问:
|
||||
|
||||
```
|
||||
http://127.0.0.1:9999/jaeger_test
|
||||
```
|
||||
|
||||
服务端测试代码:
|
||||
|
||||
- [https://github.com/xinliangnote/go-jaeger-demo](https://github.com/xinliangnote/go-jaeger-demo)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### pprof
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
[db]
|
||||
host = '127.0.0.1'
|
||||
port = 3306
|
||||
[mail]
|
||||
host = 'smtp.163.com'
|
||||
port = 465
|
||||
user = ""
|
||||
pass = ""
|
||||
to = ""
|
||||
|
||||
[jwt]
|
||||
secret = 'i1ydX9RtHyuJTrw7frcu'
|
||||
|
||||
[aes]
|
||||
key = 'IgkibX71IEf382PT'
|
||||
|
||||
+67
-2
@@ -40,10 +40,17 @@ var doc = `{
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "用户名",
|
||||
"description": "用户名(Tom)",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -68,6 +75,64 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/login": {
|
||||
"post": {
|
||||
"description": "登录获取 Authorization 码",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "登录获取 Authorization 码",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
"name": "loginRequest",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/demo.loginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "签名信息",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/demo.loginResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"demo.loginRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user_id": {
|
||||
"description": "用户ID(\u003e0)",
|
||||
"type": "integer"
|
||||
},
|
||||
"user_name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"demo.loginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization": {
|
||||
"description": "签名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
@@ -84,7 +149,7 @@ type swaggerInfo struct {
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = swaggerInfo{
|
||||
Version: "",
|
||||
Host: "localhost:9999",
|
||||
Host: "127.0.0.1:9999",
|
||||
BasePath: "",
|
||||
Schemes: []string{},
|
||||
Title: "go-gin-api docs api",
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
## Jaeger Demo 代码
|
||||
|
||||
- 代码在 [v1.0](https://github.com/xinliangnote/go-gin-api/releases/tag/v1.0) 版本。
|
||||
|
||||
#### Jaeger Demo 文档
|
||||
|
||||
访问:
|
||||
|
||||
```
|
||||
http://127.0.0.1:9999/jaeger_test
|
||||
```
|
||||
|
||||
服务端测试代码:
|
||||
|
||||
- [https://github.com/xinliangnote/go-jaeger-demo](https://github.com/xinliangnote/go-jaeger-demo)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
+67
-2
@@ -4,7 +4,7 @@
|
||||
"title": "go-gin-api docs api",
|
||||
"contact": {}
|
||||
},
|
||||
"host": "localhost:9999",
|
||||
"host": "127.0.0.1:9999",
|
||||
"paths": {
|
||||
"/demo/user/{name}": {
|
||||
"get": {
|
||||
@@ -22,10 +22,17 @@
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "用户名",
|
||||
"description": "用户名(Tom)",
|
||||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -50,6 +57,64 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/login": {
|
||||
"post": {
|
||||
"description": "登录获取 Authorization 码",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "登录获取 Authorization 码",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
"name": "loginRequest",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/demo.loginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "签名信息",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/demo.loginResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"demo.loginRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user_id": {
|
||||
"description": "用户ID(\u003e0)",
|
||||
"type": "integer"
|
||||
},
|
||||
"user_name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"demo.loginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization": {
|
||||
"description": "签名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
-2
@@ -1,4 +1,20 @@
|
||||
host: localhost:9999
|
||||
definitions:
|
||||
demo.loginRequest:
|
||||
properties:
|
||||
user_id:
|
||||
description: 用户ID(>0)
|
||||
type: integer
|
||||
user_name:
|
||||
description: 用户名
|
||||
type: string
|
||||
type: object
|
||||
demo.loginResponse:
|
||||
properties:
|
||||
authorization:
|
||||
description: 签名
|
||||
type: string
|
||||
type: object
|
||||
host: 127.0.0.1:9999
|
||||
info:
|
||||
contact: {}
|
||||
title: go-gin-api docs api
|
||||
@@ -9,11 +25,16 @@ paths:
|
||||
- application/json
|
||||
description: 获取用户信息
|
||||
parameters:
|
||||
- description: 用户名
|
||||
- description: 用户名(Tom)
|
||||
in: path
|
||||
name: name
|
||||
required: true
|
||||
type: string
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
@@ -33,4 +54,26 @@ paths:
|
||||
summary: 获取用户信息
|
||||
tags:
|
||||
- Demo
|
||||
/user/login:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 登录获取 Authorization 码
|
||||
parameters:
|
||||
- description: 请求信息
|
||||
in: body
|
||||
name: loginRequest
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/demo.loginRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 签名信息
|
||||
schema:
|
||||
$ref: '#/definitions/demo.loginResponse'
|
||||
summary: 登录获取 Authorization 码
|
||||
tags:
|
||||
- Demo
|
||||
swagger: "2.0"
|
||||
|
||||
@@ -4,13 +4,10 @@ go 1.12
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/gin-contrib/pprof v1.2.1
|
||||
github.com/gin-gonic/gin v1.4.0
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-openapi/spec v0.20.0 // indirect
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
|
||||
github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v0.9.3
|
||||
github.com/rs/cors v1.7.0
|
||||
@@ -18,19 +15,15 @@ require (
|
||||
github.com/swaggo/gin-swagger v1.3.0
|
||||
github.com/swaggo/swag v1.7.0
|
||||
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/multierr v1.5.0
|
||||
go.uber.org/zap v1.16.0
|
||||
golang.org/x/mod v0.4.0 // indirect
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
|
||||
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 // indirect
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0
|
||||
golang.org/x/tools v0.0.0-20201226215659-b1c90890d22a // indirect
|
||||
google.golang.org/grpc v1.23.1
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
)
|
||||
|
||||
@@ -17,7 +17,6 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.1.0 h1:rmGxhojJlM0tuKtfdvliR84CFHljx9ag64t2xmVkjK4=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
@@ -26,7 +25,6 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
|
||||
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=
|
||||
@@ -38,8 +36,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
||||
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/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=
|
||||
@@ -50,55 +46,58 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
||||
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 h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
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 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc=
|
||||
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
|
||||
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-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
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-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
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/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
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-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk=
|
||||
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4=
|
||||
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
|
||||
github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I=
|
||||
github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi880=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
|
||||
github.com/go-openapi/swag v0.19.12 h1:Bc0bnY2c3AoF7Gc+IMIAQQsD8fLHjHpc19wXvYuayQI=
|
||||
github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
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=
|
||||
@@ -106,12 +105,14 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
|
||||
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/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/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
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=
|
||||
@@ -122,8 +123,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa
|
||||
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=
|
||||
@@ -151,8 +150,9 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
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/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
@@ -161,18 +161,17 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
|
||||
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/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/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
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/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@@ -181,10 +180,10 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
|
||||
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.4/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/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
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=
|
||||
@@ -196,15 +195,15 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
||||
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-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
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 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
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/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=
|
||||
@@ -237,8 +236,6 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
@@ -259,7 +256,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
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/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/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -268,7 +264,6 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
||||
github.com/swaggo/gin-swagger v1.3.0 h1:eOmp7r57oUgZPw2dJOjcGNMse9cvXcI4tTqBcnZtPsI=
|
||||
github.com/swaggo/gin-swagger v1.3.0/go.mod h1:oy1BRA6WvgtCp848lhxce7BnWH4C8Bxa0m5SkWx+cS0=
|
||||
github.com/swaggo/swag v1.5.1 h1:2Agm8I4K5qb00620mHq0VJ05/KT4FtmALPIcQR9lEZM=
|
||||
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
|
||||
github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E=
|
||||
github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo=
|
||||
@@ -279,26 +274,17 @@ github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JT
|
||||
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=
|
||||
github.com/uber/jaeger-client-go v2.18.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-lib v2.1.1+incompatible h1:VY/6p2WopO09BPnw787RbaCIlfKbCRC/kq3p5D0F168=
|
||||
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/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go v1.1.13 h1:nB3O5kBSQGjEQAcfe1aLUYuxmXdFKmYgBZhY32rQb6Q=
|
||||
github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn4=
|
||||
github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU=
|
||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
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=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
@@ -358,7 +344,6 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
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-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
@@ -385,13 +370,12 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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/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-20190610200419-93c9922d18ae/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/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo=
|
||||
@@ -399,7 +383,6 @@ golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
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/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
@@ -418,7 +401,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
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-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
@@ -429,7 +411,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
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/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
@@ -456,27 +437,20 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn
|
||||
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 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
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/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/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
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/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=
|
||||
@@ -489,8 +463,8 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
|
||||
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.3/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=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
@@ -500,7 +474,6 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
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,45 +0,0 @@
|
||||
package config
|
||||
|
||||
var (
|
||||
ApiAuthConfig = map[string]map[string]string{
|
||||
|
||||
// 调用方
|
||||
"DEMO": {
|
||||
"md5": "IgkibX71IEf382PT",
|
||||
"aes": "IgkibX71IEf382PT",
|
||||
"rsa": "rsa/public.pem",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
AppName = "go-gin-api"
|
||||
|
||||
// 签名超时时间
|
||||
AppSignExpiry = "120"
|
||||
|
||||
// RSA Private File
|
||||
AppRsaPrivateFile = "rsa/private.pem"
|
||||
|
||||
// 日志文件
|
||||
AppErrorLogName = "log/" + AppName + "-error.log"
|
||||
AppGrpcLogName = "log/" + AppName + "-grpc.log"
|
||||
|
||||
// 系统告警邮箱信息
|
||||
SystemEmailUser = "xinliangnote@163.com"
|
||||
SystemEmailPass = "" //密码或授权码
|
||||
SystemEmailHost = "smtp.163.com"
|
||||
SystemEmailPort = 465
|
||||
|
||||
// 告警接收人
|
||||
ErrorNotifyUser = "xinliangnote@163.com"
|
||||
|
||||
// 告警开关 1=开通 -1=关闭
|
||||
ErrorNotifyOpen = -1
|
||||
|
||||
// Jaeger 配置信息
|
||||
JaegerHostPort = "172.20.2.212:6831"
|
||||
|
||||
// Jaeger 配置开关 1=开通 -1=关闭
|
||||
JaegerOpen = 1
|
||||
)
|
||||
@@ -101,7 +101,8 @@ type response []struct {
|
||||
// @Tags Demo
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param name path string true "用户名"
|
||||
// @Param name path string true "用户名(Tom)"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} response "用户信息"
|
||||
// @Router /demo/user/{name} [get]
|
||||
func (d *Demo) User() core.HandlerFunc {
|
||||
@@ -121,6 +122,7 @@ func (d *Demo) User() core.HandlerFunc {
|
||||
httpclient.WithTTL(time.Second*2),
|
||||
httpclient.WithJournal(c.Journal()),
|
||||
httpclient.WithLogger(c.Logger()),
|
||||
httpclient.WithHeader("Authorization", c.GetHeader("Authorization")),
|
||||
)
|
||||
if err1 != nil {
|
||||
d.logger.Error("get [demo/get] err", zap.Error(err1))
|
||||
@@ -132,22 +134,25 @@ func (d *Demo) User() core.HandlerFunc {
|
||||
httpclient.WithTTL(time.Second*2),
|
||||
httpclient.WithJournal(c.Journal()),
|
||||
httpclient.WithLogger(c.Logger()),
|
||||
httpclient.WithHeader("Authorization", c.GetHeader("Authorization")),
|
||||
)
|
||||
if err2 != nil {
|
||||
d.logger.Error("post [demo/post] err", zap.Error(err2))
|
||||
}
|
||||
|
||||
data := &response{
|
||||
{
|
||||
Name: jsonparse.Get(string(body1), "data.name").(string),
|
||||
Job: jsonparse.Get(string(body1), "data.job").(string),
|
||||
},
|
||||
{
|
||||
Name: jsonparse.Get(string(body2), "data.name").(string),
|
||||
Job: jsonparse.Get(string(body2), "data.job").(string),
|
||||
},
|
||||
data := &response{}
|
||||
if err1 == nil && err2 == nil {
|
||||
data = &response{
|
||||
{
|
||||
Name: jsonparse.Get(string(body1), "data.name").(string),
|
||||
Job: jsonparse.Get(string(body1), "data.job").(string),
|
||||
},
|
||||
{
|
||||
Name: jsonparse.Get(string(body2), "data.name").(string),
|
||||
Job: jsonparse.Get(string(body2), "data.job").(string),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
c.SetPayload(errno.OK.WithData(data))
|
||||
}
|
||||
}
|
||||
@@ -158,9 +163,9 @@ func (d *Demo) RsaTest() core.HandlerFunc {
|
||||
encryptStr := "param_1=xxx¶m_2=xxx&ak=xxx&ts=1111111111"
|
||||
count := 500
|
||||
|
||||
cfg := configs.Get()
|
||||
rsaPublic := rsa.NewPublic(cfg.Rsa.Public)
|
||||
rsaPrivate := rsa.NewPrivate(cfg.Rsa.Private)
|
||||
cfg := configs.Get().Rsa
|
||||
rsaPublic := rsa.NewPublic(cfg.Public)
|
||||
rsaPrivate := rsa.NewPrivate(cfg.Private)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
// 生成签名
|
||||
@@ -187,8 +192,8 @@ func (d *Demo) AesTest() core.HandlerFunc {
|
||||
encryptStr := "param_1=xxx¶m_2=xxx&ak=xxx&ts=1111111111"
|
||||
count := 1000000
|
||||
|
||||
cfg := configs.Get()
|
||||
aes := aes.New(cfg.Aes.Key, cfg.Aes.Iv)
|
||||
cfg := configs.Get().Aes
|
||||
aes := aes.New(cfg.Key, cfg.Iv)
|
||||
for i := 0; i < count; i++ {
|
||||
// 生成签名
|
||||
sn, err := aes.Encrypt(encryptStr)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package demo
|
||||
|
||||
import (
|
||||
"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/token"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type loginRequest struct {
|
||||
UserID int `json:"user_id" form:"user_id"` // 用户ID(>0)
|
||||
UserName string `json:"user_name" form:"user_name"` // 用户名
|
||||
}
|
||||
|
||||
type loginResponse struct {
|
||||
Authorization string `json:"authorization"` // 签名
|
||||
}
|
||||
|
||||
// 登录获取 Authorization 码
|
||||
// @Summary 登录获取 Authorization 码
|
||||
// @Description 登录获取 Authorization 码
|
||||
// @Tags Demo
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param loginRequest body loginRequest true "请求信息"
|
||||
// @Success 200 {object} loginResponse "签名信息"
|
||||
// @Router /user/login [post]
|
||||
func (d *Demo) Login() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(loginRequest)
|
||||
res := new(loginResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
c.SetPayload(errno.ErrParam)
|
||||
return
|
||||
}
|
||||
|
||||
tokenString, err := token.Sign(req.UserID, req.UserName)
|
||||
if err != nil {
|
||||
d.logger.Error("token sign err", zap.Error(err))
|
||||
res.Authorization = ""
|
||||
} else {
|
||||
res.Authorization = tokenString
|
||||
}
|
||||
c.SetPayload(errno.OK.WithData(res))
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
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"
|
||||
)
|
||||
|
||||
func JaegerTest(c *gin.Context) {
|
||||
|
||||
// 调用 gRPC 服务
|
||||
conn := grpc_client.CreateServiceListenConn(c)
|
||||
grpcListenClient := listen.NewListenClient(conn)
|
||||
resListen, _ := grpcListenClient.ListenData(context.Background(), &listen.Request{Name: "listen"})
|
||||
|
||||
// 调用 gRPC 服务
|
||||
conn = grpc_client.CreateServiceSpeakConn(c)
|
||||
grpcSpeakClient := speak.NewSpeakClient(conn)
|
||||
resSpeak, _ := grpcSpeakClient.SpeakData(context.Background(), &speak.Request{Name: "speak"})
|
||||
|
||||
// 调用 gRPC 服务
|
||||
conn = grpc_client.CreateServiceReadConn(c)
|
||||
grpcReadClient := read.NewReadClient(conn)
|
||||
resRead, _ := grpcReadClient.ReadData(context.Background(), &read.Request{Name: "read"})
|
||||
|
||||
// 调用 gRPC 服务
|
||||
conn = grpc_client.CreateServiceWriteConn(c)
|
||||
grpcWriteClient := write.NewWriteClient(conn)
|
||||
resWrite, _ := grpcWriteClient.WriteData(context.Background(), &write.Request{Name: "write"})
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
// 调用 HTTP 服务
|
||||
resHttpGet := ""
|
||||
_, err := request.HttpGet("http://localhost:9905/sing", c)
|
||||
if err == nil {
|
||||
resHttpGet = "[HttpGetOk]"
|
||||
}
|
||||
|
||||
// 业务处理...
|
||||
|
||||
msg := resListen.Message + "-" +
|
||||
resSpeak.Message + "-" +
|
||||
resRead.Message + "-" +
|
||||
resWrite.Message + "-" +
|
||||
resHttpGet
|
||||
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1, msg, nil)
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: listen.proto
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// Request 请求结构
|
||||
type Request struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Request) Reset() { *m = Request{} }
|
||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||
func (*Request) ProtoMessage() {}
|
||||
func (*Request) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f05da38a4a3e5177, []int{0}
|
||||
}
|
||||
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Request) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Request.Merge(m, src)
|
||||
}
|
||||
func (m *Request) XXX_Size() int {
|
||||
return xxx_messageInfo_Request.Size(m)
|
||||
}
|
||||
func (m *Request) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Request.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Request proto.InternalMessageInfo
|
||||
|
||||
func (m *Request) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Response 响应结构
|
||||
type Response struct {
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Response) Reset() { *m = Response{} }
|
||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
||||
func (*Response) ProtoMessage() {}
|
||||
func (*Response) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f05da38a4a3e5177, []int{1}
|
||||
}
|
||||
|
||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Response) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Response.Merge(m, src)
|
||||
}
|
||||
func (m *Response) XXX_Size() int {
|
||||
return xxx_messageInfo_Response.Size(m)
|
||||
}
|
||||
func (m *Response) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Response.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Response proto.InternalMessageInfo
|
||||
|
||||
func (m *Response) GetMessage() string {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Request)(nil), "listen.Request")
|
||||
proto.RegisterType((*Response)(nil), "listen.Response")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("listen.proto", fileDescriptor_f05da38a4a3e5177) }
|
||||
|
||||
var fileDescriptor_f05da38a4a3e5177 = []byte{
|
||||
// 133 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xc9, 0xc9, 0x2c, 0x2e,
|
||||
0x49, 0xcd, 0xd3, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x83, 0xf0, 0x94, 0x64, 0xb9, 0xd8,
|
||||
0x83, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25,
|
||||
0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25, 0x15, 0x2e, 0x8e, 0xa0, 0xd4, 0xe2, 0x82,
|
||||
0xfc, 0xbc, 0xe2, 0x54, 0x21, 0x09, 0x2e, 0xf6, 0xdc, 0xd4, 0xe2, 0xe2, 0xc4, 0x74, 0x98, 0x12,
|
||||
0x18, 0xd7, 0xc8, 0x9a, 0x8b, 0xcd, 0x07, 0x6c, 0x9c, 0x90, 0x21, 0x17, 0x17, 0x84, 0xe5, 0x92,
|
||||
0x58, 0x92, 0x28, 0xc4, 0xaf, 0x07, 0xb5, 0x13, 0x6a, 0x85, 0x94, 0x00, 0x42, 0x00, 0x62, 0xa8,
|
||||
0x12, 0x43, 0x12, 0x1b, 0xd8, 0x41, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0xbf, 0x9d,
|
||||
0x0d, 0xa0, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// ListenClient is the client API for Listen service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type ListenClient interface {
|
||||
// 定义 ListenData 方法
|
||||
ListenData(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||
}
|
||||
|
||||
type listenClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewListenClient(cc *grpc.ClientConn) ListenClient {
|
||||
return &listenClient{cc}
|
||||
}
|
||||
|
||||
func (c *listenClient) ListenData(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
out := new(Response)
|
||||
err := c.cc.Invoke(ctx, "/listen.Listen/ListenData", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ListenServer is the server API for Listen service.
|
||||
type ListenServer interface {
|
||||
// 定义 ListenData 方法
|
||||
ListenData(context.Context, *Request) (*Response, error)
|
||||
}
|
||||
|
||||
// UnimplementedListenServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedListenServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedListenServer) ListenData(ctx context.Context, req *Request) (*Response, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListenData not implemented")
|
||||
}
|
||||
|
||||
func RegisterListenServer(s *grpc.Server, srv ListenServer) {
|
||||
s.RegisterService(&_Listen_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Listen_ListenData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ListenServer).ListenData(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/listen.Listen/ListenData",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ListenServer).ListenData(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Listen_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "listen.Listen",
|
||||
HandlerType: (*ListenServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "ListenData",
|
||||
Handler: _Listen_ListenData_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "listen.proto",
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: read.proto
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// Request 请求结构
|
||||
type Request struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Request) Reset() { *m = Request{} }
|
||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||
func (*Request) ProtoMessage() {}
|
||||
func (*Request) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7b10ec61df6818dd, []int{0}
|
||||
}
|
||||
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Request) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Request.Merge(m, src)
|
||||
}
|
||||
func (m *Request) XXX_Size() int {
|
||||
return xxx_messageInfo_Request.Size(m)
|
||||
}
|
||||
func (m *Request) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Request.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Request proto.InternalMessageInfo
|
||||
|
||||
func (m *Request) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Response 响应结构
|
||||
type Response struct {
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Response) Reset() { *m = Response{} }
|
||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
||||
func (*Response) ProtoMessage() {}
|
||||
func (*Response) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7b10ec61df6818dd, []int{1}
|
||||
}
|
||||
|
||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Response) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Response.Merge(m, src)
|
||||
}
|
||||
func (m *Response) XXX_Size() int {
|
||||
return xxx_messageInfo_Response.Size(m)
|
||||
}
|
||||
func (m *Response) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Response.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Response proto.InternalMessageInfo
|
||||
|
||||
func (m *Response) GetMessage() string {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Request)(nil), "read.Request")
|
||||
proto.RegisterType((*Response)(nil), "read.Response")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("read.proto", fileDescriptor_7b10ec61df6818dd) }
|
||||
|
||||
var fileDescriptor_7b10ec61df6818dd = []byte{
|
||||
// 132 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2a, 0x4a, 0x4d, 0x4c,
|
||||
0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x01, 0xb1, 0x95, 0x64, 0xb9, 0xd8, 0x83, 0x52,
|
||||
0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25, 0x18, 0x15,
|
||||
0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25, 0x15, 0x2e, 0x8e, 0xa0, 0xd4, 0xe2, 0x82, 0xfc, 0xbc,
|
||||
0xe2, 0x54, 0x21, 0x09, 0x2e, 0xf6, 0xdc, 0xd4, 0xe2, 0xe2, 0xc4, 0x74, 0x98, 0x12, 0x18, 0xd7,
|
||||
0xc8, 0x98, 0x8b, 0x25, 0x28, 0x35, 0x31, 0x45, 0x48, 0x1b, 0xa4, 0x3a, 0x31, 0xc5, 0x25, 0xb1,
|
||||
0x24, 0x51, 0x88, 0x57, 0x0f, 0x6c, 0x17, 0xd4, 0x70, 0x29, 0x3e, 0x18, 0x17, 0x62, 0x98, 0x12,
|
||||
0x43, 0x12, 0x1b, 0xd8, 0x19, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x42, 0x4a, 0x9b, 0x2d,
|
||||
0x94, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// ReadClient is the client API for Read service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type ReadClient interface {
|
||||
// 定义方法
|
||||
ReadData(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||
}
|
||||
|
||||
type readClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewReadClient(cc *grpc.ClientConn) ReadClient {
|
||||
return &readClient{cc}
|
||||
}
|
||||
|
||||
func (c *readClient) ReadData(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
out := new(Response)
|
||||
err := c.cc.Invoke(ctx, "/read.Read/ReadData", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ReadServer is the server API for Read service.
|
||||
type ReadServer interface {
|
||||
// 定义方法
|
||||
ReadData(context.Context, *Request) (*Response, error)
|
||||
}
|
||||
|
||||
// UnimplementedReadServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedReadServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedReadServer) ReadData(ctx context.Context, req *Request) (*Response, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ReadData not implemented")
|
||||
}
|
||||
|
||||
func RegisterReadServer(s *grpc.Server, srv ReadServer) {
|
||||
s.RegisterService(&_Read_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Read_ReadData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ReadServer).ReadData(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/read.Read/ReadData",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ReadServer).ReadData(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Read_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "read.Read",
|
||||
HandlerType: (*ReadServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "ReadData",
|
||||
Handler: _Read_ReadData_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "read.proto",
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: speak.proto
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// Request 请求结构
|
||||
type Request struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Request) Reset() { *m = Request{} }
|
||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||
func (*Request) ProtoMessage() {}
|
||||
func (*Request) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_3c7d3e2f29338937, []int{0}
|
||||
}
|
||||
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Request) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Request.Merge(m, src)
|
||||
}
|
||||
func (m *Request) XXX_Size() int {
|
||||
return xxx_messageInfo_Request.Size(m)
|
||||
}
|
||||
func (m *Request) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Request.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Request proto.InternalMessageInfo
|
||||
|
||||
func (m *Request) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Response 响应结构
|
||||
type Response struct {
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Response) Reset() { *m = Response{} }
|
||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
||||
func (*Response) ProtoMessage() {}
|
||||
func (*Response) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_3c7d3e2f29338937, []int{1}
|
||||
}
|
||||
|
||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Response) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Response.Merge(m, src)
|
||||
}
|
||||
func (m *Response) XXX_Size() int {
|
||||
return xxx_messageInfo_Response.Size(m)
|
||||
}
|
||||
func (m *Response) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Response.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Response proto.InternalMessageInfo
|
||||
|
||||
func (m *Response) GetMessage() string {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Request)(nil), "speak.Request")
|
||||
proto.RegisterType((*Response)(nil), "speak.Response")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("speak.proto", fileDescriptor_3c7d3e2f29338937) }
|
||||
|
||||
var fileDescriptor_3c7d3e2f29338937 = []byte{
|
||||
// 132 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2e, 0x2e, 0x48, 0x4d,
|
||||
0xcc, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0x94, 0x64, 0xb9, 0xd8, 0x83,
|
||||
0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25, 0x18,
|
||||
0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25, 0x15, 0x2e, 0x8e, 0xa0, 0xd4, 0xe2, 0x82, 0xfc,
|
||||
0xbc, 0xe2, 0x54, 0x21, 0x09, 0x2e, 0xf6, 0xdc, 0xd4, 0xe2, 0xe2, 0xc4, 0x74, 0x98, 0x12, 0x18,
|
||||
0xd7, 0xc8, 0x9c, 0x8b, 0x35, 0x18, 0x64, 0x9a, 0x90, 0x1e, 0x17, 0x27, 0x98, 0xe1, 0x92, 0x58,
|
||||
0x92, 0x28, 0xc4, 0xa7, 0x07, 0xb1, 0x0f, 0x6a, 0xbe, 0x14, 0x3f, 0x9c, 0x0f, 0x31, 0x50, 0x89,
|
||||
0x21, 0x89, 0x0d, 0xec, 0x16, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4d, 0x04, 0x6f, 0x05,
|
||||
0x9a, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// SpeakClient is the client API for Speak service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type SpeakClient interface {
|
||||
// 定义方法
|
||||
SpeakData(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||
}
|
||||
|
||||
type speakClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewSpeakClient(cc *grpc.ClientConn) SpeakClient {
|
||||
return &speakClient{cc}
|
||||
}
|
||||
|
||||
func (c *speakClient) SpeakData(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
out := new(Response)
|
||||
err := c.cc.Invoke(ctx, "/speak.Speak/SpeakData", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// SpeakServer is the server API for Speak service.
|
||||
type SpeakServer interface {
|
||||
// 定义方法
|
||||
SpeakData(context.Context, *Request) (*Response, error)
|
||||
}
|
||||
|
||||
// UnimplementedSpeakServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedSpeakServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedSpeakServer) SpeakData(ctx context.Context, req *Request) (*Response, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SpeakData not implemented")
|
||||
}
|
||||
|
||||
func RegisterSpeakServer(s *grpc.Server, srv SpeakServer) {
|
||||
s.RegisterService(&_Speak_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Speak_SpeakData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SpeakServer).SpeakData(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/speak.Speak/SpeakData",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SpeakServer).SpeakData(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Speak_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "speak.Speak",
|
||||
HandlerType: (*SpeakServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "SpeakData",
|
||||
Handler: _Speak_SpeakData_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "speak.proto",
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: write.proto
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// Request 请求结构
|
||||
type Request struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Request) Reset() { *m = Request{} }
|
||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||
func (*Request) ProtoMessage() {}
|
||||
func (*Request) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_67966b2b12a73214, []int{0}
|
||||
}
|
||||
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Request) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Request.Merge(m, src)
|
||||
}
|
||||
func (m *Request) XXX_Size() int {
|
||||
return xxx_messageInfo_Request.Size(m)
|
||||
}
|
||||
func (m *Request) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Request.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Request proto.InternalMessageInfo
|
||||
|
||||
func (m *Request) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Response 响应结构
|
||||
type Response struct {
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Response) Reset() { *m = Response{} }
|
||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
||||
func (*Response) ProtoMessage() {}
|
||||
func (*Response) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_67966b2b12a73214, []int{1}
|
||||
}
|
||||
|
||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Response) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Response.Merge(m, src)
|
||||
}
|
||||
func (m *Response) XXX_Size() int {
|
||||
return xxx_messageInfo_Response.Size(m)
|
||||
}
|
||||
func (m *Response) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Response.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Response proto.InternalMessageInfo
|
||||
|
||||
func (m *Response) GetMessage() string {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Request)(nil), "write.Request")
|
||||
proto.RegisterType((*Response)(nil), "write.Response")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("write.proto", fileDescriptor_67966b2b12a73214) }
|
||||
|
||||
var fileDescriptor_67966b2b12a73214 = []byte{
|
||||
// 132 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2e, 0x2f, 0xca, 0x2c,
|
||||
0x49, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0x94, 0x64, 0xb9, 0xd8, 0x83,
|
||||
0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0x84, 0xb8, 0x58, 0xf2, 0x12, 0x73, 0x53, 0x25, 0x18,
|
||||
0x15, 0x18, 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x25, 0x15, 0x2e, 0x8e, 0xa0, 0xd4, 0xe2, 0x82, 0xfc,
|
||||
0xbc, 0xe2, 0x54, 0x21, 0x09, 0x2e, 0xf6, 0xdc, 0xd4, 0xe2, 0xe2, 0xc4, 0x74, 0x98, 0x12, 0x18,
|
||||
0xd7, 0xc8, 0x9c, 0x8b, 0x35, 0x1c, 0x64, 0x9a, 0x90, 0x1e, 0x17, 0x27, 0x98, 0xe1, 0x92, 0x58,
|
||||
0x92, 0x28, 0xc4, 0xa7, 0x07, 0xb1, 0x0f, 0x6a, 0xbe, 0x14, 0x3f, 0x9c, 0x0f, 0x31, 0x50, 0x89,
|
||||
0x21, 0x89, 0x0d, 0xec, 0x16, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb3, 0x7d, 0xc4, 0x7d,
|
||||
0x9a, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// WriteClient is the client API for Write service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type WriteClient interface {
|
||||
// 定义方法
|
||||
WriteData(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||
}
|
||||
|
||||
type writeClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewWriteClient(cc *grpc.ClientConn) WriteClient {
|
||||
return &writeClient{cc}
|
||||
}
|
||||
|
||||
func (c *writeClient) WriteData(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
out := new(Response)
|
||||
err := c.cc.Invoke(ctx, "/write.Write/WriteData", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// WriteServer is the server API for Write service.
|
||||
type WriteServer interface {
|
||||
// 定义方法
|
||||
WriteData(context.Context, *Request) (*Response, error)
|
||||
}
|
||||
|
||||
// UnimplementedWriteServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedWriteServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedWriteServer) WriteData(ctx context.Context, req *Request) (*Response, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method WriteData not implemented")
|
||||
}
|
||||
|
||||
func RegisterWriteServer(s *grpc.Server, srv WriteServer) {
|
||||
s.RegisterService(&_Write_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Write_WriteData_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WriteServer).WriteData(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/write.Write/WriteData",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WriteServer).WriteData(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Write_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "write.Write",
|
||||
HandlerType: (*WriteServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "WriteData",
|
||||
Handler: _Write_WriteData_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "write.proto",
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
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"
|
||||
)
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
return func(c *gin.Context) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
|
||||
DebugStack := ""
|
||||
for _, v := range strings.Split(string(debug.Stack()), "\n") {
|
||||
DebugStack += v + "<br>"
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(500, "系统异常,请联系管理员!", nil)
|
||||
}
|
||||
}()
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -1,946 +0,0 @@
|
||||
package exception
|
||||
|
||||
var MailTemplate = `<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="content-wrap" style="margin: 0px auto; overflow: hidden; padding-top: 15px; background-color: rgb(255, 255, 255); width: 600px;">
|
||||
<!---->
|
||||
<div>
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="background-color: rgb(62, 207, 88); background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 1% 50%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; text-align: center; vertical-align: top; width: 600px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 100%; max-width: 100%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: center; color: rgb(255, 255, 255); font-size: 16px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">系统告警</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; padding-top: 0px; text-align: center; vertical-align: top;">
|
||||
<div class="outlook-group-fix" style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" vertical-align="middle" style="padding-top: 40px; width: 600px; background-image: url(""); background-size: 100px; background-position: 10% 50%; background-repeat: no-repeat;"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="background-color: rgb(255, 255, 255); background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 1% 50%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; text-align: center; vertical-align: top; width: 600px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 40%; max-width: 40%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px; line-height: 0px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 240px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; padding: 0px; text-align: center; vertical-align: top;">
|
||||
<div class="outlook-group-fix" style="line-height: 0px; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; padding: 25px 0px; word-break: break-word; width: 240px; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse: collapse; border-spacing: 0px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 375px; border-top: 1px solid rgb(204, 204, 204);"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
<td style="width: 20%; max-width: 20%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 120px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 120px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 13px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: center; color: rgb(51, 51, 51); font-size: 16px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">告警</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
<td style="width: 40%; max-width: 40%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px; line-height: 0px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 240px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; padding: 0px; text-align: center; vertical-align: top;">
|
||||
<div class="outlook-group-fix" style="line-height: 0px; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; padding: 25px 0px; word-break: break-word; width: 240px; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse: collapse; border-spacing: 0px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 375px; border-top: 1px solid rgb(204, 204, 204);"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 6px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(188, 12, 39); font-size: 21px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">{ErrorMsg}</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; padding-top: 0px; text-align: center; vertical-align: top;">
|
||||
<div class="outlook-group-fix" style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" vertical-align="middle" style="padding-top: 15px; width: 600px; background-image: url(""); background-size: 100px; background-position: 10% 50%; background-repeat: no-repeat;"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="background-color: rgb(255, 255, 255); background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 1% 50%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; text-align: center; vertical-align: top; width: 600px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 40%; max-width: 40%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px; line-height: 0px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 240px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; padding: 0px; text-align: center; vertical-align: top;">
|
||||
<div class="outlook-group-fix" style="line-height: 0px; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; padding: 25px 0px; word-break: break-word; width: 240px; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse: collapse; border-spacing: 0px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 375px; border-top: 1px solid rgb(204, 204, 204);"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
<td style="width: 20%; max-width: 20%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 120px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 120px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 13px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: center; color: rgb(51, 51, 51); font-size: 16px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">详情</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
<td style="width: 40%; max-width: 40%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px; line-height: 0px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 240px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; padding: 0px; text-align: center; vertical-align: top;">
|
||||
<div class="outlook-group-fix" style="line-height: 0px; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; padding: 25px 0px; word-break: break-word; width: 240px; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse: collapse; border-spacing: 0px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 375px; border-top: 1px solid rgb(204, 204, 204);"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="background-color: rgb(241, 245, 240); background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 1% 50%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; text-align: center; vertical-align: top; width: 600px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 100%; max-width: 100%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div columnnumber="3">
|
||||
<div>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; text-align: center; vertical-align: top; border: 0px;"><a target="_blank" href="javascript:;" style="cursor: default;">
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 10px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">请求时间:</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 0px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">{RequestTime}</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 10px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">请求地址:</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 0px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">{RequestURL}</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 10px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">请求 UA:</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 0px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">{RequestUA}</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 10px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">请求 IP:</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 0px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">{RequestIP}</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 10px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">DebugStack:</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="mj-column-per-25" style="width: 100%; max-width: 100%; font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" border="0" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td border="0">
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 0px 20px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(102, 102, 102); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">{DebugStack}</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; padding-top: 0px; text-align: center; vertical-align: top;">
|
||||
<div class="outlook-group-fix" style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" vertical-align="middle" style="padding-top: 15px; width: 600px; background-image: url(""); background-size: 100px; background-position: 10% 50%; background-repeat: no-repeat;"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="background-color: rgb(65, 207, 88); background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 1% 50%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; font-size: 0px; text-align: center; vertical-align: top; width: 600px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 100%; max-width: 100%; min-height: 1px; font-size: 13px; text-align: left; direction: ltr; vertical-align: top; padding: 0px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" style="font-size: 0px; word-break: break-word;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border-spacing: 0px; width: 100%;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="full">
|
||||
<div style="margin: 0px auto; max-width: 600px;">
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="direction: ltr; width: 600px; font-size: 0px; padding-bottom: 0px; text-align: center; vertical-align: top; background-image: url(""); background-repeat: no-repeat; background-size: 100px; background-position: 10% 50%;">
|
||||
<div style="font-size: 13px; text-align: left; direction: ltr; display: inline-block; vertical-align: top; width: 100%;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%" style="vertical-align: top;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left" style="font-size: 0px; padding: 20px 10px; word-break: break-word;">
|
||||
<div class="text" style="margin: 0px; text-align: left; color: rgb(255, 255, 255); font-size: 12px;">
|
||||
<div>
|
||||
<p style="line-height: 20px; margin: 0px;">请注意,该邮件地址不接收回复邮件。</p>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
@@ -1,40 +0,0 @@
|
||||
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"
|
||||
)
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
return func(c *gin.Context) {
|
||||
if config.JaegerOpen == 1 {
|
||||
|
||||
var parentSpan opentracing.Span
|
||||
|
||||
tracer, closer := jaeger_trace.NewJaegerTracer("LXL-TEST", config.JaegerHostPort)
|
||||
defer closer.Close()
|
||||
|
||||
spCtx, err := opentracing.GlobalTracer().Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(c.Request.Header))
|
||||
if err != nil {
|
||||
parentSpan = tracer.StartSpan(c.Request.URL.Path)
|
||||
defer parentSpan.Finish()
|
||||
} else {
|
||||
parentSpan = opentracing.StartSpan(
|
||||
c.Request.URL.Path,
|
||||
opentracing.ChildOf(spCtx),
|
||||
opentracing.Tag{Key: string(ext.Component), Value: "HTTP"},
|
||||
ext.SpanKindRPCServer,
|
||||
)
|
||||
defer parentSpan.Finish()
|
||||
}
|
||||
c.Set("Tracer", tracer)
|
||||
c.Set("ParentSpanContext", parentSpan.Context())
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package sign_aes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"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
|
||||
|
||||
// AES 对称加密
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
return func(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
|
||||
sign, err := verifySign(c)
|
||||
|
||||
if sign != nil {
|
||||
utilGin.Response(-1, "Debug Sign", sign)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
utilGin.Response(-1, err.Error(), sign)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
_ = c.Request.ParseForm()
|
||||
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"], "")
|
||||
|
||||
// 验证来源
|
||||
value, ok := config.ApiAuthConfig[ak]
|
||||
if ok {
|
||||
AppSecret = value["aes"]
|
||||
} else {
|
||||
return nil, errors.New("ak Error")
|
||||
}
|
||||
|
||||
if debug == "1" {
|
||||
currentUnix := timeUtil.GetCurrentUnix()
|
||||
req.Set("ts", strconv.FormatInt(currentUnix, 10))
|
||||
|
||||
sn, err := createSign(req)
|
||||
if err != nil {
|
||||
return nil, errors.New("sn Exception")
|
||||
}
|
||||
|
||||
res := map[string]string{
|
||||
"ts": strconv.FormatInt(currentUnix, 10),
|
||||
"sn": sn,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// 验证过期时间
|
||||
timestamp := time.Now().Unix()
|
||||
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")
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
if sn == "" {
|
||||
return nil, errors.New("sn Error")
|
||||
}
|
||||
|
||||
decryptStr, decryptErr := aes.Decrypt(sn, []byte(AppSecret), AppSecret)
|
||||
if decryptErr != nil {
|
||||
return nil, errors.New(decryptErr.Error())
|
||||
}
|
||||
if decryptStr != createEncryptStr(req) {
|
||||
return nil, errors.New("sn Error")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 创建签名
|
||||
func createSign(params url.Values) (string, error) {
|
||||
return aes.Encrypt(createEncryptStr(params), []byte(AppSecret), AppSecret)
|
||||
}
|
||||
|
||||
func createEncryptStr(params url.Values) string {
|
||||
var key []string
|
||||
var str = ""
|
||||
for k := range params {
|
||||
if k != "sn" && k != "debug" {
|
||||
key = append(key, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(key)
|
||||
for i := 0; i < len(key); i++ {
|
||||
if i == 0 {
|
||||
str = fmt.Sprintf("%v=%v", key[i], params.Get(key[i]))
|
||||
} else {
|
||||
str = str + fmt.Sprintf("&%v=%v", key[i], params.Get(key[i]))
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package sign_md5
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"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
|
||||
|
||||
// MD5 组合加密
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
return func(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
|
||||
sign, err := verifySign(c)
|
||||
|
||||
if sign != nil {
|
||||
utilGin.Response(-1, "Debug Sign", sign)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
utilGin.Response(-1, err.Error(), sign)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
_ = c.Request.ParseForm()
|
||||
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"], "")
|
||||
|
||||
// 验证来源
|
||||
value, ok := config.ApiAuthConfig[ak]
|
||||
if ok {
|
||||
AppSecret = value["md5"]
|
||||
} else {
|
||||
return nil, errors.New("ak Error")
|
||||
}
|
||||
|
||||
if debug == "1" {
|
||||
currentUnix := timeUtil.GetCurrentUnix()
|
||||
req.Set("ts", strconv.FormatInt(currentUnix, 10))
|
||||
res := map[string]string{
|
||||
"ts": strconv.FormatInt(currentUnix, 10),
|
||||
"sn": createSign(req),
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// 验证过期时间
|
||||
timestamp := time.Now().Unix()
|
||||
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")
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
if sn == "" || sn != createSign(req) {
|
||||
return nil, errors.New("sn Error")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 创建签名
|
||||
func createSign(params url.Values) string {
|
||||
// 自定义 MD5 组合
|
||||
return md5.MD5(AppSecret + createEncryptStr(params) + AppSecret)
|
||||
}
|
||||
|
||||
func createEncryptStr(params url.Values) string {
|
||||
var key []string
|
||||
var str = ""
|
||||
for k := range params {
|
||||
if k != "sn" && k != "debug" {
|
||||
key = append(key, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(key)
|
||||
for i := 0; i < len(key); i++ {
|
||||
if i == 0 {
|
||||
str = fmt.Sprintf("%v=%v", key[i], params.Get(key[i]))
|
||||
} else {
|
||||
str = str + fmt.Sprintf("&%v=%v", key[i], params.Get(key[i]))
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package sign_rsa
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"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
|
||||
|
||||
// RSA 非对称加密
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
return func(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
|
||||
sign, err := verifySign(c)
|
||||
|
||||
if sign != nil {
|
||||
utilGin.Response(-1, "Debug Sign", sign)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
utilGin.Response(-1, err.Error(), sign)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
func verifySign(c *gin.Context) (map[string]string, error) {
|
||||
_ = c.Request.ParseForm()
|
||||
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"], "")
|
||||
|
||||
// 验证来源
|
||||
value, ok := config.ApiAuthConfig[ak]
|
||||
if ok {
|
||||
AppSecret = value["rsa"]
|
||||
} else {
|
||||
return nil, errors.New("ak Error")
|
||||
}
|
||||
|
||||
if debug == "1" {
|
||||
currentUnix := timeUtil.GetCurrentUnix()
|
||||
req.Set("ts", strconv.FormatInt(currentUnix, 10))
|
||||
|
||||
sn, err := createSign(req)
|
||||
if err != nil {
|
||||
return nil, errors.New("sn Exception")
|
||||
}
|
||||
|
||||
res := map[string]string{
|
||||
"ts": strconv.FormatInt(currentUnix, 10),
|
||||
"sn": sn,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// 验证过期时间
|
||||
timestamp := time.Now().Unix()
|
||||
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")
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
if sn == "" {
|
||||
return nil, errors.New("sn Error")
|
||||
}
|
||||
|
||||
decryptStr, decryptErr := rsa.PrivateDecrypt(sn, config.AppRsaPrivateFile)
|
||||
if decryptErr != nil {
|
||||
return nil, errors.New(decryptErr.Error())
|
||||
}
|
||||
if decryptStr != createEncryptStr(req) {
|
||||
return nil, errors.New("sn Error")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 创建签名
|
||||
func createSign(params url.Values) (string, error) {
|
||||
return rsa.PublicEncrypt(createEncryptStr(params), AppSecret)
|
||||
}
|
||||
|
||||
func createEncryptStr(params url.Values) string {
|
||||
var key []string
|
||||
var str = ""
|
||||
for k := range params {
|
||||
if k != "sn" && k != "debug" {
|
||||
key = append(key, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(key)
|
||||
for i := 0; i < len(key); i++ {
|
||||
if i == 0 {
|
||||
str = fmt.Sprintf("%v=%v", key[i], params.Get(key[i]))
|
||||
} else {
|
||||
str = str + fmt.Sprintf("&%v=%v", key[i], params.Get(key[i]))
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
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"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func CreateServiceListenConn(c *gin.Context) *grpc.ClientConn {
|
||||
return createGrpcConn("127.0.0.1:9901", c)
|
||||
}
|
||||
|
||||
func CreateServiceSpeakConn(c *gin.Context) *grpc.ClientConn {
|
||||
return createGrpcConn("127.0.0.1:9902", c)
|
||||
}
|
||||
|
||||
func CreateServiceReadConn(c *gin.Context) *grpc.ClientConn {
|
||||
return createGrpcConn("127.0.0.1:9903", c)
|
||||
}
|
||||
|
||||
func CreateServiceWriteConn(c *gin.Context) *grpc.ClientConn {
|
||||
return createGrpcConn("127.0.0.1:9904", c)
|
||||
}
|
||||
|
||||
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)
|
||||
defer cancel()
|
||||
|
||||
if config.JaegerOpen == 1 {
|
||||
|
||||
tracer, _ := c.Get("Tracer")
|
||||
parentSpanContext, _ := c.Get("ParentSpanContext")
|
||||
|
||||
conn, err = grpc.DialContext(
|
||||
ctx,
|
||||
serviceAddress,
|
||||
grpc.WithInsecure(),
|
||||
grpc.WithBlock(),
|
||||
grpc.WithUnaryInterceptor(
|
||||
grpc_middeware.ChainUnaryClient(
|
||||
jaeger_trace.ClientInterceptor(tracer.(opentracing.Tracer), parentSpanContext.(opentracing.SpanContext)),
|
||||
grpc_log.ClientInterceptor(),
|
||||
),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
conn, err = grpc.DialContext(
|
||||
ctx,
|
||||
serviceAddress,
|
||||
grpc.WithInsecure(),
|
||||
grpc.WithBlock(),
|
||||
grpc.WithUnaryInterceptor(
|
||||
grpc_middeware.ChainUnaryClient(
|
||||
grpc_log.ClientInterceptor(),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(serviceAddress, "grpc conn err:", err)
|
||||
}
|
||||
return conn
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package grpc_log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"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)
|
||||
|
||||
func ClientInterceptor() grpc.UnaryClientInterceptor {
|
||||
|
||||
go handleGrpcChannel()
|
||||
|
||||
return func(ctx context.Context, method string,
|
||||
req, reply interface{}, cc *grpc.ClientConn,
|
||||
invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
|
||||
// 开始时间
|
||||
startTime := time.GetCurrentMilliUnix()
|
||||
|
||||
err := invoker(ctx, method, req, reply, cc, opts...)
|
||||
|
||||
// 结束时间
|
||||
endTime := time.GetCurrentMilliUnix()
|
||||
|
||||
// 日志格式
|
||||
grpcLogMap := make(map[string]interface{})
|
||||
|
||||
grpcLogMap["request_time"] = startTime
|
||||
grpcLogMap["request_data"] = req
|
||||
grpcLogMap["request_method"] = method
|
||||
|
||||
grpcLogMap["response_data"] = reply
|
||||
grpcLogMap["response_error"] = err
|
||||
|
||||
grpcLogMap["cost_time"] = fmt.Sprintf("%vms", endTime-startTime)
|
||||
|
||||
grpcLogJson, _ := json.Encode(grpcLogMap)
|
||||
|
||||
grpcChannel <- grpcLogJson
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func handleGrpcChannel() {
|
||||
if f, err := os.OpenFile(config.AppGrpcLogName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666); err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
for accessLog := range grpcChannel {
|
||||
_, _ = f.WriteString(accessLog + "\n")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
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"
|
||||
"github.com/uber/jaeger-client-go"
|
||||
jaegerConfig "github.com/uber/jaeger-client-go/config"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
func NewJaegerTracer(serviceName string, jaegerHostPort string) (opentracing.Tracer, io.Closer) {
|
||||
|
||||
cfg := &jaegerConfig.Configuration{
|
||||
Sampler: &jaegerConfig.SamplerConfig{
|
||||
Type: "const", //固定采样
|
||||
Param: 1, //1=全采样、0=不采样
|
||||
},
|
||||
|
||||
Reporter: &jaegerConfig.ReporterConfig{
|
||||
LogSpans: true,
|
||||
LocalAgentHostPort: jaegerHostPort,
|
||||
},
|
||||
|
||||
ServiceName: serviceName,
|
||||
}
|
||||
|
||||
tracer, closer, err := cfg.NewTracer(jaegerConfig.Logger(jaeger.StdLogger))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("ERROR: cannot init Jaeger: %v\n", err))
|
||||
}
|
||||
opentracing.SetGlobalTracer(tracer)
|
||||
return tracer, closer
|
||||
}
|
||||
|
||||
type MDReaderWriter struct {
|
||||
metadata.MD
|
||||
}
|
||||
|
||||
// ForeachKey implements ForeachKey of opentracing.TextMapReader
|
||||
func (c MDReaderWriter) ForeachKey(handler func(key, val string) error) error {
|
||||
for k, vs := range c.MD {
|
||||
for _, v := range vs {
|
||||
if err := handler(k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set implements Set() of opentracing.TextMapWriter
|
||||
func (c MDReaderWriter) Set(key, val string) {
|
||||
key = strings.ToLower(key)
|
||||
c.MD[key] = append(c.MD[key], val)
|
||||
}
|
||||
|
||||
// ClientInterceptor grpc client
|
||||
func ClientInterceptor(tracer opentracing.Tracer, spanContext opentracing.SpanContext) grpc.UnaryClientInterceptor {
|
||||
return func(ctx context.Context, method string,
|
||||
req, reply interface{}, cc *grpc.ClientConn,
|
||||
invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
||||
|
||||
span := opentracing.StartSpan(
|
||||
"call gRPC",
|
||||
opentracing.ChildOf(spanContext),
|
||||
opentracing.Tag{Key: string(ext.Component), Value: "gRPC"},
|
||||
ext.SpanKindRPCClient,
|
||||
)
|
||||
|
||||
defer span.Finish()
|
||||
|
||||
md, ok := metadata.FromOutgoingContext(ctx)
|
||||
if !ok {
|
||||
md = metadata.New(nil)
|
||||
} else {
|
||||
md = md.Copy()
|
||||
}
|
||||
|
||||
err := tracer.Inject(span.Context(), opentracing.TextMap, MDReaderWriter{md})
|
||||
if err != nil {
|
||||
span.LogFields(log.String("inject-error", err.Error()))
|
||||
}
|
||||
|
||||
newCtx := metadata.NewOutgoingContext(ctx, md)
|
||||
err = invoker(newCtx, method, req, reply, cc, opts...)
|
||||
if err != nil {
|
||||
span.LogFields(log.String("call-error", err.Error()))
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"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},
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: time.Second * 5, //默认5秒超时时间
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if config.JaegerOpen == 1 {
|
||||
|
||||
tracer, _ := c.Get("Tracer")
|
||||
parentSpanContext, _ := c.Get("ParentSpanContext")
|
||||
|
||||
span := opentracing.StartSpan(
|
||||
"call Http Get",
|
||||
opentracing.ChildOf(parentSpanContext.(opentracing.SpanContext)),
|
||||
opentracing.Tag{Key: string(ext.Component), Value: "HTTP"},
|
||||
ext.SpanKindRPCClient,
|
||||
)
|
||||
|
||||
span.Finish()
|
||||
|
||||
injectErr := tracer.(opentracing.Tracer).Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header))
|
||||
if injectErr != nil {
|
||||
log.Fatalf("%s: Couldn't inject headers", err)
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
content, err := ioutil.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(content), err
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -9,10 +9,17 @@ import (
|
||||
var config = new(Config)
|
||||
|
||||
type Config struct {
|
||||
DB struct {
|
||||
Mail struct {
|
||||
Host string `mapstructure:"host"`
|
||||
Port int `mapstructure:"port"`
|
||||
} `mapstructure:"db"`
|
||||
User string `mapstructure:"user"`
|
||||
Pass string `mapstructure:"pass"`
|
||||
To string `mapstructure:"to"`
|
||||
} `mapstructure:"mail"`
|
||||
|
||||
JWT struct {
|
||||
Secret string `mapstructure:"secret"`
|
||||
} `mapstructure:"jwt"`
|
||||
|
||||
Aes struct {
|
||||
Key string `mapstructure:"key"`
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/errno"
|
||||
@@ -20,10 +21,14 @@ type HandlerFunc func(c Context)
|
||||
type Journal = journal.T
|
||||
|
||||
const (
|
||||
_JournalName = "_journal_"
|
||||
_LoggerName = "_logger_"
|
||||
_BodyName = "_body_"
|
||||
_PayloadName = "_payload_"
|
||||
_Alias = "_alias_"
|
||||
_JournalName = "_journal_"
|
||||
_LoggerName = "_logger_"
|
||||
_BodyName = "_body_"
|
||||
_PayloadName = "_payload_"
|
||||
_UserID = "_user_id_"
|
||||
_UserName = "_user_name_"
|
||||
_AbortErrorName = "_abort_error_"
|
||||
)
|
||||
|
||||
var contextPool = &sync.Pool{
|
||||
@@ -87,14 +92,22 @@ type Context interface {
|
||||
GetHeader(key string) string
|
||||
SetHeader(key, value string)
|
||||
|
||||
UserID() int
|
||||
setUserID(userID int)
|
||||
|
||||
UserName() string
|
||||
setUserName(userName string)
|
||||
|
||||
AbortWithError(err errno.Error)
|
||||
abortError() errno.Error
|
||||
|
||||
Alias() string
|
||||
setAlias(path string)
|
||||
|
||||
RawData() []byte
|
||||
|
||||
Method() string
|
||||
|
||||
Host() string
|
||||
|
||||
Path() string
|
||||
|
||||
URI() string
|
||||
}
|
||||
|
||||
@@ -208,6 +221,59 @@ func (c *context) SetHeader(key, value string) {
|
||||
c.ctx.Header(key, value)
|
||||
}
|
||||
|
||||
func (c *context) UserID() int {
|
||||
val, ok := c.ctx.Get(_UserID)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return val.(int)
|
||||
}
|
||||
|
||||
func (c *context) setUserID(userID int) {
|
||||
c.ctx.Set(_UserID, userID)
|
||||
}
|
||||
|
||||
func (c *context) UserName() string {
|
||||
val, ok := c.ctx.Get(_UserName)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return val.(string)
|
||||
}
|
||||
|
||||
func (c *context) setUserName(userName string) {
|
||||
c.ctx.Set(_UserName, userName)
|
||||
}
|
||||
|
||||
func (c *context) AbortWithError(err errno.Error) {
|
||||
if err != nil {
|
||||
c.ctx.AbortWithStatus(http.StatusInternalServerError)
|
||||
c.ctx.Set(_AbortErrorName, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) abortError() errno.Error {
|
||||
err, _ := c.ctx.Get(_AbortErrorName)
|
||||
return err.(errno.Error)
|
||||
}
|
||||
|
||||
func (c *context) Alias() string {
|
||||
path, ok := c.ctx.Get(_Alias)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
return path.(string)
|
||||
}
|
||||
|
||||
func (c *context) setAlias(path string) {
|
||||
if path = strings.TrimSpace(path); path != "" {
|
||||
c.ctx.Set(_Alias, path)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) RawData() []byte {
|
||||
body, ok := c.ctx.Get(_BodyName)
|
||||
if !ok {
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
cors "github.com/rs/cors/wrapper/gin"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
"github.com/swaggo/gin-swagger/swaggerFiles"
|
||||
"go.uber.org/multierr"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
@@ -41,6 +42,7 @@ type option struct {
|
||||
disableSwagger bool
|
||||
disablePrometheus bool
|
||||
panicNotify OnPanicNotify
|
||||
recordMetrics RecordMetrics
|
||||
enableCors bool
|
||||
enableRate bool
|
||||
}
|
||||
@@ -48,6 +50,10 @@ type option struct {
|
||||
// OnPanicNotify 发生panic时通知用
|
||||
type OnPanicNotify func(ctx Context, err interface{}, stackInfo string)
|
||||
|
||||
// RecordMetrics 记录prometheus指标用
|
||||
// 如果使用AliasForRecordMetrics配置了别名,uri将被替换为别名。
|
||||
type RecordMetrics func(method, uri string, success bool, httpCode, businessCode int, costSeconds float64)
|
||||
|
||||
// WithDisablePProf 禁用 pprof
|
||||
func WithDisablePProf() Option {
|
||||
return func(opt *option) {
|
||||
@@ -73,6 +79,14 @@ func WithDisableproPrometheus() Option {
|
||||
func WithPanicNotify(notify OnPanicNotify) Option {
|
||||
return func(opt *option) {
|
||||
opt.panicNotify = notify
|
||||
fmt.Println(color.Green("* [register panic notify]"))
|
||||
}
|
||||
}
|
||||
|
||||
// WithRecordMetrics 设置记录prometheus记录指标回调
|
||||
func WithRecordMetrics(record RecordMetrics) Option {
|
||||
return func(opt *option) {
|
||||
opt.recordMetrics = record
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,12 +94,14 @@ func WithPanicNotify(notify OnPanicNotify) Option {
|
||||
func WithEnableCors() Option {
|
||||
return func(opt *option) {
|
||||
opt.enableCors = true
|
||||
fmt.Println(color.Green("* [register cors]"))
|
||||
}
|
||||
}
|
||||
|
||||
func WithEnableRate() Option {
|
||||
return func(opt *option) {
|
||||
opt.enableRate = true
|
||||
fmt.Println(color.Green("* [register rate]"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +110,27 @@ func DisableJournal(ctx Context) {
|
||||
ctx.disableJournal()
|
||||
}
|
||||
|
||||
// AliasForRecordMetrics 对请求uri起个别名,用于prometheus记录指标。
|
||||
// 如:Get /user/:username 这样的uri,因为username会有非常多的情况,这样记录prometheus指标会非常的不有好。
|
||||
func AliasForRecordMetrics(path string) HandlerFunc {
|
||||
return func(ctx Context) {
|
||||
ctx.setAlias(path)
|
||||
}
|
||||
}
|
||||
|
||||
// WrapAuthHandler 用来处理 Auth 的入口,在之后的handler中只需 ctx.UserID() ctx.UserName() 即可。
|
||||
func WrapAuthHandler(handler func(Context) (userID int, userName string, err errno.Error)) HandlerFunc {
|
||||
return func(ctx Context) {
|
||||
userID, userName, err := handler(ctx)
|
||||
if err != nil {
|
||||
ctx.AbortWithError(err)
|
||||
return
|
||||
}
|
||||
ctx.setUserID(userID)
|
||||
ctx.setUserName(userName)
|
||||
}
|
||||
}
|
||||
|
||||
// RouterGroup 包装gin的RouterGroup
|
||||
type RouterGroup interface {
|
||||
Group(string, ...HandlerFunc) RouterGroup
|
||||
@@ -199,8 +236,6 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
gin.DisableBindValidation()
|
||||
engine := gin.New()
|
||||
|
||||
mux := &mux{
|
||||
engine: gin.New(),
|
||||
}
|
||||
@@ -232,15 +267,18 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
}
|
||||
|
||||
if !opt.disablePProf {
|
||||
pprof.Register(engine) // register pprof to gin
|
||||
pprof.Register(mux.engine) // register pprof to gin
|
||||
fmt.Println(color.Green("* [register pprof]"))
|
||||
}
|
||||
|
||||
if !opt.disableSwagger {
|
||||
mux.engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) // register swagger
|
||||
fmt.Println(color.Green("* [register swagger]"))
|
||||
}
|
||||
|
||||
if !opt.disablePrometheus {
|
||||
mux.engine.GET("/metrics", gin.WrapH(promhttp.Handler())) // register prometheus
|
||||
fmt.Println(color.Green("* [register prometheus]"))
|
||||
}
|
||||
|
||||
if opt.enableCors {
|
||||
@@ -303,18 +341,48 @@ func New(logger *zap.Logger, options ...Option) (Mux, error) {
|
||||
return
|
||||
}
|
||||
|
||||
response := context.GetPayload()
|
||||
if x := context.Journal(); x != nil {
|
||||
context.SetHeader(journal.JournalHeader, x.ID())
|
||||
response.WithID(x.ID())
|
||||
var (
|
||||
response errno.Error
|
||||
abortErr error
|
||||
)
|
||||
|
||||
if ctx.IsAborted() {
|
||||
for i := range ctx.Errors { // gin error
|
||||
multierr.AppendInto(&abortErr, ctx.Errors[i])
|
||||
}
|
||||
|
||||
if err := context.abortError(); err != nil { // customer err
|
||||
multierr.AppendInto(&abortErr, errors.New(err.GetMsg()))
|
||||
response = err
|
||||
}
|
||||
} else {
|
||||
response.WithID("")
|
||||
response = context.GetPayload()
|
||||
}
|
||||
|
||||
if response != nil {
|
||||
if x := context.Journal(); x != nil {
|
||||
context.SetHeader(journal.JournalHeader, x.ID())
|
||||
response.WithID(x.ID())
|
||||
} else {
|
||||
response.WithID("")
|
||||
}
|
||||
ctx.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
if opt.recordMetrics != nil {
|
||||
uri := context.URI()
|
||||
if alias := context.Alias(); alias != "" {
|
||||
uri = alias
|
||||
}
|
||||
|
||||
businessCode := 0
|
||||
if response != nil {
|
||||
businessCode = response.GetCode()
|
||||
}
|
||||
|
||||
opt.recordMetrics(context.Method(), uri, !ctx.IsAborted() && ctx.Writer.Status() == http.StatusOK, ctx.Writer.Status(), businessCode, time.Since(ts).Seconds())
|
||||
}
|
||||
|
||||
var j *journal.Journal
|
||||
if x := context.Journal(); x != nil {
|
||||
j = x.(*journal.Journal)
|
||||
|
||||
@@ -13,6 +13,10 @@ type Error interface {
|
||||
WithData(data interface{}) Error
|
||||
// WithID 设置当前请求的唯一ID
|
||||
WithID(id string) Error
|
||||
// GetCode 获取 Code
|
||||
GetCode() int
|
||||
// GetMsg 获取 Msg
|
||||
GetMsg() string
|
||||
// ToString 返回 JSON 格式的错误详情
|
||||
ToString() string
|
||||
}
|
||||
@@ -44,6 +48,14 @@ func (e *err) WithID(id string) Error {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *err) GetCode() int {
|
||||
return e.Code
|
||||
}
|
||||
|
||||
func (e *err) GetMsg() string {
|
||||
return e.Msg
|
||||
}
|
||||
|
||||
// ToString 返回 JSON 格式的错误详情
|
||||
func (e *err) ToString() string {
|
||||
err := &struct {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package metrics
|
||||
|
||||
// RecordMetrics 记录指标
|
||||
func RecordMetrics(method, uri string, success bool, httpCode, businessCode int, costSeconds float64) {
|
||||
//fmt.Printf(">>>>>>>Metrics\nmethod:%s\nuri:%s\nsuccess:%t\nhttp code:%d\nbusiness code:%d\ncost seconds:%.9f\n<<<<<<<\n", method, uri, success, httpCode, businessCode, costSeconds)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
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,0 +1,39 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"gopkg.in/gomail.v2"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
MailHost string
|
||||
MailPort int
|
||||
MailUser string // 发件人
|
||||
MailPass string // 发件人密码
|
||||
MailTo string // 收件人 多个用,分割
|
||||
Subject string // 邮件主题
|
||||
Body string // 邮件内容
|
||||
}
|
||||
|
||||
func Send(o *Options) error {
|
||||
|
||||
m := gomail.NewMessage()
|
||||
|
||||
//设置发件人
|
||||
m.SetHeader("From", o.MailUser)
|
||||
|
||||
//设置发送给多个用户
|
||||
mailArrTo := strings.Split(o.MailTo, ",")
|
||||
m.SetHeader("To", mailArrTo...)
|
||||
|
||||
//设置邮件主题
|
||||
m.SetHeader("Subject", o.Subject)
|
||||
|
||||
//设置邮件正文
|
||||
m.SetBody("text/html", o.Body)
|
||||
|
||||
d := gomail.NewDialer(o.MailHost, o.MailPort, o.MailUser, o.MailPass)
|
||||
|
||||
return d.DialAndSend(m)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSend(t *testing.T) {
|
||||
options := &Options{
|
||||
MailHost: "smtp.163.com",
|
||||
MailPort: 465,
|
||||
MailUser: "xxx@163.com",
|
||||
MailPass: "", //密码或授权码
|
||||
MailTo: "",
|
||||
Subject: "subject",
|
||||
Body: "body",
|
||||
}
|
||||
err := Send(options)
|
||||
if err != nil {
|
||||
t.Error("Mail Send error", err)
|
||||
return
|
||||
}
|
||||
t.Log("success")
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify/mail/templates"
|
||||
)
|
||||
|
||||
// NewPanicHTMLEmail 发送系统异常邮件 html
|
||||
func NewPanicHTMLEmail(method, host, uri, id string, msg interface{}, stack string) (subject string, body string, err error) {
|
||||
mailData := &struct {
|
||||
URL string
|
||||
ID string
|
||||
Msg string
|
||||
Stack string
|
||||
Year int
|
||||
}{
|
||||
URL: fmt.Sprintf("%s %s%s", method, host, uri),
|
||||
ID: id,
|
||||
Msg: fmt.Sprintf("%+v", msg),
|
||||
Stack: stack,
|
||||
Year: time.Now().Year(),
|
||||
}
|
||||
|
||||
mailTplContent, err := getEmailHTMLContent(templates.PanicMail, mailData)
|
||||
return fmt.Sprintf("[系统异常]-%s", uri), mailTplContent, err
|
||||
}
|
||||
|
||||
// getEmailHTMLContent 获取邮件模板
|
||||
func getEmailHTMLContent(mailTpl string, mailData interface{}) (string, error) {
|
||||
tpl, err := template.New("email tpl").Parse(mailTpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
buffer := new(bytes.Buffer)
|
||||
err = tpl.Execute(buffer, mailData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buffer.String(), nil
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package templates
|
||||
|
||||
const PanicMail = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
|
||||
<style type="text/css" rel="stylesheet" media="all">
|
||||
/* Media Queries */
|
||||
@media only screen and (max-width: 500px) {
|
||||
.button {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
<body style="margin: 0; padding: 0; width: 100%; background-color: #F2F4F6;">
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="width: 100%; margin: 0; padding: 0; background-color: #F2F4F6;" align="center">
|
||||
<table width="100%" cellpadding="0" cellspacing="0">
|
||||
<!-- Logo -->
|
||||
<tr>
|
||||
<td style="padding: 25px 0; text-align: center;">
|
||||
系统异常
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Email Body -->
|
||||
<tr>
|
||||
<td style="width: 100%; margin: 0; padding: 0; border-top: 1px solid #EDEFF2; border-bottom: 1px solid #EDEFF2; background-color: #FFF;"
|
||||
width="100%">
|
||||
<table style="width: auto; max-width: 750px; margin: 0 auto; padding: 0;" align="center"
|
||||
width="750" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; padding: 35px;">
|
||||
<!-- Greeting -->
|
||||
<h1 style="margin-top: 0; color: #2F3133; font-size: 19px; font-weight: bold; text-align: left;">
|
||||
Hello!
|
||||
</h1>
|
||||
|
||||
<!-- Intro -->
|
||||
<p style="margin-top: 0; color: #74787E; line-height: 1.5em;">
|
||||
您收到此电子邮件,请紧急安排处理。
|
||||
</p>
|
||||
|
||||
<!-- Action Button -->
|
||||
<table style="width: 100%; margin: 30px auto; padding: 0;"
|
||||
width="100%" cellpadding="0" cellspacing="0">
|
||||
<tr style="margin-top: 0; color: #74787E; line-height: 1.5em;">
|
||||
<td style="width: 10%;">
|
||||
ID:
|
||||
</td>
|
||||
<td style="width: 90%">
|
||||
{{.ID}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr style="margin-top: 0; color: #74787E; font-size: 16px; line-height: 1.5em;">
|
||||
<td style="width: 10%;">
|
||||
URL:
|
||||
</td>
|
||||
<td style="width: 90%">
|
||||
{{.URL}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr style="margin-top: 0; color: #74787E; font-size: 16px; line-height: 1.5em;">
|
||||
<td style="width: 10%;">
|
||||
Error:
|
||||
</td>
|
||||
<td style="width: 90%">
|
||||
{{.Msg}}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr style="margin-top: 0; color: #74787E; font-size: 16px; line-height: 1.5em;">
|
||||
<td style="width: 10%;">
|
||||
Stack:
|
||||
</td>
|
||||
<td style="width: 90%;">
|
||||
{{.Stack}}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Footer -->
|
||||
<tr>
|
||||
<td>
|
||||
<table style="width: auto; max-width: 570px; margin: 0 auto; padding: 0; text-align: center;"
|
||||
align="center" width="750" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; color: #AEAEAE; padding: 35px; text-align: center;">
|
||||
<p style="margin-top: 0; color: #74787E; font-size: 12px; line-height: 1.5em;">
|
||||
© {{.Year}}
|
||||
All rights reserved.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
@@ -0,0 +1,38 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify/mail"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// OnPanicNotify
|
||||
func OnPanicNotify(ctx core.Context, err interface{}, stackInfo string) {
|
||||
cfg := configs.Get().Mail
|
||||
if cfg.Host == "" || cfg.Port == 0 || cfg.User == "" || cfg.Pass == "" || cfg.To == "" {
|
||||
ctx.Logger().Error("Mail config error")
|
||||
return
|
||||
}
|
||||
|
||||
subject, body, htmlErr := mail.NewPanicHTMLEmail(ctx.Method(), ctx.Host(), ctx.URI(), ctx.Journal().ID(), err, stackInfo)
|
||||
if htmlErr != nil {
|
||||
ctx.Logger().Error("NewPanicHTMLEmail error", zap.Error(htmlErr))
|
||||
return
|
||||
}
|
||||
options := &mail.Options{
|
||||
MailHost: cfg.Host,
|
||||
MailPort: cfg.Port,
|
||||
MailUser: cfg.User,
|
||||
MailPass: cfg.Pass,
|
||||
MailTo: cfg.To,
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
}
|
||||
sendErr := mail.Send(options)
|
||||
if sendErr != nil {
|
||||
ctx.Logger().Error("Mail Send error", zap.Error(sendErr))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
//var secret = configs.Get().JWT.Secret
|
||||
var secret = "i1ydX9RtHyuJTrw7frcu"
|
||||
|
||||
type claims struct {
|
||||
UserID int
|
||||
UserName string
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
func Sign(userId int, userName string) (tokenString string, err error) {
|
||||
// The token content.
|
||||
// iss: (Issuer)签发者
|
||||
// iat: (Issued At)签发时间,用Unix时间戳表示
|
||||
// exp: (Expiration Time)过期时间,用Unix时间戳表示
|
||||
// aud: (Audience)接收该JWT的一方
|
||||
// sub: (Subject)该JWT的主题
|
||||
// nbf: (Not Before)不要早于这个时间
|
||||
// jti: (JWT ID)用于标识JWT的唯一ID
|
||||
claims := claims{
|
||||
userId,
|
||||
userName,
|
||||
jwt.StandardClaims{
|
||||
NotBefore: time.Now().Unix(),
|
||||
IssuedAt: time.Now().Unix(),
|
||||
ExpiresAt: time.Now().Add(24 * time.Hour).Unix(),
|
||||
Issuer: "go-gin-api",
|
||||
},
|
||||
}
|
||||
tokenString, err = jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(secret))
|
||||
return
|
||||
}
|
||||
|
||||
func Parse(tokenString string) (*claims, error) {
|
||||
tokenClaims, err := jwt.ParseWithClaims(tokenString, &claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(secret), nil
|
||||
})
|
||||
|
||||
if tokenClaims != nil {
|
||||
if claims, ok := tokenClaims.Claims.(*claims); ok && tokenClaims.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// 执行 Test 时,先将 token.secret 设置值
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
tokenString, err := Sign(123456789, "xinliangnote")
|
||||
if err != nil {
|
||||
t.Error("sign error", err)
|
||||
return
|
||||
}
|
||||
t.Log(tokenString)
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjEyMzQ1Njc4OSwidXNlcm5hbWUiOiJ4aW5saWFuZyIsImV4cCI6MTYwOTQ2NzcwNCwiaWF0IjoxNjA5MzgxMzA0LCJpc3MiOiJnby1naW4tYXBpIiwibmJmIjoxNjA5MzgxMzA0fQ.hccv8F713WpKcwiSldBrFLZz_2SZzOTPedPi-8ps7M4"
|
||||
user, err := Parse(tokenString)
|
||||
if err != nil {
|
||||
t.Error("parse error", err)
|
||||
return
|
||||
}
|
||||
t.Log(user)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"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/token"
|
||||
)
|
||||
|
||||
func AuthHandler(ctx core.Context) (userId int, userName string, err errno.Error) {
|
||||
auth := ctx.GetHeader("Authorization")
|
||||
if auth == "" {
|
||||
err = errno.ErrSignParam
|
||||
return
|
||||
}
|
||||
|
||||
claims, errParse := token.Parse(auth)
|
||||
if errParse != nil {
|
||||
err = errno.ErrSignParam
|
||||
return
|
||||
}
|
||||
|
||||
userId = claims.UserID
|
||||
if userId <= 0 {
|
||||
err = errno.ErrSignParam
|
||||
return
|
||||
}
|
||||
userName = claims.UserName
|
||||
return
|
||||
}
|
||||
@@ -3,7 +3,9 @@ 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/metrics"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
|
||||
"github.com/xinliangnote/go-gin-api/internal/router/middleware"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
@@ -18,24 +20,27 @@ func NewHTTPMux(logger *zap.Logger) (core.Mux, error) {
|
||||
mux, err := core.New(logger,
|
||||
core.WithEnableCors(),
|
||||
core.WithEnableRate(),
|
||||
core.WithPanicNotify(notify.Email),
|
||||
core.WithPanicNotify(notify.OnPanicNotify),
|
||||
core.WithRecordMetrics(metrics.RecordMetrics),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//设置路由中间件
|
||||
//engine.Use(exception.SetUp(), jaeger.SetUp())
|
||||
|
||||
demoHandler := demo.NewDemo(logger)
|
||||
|
||||
d := mux.Group("/demo")
|
||||
u := mux.Group("/user")
|
||||
{
|
||||
d.GET("user/:name", demoHandler.User())
|
||||
u.POST("/login", demoHandler.Login())
|
||||
}
|
||||
|
||||
d := mux.Group("/demo", core.WrapAuthHandler(middleware.AuthHandler)) //使用 auth 验证
|
||||
{
|
||||
d.GET("user/:name", demoHandler.User(), core.DisableJournal)
|
||||
|
||||
// 模拟数据
|
||||
d.GET("get/:name", demoHandler.Get(), core.DisableJournal)
|
||||
d.GET("get/:name", demoHandler.Get())
|
||||
d.POST("post", demoHandler.Post(), core.DisableJournal)
|
||||
|
||||
// 测试加密性能
|
||||
@@ -44,8 +49,5 @@ func NewHTTPMux(logger *zap.Logger) (core.Mux, error) {
|
||||
d.GET("/md5/test", demoHandler.MD5Test())
|
||||
}
|
||||
|
||||
// 测试链路追踪
|
||||
//mux.GET("/jaeger_test", jaeger_conn.JaegerTest)
|
||||
|
||||
return mux, nil
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"net/http"
|
||||
"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/internal/router"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/logger"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/shutdown"
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
// @contact.url
|
||||
// @contact.email
|
||||
|
||||
// @host localhost:9999
|
||||
// @host 127.0.0.1:9999
|
||||
// @BasePath
|
||||
func main() {
|
||||
loggers, err := logger.NewJSONLogger(
|
||||
@@ -33,6 +33,7 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer loggers.Sync()
|
||||
|
||||
mux, err := router.NewHTTPMux(loggers)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package aes
|
||||
|
||||
import "testing"
|
||||
|
||||
const (
|
||||
Key = "IgkibX71IEf382PT"
|
||||
Iv = "IgkibX71IEf382PT"
|
||||
)
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
t.Log(New(Key, Iv).Encrypt("123456"))
|
||||
}
|
||||
|
||||
func TestDecrypt(t *testing.T) {
|
||||
t.Log(New(Key, Iv).Decrypt("GO-ri84zevE-z1biJwfQPw=="))
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
package env
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestActive(t *testing.T) {
|
||||
t.Log(Active().Value())
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package md5
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
t.Log(New().Encrypt("123456"))
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package rsa
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
publicKey := `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1O3p0JN0/RrP7eY3f81i
|
||||
zPf16FS0WMNGCJkd+y5c6yBzUvN0IEeoxiIWIBhoMKH0pzlzBg0rfttojSodOgNo
|
||||
m/UCAzAYEgdIsNee5LSN/7e0T2/QvsIAHINuA8gI8fGoGiSA2TEzpUo6aVXwhZT3
|
||||
4GGRdrSJ+m4iVk/Kt95tavBNk+NDVSeb5xAjxBchT5BjAMMlE0ffGZb0MMjjO5+e
|
||||
9Tn8f99M2VMqpzXHXZzv1ABmqufzS20iWcSvnjhWcJ9hiKwO8Z30GgJyACmml+HM
|
||||
xLYEFN9h2MWYgxLm9Z0rLMrWwMM+E2rCs8tsxAD5sO9RZMJPl1C0FIsMR53ngqbz
|
||||
owIDAQAB
|
||||
-----END PUBLIC KEY-----`
|
||||
|
||||
rsaPublic := NewPublic(publicKey)
|
||||
str, err := rsaPublic.Encrypt("123456")
|
||||
if err != nil {
|
||||
t.Error("rsa public encrypt error", err)
|
||||
return
|
||||
}
|
||||
t.Log(str)
|
||||
}
|
||||
|
||||
func TestDecrypt(t *testing.T) {
|
||||
privateKey := `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpgIBAAKCAQEA1O3p0JN0/RrP7eY3f81izPf16FS0WMNGCJkd+y5c6yBzUvN0
|
||||
IEeoxiIWIBhoMKH0pzlzBg0rfttojSodOgNom/UCAzAYEgdIsNee5LSN/7e0T2/Q
|
||||
vsIAHINuA8gI8fGoGiSA2TEzpUo6aVXwhZT34GGRdrSJ+m4iVk/Kt95tavBNk+ND
|
||||
VSeb5xAjxBchT5BjAMMlE0ffGZb0MMjjO5+e9Tn8f99M2VMqpzXHXZzv1ABmqufz
|
||||
S20iWcSvnjhWcJ9hiKwO8Z30GgJyACmml+HMxLYEFN9h2MWYgxLm9Z0rLMrWwMM+
|
||||
E2rCs8tsxAD5sO9RZMJPl1C0FIsMR53ngqbzowIDAQABAoIBAQCO1RE1ItUlO6kj
|
||||
Un0ENAgEqojAUqGvsT33Yo7kAZO+/cOeb0UEqk0iq5bf7L9ncBynWDg6ZPc6X3/g
|
||||
wdFdKxAvHck9zjM3VL+EMP+bNyrR0K8ZYk5Kx+Q/PEK+Mp8dfRdgggAUsZaNWB+a
|
||||
rVVspiMo1wo28KBl5x8NevTnJkOLqXAyB7UyLWqnOL1fb988lZvZPR7ZUYroVIZa
|
||||
pyXtZcafIJeKyQ3bvWI5+eFqOe61Z4Bx1+TpfZ3fKfSDW0vhxzNqaimOa8jSXtMJ
|
||||
jMeOctL4nZ0TPo/jS3I+XlaH4ZQlFLuUWGscpxwfEeBN23I8HRLkZXJsw66yvRN3
|
||||
s4bUKPXRAoGBAP/3oSZAECvfsYYzs76tnrAmR/0GxCqgguxDlWn5DowQzdWFOdHC
|
||||
ZbTo/hUVoMSQnO1EKCFlnBS+wg/3TuIzUO0ewC1aeT7qHbOMDl0zKbNpS2Z9/j+U
|
||||
zro+qz7XmkWolMCfmDrCrw9CtCxcMSII+ajbI8SAgFVMz9XnDt+xW9E9AoGBANT0
|
||||
4F6kCUJTEyqf2+v84tjQ2wGIF6XtZPU9JR806zeMyahQ9F6z3hY8BYb0tIy5b3uJ
|
||||
VlJ9TG1qg/t59TWxIq43mYSUJHe0aJi3ilooObQtHlhPu8nwmmX47sX0PyG2hMoD
|
||||
kBVxTpTDmBaDz7O9uBnlMXJN5qEygctaixpEbmZfAoGBAMBA9kEMjRjnAyeRXcgy
|
||||
D6aumhNqKZz6wltCx864yjxZwsBFOJBcOpgPCAg+HmqFU9jCAIJVF05dmNT1I8Ky
|
||||
WG5BUoa+FaMzpOtenstRylh/Far9pyGKW1t4BpdEyRLY9CFZvbUk1OfZagqHlD/E
|
||||
DgDN16eX/MwUzWYUDg/l3tjhAoGBAKGip/ZNjVWRFpggs9z/mfK1O7WC5Wgksp9N
|
||||
ZLK2CN6l9p3RrFmBLk00C4HulGfHi+15RVLhFbRqx3iFje/N3iPbwaMWikNtZIKd
|
||||
tN5Pb9To9gJTqpZRD+/cLOeFRrHBBjMK1z7fPKS/fN2B+JFVq7nD827t3+J0In4F
|
||||
4FT0odMDAoGBAJk3ELB/FHY8xzZ4jF1wG/a1CK681Xm6SuU5KIELDSAUNoou6OPG
|
||||
mS8gU20MMPAeV2z7khyDcSxlHsUyL73eLeaakbQov9NMW7cc99XX4wnP4W7FRpmr
|
||||
QbHmKuHIRFHCFv+XX8c0aK2mDZMUlzJdy4FgD/YCEZ7kZMZKyvZW/ZuV
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
decryptStr := "KTKXckjkCLI6Vk_y_XROnY-a6nJpllruL-CX-v_2AFxfghA2tZ2nkQyS6d1-IIYMlgwm4ivwlzy-phLtaN9BB03htA5D9rwjA_JwYtqAG4iwuvgaDl2SiZ_H2ACv-aV1kNRgnyjh14hs0JiSt5VHEiJ3D2xYzOCKwtEzoo0WczJ-MYb3u_-bfcnm9YtvgtG5-y3Jy7WYr-IwXdBKqPO0E-jzrtY7m3Q1yC4znHdzjNpxCj0I6YRx4CZ362b706qNX7sl3E5KTJeSmYrsurB-SxQT1CaqGzVt7mshx1v2qGnv5NBNXpj7ZPKWGJbgaCUxcuxd1Mg0o81HnfbsGuSlFQ=="
|
||||
|
||||
rsaPrivate := NewPrivate(privateKey)
|
||||
str, err := rsaPrivate.Decrypt(decryptStr)
|
||||
if err != nil {
|
||||
t.Error("rsa private decrypt error", err)
|
||||
return
|
||||
}
|
||||
t.Log(str)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package sql
|
||||
|
||||
import "strings"
|
||||
|
||||
// EscapeString 转义 SQL 语句中使用的字符串中的特殊字符
|
||||
func EscapeString(value string) string {
|
||||
replace := map[string]string{"\\": "\\\\", "'": `\'`, "\\0": "\\\\0", "\n": "\\n", "\r": "\\r", `"`: `\"`, "\x1a": "\\Z"}
|
||||
|
||||
for b, a := range replace {
|
||||
value = strings.Replace(value, b, a, -1)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package sql
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEscapeString(t *testing.T) {
|
||||
str := "' OR ''=' union select 1,database(),2#"
|
||||
t.Log(EscapeString(str))
|
||||
}
|
||||
Reference in New Issue
Block a user