mirror of
https://github.com/xinliangnote/go-gin-api.git
synced 2024-04-21 12:31:46 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3823eee2ca | ||
|
|
0b6b9dd69f | ||
|
|
7327275b7a | ||
|
|
9b5028e9de | ||
|
|
cc8012b09d | ||
|
|
334bfbb4aa | ||
|
|
a4701309cb | ||
|
|
e5ea279f2e | ||
|
|
ad8639fea8 | ||
|
|
b346216f79 | ||
|
|
e1314cf139 | ||
|
|
a1a9208a27 | ||
|
|
4ed8b81c57 | ||
|
|
106d5b65d7 | ||
|
|
d17c58ffe1 | ||
|
|
845ef70a77 | ||
|
|
f32a8a1fb5 | ||
|
|
2466dfcbfc | ||
|
|
f96d33fdef | ||
|
|
f2cd04993f | ||
|
|
f4072dc5fb | ||
|
|
458ebe10c6 | ||
|
|
aa5dec6eeb | ||
|
|
ef8989fe33 | ||
|
|
34f85ad14b | ||
|
|
155f5fca1b | ||
|
|
f8cfc2f16c | ||
|
|
a017831aba |
+5
-1
@@ -1 +1,5 @@
|
||||
.idea
|
||||
/.vscode
|
||||
.vscode
|
||||
/.idea
|
||||
.idea
|
||||
mfmt
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 Gin-Gonic
|
||||
Copyright (c) 2020 新亮笔记
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -1,159 +1,49 @@
|
||||

|
||||
## 关于
|
||||
|
||||
## go-gin-api
|
||||
`go-gin-api` 是基于 [Gin](https://github.com/gin-gonic/gin) 进行模块化设计的 API 框架,封装了常用的功能,使用简单,致力于进行快速的业务研发,同时增加了更多限制,约束项目组开发成员,规避混乱无序及自由随意的编码。
|
||||
|
||||
基于 [Gin](https://github.com/gin-gonic/gin) 进行模块化设计的 API 框架,封装了常用的功能,使用简单,致力于进行快速的业务研发。
|
||||
供参考学习,线上使用请谨慎!
|
||||
|
||||
持续更新...
|
||||
集成组件:
|
||||
|
||||
## Features
|
||||
1. 支持 [rate](https://golang.org/x/time/rate) 接口限流
|
||||
1. 支持 panic 异常时邮件通知
|
||||
1. 支持 [cors](https://github.com/rs/cors) 接口跨域
|
||||
1. 支持 [Prometheus](https://github.com/prometheus/client_golang) 指标记录
|
||||
1. 支持 [Swagger](https://github.com/swaggo/gin-swagger) 接口文档生成
|
||||
1. 支持 [GraphQL](https://github.com/99designs/gqlgen) 查询语言
|
||||
1. 支持 trace 项目内部链路追踪
|
||||
1. 支持 [pprof](https://github.com/gin-contrib/pprof) 性能剖析
|
||||
1. 支持 [jwt](https://github.com/dgrijalva/jwt-go) 接口鉴权
|
||||
1. 支持 errno 统一定义错误码
|
||||
1. 支持 [zap](https://go.uber.org/zap) 日志收集
|
||||
1. 支持 [viper](https://github.com/spf13/viper) 配置文件解析
|
||||
1. 支持 [gorm](https://gorm.io/gorm) 数据库组件
|
||||
1. 支持 [go-redis](https://github.com/go-redis/redis/v7) 组件
|
||||
1. 支持 RESTful API 返回值规范
|
||||
|
||||
- [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)
|
||||
- [ ] 微信
|
||||
- [ ] 短信
|
||||
- [ ] 钉钉
|
||||
- [ ] 存储
|
||||
- [ ] MySQL
|
||||
- [ ] Redis
|
||||
- [ ] MongoDB
|
||||
- [ ] gRPC
|
||||
- [ ] ...
|
||||
|
||||
## Download
|
||||
|
||||
```
|
||||
git clone https://github.com/xinliangnote/go-gin-api.git
|
||||
```
|
||||
## 文档索引
|
||||
|
||||
## Quick start
|
||||
go-gin-api 文档由以下几个主要部分组成:
|
||||
|
||||
#### Requirements
|
||||
- 准备工作
|
||||
- 快速开始
|
||||
- 目录接口
|
||||
- 核心封装
|
||||
- 组件指南
|
||||
- 工具包
|
||||
|
||||
- Go version >= 1.12
|
||||
- Global environment configure (Linux/Mac)
|
||||
**地址:[https://www.yuque.com/xinliangnote/go-gin-api/ngc3x5](https://www.yuque.com/xinliangnote/go-gin-api/ngc3x5)**
|
||||
|
||||
```
|
||||
export GO111MODULE=on
|
||||
export GOPROXY=https://goproxy.io
|
||||
```
|
||||
## 其他
|
||||
|
||||
#### Build & Run
|
||||
查看 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) 。
|
||||
|
||||
```
|
||||
cd go-gin-api
|
||||
## Special Thanks
|
||||
|
||||
go run main.go
|
||||
|
||||
输出如下,表示 Http Server 启动成功。
|
||||
|-----------------------------------|
|
||||
| go-gin-api |
|
||||
|-----------------------------------|
|
||||
| Go Http Server Start Successful |
|
||||
| Port:9999 Pid:xxxxx |
|
||||
|-----------------------------------|
|
||||
```
|
||||
|
||||
#### HTTP Demo
|
||||
|
||||
```
|
||||
curl -X POST http://127.0.0.1:9999/product
|
||||
```
|
||||
|
||||
#### 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
|
||||
|
||||
```go
|
||||
http://127.0.0.1:9999/debug/pprof
|
||||
```
|
||||
|
||||
说明文档:
|
||||
|
||||
```go
|
||||
// 查看 CPU 信息
|
||||
go tool pprof 127.0.0.1:9999/debug/pprof/profile
|
||||
...
|
||||
(pprof)
|
||||
|
||||
//输入 web,生成 svg 文件。
|
||||
//输入 png,生成 png 文件。
|
||||
//输入 top,查看排名前 20 的信息。
|
||||
//查看更多命令,请执行 pprof help。
|
||||
```
|
||||
|
||||
其他同理,比如:
|
||||
|
||||
```go
|
||||
// 查看 内存 信息
|
||||
go tool pprof 127.0.0.1:9999/debug/pprof/heap
|
||||
|
||||
// 查看 协程 信息
|
||||
go tool pprof 127.0.0.1:9999/debug/pprof/goroutine
|
||||
|
||||
// 查看 锁 信息
|
||||
go tool pprof 127.0.0.1:9999/debug/pprof/mutex
|
||||
```
|
||||
如果还想查看火焰图,请执行如下命令:
|
||||
|
||||
```go
|
||||
// 1.下载 pprof 工具
|
||||
go get -u github.com/google/pprof
|
||||
|
||||
// 2.启动可视化界面
|
||||
pprof -http=:9998 xxx.cpu.prof
|
||||
|
||||
// 3.查看可视化界面
|
||||
http://127.0.0.1:9998/ui/
|
||||
```
|
||||
|
||||
## Dependence
|
||||
|
||||
- WEB 框架:github.com/gin-gonic/gin
|
||||
- 链路追踪:github.com/jaegertracing/jaeger-client-go
|
||||
- 限流:golang.org/x/time/rate
|
||||
- 工具包:github.com/xinliangnote/go-util
|
||||
|
||||
## Document
|
||||
|
||||
- [1. 使用 go modules 初始化项目](https://mp.weixin.qq.com/s/1XNTEgZ0XGZZdxFOfR5f_A)
|
||||
- [2. 规划项目目录和参数验证](https://mp.weixin.qq.com/s/11AuXptWGmL5QfiJArNLnA)
|
||||
- [3. 路由中间件 - 日志记录](https://mp.weixin.qq.com/s/eTygPXnrYM2xfrRQyfn8Tg)
|
||||
- [4. 路由中间件 - 捕获异常](https://mp.weixin.qq.com/s/SconDXB_x7Gan6T0Awdh9A)
|
||||
- [5. 路由中间件 - Jaeger 链路追踪(理论篇)](https://mp.weixin.qq.com/s/28UBEsLOAHDv530ePilKQA)
|
||||
- [6. 路由中间件 - Jaeger 链路追踪(实战篇)](https://mp.weixin.qq.com/s/Ea28475_UTNaM9RNfgPqJA)
|
||||
- [7. 路由中间件 - 签名验证](https://mp.weixin.qq.com/s/0cozELotcpX3Gd6WPJiBbQ)
|
||||
[@koketama](https://github.com/koketama)
|
||||
|
||||
## Learning together
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
package config
|
||||
|
||||
var (
|
||||
ApiAuthConfig = map[string] map[string]string {
|
||||
|
||||
// 调用方
|
||||
"DEMO" : {
|
||||
"md5" : "IgkibX71IEf382PT",
|
||||
"aes" : "IgkibX71IEf382PT",
|
||||
"rsa" : "rsa/public.pem",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
AppMode = "release" //debug or release
|
||||
AppPort = ":9999"
|
||||
AppName = "go-gin-api"
|
||||
|
||||
// 签名超时时间
|
||||
AppSignExpiry = "120"
|
||||
|
||||
// RSA Private File
|
||||
AppRsaPrivateFile = "rsa/private.pem"
|
||||
|
||||
// 超时时间
|
||||
AppReadTimeout = 120
|
||||
AppWriteTimeout = 120
|
||||
|
||||
// 日志文件
|
||||
AppAccessLogName = "log/" + AppName + "-access.log"
|
||||
AppErrorLogName = "log/" + AppName + "-error.log"
|
||||
AppGrpcLogName = "log/" + AppName + "-grpc.log"
|
||||
|
||||
// 系统告警邮箱信息
|
||||
SystemEmailUser = "xinliangnote@163.com"
|
||||
SystemEmailPass = "" //密码或授权码
|
||||
SystemEmailHost = "smtp.163.com"
|
||||
SystemEmailPort = 465
|
||||
|
||||
// 告警接收人
|
||||
ErrorNotifyUser = "xinliangnote@163.com"
|
||||
|
||||
// 告警开关 1=开通 -1=关闭
|
||||
ErrorNotifyOpen = -1
|
||||
|
||||
// Jaeger 配置信息
|
||||
JaegerHostPort = "127.0.0.1:6831"
|
||||
|
||||
// Jaeger 配置开关 1=开通 -1=关闭
|
||||
JaegerOpen = 1
|
||||
)
|
||||
@@ -1,57 +0,0 @@
|
||||
package jaeger_conn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/model/proto/listen"
|
||||
"go-gin-api/app/model/proto/read"
|
||||
"go-gin-api/app/model/proto/speak"
|
||||
"go-gin-api/app/model/proto/write"
|
||||
"go-gin-api/app/util/grpc_client"
|
||||
"go-gin-api/app/util/request"
|
||||
"go-gin-api/app/util/response"
|
||||
)
|
||||
|
||||
func JaegerTest(c *gin.Context) {
|
||||
|
||||
// 调用 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,5 +0,0 @@
|
||||
package param_bind
|
||||
|
||||
type ProductAdd struct {
|
||||
Name string `form:"name" json:"name" validate:"required,NameValid"`
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package param_verify
|
||||
|
||||
import (
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
)
|
||||
|
||||
func NameValid(fl validator.FieldLevel) bool {
|
||||
val := fl.Field().String()
|
||||
if val == "admin" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package product
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/controller/param_bind"
|
||||
"go-gin-api/app/controller/param_verify"
|
||||
"go-gin-api/app/util/bind"
|
||||
"go-gin-api/app/util/response"
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
)
|
||||
|
||||
// 新增
|
||||
func Add(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
|
||||
// 参数绑定
|
||||
s, e := bind.Bind(¶m_bind.ProductAdd{}, c)
|
||||
if e != nil {
|
||||
utilGin.Response(-1, e.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 参数验证
|
||||
validate := validator.New()
|
||||
|
||||
// 注册自定义验证
|
||||
_ = validate.RegisterValidation("NameValid", param_verify.NameValid)
|
||||
|
||||
if err := validate.Struct(s); err != nil {
|
||||
utilGin.Response(-1, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 业务处理...
|
||||
|
||||
utilGin.Response(1, "success", nil)
|
||||
}
|
||||
|
||||
// 编辑
|
||||
func Edit(c *gin.Context) {
|
||||
fmt.Println(c.Request.RequestURI)
|
||||
}
|
||||
|
||||
// 删除
|
||||
func Delete(c *gin.Context) {
|
||||
fmt.Println(c.Request.RequestURI)
|
||||
}
|
||||
|
||||
// 详情
|
||||
|
||||
func Detail(c *gin.Context) {
|
||||
fmt.Println(c.Request.RequestURI)
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/aes"
|
||||
"github.com/xinliangnote/go-util/md5"
|
||||
"github.com/xinliangnote/go-util/rsa"
|
||||
"go-gin-api/app/util/response"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Md5Test(c *gin.Context) {
|
||||
startTime := time.Now()
|
||||
appSecret := "IgkibX71IEf382PT"
|
||||
encryptStr := "param_1=xxx¶m_2=xxx&ak=xxx&ts=1111111111"
|
||||
count := 1000000
|
||||
for i := 0; i < count; i++ {
|
||||
// 生成签名
|
||||
md5.MD5(appSecret + encryptStr + appSecret)
|
||||
|
||||
// 验证签名
|
||||
md5.MD5(appSecret + encryptStr + appSecret)
|
||||
}
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1, fmt.Sprintf("%v次 - %v", count, time.Since(startTime)), nil)
|
||||
}
|
||||
|
||||
func AesTest(c *gin.Context) {
|
||||
startTime := time.Now()
|
||||
appSecret := "IgkibX71IEf382PT"
|
||||
encryptStr := "param_1=xxx¶m_2=xxx&ak=xxx&ts=1111111111"
|
||||
count := 1000000
|
||||
for i := 0; i < count; i++ {
|
||||
// 生成签名
|
||||
sn, _ := aes.Encrypt(encryptStr, []byte(appSecret), appSecret)
|
||||
|
||||
// 验证签名
|
||||
aes.Decrypt(sn, []byte(appSecret), appSecret)
|
||||
}
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1, fmt.Sprintf("%v次 - %v", count, time.Since(startTime)), nil)
|
||||
}
|
||||
|
||||
func RsaTest(c *gin.Context) {
|
||||
startTime := time.Now()
|
||||
encryptStr := "param_1=xxx¶m_2=xxx&ak=xxx&ts=1111111111"
|
||||
count := 500
|
||||
for i := 0; i < count; i++ {
|
||||
// 生成签名
|
||||
sn, _ := rsa.PublicEncrypt(encryptStr, "rsa/public.pem")
|
||||
|
||||
// 验证签名
|
||||
rsa.PrivateDecrypt(sn, "rsa/private.pem")
|
||||
}
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1, fmt.Sprintf("%v次 - %v", count, time.Since(startTime)), nil)
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: listen.proto
|
||||
|
||||
package listen
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
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,207 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: read.proto
|
||||
|
||||
package read
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
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,207 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: speak.proto
|
||||
|
||||
package speak
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
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,207 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: write.proto
|
||||
|
||||
package write
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
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,51 +0,0 @@
|
||||
package exception
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/mail"
|
||||
"github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
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,39 +0,0 @@
|
||||
package jaeger
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/jaeger_trace"
|
||||
)
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
return func(c *gin.Context) {
|
||||
if config.JaegerOpen == 1 {
|
||||
|
||||
var parentSpan opentracing.Span
|
||||
|
||||
tracer, closer := jaeger_trace.NewJaegerTracer(config.AppName, 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,25 +0,0 @@
|
||||
package limiter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/util/response"
|
||||
"golang.org/x/time/rate"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SetUp (maxBurstSize int) gin.HandlerFunc {
|
||||
|
||||
limiter := rate.NewLimiter(rate.Every(time.Second*1), maxBurstSize)
|
||||
return func(c *gin.Context) {
|
||||
if limiter.Allow() {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
fmt.Println("Too many requests")
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(-1, "Too many requests", nil)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
jsonUtil "github.com/xinliangnote/go-util/json"
|
||||
"github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type bodyLogWriter struct {
|
||||
gin.ResponseWriter
|
||||
body *bytes.Buffer
|
||||
}
|
||||
|
||||
var accessChannel = make(chan string, 100)
|
||||
|
||||
func (w bodyLogWriter) Write(b []byte) (int, error) {
|
||||
w.body.Write(b)
|
||||
return w.ResponseWriter.Write(b)
|
||||
}
|
||||
|
||||
func (w bodyLogWriter) WriteString(s string) (int, error) {
|
||||
w.body.WriteString(s)
|
||||
return w.ResponseWriter.WriteString(s)
|
||||
}
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
go handleAccessChannel()
|
||||
|
||||
return func(c *gin.Context) {
|
||||
bodyLogWriter := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
|
||||
c.Writer = bodyLogWriter
|
||||
|
||||
// 开始时间
|
||||
startTime := time.GetCurrentMilliUnix()
|
||||
|
||||
// 处理请求
|
||||
c.Next()
|
||||
|
||||
responseBody := bodyLogWriter.body.String()
|
||||
|
||||
var responseCode int
|
||||
var responseMsg string
|
||||
var responseData interface{}
|
||||
|
||||
if responseBody != "" {
|
||||
res := response.Response{}
|
||||
err := json.Unmarshal([]byte(responseBody), &res)
|
||||
if err == nil {
|
||||
responseCode = res.Code
|
||||
responseMsg = res.Message
|
||||
responseData = res.Data
|
||||
}
|
||||
}
|
||||
|
||||
// 结束时间
|
||||
endTime := time.GetCurrentMilliUnix()
|
||||
|
||||
if c.Request.Method == "POST" {
|
||||
_ = c.Request.ParseForm()
|
||||
}
|
||||
|
||||
// 日志格式
|
||||
accessLogMap := make(map[string]interface{})
|
||||
|
||||
accessLogMap["request_time"] = startTime
|
||||
accessLogMap["request_method"] = c.Request.Method
|
||||
accessLogMap["request_uri"] = c.Request.RequestURI
|
||||
accessLogMap["request_proto"] = c.Request.Proto
|
||||
accessLogMap["request_ua"] = c.Request.UserAgent()
|
||||
accessLogMap["request_referer"] = c.Request.Referer()
|
||||
accessLogMap["request_post_data"] = c.Request.PostForm.Encode()
|
||||
accessLogMap["request_client_ip"] = c.ClientIP()
|
||||
|
||||
accessLogMap["response_time"] = endTime
|
||||
accessLogMap["response_code"] = responseCode
|
||||
accessLogMap["response_msg"] = responseMsg
|
||||
accessLogMap["response_data"] = responseData
|
||||
|
||||
accessLogMap["cost_time"] = fmt.Sprintf("%vms", endTime-startTime)
|
||||
|
||||
accessLogJson, _ := jsonUtil.Encode(accessLogMap)
|
||||
accessChannel <- accessLogJson
|
||||
}
|
||||
}
|
||||
|
||||
func handleAccessChannel() {
|
||||
if f, err := os.OpenFile(config.AppAccessLogName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666); err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
for accessLog := range accessChannel {
|
||||
_, _ = f.WriteString(accessLog + "\n")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package requestid
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/uuid"
|
||||
)
|
||||
|
||||
func SetUp() gin.HandlerFunc {
|
||||
|
||||
return func(c *gin.Context) {
|
||||
requestId := c.Request.Header.Get("X-Request-Id")
|
||||
if requestId == "" {
|
||||
requestId = uuid.GenUUID()
|
||||
}
|
||||
c.Set("X-Request-Id", requestId)
|
||||
c.Writer.Header().Set("X-Request-Id", requestId)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package sign_aes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/aes"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
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,110 +0,0 @@
|
||||
package sign_md5
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/md5"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
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,122 +0,0 @@
|
||||
package sign_rsa
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xinliangnote/go-util/rsa"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/response"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
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,62 +0,0 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"go-gin-api/app/controller/jaeger_conn"
|
||||
"go-gin-api/app/controller/product"
|
||||
"go-gin-api/app/controller/test"
|
||||
"go-gin-api/app/route/middleware/exception"
|
||||
"go-gin-api/app/route/middleware/jaeger"
|
||||
"go-gin-api/app/route/middleware/logger"
|
||||
"go-gin-api/app/util/response"
|
||||
)
|
||||
|
||||
func SetupRouter(engine *gin.Engine) {
|
||||
|
||||
//设置路由中间件
|
||||
engine.Use(logger.SetUp(), exception.SetUp(), jaeger.SetUp())
|
||||
|
||||
//404
|
||||
engine.NoRoute(func(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(404,"请求方法不存在", nil)
|
||||
})
|
||||
|
||||
engine.GET("/ping", func(c *gin.Context) {
|
||||
utilGin := response.Gin{Ctx: c}
|
||||
utilGin.Response(1,"pong", nil)
|
||||
})
|
||||
|
||||
// 测试链路追踪
|
||||
engine.GET("/jaeger_test", jaeger_conn.JaegerTest)
|
||||
|
||||
//@todo 记录请求超时的路由
|
||||
|
||||
ProductRouter := engine.Group("/product")
|
||||
{
|
||||
// 新增产品
|
||||
ProductRouter.POST("", product.Add)
|
||||
|
||||
// 更新产品
|
||||
ProductRouter.PUT("/:id", product.Edit)
|
||||
|
||||
// 删除产品
|
||||
ProductRouter.DELETE("/:id", product.Delete)
|
||||
|
||||
// 获取产品详情
|
||||
ProductRouter.GET("/:id", product.Detail)
|
||||
}
|
||||
|
||||
// 测试加密性能
|
||||
TestRouter := engine.Group("/test")
|
||||
{
|
||||
// 测试 MD5 组合 的性能
|
||||
TestRouter.GET("/md5", test.Md5Test)
|
||||
|
||||
// 测试 AES 的性能
|
||||
TestRouter.GET("/aes", test.AesTest)
|
||||
|
||||
// 测试 RSA 的性能
|
||||
TestRouter.GET("/rsa", test.RsaTest)
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package bind
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
func Bind(s interface{}, c *gin.Context) (interface{}, error) {
|
||||
b := binding.Default(c.Request.Method, c.ContentType())
|
||||
if err := c.ShouldBindWith(s, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package error
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/xinliangnote/go-util/json"
|
||||
"github.com/xinliangnote/go-util/mail"
|
||||
timeUtil "github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/route/middleware/exception"
|
||||
"log"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type errorString struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (e *errorString) Error() string {
|
||||
return e.s
|
||||
}
|
||||
|
||||
func ErrorNew (text string) error {
|
||||
alarm("INFO", text)
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// 发邮件
|
||||
func ErrorMail (text string) error {
|
||||
alarm("MAIL",text)
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// 发短信
|
||||
func ErrorSms (text string) error {
|
||||
alarm("SMS", text)
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// 发微信
|
||||
func ErrorWeChat (text string) error {
|
||||
alarm("WX", text)
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// 告警方法
|
||||
func alarm(level string, str string) {
|
||||
if level == "MAIL" {
|
||||
DebugStack := ""
|
||||
for _, v := range strings.Split(string(debug.Stack()), "\n") {
|
||||
DebugStack += v + "<br>"
|
||||
}
|
||||
|
||||
subject := fmt.Sprintf("【系统告警】%s 项目出错了!", config.AppName)
|
||||
|
||||
body := strings.ReplaceAll(exception.MailTemplate, "{ErrorMsg}", fmt.Sprintf("%s", str))
|
||||
body = strings.ReplaceAll(body, "{RequestTime}", timeUtil.GetCurrentDate())
|
||||
body = strings.ReplaceAll(body, "{RequestURL}", "--")
|
||||
body = strings.ReplaceAll(body, "{RequestUA}", "--")
|
||||
body = strings.ReplaceAll(body, "{RequestIP}", "--")
|
||||
body = strings.ReplaceAll(body, "{DebugStack}", DebugStack)
|
||||
|
||||
// 执行发邮件
|
||||
options := &mail.Options{
|
||||
MailHost : config.SystemEmailHost,
|
||||
MailPort : config.SystemEmailPort,
|
||||
MailUser : config.SystemEmailUser,
|
||||
MailPass : config.SystemEmailPass,
|
||||
MailTo : config.ErrorNotifyUser,
|
||||
Subject : subject,
|
||||
Body : body,
|
||||
}
|
||||
_ = mail.Send(options)
|
||||
|
||||
} else if level == "SMS" {
|
||||
// 执行发短信
|
||||
|
||||
} else if level == "WX" {
|
||||
// 执行发微信
|
||||
|
||||
} else if level == "INFO" {
|
||||
// 执行记日志
|
||||
|
||||
if f, err := os.OpenFile(config.AppErrorLogName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666); err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
errorLogMap := make(map[string]interface{})
|
||||
errorLogMap["time"] = time.Now().Format("2006/01/02 - 15:04:05")
|
||||
errorLogMap["info"] = str
|
||||
|
||||
errorLogJson, _ := json.Encode(errorLogMap)
|
||||
_, _ = f.WriteString(errorLogJson + "\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package grpc_client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
grpc_middeware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"go-gin-api/app/config"
|
||||
"go-gin-api/app/util/grpc_log"
|
||||
"go-gin-api/app/util/jaeger_trace"
|
||||
"google.golang.org/grpc"
|
||||
"time"
|
||||
)
|
||||
|
||||
func CreateServiceListenConn(c *gin.Context) *grpc.ClientConn {
|
||||
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,61 +0,0 @@
|
||||
package grpc_log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/xinliangnote/go-util/json"
|
||||
"github.com/xinliangnote/go-util/time"
|
||||
"go-gin-api/app/config"
|
||||
"google.golang.org/grpc"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
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,97 +0,0 @@
|
||||
package jaeger_trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"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"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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,62 +0,0 @@
|
||||
package request
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/opentracing/opentracing-go"
|
||||
"github.com/opentracing/opentracing-go/ext"
|
||||
"go-gin-api/app/config"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
## 执行命令
|
||||
1. 定义生成的表,设置 config 中 cmd.genTables,可以自定义设置多张表,为空表示生成库中所有的表,如果设置多个表可用','分割;
|
||||
1. 在根目录下执行脚本文件:`./scripts/gormgen.sh`;
|
||||
|
||||
## 参考
|
||||
- https://github.com/MohamedBassem/gormgen
|
||||
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/cmd/gormgen/pkg"
|
||||
)
|
||||
|
||||
var (
|
||||
input string
|
||||
structs []string
|
||||
)
|
||||
|
||||
func init() {
|
||||
flagStructs := flag.String("structs", "", "[Required] The name of schema structs to generate structs for, comma seperated\n")
|
||||
flagInput := flag.String("input", "", "[Required] The name of the input file dir\n")
|
||||
flag.Parse()
|
||||
|
||||
if *flagStructs == "" || *flagInput == "" {
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
structs = strings.Split(*flagStructs, ",")
|
||||
input = *flagInput
|
||||
}
|
||||
|
||||
func main() {
|
||||
gen := pkg.NewGenerator(input)
|
||||
p := pkg.NewParser(input)
|
||||
if err := gen.ParserAST(p, structs).Generate().Format().Flush(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// fieldConfig
|
||||
type fieldConfig struct {
|
||||
FieldName string
|
||||
ColumnName string
|
||||
FieldType string
|
||||
HumpName string
|
||||
}
|
||||
|
||||
// structConfig
|
||||
type structConfig struct {
|
||||
config
|
||||
StructName string
|
||||
OnlyFields []fieldConfig
|
||||
OptionFields []fieldConfig
|
||||
}
|
||||
|
||||
type ImportPkg struct {
|
||||
Pkg string
|
||||
}
|
||||
|
||||
type structHelpers struct {
|
||||
Titelize func(string) string
|
||||
}
|
||||
|
||||
type config struct {
|
||||
PkgName string
|
||||
Helpers structHelpers
|
||||
QueryBuilderName string
|
||||
}
|
||||
|
||||
// The Generator is the one responsible for generating the code, adding the imports, formating, and writing it to the file.
|
||||
type Generator struct {
|
||||
buf map[string]*bytes.Buffer
|
||||
inputFile string
|
||||
config config
|
||||
structConfigs []structConfig
|
||||
}
|
||||
|
||||
// NewGenerator function creates an instance of the generator given the name of the output file as an argument.
|
||||
func NewGenerator(outputFile string) *Generator {
|
||||
return &Generator{
|
||||
buf: map[string]*bytes.Buffer{},
|
||||
inputFile: outputFile,
|
||||
}
|
||||
}
|
||||
|
||||
// ParserAST parse by go file
|
||||
func (g *Generator) ParserAST(p *Parser, structs []string) (ret *Generator) {
|
||||
for _, v := range structs {
|
||||
g.buf[gorm.ToDBName(v)] = new(bytes.Buffer)
|
||||
}
|
||||
g.structConfigs = p.Parse()
|
||||
g.config.PkgName = p.pkg.Name
|
||||
g.config.Helpers = structHelpers{
|
||||
Titelize: strings.Title,
|
||||
}
|
||||
g.config.QueryBuilderName = SQLColumnToHumpStyle(p.pkg.Name) + "QueryBuilder"
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Generator) checkConfig() (err error) {
|
||||
if len(g.config.PkgName) == 0 {
|
||||
err = errors.New("package name dose'n set")
|
||||
return
|
||||
}
|
||||
for i := 0; i < len(g.structConfigs); i++ {
|
||||
g.structConfigs[i].config = g.config
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Generate executes the template and store it in an internal buffer.
|
||||
func (g *Generator) Generate() *Generator {
|
||||
if err := g.checkConfig(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, v := range g.structConfigs {
|
||||
if _, ok := g.buf[gorm.ToDBName(v.StructName)]; !ok {
|
||||
continue
|
||||
}
|
||||
if err := outputTemplate.Execute(g.buf[gorm.ToDBName(v.StructName)], v); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
// Format function formats the output of the generation.
|
||||
func (g *Generator) Format() *Generator {
|
||||
for k := range g.buf {
|
||||
formattedOutput, err := format.Source(g.buf[k].Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.buf[k] = bytes.NewBuffer(formattedOutput)
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
// Flush function writes the output to the output file.
|
||||
func (g *Generator) Flush() error {
|
||||
for k := range g.buf {
|
||||
filename := g.inputFile + "/gen_" + strings.ToLower(k) + ".go"
|
||||
if err := ioutil.WriteFile(filename, g.buf[k].Bytes(), 0777); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
// The Parser is used to parse a directory and expose information about the structs defined in the files of this directory.
|
||||
type Parser struct {
|
||||
dir string
|
||||
pkg *build.Package
|
||||
parsedFiles []*ast.File
|
||||
}
|
||||
|
||||
// NewParser create a new parser instance.
|
||||
func NewParser(dir string) *Parser {
|
||||
return &Parser{
|
||||
dir: dir,
|
||||
}
|
||||
}
|
||||
|
||||
// getPackage parse dir get go file and package
|
||||
func (p *Parser) getPackage() {
|
||||
pkg, err := build.Default.ImportDir(p.dir, build.ImportComment)
|
||||
if err != nil {
|
||||
log.Fatalf("cannot process directory %s: %s", p.dir, err)
|
||||
}
|
||||
p.pkg = pkg
|
||||
|
||||
}
|
||||
|
||||
// parseGoFiles parse go file
|
||||
func (p *Parser) parseGoFiles() {
|
||||
var parsedFiles []*ast.File
|
||||
fs := token.NewFileSet()
|
||||
for _, file := range p.pkg.GoFiles {
|
||||
file = p.dir + "/" + file
|
||||
parsedFile, err := parser.ParseFile(fs, file, nil, 0)
|
||||
if err != nil {
|
||||
log.Fatalf("parsing package: %s: %s\n", file, err)
|
||||
}
|
||||
parsedFiles = append(parsedFiles, parsedFile)
|
||||
}
|
||||
p.parsedFiles = parsedFiles
|
||||
}
|
||||
|
||||
// parseTypes parse type of struct
|
||||
func (p *Parser) parseTypes(file *ast.File) (ret []structConfig) {
|
||||
ast.Inspect(file, func(n ast.Node) bool {
|
||||
decl, ok := n.(*ast.GenDecl)
|
||||
if !ok || decl.Tok != token.TYPE {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, spec := range decl.Specs {
|
||||
var (
|
||||
data structConfig
|
||||
)
|
||||
typeSpec, _ok := spec.(*ast.TypeSpec)
|
||||
if !_ok {
|
||||
continue
|
||||
}
|
||||
// We only care about struct declaration (for now)
|
||||
var structType *ast.StructType
|
||||
if structType, ok = typeSpec.Type.(*ast.StructType); !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
data.StructName = typeSpec.Name.Name
|
||||
for _, v := range structType.Fields.List {
|
||||
var (
|
||||
optionField fieldConfig
|
||||
)
|
||||
|
||||
// type is ident, get onlyField type
|
||||
if t, _ok := v.Type.(*ast.Ident); _ok {
|
||||
optionField.FieldType = t.String()
|
||||
} else {
|
||||
if v.Tag != nil {
|
||||
if strings.Contains(v.Tag.Value, "gorm") && strings.Contains(v.Tag.Value, "time") {
|
||||
optionField.FieldType = "time.Time"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get file name
|
||||
if len(v.Names) > 0 {
|
||||
optionField.FieldName = v.Names[0].String()
|
||||
optionField.ColumnName = gorm.ToDBName(optionField.FieldName)
|
||||
optionField.HumpName = SQLColumnToHumpStyle(optionField.ColumnName)
|
||||
}
|
||||
|
||||
data.OptionFields = append(data.OptionFields, optionField)
|
||||
}
|
||||
|
||||
ret = append(ret, data)
|
||||
}
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Parse should be called before any type querying for the parser. It takes the directory to be parsed and extracts all the structs defined in this directory.
|
||||
func (p *Parser) Parse() (ret []structConfig) {
|
||||
var (
|
||||
data []structConfig
|
||||
)
|
||||
p.getPackage()
|
||||
p.parseGoFiles()
|
||||
for _, f := range p.parsedFiles {
|
||||
data = append(data, p.parseTypes(f)...)
|
||||
}
|
||||
return data
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package pkg
|
||||
|
||||
import "text/template"
|
||||
|
||||
// Make sure that the template compiles during package initialization
|
||||
func parseTemplateOrPanic(t string) *template.Template {
|
||||
tpl, err := template.New("output_template").Parse(t)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return tpl
|
||||
}
|
||||
|
||||
var outputTemplate = parseTemplateOrPanic(`
|
||||
///////////////////////////////////////////////////////////
|
||||
// THIS FILE IS AUTO GENERATED by gormgen, DON'T EDIT IT //
|
||||
// ANY CHANGES DONE HERE WILL BE LOST //
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
package {{.PkgName}}
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func NewModel() *{{.StructName}} {
|
||||
return new({{.StructName}})
|
||||
}
|
||||
|
||||
func NewQueryBuilder() *{{.QueryBuilderName}} {
|
||||
return new({{.QueryBuilderName}})
|
||||
}
|
||||
|
||||
func (t *{{.StructName}}) Create(db *gorm.DB) (id int32, err error) {
|
||||
if err = db.Create(t).Error; err != nil {
|
||||
return 0, errors.Wrap(err, "create err")
|
||||
}
|
||||
return t.Id, nil
|
||||
}
|
||||
|
||||
func (t *{{.StructName}}) Delete(db *gorm.DB) (err error) {
|
||||
if err = db.Delete(t).Error; err != nil {
|
||||
return errors.Wrap(err, "delete err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *{{.StructName}}) Updates(db *gorm.DB, m map[string]interface{}) (err error) {
|
||||
if err = db.Model(&UserDemo{}).Where("id = ?", t.Id).Updates(m).Error; err != nil {
|
||||
return errors.Wrap(err, "updates err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type {{.QueryBuilderName}} struct {
|
||||
order []string
|
||||
where []struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}
|
||||
limit int
|
||||
offset int
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) buildQuery(db *gorm.DB) *gorm.DB {
|
||||
ret := db
|
||||
for _, where := range qb.where {
|
||||
ret = ret.Where(where.prefix, where.value)
|
||||
}
|
||||
for _, order := range qb.order {
|
||||
ret = ret.Order(order)
|
||||
}
|
||||
ret = ret.Limit(qb.limit).Offset(qb.offset)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) Count(db *gorm.DB) (int64, error) {
|
||||
var c int64
|
||||
res := qb.buildQuery(db).Model(&{{.StructName}}{}).Count(&c)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
c = 0
|
||||
}
|
||||
return c, res.Error
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) First(db *gorm.DB) (*{{.StructName}}, error) {
|
||||
ret := &{{.StructName}}{}
|
||||
res := qb.buildQuery(db).First(ret)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
ret = nil
|
||||
}
|
||||
return ret, res.Error
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) QueryOne(db *gorm.DB) (*{{.StructName}}, error) {
|
||||
qb.limit = 1
|
||||
ret, err := qb.QueryAll(db)
|
||||
if len(ret) > 0 {
|
||||
return ret[0], err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) QueryAll(db *gorm.DB) ([]*{{.StructName}}, error) {
|
||||
var ret []*{{.StructName}}
|
||||
err := qb.buildQuery(db).Find(&ret).Error
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) Limit(limit int) *{{.QueryBuilderName}} {
|
||||
qb.limit = limit
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *{{.QueryBuilderName}}) Offset(offset int) *{{.QueryBuilderName}} {
|
||||
qb.offset = offset
|
||||
return qb
|
||||
}
|
||||
|
||||
{{$queryBuilderName := .QueryBuilderName}}
|
||||
{{range .OptionFields}}
|
||||
func (qb *{{$queryBuilderName}}) Where{{call $.Helpers.Titelize .FieldName}}(p db_repo.Predicate, value {{.FieldType}}) *{{$queryBuilderName}} {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "{{.ColumnName}}", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *{{$queryBuilderName}}) OrderBy{{call $.Helpers.Titelize .FieldName}}(asc bool) *{{$queryBuilderName}} {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "{{.ColumnName}} " + order)
|
||||
return qb
|
||||
}
|
||||
{{end}}
|
||||
`)
|
||||
@@ -0,0 +1,18 @@
|
||||
package pkg
|
||||
|
||||
import "strings"
|
||||
|
||||
// SQLColumnToHumpStyle sql转换成驼峰模式
|
||||
func SQLColumnToHumpStyle(in string) (ret string) {
|
||||
for i := 0; i < len(in); i++ {
|
||||
if i > 0 && in[i-1] == '_' && in[i] != '_' {
|
||||
s := strings.ToUpper(string(in[i]))
|
||||
ret += s
|
||||
} else if in[i] == '_' {
|
||||
continue
|
||||
} else {
|
||||
ret += string(in[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
## 执行命令
|
||||
|
||||
```$xslt
|
||||
// test_handler 为 ./internal/api/controller/ 中的包名
|
||||
./scripts/handlergen.sh test_handler
|
||||
```
|
||||
@@ -0,0 +1,84 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var handlerName string
|
||||
|
||||
func init() {
|
||||
handler := flag.String("handler", "", "请输入需要生成的 handler 名称\n")
|
||||
flag.Parse()
|
||||
|
||||
handlerName = strings.ToLower(*handler)
|
||||
}
|
||||
|
||||
func main() {
|
||||
fs := token.NewFileSet()
|
||||
file := fmt.Sprintf("./internal/api/controller/%s/handler.go", handlerName)
|
||||
parsedFile, err := parser.ParseFile(fs, file, nil, 0)
|
||||
if err != nil {
|
||||
log.Fatalf("parsing package: %s: %s\n", file, err)
|
||||
}
|
||||
|
||||
ast.Inspect(parsedFile, func(n ast.Node) bool {
|
||||
decl, ok := n.(*ast.GenDecl)
|
||||
if !ok || decl.Tok != token.TYPE {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, spec := range decl.Specs {
|
||||
typeSpec, _ok := spec.(*ast.TypeSpec)
|
||||
if !_ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var interfaceType *ast.InterfaceType
|
||||
if interfaceType, ok = typeSpec.Type.(*ast.InterfaceType); !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, v := range interfaceType.Methods.List {
|
||||
if len(v.Names) > 0 {
|
||||
if v.Names[0].String() == "i" {
|
||||
continue
|
||||
}
|
||||
|
||||
filepath := "./internal/api/controller/" + handlerName
|
||||
filename := fmt.Sprintf("%s/func_%s.go", filepath, strings.ToLower(v.Names[0].String()))
|
||||
funcFile, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
|
||||
if err != nil {
|
||||
fmt.Printf("create and open func file error %v\n", err.Error())
|
||||
}
|
||||
|
||||
funcContent := fmt.Sprintf("package %s\n\n", handlerName)
|
||||
funcContent += "import (\n"
|
||||
funcContent += `"github.com/xinliangnote/go-gin-api/internal/pkg/core"`
|
||||
funcContent += "\n)\n\n"
|
||||
funcContent += fmt.Sprintf("\n\ntype %sRequest struct {}\n\n", Lcfirst(v.Names[0].String()))
|
||||
funcContent += fmt.Sprintf("type %sResponse struct {}\n\n", Lcfirst(v.Names[0].String()))
|
||||
funcContent += fmt.Sprintf("func (h *handler) %s() core.HandlerFunc { \n return func(c core.Context) {\n\n}}", v.Names[0].String())
|
||||
|
||||
funcFile.WriteString(funcContent)
|
||||
funcFile.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func Lcfirst(str string) string {
|
||||
for i, v := range str {
|
||||
return string(unicode.ToLower(v)) + str[i+1:]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/logger"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type tableInfo struct {
|
||||
Name string `db:"table_name"` // name
|
||||
Comment sql.NullString `db:"table_comment"` // comment
|
||||
}
|
||||
|
||||
type tableColumn struct {
|
||||
OrdinalPosition uint16 `db:"ORDINAL_POSITION"` // position
|
||||
ColumnName string `db:"COLUMN_NAME"` // name
|
||||
ColumnType string `db:"COLUMN_TYPE"` // column_type
|
||||
DataType string `db:"DATA_TYPE"` // data_type
|
||||
ColumnKey sql.NullString `db:"COLUMN_KEY"` // key
|
||||
IsNullable string `db:"IS_NULLABLE"` // nullable
|
||||
Extra sql.NullString `db:"EXTRA"` // extra
|
||||
ColumnComment sql.NullString `db:"COLUMN_COMMENT"` // comment
|
||||
ColumnDefault sql.NullString `db:"COLUMN_DEFAULT"` // default value
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 初始化 logger
|
||||
loggers, err := logger.NewJSONLogger(
|
||||
logger.WithField("domain", fmt.Sprintf("%s[%s]", configs.ProjectName(), env.Active().Value())),
|
||||
logger.WithTimeLayout("2006-01-02 15:04:05"),
|
||||
logger.WithFileP(configs.ProjectLogFile()),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer loggers.Sync()
|
||||
|
||||
// 初始化 DB
|
||||
dbRepo, err := db.New()
|
||||
if err != nil {
|
||||
loggers.Fatal("new db err", zap.Error(err))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := dbRepo.DbWClose(); err != nil {
|
||||
loggers.Error("dbw close err", zap.Error(err))
|
||||
}
|
||||
|
||||
if err := dbRepo.DbRClose(); err != nil {
|
||||
loggers.Error("dbr close err", zap.Error(err))
|
||||
}
|
||||
}()
|
||||
|
||||
dbName := configs.Get().MySQL.Read.Name
|
||||
genTables := configs.Get().Cmd.GenTables
|
||||
tables, err := queryTables(dbRepo.GetDbR(), dbName, genTables)
|
||||
if err != nil {
|
||||
loggers.Error("query tables of database err", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
|
||||
filepath := "./internal/api/repository/db_repo/" + table.Name + "_repo"
|
||||
_ = os.Mkdir(filepath, 0766)
|
||||
|
||||
mdName := fmt.Sprintf("%s/gen_table.md", filepath)
|
||||
mdFile, err := os.OpenFile(mdName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
|
||||
if err != nil {
|
||||
fmt.Printf("create and open markdown file error %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
modelName := fmt.Sprintf("%s/gen_model.go", filepath)
|
||||
modelFile, err := os.OpenFile(modelName, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0766)
|
||||
if err != nil {
|
||||
fmt.Printf("create and open model file error %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
modelContent := fmt.Sprintf("package %s%s\n", table.Name, "_repo")
|
||||
modelContent += fmt.Sprintf(`import "time"`)
|
||||
modelContent += fmt.Sprintf("\n\n// %s \n", table.Comment.String)
|
||||
modelContent += fmt.Sprintf("//go:generate gormgen -structs %s -input . \n", capitalize(table.Name))
|
||||
modelContent += fmt.Sprintf("type %s struct {\n", capitalize(table.Name))
|
||||
|
||||
tableContent := fmt.Sprintf("#### %s.%s \n", dbName, table.Name)
|
||||
if table.Comment.String != "" {
|
||||
tableContent += table.Comment.String + "\n"
|
||||
}
|
||||
tableContent += "\n" +
|
||||
"| 序号 | 名称 | 描述 | 类型 | 键 | 为空 | 额外 | 默认值 |\n" +
|
||||
"| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |\n"
|
||||
|
||||
columnInfo, columnInfoErr := queryTableColumn(dbRepo.GetDbR(), dbName, table.Name)
|
||||
if columnInfoErr != nil {
|
||||
continue
|
||||
}
|
||||
for _, info := range columnInfo {
|
||||
tableContent += fmt.Sprintf(
|
||||
"| %d | %s | %s | %s | %s | %s | %s | %s |\n",
|
||||
info.OrdinalPosition,
|
||||
info.ColumnName,
|
||||
strings.ReplaceAll(strings.ReplaceAll(info.ColumnComment.String, "|", "\\|"), "\n", ""),
|
||||
info.ColumnType,
|
||||
info.ColumnKey.String,
|
||||
info.IsNullable,
|
||||
info.Extra.String,
|
||||
info.ColumnDefault.String,
|
||||
)
|
||||
|
||||
if textType(info.DataType) == "time.Time" {
|
||||
modelContent += fmt.Sprintf("%s %s `%s` // %s\n", capitalize(info.ColumnName), textType(info.DataType), "gorm:\"time\"", info.ColumnComment.String)
|
||||
} else {
|
||||
modelContent += fmt.Sprintf("%s %s // %s\n", capitalize(info.ColumnName), textType(info.DataType), info.ColumnComment.String)
|
||||
}
|
||||
}
|
||||
|
||||
mdFile.WriteString(tableContent)
|
||||
mdFile.Close()
|
||||
|
||||
modelContent += "}\n"
|
||||
modelFile.WriteString(modelContent)
|
||||
modelFile.Close()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func queryTables(db *gorm.DB, dbName string, tableName string) ([]tableInfo, error) {
|
||||
var tableCollect []tableInfo
|
||||
var tableArray []string
|
||||
var commentArray []sql.NullString
|
||||
|
||||
sqlTables := fmt.Sprintf("SELECT `table_name`,`table_comment` FROM `information_schema`.`tables` WHERE `table_schema`= '%s'", dbName)
|
||||
rows, err := db.Raw(sqlTables).Rows()
|
||||
if err != nil {
|
||||
return tableCollect, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var info tableInfo
|
||||
err = rows.Scan(&info.Name, &info.Comment)
|
||||
if err != nil {
|
||||
fmt.Printf("execute query tables action error,had ignored, detail is [%v]\n", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
tableCollect = append(tableCollect, info)
|
||||
tableArray = append(tableArray, info.Name)
|
||||
commentArray = append(commentArray, info.Comment)
|
||||
}
|
||||
|
||||
// filter tables when specified tables params
|
||||
if tableName != "" {
|
||||
tableCollect = nil
|
||||
chooseTables := strings.Split(tableName, ",")
|
||||
indexMap := make(map[int]int)
|
||||
for _, item := range chooseTables {
|
||||
subIndexMap := getTargetIndexMap(tableArray, item)
|
||||
for k, v := range subIndexMap {
|
||||
if _, ok := indexMap[k]; ok {
|
||||
continue
|
||||
}
|
||||
indexMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
if len(indexMap) != 0 {
|
||||
for _, v := range indexMap {
|
||||
var info tableInfo
|
||||
info.Name = tableArray[v]
|
||||
info.Comment = commentArray[v]
|
||||
tableCollect = append(tableCollect, info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tableCollect, err
|
||||
}
|
||||
|
||||
func queryTableColumn(db *gorm.DB, dbName string, tableName string) ([]tableColumn, error) {
|
||||
// 定义承载列信息的切片
|
||||
var columns []tableColumn
|
||||
|
||||
sqlTableColumn := fmt.Sprintf("SELECT `ORDINAL_POSITION`,`COLUMN_NAME`,`COLUMN_TYPE`,`DATA_TYPE`,`COLUMN_KEY`,`IS_NULLABLE`,`EXTRA`,`COLUMN_COMMENT`,`COLUMN_DEFAULT` FROM `information_schema`.`columns` WHERE `table_schema`= '%s' AND `table_name`= '%s' ORDER BY `ORDINAL_POSITION` ASC",
|
||||
dbName, tableName)
|
||||
|
||||
rows, err := db.Raw(sqlTableColumn).Rows()
|
||||
if err != nil {
|
||||
fmt.Printf("execute query table column action error, detail is [%v]\n", err.Error())
|
||||
return columns, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var column tableColumn
|
||||
err = rows.Scan(
|
||||
&column.OrdinalPosition,
|
||||
&column.ColumnName,
|
||||
&column.ColumnType,
|
||||
&column.DataType,
|
||||
&column.ColumnKey,
|
||||
&column.IsNullable,
|
||||
&column.Extra,
|
||||
&column.ColumnComment,
|
||||
&column.ColumnDefault)
|
||||
if err != nil {
|
||||
fmt.Printf("query table column scan error, detail is [%v]\n", err.Error())
|
||||
return columns, err
|
||||
}
|
||||
columns = append(columns, column)
|
||||
}
|
||||
|
||||
return columns, err
|
||||
}
|
||||
|
||||
func getTargetIndexMap(tableNameArr []string, item string) map[int]int {
|
||||
indexMap := make(map[int]int)
|
||||
for i := 0; i < len(tableNameArr); i++ {
|
||||
if match, _ := regexp.MatchString(item, tableNameArr[i]); match {
|
||||
if _, ok := indexMap[i]; ok {
|
||||
continue
|
||||
}
|
||||
indexMap[i] = i
|
||||
}
|
||||
}
|
||||
return indexMap
|
||||
}
|
||||
|
||||
func capitalize(s string) string {
|
||||
var upperStr string
|
||||
chars := strings.Split(s, "_")
|
||||
for _, val := range chars {
|
||||
vv := []rune(val)
|
||||
for i := 0; i < len(vv); i++ {
|
||||
if i == 0 {
|
||||
if vv[i] >= 97 && vv[i] <= 122 {
|
||||
vv[i] -= 32
|
||||
upperStr += string(vv[i])
|
||||
}
|
||||
} else {
|
||||
upperStr += string(vv[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return upperStr
|
||||
}
|
||||
|
||||
func textType(s string) string {
|
||||
var mysqlTypeToGoType = map[string]string{
|
||||
"tinyint": "int32",
|
||||
"smallint": "int32",
|
||||
"mediumint": "int32",
|
||||
"int": "int32",
|
||||
"integer": "int64",
|
||||
"bigint": "int64",
|
||||
"float": "float64",
|
||||
"double": "float64",
|
||||
"decimal": "float64",
|
||||
"date": "string",
|
||||
"time": "string",
|
||||
"year": "string",
|
||||
"datetime": "time.Time",
|
||||
"timestamp": "time.Time",
|
||||
"char": "string",
|
||||
"varchar": "string",
|
||||
"tinyblob": "string",
|
||||
"tinytext": "string",
|
||||
"blob": "string",
|
||||
"text": "string",
|
||||
"mediumblob": "string",
|
||||
"mediumtext": "string",
|
||||
"longblob": "string",
|
||||
"longtext": "string",
|
||||
}
|
||||
return mysqlTypeToGoType[s]
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package configs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/pkg/env"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var config = new(Config)
|
||||
|
||||
type Config struct {
|
||||
MySQL struct {
|
||||
Read struct {
|
||||
Addr string `toml:"addr"`
|
||||
User string `toml:"user"`
|
||||
Pass string `toml:"pass"`
|
||||
Name string `toml:"name"`
|
||||
} `toml:"read"`
|
||||
Write struct {
|
||||
Addr string `toml:"addr"`
|
||||
User string `toml:"user"`
|
||||
Pass string `toml:"pass"`
|
||||
Name string `toml:"name"`
|
||||
} `toml:"write"`
|
||||
Base struct {
|
||||
MaxOpenConn int `toml:"maxOpenConn"`
|
||||
MaxIdleConn int `toml:"maxIdleConn"`
|
||||
ConnMaxLifeTime time.Duration `toml:"connMaxLifeTime"`
|
||||
} `toml:"base"`
|
||||
} `toml:"mysql"`
|
||||
|
||||
Redis struct {
|
||||
Addr string `toml:"addr"`
|
||||
Pass string `toml:"pass"`
|
||||
Db int `toml:"db"`
|
||||
MaxRetries int `toml:"maxRetries"`
|
||||
PoolSize int `toml:"poolSize"`
|
||||
MinIdleConns int `toml:"minIdleConns"`
|
||||
} `toml:"redis"`
|
||||
|
||||
Mail struct {
|
||||
Host string `toml:"host"`
|
||||
Port int `toml:"port"`
|
||||
User string `toml:"user"`
|
||||
Pass string `toml:"pass"`
|
||||
To string `toml:"to"`
|
||||
} `toml:"mail"`
|
||||
|
||||
JWT struct {
|
||||
Secret string `toml:"secret"`
|
||||
ExpireDuration time.Duration `toml:"expireDuration"`
|
||||
} `toml:"jwt"`
|
||||
|
||||
Aes struct {
|
||||
Key string `toml:"key"`
|
||||
Iv string `toml:"iv"`
|
||||
} `toml:"aes"`
|
||||
|
||||
Rsa struct {
|
||||
Private string `toml:"private"`
|
||||
Public string `toml:"public"`
|
||||
} `toml:"rsa"`
|
||||
|
||||
Cmd struct {
|
||||
GenTables string `toml:"genTables"`
|
||||
} `toml:"cmd"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
viper.SetConfigName(env.Active().Value() + "_configs")
|
||||
viper.SetConfigType("toml")
|
||||
viper.AddConfigPath("./configs")
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := viper.Unmarshal(config); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Get() Config {
|
||||
return *config
|
||||
}
|
||||
|
||||
func ProjectName() string {
|
||||
return "go-gin-api"
|
||||
}
|
||||
|
||||
func ProjectPort() string {
|
||||
return ":9999"
|
||||
}
|
||||
|
||||
func ProjectLogFile() string {
|
||||
return fmt.Sprintf("./logs/%s-access.log", ProjectName())
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
[db]
|
||||
host = '127.0.0.1'
|
||||
port = 3306
|
||||
@@ -0,0 +1,81 @@
|
||||
[mysql]
|
||||
|
||||
[mysql.read] # 从库信息,可读
|
||||
addr = '127.0.0.1:3306' # MySQL 地址:端口
|
||||
user = 'root' # 用户名
|
||||
pass = 'root' # 密码
|
||||
name = 'go_gin_api' # 数据库名称
|
||||
[mysql.write] # 主库信息,可读写
|
||||
addr = '127.0.0.1:3306' # MySQL 地址:端口
|
||||
user = 'root' # 用户名
|
||||
pass = 'root' # 密码
|
||||
name = 'go_gin_api' # 数据库名称
|
||||
[mysql.base] # 基础配置
|
||||
maxOpenConn = 10 # 最大打开的连接数
|
||||
maxIdleConn = 60 # 闲置的连接数
|
||||
connMaxLifeTime = 60 # 最大连接超时(单位:分)
|
||||
|
||||
[redis]
|
||||
addr = '127.0.0.1:6379' # Redis 地址:端口
|
||||
pass = '' # 密码
|
||||
db = 0 # 序号从 0 开始,默认是0,可以不用设置
|
||||
maxRetries = 3 # 命令执行失败时,最多重试多少次,默认为 0 即不重试
|
||||
poolSize = 10 # 连接池最大连接数,默认为 CPU 数 * 10
|
||||
minIdleConns = 5 # 最小空闲连接数
|
||||
|
||||
[mail]
|
||||
host = 'smtp.163.com' # 邮箱服务器,比如 smtp.163.com
|
||||
port = 465 # 端口
|
||||
user = "" # 发件人邮箱
|
||||
pass = "" # 发件人邮箱密码或授权码,根据邮箱服务器而定
|
||||
to = "" # 收件人邮箱,多个可以逗号(,)分割
|
||||
|
||||
[jwt]
|
||||
secret = 'i1ydX9RtHyuJTrw7frcu' # JWT secret
|
||||
expireDuration = 24 # JWT ExpiresAt 过期时间(单位:小时)
|
||||
|
||||
[aes]
|
||||
key = 'IgkibX71IEf382PT'
|
||||
iv = 'IgkibX71IEf382PT'
|
||||
|
||||
[rsa]
|
||||
private = '-----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-----'
|
||||
|
||||
public = '-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1O3p0JN0/RrP7eY3f81i
|
||||
zPf16FS0WMNGCJkd+y5c6yBzUvN0IEeoxiIWIBhoMKH0pzlzBg0rfttojSodOgNo
|
||||
m/UCAzAYEgdIsNee5LSN/7e0T2/QvsIAHINuA8gI8fGoGiSA2TEzpUo6aVXwhZT3
|
||||
4GGRdrSJ+m4iVk/Kt95tavBNk+NDVSeb5xAjxBchT5BjAMMlE0ffGZb0MMjjO5+e
|
||||
9Tn8f99M2VMqpzXHXZzv1ABmqufzS20iWcSvnjhWcJ9hiKwO8Z30GgJyACmml+HM
|
||||
xLYEFN9h2MWYgxLm9Z0rLMrWwMM+E2rCs8tsxAD5sO9RZMJPl1C0FIsMR53ngqbz
|
||||
owIDAQAB
|
||||
-----END PUBLIC KEY-----'
|
||||
|
||||
[cmd]
|
||||
genTables = 'user_demo'
|
||||
@@ -0,0 +1,4 @@
|
||||
[db]
|
||||
host = '127.0.0.1'
|
||||
port = 3306
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
[db]
|
||||
host = '127.0.0.1'
|
||||
port = 3306
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
auth_enabled: false
|
||||
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
|
||||
ingester:
|
||||
lifecycler:
|
||||
address: 127.0.0.1
|
||||
ring:
|
||||
kvstore:
|
||||
store: inmemory
|
||||
replication_factor: 1
|
||||
final_sleep: 0s
|
||||
chunk_idle_period: 5m
|
||||
chunk_retain_period: 30s
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2020-01-01
|
||||
store: boltdb
|
||||
object_store: filesystem
|
||||
schema: v9
|
||||
index:
|
||||
prefix: index_
|
||||
period: 168h # 每张表的时间范围6天
|
||||
|
||||
storage_config:
|
||||
boltdb:
|
||||
directory: /data/loki/index # 索引文件存储地址
|
||||
|
||||
filesystem:
|
||||
directory: /data/loki/chunks # 块存储地址
|
||||
|
||||
limits_config:
|
||||
enforce_metric_name: false
|
||||
reject_old_samples: true
|
||||
reject_old_samples_max_age: 168h
|
||||
|
||||
chunk_store_config:
|
||||
max_look_back_period: 0s
|
||||
|
||||
table_manager:
|
||||
retention_deletes_enabled: false
|
||||
retention_period: 0s
|
||||
@@ -0,0 +1,20 @@
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
grpc_listen_port: 0
|
||||
|
||||
# Positions
|
||||
positions:
|
||||
filename: /data/loki/positions.yaml
|
||||
|
||||
# Loki服务器的地址
|
||||
clients:
|
||||
- url: http://127.0.0.1:3100/loki/api/v1/push
|
||||
|
||||
scrape_configs:
|
||||
- job_name: go-gin-api
|
||||
static_configs:
|
||||
- targets:
|
||||
- localhost
|
||||
labels:
|
||||
job: accesslog
|
||||
__path__: /data/logs/*.log # 日志目录
|
||||
@@ -0,0 +1,12 @@
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: "prometheus"
|
||||
static_configs:
|
||||
- targets: ["127.0.0.1:9090"]
|
||||
- job_name: "go_app_server"
|
||||
static_configs:
|
||||
- targets:
|
||||
- "127.0.0.1:9999"
|
||||
+479
@@ -0,0 +1,479 @@
|
||||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag
|
||||
|
||||
package docs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/template"
|
||||
"github.com/swaggo/swag"
|
||||
)
|
||||
|
||||
var doc = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{.Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"contact": {},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://github.com/xinliangnote/go-gin-api/blob/master/LICENSE"
|
||||
},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/auth/get": {
|
||||
"post": {
|
||||
"description": "获取授权信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "获取授权信息",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/demo_handler.authResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/demo/trace": {
|
||||
"get": {
|
||||
"description": "Trace 示例",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "Trace 示例",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"job": {
|
||||
"description": "工作",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/create": {
|
||||
"post": {
|
||||
"description": "创建用户",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "创建用户",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
"name": "Request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.createRequest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.createResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/delete/{id}": {
|
||||
"patch": {
|
||||
"description": "删除用户",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "删除用户",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "用户ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.deleteResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/info/{username}": {
|
||||
"get": {
|
||||
"description": "用户详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "用户详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "用户名",
|
||||
"name": "username",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.detailResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/update": {
|
||||
"put": {
|
||||
"description": "编辑用户 - 通过用户主键ID更新用户昵称",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "编辑用户 - 通过用户主键ID更新用户昵称",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
"name": "Request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.updateNickNameByIDRequest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.updateNickNameByIDResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"code.Failure": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"description": "业务码",
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"description": "描述信息",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"demo_handler.authResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization": {
|
||||
"description": "签名",
|
||||
"type": "string"
|
||||
},
|
||||
"expire_time": {
|
||||
"description": "过期时间",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.createRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mobile": {
|
||||
"description": "手机号",
|
||||
"type": "string"
|
||||
},
|
||||
"nick_name": {
|
||||
"description": "昵称",
|
||||
"type": "string"
|
||||
},
|
||||
"user_name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.createResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "主键ID",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.deleteResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "用户主键ID",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.detailResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "用户主键ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"mobile": {
|
||||
"description": "手机号(脱敏)",
|
||||
"type": "string"
|
||||
},
|
||||
"nick_name": {
|
||||
"description": "昵称",
|
||||
"type": "string"
|
||||
},
|
||||
"user_name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.updateNickNameByIDRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "用户主键ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"nick_name": {
|
||||
"description": "昵称",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.updateNickNameByIDResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "用户主键ID",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
type swaggerInfo struct {
|
||||
Version string
|
||||
Host string
|
||||
BasePath string
|
||||
Schemes []string
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = swaggerInfo{
|
||||
Version: "2.0",
|
||||
Host: "127.0.0.1:9999",
|
||||
BasePath: "",
|
||||
Schemes: []string{},
|
||||
Title: "swagger 接口文档",
|
||||
Description: "",
|
||||
}
|
||||
|
||||
type s struct{}
|
||||
|
||||
func (s *s) ReadDoc() string {
|
||||
sInfo := SwaggerInfo
|
||||
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
|
||||
|
||||
t, err := template.New("swagger_info").Funcs(template.FuncMap{
|
||||
"marshal": func(v interface{}) string {
|
||||
a, _ := json.Marshal(v)
|
||||
return string(a)
|
||||
},
|
||||
}).Parse(doc)
|
||||
if err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
var tpl bytes.Buffer
|
||||
if err := t.Execute(&tpl, sInfo); err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
return tpl.String()
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(swag.Name, &s{})
|
||||
}
|
||||
@@ -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)
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "swagger 接口文档",
|
||||
"contact": {},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "https://github.com/xinliangnote/go-gin-api/blob/master/LICENSE"
|
||||
},
|
||||
"version": "2.0"
|
||||
},
|
||||
"host": "127.0.0.1:9999",
|
||||
"paths": {
|
||||
"/auth/get": {
|
||||
"post": {
|
||||
"description": "获取授权信息",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "获取授权信息",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/demo_handler.authResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/demo/trace": {
|
||||
"get": {
|
||||
"description": "Trace 示例",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Demo"
|
||||
],
|
||||
"summary": "Trace 示例",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"job": {
|
||||
"description": "工作",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/create": {
|
||||
"post": {
|
||||
"description": "创建用户",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "创建用户",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
"name": "Request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.createRequest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.createResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/delete/{id}": {
|
||||
"patch": {
|
||||
"description": "删除用户",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "删除用户",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "用户ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.deleteResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/info/{username}": {
|
||||
"get": {
|
||||
"description": "用户详情",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "用户详情",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "用户名",
|
||||
"name": "username",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.detailResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/user/update": {
|
||||
"put": {
|
||||
"description": "编辑用户 - 通过用户主键ID更新用户昵称",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"User"
|
||||
],
|
||||
"summary": "编辑用户 - 通过用户主键ID更新用户昵称",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "请求信息",
|
||||
"name": "Request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.updateNickNameByIDRequest"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "签名",
|
||||
"name": "Authorization",
|
||||
"in": "header",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/user_handler.updateNickNameByIDResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.Failure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"code.Failure": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"description": "业务码",
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"description": "描述信息",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"demo_handler.authResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"authorization": {
|
||||
"description": "签名",
|
||||
"type": "string"
|
||||
},
|
||||
"expire_time": {
|
||||
"description": "过期时间",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.createRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mobile": {
|
||||
"description": "手机号",
|
||||
"type": "string"
|
||||
},
|
||||
"nick_name": {
|
||||
"description": "昵称",
|
||||
"type": "string"
|
||||
},
|
||||
"user_name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.createResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "主键ID",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.deleteResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "用户主键ID",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.detailResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "用户主键ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"mobile": {
|
||||
"description": "手机号(脱敏)",
|
||||
"type": "string"
|
||||
},
|
||||
"nick_name": {
|
||||
"description": "昵称",
|
||||
"type": "string"
|
||||
},
|
||||
"user_name": {
|
||||
"description": "用户名",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.updateNickNameByIDRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "用户主键ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"nick_name": {
|
||||
"description": "昵称",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"user_handler.updateNickNameByIDResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "用户主键ID",
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
definitions:
|
||||
code.Failure:
|
||||
properties:
|
||||
code:
|
||||
description: 业务码
|
||||
type: integer
|
||||
message:
|
||||
description: 描述信息
|
||||
type: string
|
||||
type: object
|
||||
demo_handler.authResponse:
|
||||
properties:
|
||||
authorization:
|
||||
description: 签名
|
||||
type: string
|
||||
expire_time:
|
||||
description: 过期时间
|
||||
type: integer
|
||||
type: object
|
||||
user_handler.createRequest:
|
||||
properties:
|
||||
mobile:
|
||||
description: 手机号
|
||||
type: string
|
||||
nick_name:
|
||||
description: 昵称
|
||||
type: string
|
||||
user_name:
|
||||
description: 用户名
|
||||
type: string
|
||||
type: object
|
||||
user_handler.createResponse:
|
||||
properties:
|
||||
id:
|
||||
description: 主键ID
|
||||
type: integer
|
||||
type: object
|
||||
user_handler.deleteResponse:
|
||||
properties:
|
||||
id:
|
||||
description: 用户主键ID
|
||||
type: integer
|
||||
type: object
|
||||
user_handler.detailResponse:
|
||||
properties:
|
||||
id:
|
||||
description: 用户主键ID
|
||||
type: integer
|
||||
mobile:
|
||||
description: 手机号(脱敏)
|
||||
type: string
|
||||
nick_name:
|
||||
description: 昵称
|
||||
type: string
|
||||
user_name:
|
||||
description: 用户名
|
||||
type: string
|
||||
type: object
|
||||
user_handler.updateNickNameByIDRequest:
|
||||
properties:
|
||||
id:
|
||||
description: 用户主键ID
|
||||
type: integer
|
||||
nick_name:
|
||||
description: 昵称
|
||||
type: string
|
||||
type: object
|
||||
user_handler.updateNickNameByIDResponse:
|
||||
properties:
|
||||
id:
|
||||
description: 用户主键ID
|
||||
type: integer
|
||||
type: object
|
||||
host: 127.0.0.1:9999
|
||||
info:
|
||||
contact: {}
|
||||
license:
|
||||
name: MIT
|
||||
url: https://github.com/xinliangnote/go-gin-api/blob/master/LICENSE
|
||||
title: swagger 接口文档
|
||||
version: "2.0"
|
||||
paths:
|
||||
/auth/get:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 获取授权信息
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/demo_handler.authResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 获取授权信息
|
||||
tags:
|
||||
- Demo
|
||||
/demo/trace:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Trace 示例
|
||||
parameters:
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
properties:
|
||||
job:
|
||||
description: 工作
|
||||
type: string
|
||||
name:
|
||||
description: 用户名
|
||||
type: string
|
||||
type: object
|
||||
type: array
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: Trace 示例
|
||||
tags:
|
||||
- Demo
|
||||
/user/create:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 创建用户
|
||||
parameters:
|
||||
- description: 请求信息
|
||||
in: body
|
||||
name: Request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/user_handler.createRequest'
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/user_handler.createResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 创建用户
|
||||
tags:
|
||||
- User
|
||||
/user/delete/{id}:
|
||||
patch:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 删除用户
|
||||
parameters:
|
||||
- description: 用户ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/user_handler.deleteResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 删除用户
|
||||
tags:
|
||||
- User
|
||||
/user/info/{username}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 用户详情
|
||||
parameters:
|
||||
- description: 用户名
|
||||
in: path
|
||||
name: username
|
||||
required: true
|
||||
type: string
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/user_handler.detailResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 用户详情
|
||||
tags:
|
||||
- User
|
||||
/user/update:
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
parameters:
|
||||
- description: 请求信息
|
||||
in: body
|
||||
name: Request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/user_handler.updateNickNameByIDRequest'
|
||||
- description: 签名
|
||||
in: header
|
||||
name: Authorization
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/user_handler.updateNickNameByIDResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
summary: 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
tags:
|
||||
- User
|
||||
swagger: "2.0"
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,25 +1,41 @@
|
||||
module go-gin-api
|
||||
module github.com/xinliangnote/go-gin-api
|
||||
|
||||
go 1.12
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
||||
github.com/99designs/gqlgen v0.13.0
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
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/go-playground/locales v0.12.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/google/uuid v1.1.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
|
||||
github.com/leodido/go-urn v1.1.0 // indirect
|
||||
github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/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
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-openapi/spec v0.20.0 // indirect
|
||||
github.com/go-redis/redis/v7 v7.4.0
|
||||
github.com/golang/protobuf v1.4.3
|
||||
github.com/google/go-cmp v0.5.4 // indirect
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
github.com/onsi/ginkgo v1.14.2 // indirect
|
||||
github.com/onsi/gomega v1.10.4 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v0.9.3
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/spf13/cast v1.3.0
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/swaggo/gin-swagger v1.3.0
|
||||
github.com/swaggo/swag v1.7.0
|
||||
github.com/vektah/gqlparser/v2 v2.1.0
|
||||
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
|
||||
google.golang.org/grpc v1.23.1
|
||||
golang.org/x/tools v0.0.0-20201226215659-b1c90890d22a // indirect
|
||||
google.golang.org/grpc v1.27.0
|
||||
google.golang.org/protobuf v1.25.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gorm.io/driver/mysql v1.0.3
|
||||
gorm.io/gorm v1.20.9
|
||||
)
|
||||
|
||||
@@ -1,129 +1,625 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/99designs/gqlgen v0.13.0 h1:haLTcUp3Vwp80xMVEg5KRNwzfUrgFdRmtBY8fuB8scA=
|
||||
github.com/99designs/gqlgen v0.13.0/go.mod h1:NV130r6f4tpRWuAI+zsrSdooO/eWUv+Gyyoi3rEfXIk=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/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/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
|
||||
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=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
|
||||
github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0=
|
||||
github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs=
|
||||
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/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
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/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
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/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMNtWtNvI9mIV6isjEb9lBMNv+77IGM=
|
||||
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
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/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
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-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
|
||||
github.com/gin-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/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
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/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/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/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/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-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4=
|
||||
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
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-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/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/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
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/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
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/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
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-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
|
||||
github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
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/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=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
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/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/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
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/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=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
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/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
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/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
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=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/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/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/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/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
|
||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U=
|
||||
github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/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=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
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=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/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/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/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/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=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/xinliangnote/go-util v0.0.0-20191115235314-e7d1576d41db h1:yReVDmqk6oBUOcSRUofahYHJlIwr7wrJ8yx1Ymkz84E=
|
||||
github.com/xinliangnote/go-util v0.0.0-20191115235314-e7d1576d41db/go.mod h1:3ZornrplU9tYj9ar9jchik1XPQ10ZbSXkbgxXR5PVaU=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
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.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||
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/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
||||
github.com/vektah/gqlparser/v2 v2.1.0 h1:uiKJ+T5HMGGQM2kRKQ8Pxw8+Zq9qhhZhz/lieYvCMns=
|
||||
github.com/vektah/gqlparser/v2 v2.1.0/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
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=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
|
||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0 h1:8pl+sMODzuvGJkmj2W4kZihvVb5mKm8pB/X44PIQHv8=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
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-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/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/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=
|
||||
golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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/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=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0 h1:xQwXv67TxFo9nC1GJFyab5eq/5B590r6RlnL/G8Sz7w=
|
||||
golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/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=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201226215659-b1c90890d22a h1:pdfjQ7VswBeGam3EpuEJ4e8EAb7JgaubV570LO/SIQM=
|
||||
golang.org/x/tools v0.0.0-20201226215659-b1c90890d22a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a h1:Ob5/580gVHBJZgXnff1cZDbG+xLtMVE5mDRTe+nIsX4=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg=
|
||||
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
|
||||
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
gorm.io/gorm v1.20.9 h1:M3aIZKXAC1PtPVu9t3WGwkBTE1le5c2telz3I/qjRNg=
|
||||
gorm.io/gorm v1.20.9/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
|
||||
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=
|
||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Where are all the schema files located? globs are supported eg src/**/*.graphqls
|
||||
schema:
|
||||
- internal/graph/schemas/*.graphql
|
||||
|
||||
# Where should the generated server code go?
|
||||
exec:
|
||||
filename: internal/graph/generated/generated.go
|
||||
package: generated
|
||||
|
||||
# Uncomment to enable federation
|
||||
# federation:
|
||||
# filename: graph/generated/federation.go
|
||||
# package: generated
|
||||
|
||||
# Where should any generated models go?
|
||||
model:
|
||||
filename: internal/graph/model/generated.go
|
||||
package: model
|
||||
|
||||
# Where should the resolver implementations go?
|
||||
resolver:
|
||||
filename: internal/graph/resolvers/generated/generated.go
|
||||
type: Resolver
|
||||
package: resolvers
|
||||
|
||||
# Optional: turn on use `gqlgen:"fieldName"` tags in your models
|
||||
# struct_tag: json
|
||||
|
||||
# Optional: turn on to use []Thing instead of []*Thing
|
||||
# omit_slice_element_pointers: false
|
||||
|
||||
# Optional: set to speed up generation time by not performing a final validation pass.
|
||||
# skip_validation: true
|
||||
|
||||
# gqlgen will search for any type names in the schema in these go packages
|
||||
# if they match it will use them, otherwise it will generate them.
|
||||
autobind:
|
||||
- "github.com/xinliangnote/go-gin-api/internal/graph/model"
|
||||
|
||||
# This section declares type mapping between the GraphQL and go type systems
|
||||
#
|
||||
# The first line in each type will be used as defaults for resolver arguments and
|
||||
# modelgen, the others will be allowed when binding to fields. Configure them to
|
||||
# your liking
|
||||
models:
|
||||
ID:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.ID
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
||||
Int:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
||||
@@ -0,0 +1,5 @@
|
||||
## init
|
||||
|
||||
项目初始脚本。
|
||||
|
||||
- DB 相关 SQL;
|
||||
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE `user_demo` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`user_name` varchar(32) NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
`nick_name` varchar(100) NOT NULL DEFAULT '' COMMENT '昵称',
|
||||
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号',
|
||||
`is_deleted` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '是否删除 1:是 -1:否',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户Demo表';
|
||||
@@ -0,0 +1,13 @@
|
||||
## 错误码规则
|
||||
|
||||
- 错误码需在 `code` 包中进行定义。
|
||||
|
||||
#### 错误码为 5 位数
|
||||
|
||||
| 1 | 01 | 01 |
|
||||
| :------ | :------ | :------ |
|
||||
| 服务级错误码 | 模块级错误码 | 具体错误码 |
|
||||
|
||||
- 服务级错误码:1 位数进行表示,比如 1 为系统级错误;2 为普通错误,通常是由用户非法操作引起。
|
||||
- 模块级错误码:2 位数进行表示,比如 01 为用户模块;02 为订单模块。
|
||||
- 具体的错误码:2 位数进行表示,比如 01 为手机号不合法;02 为验证码输入错误。
|
||||
@@ -0,0 +1,41 @@
|
||||
package code
|
||||
|
||||
// 错误时返回结构
|
||||
type Failure struct {
|
||||
Code int `json:"code"` // 业务码
|
||||
Message string `json:"message"` // 描述信息
|
||||
}
|
||||
|
||||
const (
|
||||
// 服务级错误码
|
||||
ServerError = 10101
|
||||
TooManyRequests = 10102
|
||||
ParamBindError = 10103
|
||||
AuthorizationError = 10104
|
||||
CallHTTPError = 10105
|
||||
|
||||
// 模块级错误码 - 用户模块
|
||||
IllegalUserName = 20101
|
||||
UserCreateError = 20102
|
||||
UserUpdateError = 20103
|
||||
UserSearchError = 20104
|
||||
|
||||
// ...
|
||||
)
|
||||
|
||||
var codeText = map[int]string{
|
||||
ServerError: "Internal Server Error",
|
||||
TooManyRequests: "Too Many Requests",
|
||||
ParamBindError: "参数信息有误",
|
||||
AuthorizationError: "签名信息有误",
|
||||
CallHTTPError: "调用第三方 HTTP 接口失败",
|
||||
|
||||
IllegalUserName: "非法用户名",
|
||||
UserCreateError: "创建用户失败",
|
||||
UserUpdateError: "更新用户失败",
|
||||
UserSearchError: "查询用户失败",
|
||||
}
|
||||
|
||||
func Text(code int) string {
|
||||
return codeText[code]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
## controller
|
||||
|
||||
控制器层。
|
||||
|
||||
主要接收参数、验证参数、调用 `service` 层的业务逻辑处理,最后返回数据。
|
||||
|
||||
命名规范:
|
||||
|
||||
- 包名以 `_handler` 结尾。
|
||||
@@ -0,0 +1,47 @@
|
||||
package demo_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/token"
|
||||
)
|
||||
|
||||
type authResponse struct {
|
||||
Authorization string `json:"authorization"` // 签名
|
||||
ExpireTime int64 `json:"expire_time"` // 过期时间
|
||||
}
|
||||
|
||||
// 获取授权信息
|
||||
// @Summary 获取授权信息
|
||||
// @Description 获取授权信息
|
||||
// @Tags Demo
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} authResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Router /auth/get [post]
|
||||
func (h *handler) Auth() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
cfg := configs.Get().JWT
|
||||
tokenString, err := token.New(cfg.Secret).Sign(1, "xinliangnote", time.Hour*cfg.ExpireDuration)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res := new(authResponse)
|
||||
res.Authorization = tokenString
|
||||
res.ExpireTime = time.Now().Add(time.Hour * cfg.ExpireDuration).Unix()
|
||||
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package demo_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (h *handler) Get() core.HandlerFunc {
|
||||
type request struct {
|
||||
Name string `uri:"name"`
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Name string `json:"name"`
|
||||
Job string `json:"job"`
|
||||
}
|
||||
|
||||
return func(c core.Context) {
|
||||
req := new(request)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "Tom" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.IllegalUserName,
|
||||
code.Text(code.IllegalUserName)).WithErr(errors.New("req.Name != Tom")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
c.Payload(&response{
|
||||
Name: "Tom",
|
||||
Job: "Student",
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package demo_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (h *handler) Post() core.HandlerFunc {
|
||||
type request struct {
|
||||
Name string `form:"name"`
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Name string `json:"name"`
|
||||
Job string `json:"job"`
|
||||
}
|
||||
|
||||
return func(c core.Context) {
|
||||
req := new(request)
|
||||
if err := c.ShouldBindPostForm(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Name != "Jack" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.IllegalUserName,
|
||||
code.Text(code.IllegalUserName)).WithErr(errors.New("req.Name != Jack")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
c.Payload(&response{
|
||||
Name: "Jack",
|
||||
Job: "Teacher",
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package demo_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/third_party_request/go_gin_api_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/p"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type traceResponse []struct {
|
||||
Name string `json:"name"` //用户名
|
||||
Job string `json:"job"` //工作
|
||||
}
|
||||
|
||||
// Trace 示例
|
||||
// @Summary Trace 示例
|
||||
// @Description Trace 示例
|
||||
// @Tags Demo
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} traceResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Failure 401 {object} code.Failure
|
||||
// @Router /demo/trace [get]
|
||||
func (h *handler) Trace() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
// 三方请求信息
|
||||
res1, err := go_gin_api_repo.DemoGet("Tom",
|
||||
httpclient.WithTTL(time.Second*5),
|
||||
httpclient.WithTrace(c.Trace()),
|
||||
httpclient.WithLogger(c.Logger()),
|
||||
httpclient.WithHeader("Authorization", c.GetHeader("Authorization")),
|
||||
httpclient.WithOnFailedRetry(3, time.Second*1, go_gin_api_repo.DemoGetRetryVerify),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("get [demo/get] err", zap.Error(err))
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.CallHTTPError,
|
||||
code.Text(code.CallHTTPError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 调试信息
|
||||
p.Println("res1.Name", res1.Name, p.WithTrace(c.Trace()))
|
||||
|
||||
// 三方请求信息
|
||||
res2, err := go_gin_api_repo.DemoPost("Jack",
|
||||
httpclient.WithTTL(time.Second*5),
|
||||
httpclient.WithTrace(c.Trace()),
|
||||
httpclient.WithLogger(c.Logger()),
|
||||
httpclient.WithHeader("Authorization", c.GetHeader("Authorization")),
|
||||
httpclient.WithOnFailedRetry(3, time.Second*1, go_gin_api_repo.DemoPostRetryVerify),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("post [demo/post] err", zap.Error(err))
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.CallHTTPError,
|
||||
code.Text(code.CallHTTPError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 调试信息
|
||||
p.Println("res2.Name",
|
||||
res2.Name,
|
||||
p.WithTrace(c.Trace()),
|
||||
)
|
||||
|
||||
// 执行 SQL 信息
|
||||
h.userService.GetUserByUserName(c, "test_user")
|
||||
|
||||
// 执行 Redis 信息
|
||||
_ = h.cache.Set("name", "tom", time.Minute*10, cache.WithTrace(c.Trace()))
|
||||
val, _ := h.cache.Get("name", cache.WithTrace(c.Trace()))
|
||||
p.Println("redis-name", val, p.WithTrace(c.Trace()))
|
||||
|
||||
// 初始化客户端
|
||||
// client := hello.NewHelloClient(d.grpConn.Conn())
|
||||
// client.SayHello(grpc.ContextWithValueAndTimeout(c, time.Second*3), &hello.HelloRequest{Name: "Hello World"})
|
||||
|
||||
data := &traceResponse{
|
||||
{
|
||||
Name: res1.Name,
|
||||
Job: res1.Job,
|
||||
},
|
||||
{
|
||||
Name: res2.Name,
|
||||
Job: res2.Job,
|
||||
},
|
||||
}
|
||||
c.Payload(data)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package demo_handler
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/user_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/grpc"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Handler = (*handler)(nil)
|
||||
|
||||
type Handler interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
// 示例:支持 get 请求的方法
|
||||
Get() core.HandlerFunc
|
||||
// 示例:支持 post 请求的方法
|
||||
Post() core.HandlerFunc
|
||||
// 获取授权信息
|
||||
Auth() core.HandlerFunc
|
||||
// Trace 示例
|
||||
Trace() core.HandlerFunc
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
grpConn grpc.ClientConn
|
||||
userService user_service.UserService
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, db db.Repo, cache cache.Repo, grpConn grpc.ClientConn) Handler {
|
||||
return &handler{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
grpConn: grpConn,
|
||||
userService: user_service.NewUserService(db, cache),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) i() {}
|
||||
@@ -0,0 +1,77 @@
|
||||
package user_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/user_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type createRequest struct {
|
||||
UserName string `json:"user_name"` // 用户名
|
||||
NickName string `json:"nick_name"` // 昵称
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
}
|
||||
|
||||
type createResponse struct {
|
||||
Id int32 `json:"id"` // 主键ID
|
||||
}
|
||||
|
||||
// 创建用户
|
||||
// @Summary 创建用户
|
||||
// @Description 创建用户
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Request body createRequest true "请求信息"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} createResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Failure 401 {object} code.Failure
|
||||
// @Router /user/create [post]
|
||||
func (h *handler) Create() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(createRequest)
|
||||
res := new(createResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if req.UserName == "" {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.IllegalUserName,
|
||||
code.Text(code.IllegalUserName)).WithErr(errors.New("req.UserName = ''")),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
createUserData := new(user_service.CreateUserInfo)
|
||||
createUserData.Mobile = req.Mobile
|
||||
createUserData.NickName = req.NickName
|
||||
createUserData.UserName = req.UserName
|
||||
|
||||
id, err := h.userService.Create(c, createUserData)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.UserCreateError,
|
||||
code.Text(code.UserCreateError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = id
|
||||
c.Payload(res)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package user_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type deleteRequest struct {
|
||||
Id int32 `uri:"id"` // 用户ID
|
||||
}
|
||||
|
||||
type deleteResponse struct {
|
||||
Id int32 `json:"id"` // 用户主键ID
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
// @Summary 删除用户
|
||||
// @Description 删除用户
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "用户ID"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} deleteResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Failure 401 {object} code.Failure
|
||||
// @Router /user/delete/{id} [patch]
|
||||
func (h *handler) Delete() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(deleteRequest)
|
||||
res := new(deleteResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.userService.Delete(c, req.Id)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.UserUpdateError,
|
||||
code.Text(code.UserUpdateError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = req.Id
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package user_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/ddm"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type detailRequest struct {
|
||||
UserName string `uri:"username"` // 用户名
|
||||
}
|
||||
|
||||
type detailResponse struct {
|
||||
Id int32 `json:"id"` // 用户主键ID
|
||||
UserName string `json:"user_name"` // 用户名
|
||||
NickName string `json:"nick_name"` // 昵称
|
||||
Mobile ddm.Mobile `json:"mobile"` // 手机号(脱敏)
|
||||
}
|
||||
|
||||
// 用户详情
|
||||
// @Summary 用户详情
|
||||
// @Description 用户详情
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param username path string true "用户名"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} detailResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Failure 401 {object} code.Failure
|
||||
// @Router /user/info/{username} [get]
|
||||
func (h *handler) Detail() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(detailRequest)
|
||||
res := new(detailResponse)
|
||||
if err := c.ShouldBindURI(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.userService.GetUserByUserName(c, req.UserName)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.UserSearchError,
|
||||
code.Text(code.UserSearchError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = user.Id
|
||||
res.UserName = user.UserName
|
||||
res.NickName = user.NickName
|
||||
res.Mobile = ddm.Mobile(user.Mobile)
|
||||
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package user_handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
)
|
||||
|
||||
type updateNickNameByIDRequest struct {
|
||||
Id int32 `json:"id"` // 用户主键ID
|
||||
NickName string `json:"nick_name"` // 昵称
|
||||
}
|
||||
|
||||
type updateNickNameByIDResponse struct {
|
||||
Id int32 `json:"id"` // 用户主键ID
|
||||
}
|
||||
|
||||
// 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
// @Summary 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
// @Description 编辑用户 - 通过用户主键ID更新用户昵称
|
||||
// @Tags User
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param Request body updateNickNameByIDRequest true "请求信息"
|
||||
// @Param Authorization header string true "签名"
|
||||
// @Success 200 {object} updateNickNameByIDResponse
|
||||
// @Failure 400 {object} code.Failure
|
||||
// @Failure 401 {object} code.Failure
|
||||
// @Router /user/update [put]
|
||||
func (h *handler) UpdateNickNameByID() core.HandlerFunc {
|
||||
return func(c core.Context) {
|
||||
req := new(updateNickNameByIDRequest)
|
||||
res := new(updateNickNameByIDResponse)
|
||||
if err := c.ShouldBindJSON(req); err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.ParamBindError,
|
||||
code.Text(code.ParamBindError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.userService.UpdateNickNameByID(c, req.Id, req.NickName)
|
||||
if err != nil {
|
||||
c.AbortWithError(errno.NewError(
|
||||
http.StatusBadRequest,
|
||||
code.UserUpdateError,
|
||||
code.Text(code.UserUpdateError)).WithErr(err),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.Id = req.Id
|
||||
|
||||
c.Payload(res)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package user_handler
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/user_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Handler = (*handler)(nil)
|
||||
|
||||
type Handler interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
// Create 创建用户
|
||||
Create() core.HandlerFunc
|
||||
// UpdateNickNameByID 编辑用户 - 通过主键ID更新用户昵称
|
||||
UpdateNickNameByID() core.HandlerFunc
|
||||
// Delete 删除用户
|
||||
Delete() core.HandlerFunc
|
||||
// Detail 用户详情
|
||||
Detail() core.HandlerFunc
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
userService user_service.UserService
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
|
||||
return &handler{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
userService: user_service.NewUserService(db, cache),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handler) i() {}
|
||||
@@ -0,0 +1,32 @@
|
||||
## repository
|
||||
|
||||
#### 数据访问层。
|
||||
|
||||
- `./db_repo` 访问 DB 数据
|
||||
- `./cache_repo` 访问 Cache 数据
|
||||
- `./third_party_request` 访问外部 HTTP 接口数据。
|
||||
|
||||
#### SQL 建议:
|
||||
- 建议每张表需包含字段:主键(id)、标记删除(is_deteled)、创建时间(created_at)、更新时间(updated_at)
|
||||
|
||||
```mysql
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`is_deleted` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '是否删除 1:是 -1:否',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
```
|
||||
|
||||
#### 命名规范:
|
||||
|
||||
- 包名应以 `_repo` 结尾;
|
||||
- `./db_repo` 目录下的包名以 `数据表名`+ `_repo` 命名;
|
||||
|
||||
#### 脚本生成 MySQL CURD
|
||||
|
||||
1. 定义生成的表,设置 config 中 cmd.genTables,可以自定义设置多张表,为空表示生成库中所有的表,如果设置多个表可用','分割;
|
||||
1. 在根目录下执行脚本文件:`./scripts/gormgen.sh`;
|
||||
|
||||
以用户表(user_demo)为例:
|
||||
- 结构体文件:user_demo_repo/gen_model.go;
|
||||
- CURD 方法文件:user_demo_repo/gen_user_demo.go;
|
||||
- 表结构 MD 文件:user_demo_repo/gen_table.md;
|
||||
@@ -0,0 +1,14 @@
|
||||
package db_repo
|
||||
|
||||
// Predicate is a string that acts as a condition in the where clause
|
||||
type Predicate string
|
||||
|
||||
var (
|
||||
EqualPredicate = Predicate("=")
|
||||
NotEqualPredicate = Predicate("<>")
|
||||
GreaterThanPredicate = Predicate(">")
|
||||
GreaterThanOrEqualPredicate = Predicate(">=")
|
||||
SmallerThanPredicate = Predicate("<")
|
||||
SmallerThanOrEqualPredicate = Predicate("<=")
|
||||
LikePredicate = Predicate("LIKE")
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
package user_demo_repo
|
||||
|
||||
import "time"
|
||||
|
||||
// 用户Demo表
|
||||
//go:generate gormgen -structs UserDemo -input .
|
||||
type UserDemo struct {
|
||||
Id int32 // 主键
|
||||
UserName string // 用户名
|
||||
NickName string // 昵称
|
||||
Mobile string // 手机号
|
||||
IsDeleted int32 // 是否删除 1:是 -1:否
|
||||
CreatedAt time.Time `gorm:"time"` // 创建时间
|
||||
UpdatedAt time.Time `gorm:"time"` // 更新时间
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#### xin_ceshi.user_demo
|
||||
用户Demo表
|
||||
|
||||
| 序号 | 名称 | 描述 | 类型 | 键 | 为空 | 额外 | 默认值 |
|
||||
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
|
||||
| 1 | id | 主键 | int(11) unsigned | PRI | NO | auto_increment | |
|
||||
| 2 | user_name | 用户名 | varchar(32) | | NO | | |
|
||||
| 3 | nick_name | 昵称 | varchar(100) | | NO | | |
|
||||
| 4 | mobile | 手机号 | varchar(20) | | NO | | |
|
||||
| 5 | is_deleted | 是否删除 1:是 -1:否 | tinyint(1) | | NO | | -1 |
|
||||
| 6 | created_at | 创建时间 | timestamp | | NO | | CURRENT_TIMESTAMP |
|
||||
| 7 | updated_at | 更新时间 | timestamp | | NO | on update CURRENT_TIMESTAMP | CURRENT_TIMESTAMP |
|
||||
@@ -0,0 +1,257 @@
|
||||
///////////////////////////////////////////////////////////
|
||||
// THIS FILE IS AUTO GENERATED by gormgen, DON'T EDIT IT //
|
||||
// ANY CHANGES DONE HERE WILL BE LOST //
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
package user_demo_repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func NewModel() *UserDemo {
|
||||
return new(UserDemo)
|
||||
}
|
||||
|
||||
func NewQueryBuilder() *userDemoRepoQueryBuilder {
|
||||
return new(userDemoRepoQueryBuilder)
|
||||
}
|
||||
|
||||
func (t *UserDemo) Create(db *gorm.DB) (id int32, err error) {
|
||||
if err = db.Create(t).Error; err != nil {
|
||||
return 0, errors.Wrap(err, "create err")
|
||||
}
|
||||
return t.Id, nil
|
||||
}
|
||||
|
||||
func (t *UserDemo) Delete(db *gorm.DB) (err error) {
|
||||
if err = db.Delete(t).Error; err != nil {
|
||||
return errors.Wrap(err, "delete err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *UserDemo) Updates(db *gorm.DB, m map[string]interface{}) (err error) {
|
||||
if err = db.Model(&UserDemo{}).Where("id = ?", t.Id).Updates(m).Error; err != nil {
|
||||
return errors.Wrap(err, "updates err")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type userDemoRepoQueryBuilder struct {
|
||||
order []string
|
||||
where []struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}
|
||||
limit int
|
||||
offset int
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) buildQuery(db *gorm.DB) *gorm.DB {
|
||||
ret := db
|
||||
for _, where := range qb.where {
|
||||
ret = ret.Where(where.prefix, where.value)
|
||||
}
|
||||
for _, order := range qb.order {
|
||||
ret = ret.Order(order)
|
||||
}
|
||||
ret = ret.Limit(qb.limit).Offset(qb.offset)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) Count(db *gorm.DB) (int64, error) {
|
||||
var c int64
|
||||
res := qb.buildQuery(db).Model(&UserDemo{}).Count(&c)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
c = 0
|
||||
}
|
||||
return c, res.Error
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) First(db *gorm.DB) (*UserDemo, error) {
|
||||
ret := &UserDemo{}
|
||||
res := qb.buildQuery(db).First(ret)
|
||||
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
|
||||
ret = nil
|
||||
}
|
||||
return ret, res.Error
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) QueryOne(db *gorm.DB) (*UserDemo, error) {
|
||||
qb.limit = 1
|
||||
ret, err := qb.QueryAll(db)
|
||||
if len(ret) > 0 {
|
||||
return ret[0], err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) QueryAll(db *gorm.DB) ([]*UserDemo, error) {
|
||||
var ret []*UserDemo
|
||||
err := qb.buildQuery(db).Find(&ret).Error
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) Limit(limit int) *userDemoRepoQueryBuilder {
|
||||
qb.limit = limit
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) Offset(offset int) *userDemoRepoQueryBuilder {
|
||||
qb.offset = offset
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereId(p db_repo.Predicate, value int32) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "id", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderById(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "id "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereUserName(p db_repo.Predicate, value string) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "user_name", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByUserName(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "user_name "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereNickName(p db_repo.Predicate, value string) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "nick_name", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByNickName(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "nick_name "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereMobile(p db_repo.Predicate, value string) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "mobile", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByMobile(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "mobile "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereIsDeleted(p db_repo.Predicate, value int32) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "is_deleted", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByIsDeleted(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "is_deleted "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereCreatedAt(p db_repo.Predicate, value time.Time) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "created_at", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByCreatedAt(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "created_at "+order)
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) WhereUpdatedAt(p db_repo.Predicate, value time.Time) *userDemoRepoQueryBuilder {
|
||||
qb.where = append(qb.where, struct {
|
||||
prefix string
|
||||
value interface{}
|
||||
}{
|
||||
fmt.Sprintf("%v %v ?", "updated_at", p),
|
||||
value,
|
||||
})
|
||||
return qb
|
||||
}
|
||||
|
||||
func (qb *userDemoRepoQueryBuilder) OrderByUpdatedAt(asc bool) *userDemoRepoQueryBuilder {
|
||||
order := "DESC"
|
||||
if asc {
|
||||
order = "ASC"
|
||||
}
|
||||
|
||||
qb.order = append(qb.order, "updated_at "+order)
|
||||
return qb
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: hello.proto
|
||||
|
||||
package hello
|
||||
|
||||
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
|
||||
|
||||
// HelloRequest 请求结构
|
||||
type HelloRequest 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 *HelloRequest) Reset() { *m = HelloRequest{} }
|
||||
func (m *HelloRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*HelloRequest) ProtoMessage() {}
|
||||
func (*HelloRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_61ef911816e0a8ce, []int{0}
|
||||
}
|
||||
|
||||
func (m *HelloRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HelloRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *HelloRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HelloRequest.Merge(m, src)
|
||||
}
|
||||
func (m *HelloRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_HelloRequest.Size(m)
|
||||
}
|
||||
func (m *HelloRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HelloRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HelloRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *HelloRequest) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// HelloResponse 响应结构
|
||||
type HelloResponse 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 *HelloResponse) Reset() { *m = HelloResponse{} }
|
||||
func (m *HelloResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*HelloResponse) ProtoMessage() {}
|
||||
func (*HelloResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_61ef911816e0a8ce, []int{1}
|
||||
}
|
||||
|
||||
func (m *HelloResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HelloResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *HelloResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_HelloResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *HelloResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HelloResponse.Merge(m, src)
|
||||
}
|
||||
func (m *HelloResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_HelloResponse.Size(m)
|
||||
}
|
||||
func (m *HelloResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HelloResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HelloResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *HelloResponse) GetMessage() string {
|
||||
if m != nil {
|
||||
return m.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*HelloRequest)(nil), "hello.HelloRequest")
|
||||
proto.RegisterType((*HelloResponse)(nil), "hello.HelloResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("hello.proto", fileDescriptor_61ef911816e0a8ce) }
|
||||
|
||||
var fileDescriptor_61ef911816e0a8ce = []byte{
|
||||
// 154 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xce, 0x48, 0xcd, 0xc9,
|
||||
0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x05, 0x73, 0x94, 0x94, 0xb8, 0x78, 0x3c,
|
||||
0x40, 0x8c, 0xa0, 0xd4, 0xc2, 0xd2, 0xd4, 0xe2, 0x12, 0x21, 0x21, 0x2e, 0x96, 0xbc, 0xc4, 0xdc,
|
||||
0x54, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xce, 0x20, 0x30, 0x5b, 0x49, 0x93, 0x8b, 0x17, 0xaa, 0xa6,
|
||||
0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0x48, 0x82, 0x8b, 0x3d, 0x37, 0xb5, 0xb8, 0x38, 0x31, 0x1d,
|
||||
0xa6, 0x0e, 0xc6, 0x35, 0x6a, 0x60, 0xe4, 0x62, 0x05, 0xab, 0x15, 0x32, 0xe7, 0xe2, 0x08, 0x4e,
|
||||
0xac, 0x84, 0xb0, 0x85, 0xf5, 0x20, 0x36, 0x23, 0xdb, 0x24, 0x25, 0x82, 0x2a, 0x08, 0x31, 0x5a,
|
||||
0x89, 0x41, 0xc8, 0x8e, 0x8b, 0xd7, 0x27, 0xbf, 0xa4, 0xd8, 0x3f, 0x2d, 0x28, 0xb5, 0x20, 0x27,
|
||||
0x33, 0xb5, 0x98, 0x24, 0xdd, 0x06, 0x8c, 0x49, 0x6c, 0x60, 0xff, 0x19, 0x03, 0x02, 0x00, 0x00,
|
||||
0xff, 0xff, 0x87, 0x17, 0x0f, 0x68, 0xee, 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
|
||||
|
||||
// HelloClient is the client API for Hello service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type HelloClient interface {
|
||||
// 定义 SayHello 方法
|
||||
SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error)
|
||||
// 定义 LotsOfReplies 方法
|
||||
LotsOfReplies(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (Hello_LotsOfRepliesClient, error)
|
||||
}
|
||||
|
||||
type helloClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewHelloClient(cc *grpc.ClientConn) HelloClient {
|
||||
return &helloClient{cc}
|
||||
}
|
||||
|
||||
func (c *helloClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloResponse, error) {
|
||||
out := new(HelloResponse)
|
||||
err := c.cc.Invoke(ctx, "/hello.Hello/SayHello", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *helloClient) LotsOfReplies(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (Hello_LotsOfRepliesClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_Hello_serviceDesc.Streams[0], "/hello.Hello/LotsOfReplies", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &helloLotsOfRepliesClient{stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type Hello_LotsOfRepliesClient interface {
|
||||
Recv() (*HelloResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type helloLotsOfRepliesClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *helloLotsOfRepliesClient) Recv() (*HelloResponse, error) {
|
||||
m := new(HelloResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// HelloServer is the server API for Hello service.
|
||||
type HelloServer interface {
|
||||
// 定义 SayHello 方法
|
||||
SayHello(context.Context, *HelloRequest) (*HelloResponse, error)
|
||||
// 定义 LotsOfReplies 方法
|
||||
LotsOfReplies(*HelloRequest, Hello_LotsOfRepliesServer) error
|
||||
}
|
||||
|
||||
// UnimplementedHelloServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedHelloServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedHelloServer) SayHello(ctx context.Context, req *HelloRequest) (*HelloResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
|
||||
}
|
||||
func (*UnimplementedHelloServer) LotsOfReplies(req *HelloRequest, srv Hello_LotsOfRepliesServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method LotsOfReplies not implemented")
|
||||
}
|
||||
|
||||
func RegisterHelloServer(s *grpc.Server, srv HelloServer) {
|
||||
s.RegisterService(&_Hello_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Hello_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HelloRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(HelloServer).SayHello(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/hello.Hello/SayHello",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(HelloServer).SayHello(ctx, req.(*HelloRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Hello_LotsOfReplies_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(HelloRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(HelloServer).LotsOfReplies(m, &helloLotsOfRepliesServer{stream})
|
||||
}
|
||||
|
||||
type Hello_LotsOfRepliesServer interface {
|
||||
Send(*HelloResponse) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type helloLotsOfRepliesServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *helloLotsOfRepliesServer) Send(m *HelloResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
var _Hello_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "hello.Hello",
|
||||
HandlerType: (*HelloServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "SayHello",
|
||||
Handler: _Hello_SayHello_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "LotsOfReplies",
|
||||
Handler: _Hello_LotsOfReplies_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "hello.proto",
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
syntax = "proto3"; // 指定 proto 版本
|
||||
|
||||
package hello; // 指定包名
|
||||
|
||||
// 定义 Hello 服务
|
||||
service Hello {
|
||||
|
||||
// 定义 SayHello 方法
|
||||
rpc SayHello(HelloRequest) returns (HelloResponse) {}
|
||||
|
||||
// 定义 LotsOfReplies 方法
|
||||
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){}
|
||||
}
|
||||
|
||||
// HelloRequest 请求结构
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// HelloResponse 响应结构
|
||||
message HelloResponse {
|
||||
string message = 1;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package third_party_request
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/mail"
|
||||
)
|
||||
|
||||
// 实现 AlarmObject 告警
|
||||
var _ httpclient.AlarmObject = (*AlarmEmail)(nil)
|
||||
|
||||
type AlarmEmail struct{}
|
||||
|
||||
func (a *AlarmEmail) Send(subject, body string) error {
|
||||
options := &mail.Options{
|
||||
MailHost: "smtp.163.com",
|
||||
MailPort: 465,
|
||||
MailUser: "xx@163.com",
|
||||
MailPass: "",
|
||||
MailTo: "",
|
||||
Subject: subject,
|
||||
Body: body,
|
||||
}
|
||||
return mail.Send(options)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package go_gin_api_repo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type demoGetResponse struct {
|
||||
Name string `json:"name"`
|
||||
Job string `json:"job"`
|
||||
}
|
||||
|
||||
type demoPostResponse struct {
|
||||
Name string `json:"name"`
|
||||
Job string `json:"job"`
|
||||
}
|
||||
|
||||
func DemoGet(name string, opts ...httpclient.Option) (res *demoGetResponse, err error) {
|
||||
api := "http://127.0.0.1:9999/demo/get/" + name
|
||||
body, err := httpclient.Get(api, nil, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res = new(demoGetResponse)
|
||||
err = json.Unmarshal(body, res)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "DemoGet json unmarshal error")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func DemoGetRetryVerify(body []byte) (shouldRetry bool) {
|
||||
if len(body) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func DemoPost(name string, opts ...httpclient.Option) (res *demoPostResponse, err error) {
|
||||
api := "http://127.0.0.1:9999/demo/post"
|
||||
params := url.Values{}
|
||||
params.Set("name", name)
|
||||
body, err := httpclient.PostForm(api, params, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res = new(demoPostResponse)
|
||||
err = json.Unmarshal(body, res)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "DemoPost json unmarshal error")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func DemoPostRetryVerify(body []byte) (shouldRetry bool) {
|
||||
if len(body) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package go_gin_api_repo
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func MockDemoGet() (body []byte) {
|
||||
res := new(demoGetResponse)
|
||||
res.Name = "AA"
|
||||
res.Job = "AA_JOB"
|
||||
|
||||
body, _ = json.Marshal(res)
|
||||
return body
|
||||
}
|
||||
|
||||
func MockDemoPost() (body []byte) {
|
||||
res := new(demoPostResponse)
|
||||
res.Name = "BB"
|
||||
res.Job = "BB_JOB"
|
||||
|
||||
body, _ = json.Marshal(res)
|
||||
return body
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package go_gin_api_repo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/third_party_request"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/httpclient"
|
||||
)
|
||||
|
||||
var authorization = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySUQiOjEsIlVzZXJOYW1lIjoieGlubGlhbmdub3RlIiwiZXhwIjoxNjEzODI3MTEzLCJpYXQiOjE2MTM3NDA3MTMsIm5iZiI6MTYxMzc0MDcxM30.SnooP1ikO33ryGPdohsmOKqISa-bWzMkMvUNb5f2zc0"
|
||||
|
||||
func TestDemoGet(t *testing.T) {
|
||||
res, err := DemoGet("Tom",
|
||||
httpclient.WithTTL(time.Second*5),
|
||||
//httpclient.WithTrace(ctx.Trace()),
|
||||
//httpclient.WithLogger(ctx.Logger()),
|
||||
httpclient.WithHeader("Authorization", authorization),
|
||||
httpclient.WithOnFailedRetry(3, time.Second*1, retryVerify),
|
||||
httpclient.WithOnFailedAlarm("接口告警", new(third_party_request.AlarmEmail), alarmVerify),
|
||||
//httpclient.WithMock(MockDemoGet),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Log("get [demo/get] err", err)
|
||||
}
|
||||
|
||||
t.Log(res)
|
||||
}
|
||||
|
||||
func TestDemoPost(t *testing.T) {
|
||||
res, err := DemoPost("Jack",
|
||||
httpclient.WithTTL(time.Second*5),
|
||||
//httpclient.WithTrace(ctx.Trace()),
|
||||
//httpclient.WithLogger(ctx.Logger()),
|
||||
httpclient.WithHeader("Authorization", authorization),
|
||||
httpclient.WithMock(MockDemoPost),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
t.Log("post [demo/post] err", err)
|
||||
}
|
||||
|
||||
t.Log(res)
|
||||
}
|
||||
|
||||
// 设置重试规则
|
||||
func retryVerify(body []byte) (shouldRetry bool) {
|
||||
if len(body) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
}
|
||||
resp := new(Response)
|
||||
if err := json.Unmarshal(body, resp); err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return resp.Code != 1
|
||||
}
|
||||
|
||||
// 设置告警规则
|
||||
func alarmVerify(body []byte) (shouldAlarm bool) {
|
||||
if len(body) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Code int `json:"code"`
|
||||
}
|
||||
resp := new(Response)
|
||||
if err := json.Unmarshal(body, resp); err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return resp.Code != 1
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/code"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/token"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func AuthHandler(ctx core.Context) (userId int64, userName string, err errno.Error) {
|
||||
auth := ctx.GetHeader("Authorization")
|
||||
if auth == "" {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("Header 中缺少 Authorization 参数"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
cfg := configs.Get().JWT
|
||||
claims, errParse := token.New(cfg.Secret).Parse(auth)
|
||||
if errParse != nil {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errParse)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
userId = claims.UserID
|
||||
if userId <= 0 {
|
||||
err = errno.NewError(
|
||||
http.StatusUnauthorized,
|
||||
code.AuthorizationError,
|
||||
code.Text(code.AuthorizationError)).WithErr(errors.New("claims.UserID <= 0 "))
|
||||
|
||||
return
|
||||
}
|
||||
userName = claims.UserName
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/demo_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/controller/user_handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/router/middleware/auth"
|
||||
"github.com/xinliangnote/go-gin-api/internal/graph/handler"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/grpc"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/metrics"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/notify"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func NewHTTPMux(logger *zap.Logger, db db.Repo, cache cache.Repo, grpConn grpc.ClientConn) (core.Mux, error) {
|
||||
|
||||
if logger == nil {
|
||||
return nil, errors.New("logger required")
|
||||
}
|
||||
|
||||
mux, err := core.New(logger,
|
||||
core.WithEnableCors(),
|
||||
core.WithEnableRate(),
|
||||
core.WithPanicNotify(notify.OnPanicNotify),
|
||||
core.WithRecordMetrics(metrics.RecordMetrics),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
gqlHandler := handler.New(logger, db, cache)
|
||||
|
||||
gql := mux.Group("/graphql")
|
||||
{
|
||||
gql.GET("", gqlHandler.Playground())
|
||||
gql.POST("/query", gqlHandler.Query())
|
||||
}
|
||||
|
||||
demoHandler := demo_handler.New(logger, db, cache, grpConn)
|
||||
userHandler := user_handler.New(logger, db, cache)
|
||||
|
||||
// user_demo CURD
|
||||
user := mux.Group("/user", core.WrapAuthHandler(auth.AuthHandler))
|
||||
{
|
||||
user.POST("/create", userHandler.Create())
|
||||
user.PUT("/update", userHandler.UpdateNickNameByID())
|
||||
user.PATCH("/delete/:id", userHandler.Delete())
|
||||
user.GET("/info/:username", core.AliasForRecordMetrics("/user/info"), userHandler.Detail())
|
||||
}
|
||||
|
||||
// auth
|
||||
a := mux.Group("/auth")
|
||||
{
|
||||
a.POST("/get", demoHandler.Auth())
|
||||
}
|
||||
|
||||
// demo
|
||||
d := mux.Group("/demo", core.WrapAuthHandler(auth.AuthHandler)) //使用 auth 验证
|
||||
{
|
||||
// 为了演示 Trace ,增加了一些看起来无意义的调试信息和 SQL 信息。
|
||||
d.GET("/trace", demoHandler.Trace())
|
||||
|
||||
// 模拟数据
|
||||
d.GET("get/:name", core.AliasForRecordMetrics("/demo/get"), demoHandler.Get())
|
||||
d.POST("post", demoHandler.Post())
|
||||
}
|
||||
|
||||
return mux, nil
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
## service
|
||||
|
||||
业务逻辑层。
|
||||
|
||||
处于 `controller` 层和 `repository` 层之间,依赖接口开发。
|
||||
|
||||
命令规范:
|
||||
|
||||
- 包名以 `_service` 结尾。
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package user_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
type CreateUserInfo struct {
|
||||
UserName string `json:"user_name"` // 用户名
|
||||
NickName string `json:"nick_name"` // 昵称
|
||||
Mobile string `json:"mobile"` // 手机号
|
||||
}
|
||||
|
||||
func (u *userSer) Create(ctx core.Context, user *CreateUserInfo) (id int32, err error) {
|
||||
model := user_demo_repo.NewModel()
|
||||
model.UserName = user.UserName
|
||||
model.NickName = user.NickName
|
||||
model.Mobile = user.Mobile
|
||||
|
||||
id, err = model.Create(u.db.GetDbW().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package user_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func (u *userSer) Delete(ctx core.Context, id int32) (err error) {
|
||||
model := user_demo_repo.NewModel()
|
||||
model.Id = id
|
||||
err = model.Delete(u.db.GetDbW().WithContext(ctx.RequestContext()))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package user_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func (u *userSer) GetUserByUserName(ctx core.Context, username string) (user *user_demo_repo.UserDemo, err error) {
|
||||
user, err = user_demo_repo.NewQueryBuilder().
|
||||
WhereUserName(db_repo.EqualPredicate, username).
|
||||
QueryOne(u.db.GetDbR().WithContext(ctx.RequestContext()))
|
||||
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
user = user_demo_repo.NewModel()
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package user_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
)
|
||||
|
||||
func (u *userSer) UpdateNickNameByID(ctx core.Context, id int32, nickname string) (err error) {
|
||||
model := user_demo_repo.NewModel()
|
||||
model.Id = id
|
||||
|
||||
data := map[string]interface{}{
|
||||
"nick_name": nickname,
|
||||
}
|
||||
|
||||
err = model.Updates(u.db.GetDbW().WithContext(ctx.RequestContext()), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package user_service
|
||||
|
||||
import (
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/user_demo_repo"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
)
|
||||
|
||||
var _ UserService = (*userSer)(nil)
|
||||
|
||||
type UserService interface {
|
||||
// i 为了避免被其他包实现
|
||||
i()
|
||||
|
||||
Create(ctx core.Context, user *CreateUserInfo) (id int32, err error)
|
||||
UpdateNickNameByID(ctx core.Context, id int32, username string) (err error)
|
||||
GetUserByUserName(ctx core.Context, username string) (user *user_demo_repo.UserDemo, err error)
|
||||
Delete(ctx core.Context, id int32) (err error)
|
||||
}
|
||||
|
||||
type userSer struct {
|
||||
db db.Repo
|
||||
cache cache.Repo
|
||||
}
|
||||
|
||||
func NewUserService(db db.Repo, cache cache.Repo) UserService {
|
||||
return &userSer{
|
||||
db: db,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *userSer) i() {}
|
||||
@@ -0,0 +1,24 @@
|
||||
## example
|
||||
|
||||
```cassandraql
|
||||
1.
|
||||
query {
|
||||
bySex(sex: "男") {
|
||||
id
|
||||
name
|
||||
sex
|
||||
mobile
|
||||
}
|
||||
}
|
||||
|
||||
2.
|
||||
mutation {
|
||||
updateUserMobile(data: {id: "1", mobile: "13299999999"}) {
|
||||
id
|
||||
name
|
||||
sex
|
||||
mobile
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/graph/generated"
|
||||
"github.com/xinliangnote/go-gin-api/internal/graph/resolvers"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/handler/extension"
|
||||
"github.com/99designs/gqlgen/graphql/handler/lru"
|
||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ Gql = (*gql)(nil)
|
||||
|
||||
type Gql interface {
|
||||
i()
|
||||
Playground() core.HandlerFunc
|
||||
Query() core.HandlerFunc
|
||||
}
|
||||
|
||||
type gql struct {
|
||||
logger *zap.Logger
|
||||
db db.Repo
|
||||
cache cache.Repo
|
||||
}
|
||||
|
||||
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Gql {
|
||||
return &gql{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *gql) i() {}
|
||||
|
||||
func (g *gql) Query() core.HandlerFunc {
|
||||
|
||||
// 定义扩展字段
|
||||
extensions := make(map[string]interface{})
|
||||
|
||||
h := handler.New(generated.NewExecutableSchema(
|
||||
resolvers.NewRootResolvers(g.logger, g.db, g.cache)),
|
||||
)
|
||||
|
||||
h.AddTransport(transport.Websocket{
|
||||
KeepAlivePingInterval: 10 * time.Second,
|
||||
})
|
||||
|
||||
// 设置 transport
|
||||
h.AddTransport(transport.Options{})
|
||||
h.AddTransport(transport.GET{})
|
||||
h.AddTransport(transport.POST{})
|
||||
|
||||
h.SetQueryCache(lru.New(1000))
|
||||
|
||||
// 启用侧边栏文档
|
||||
h.Use(extension.Introspection{})
|
||||
|
||||
h.Use(extension.AutomaticPersistedQuery{
|
||||
Cache: lru.New(100),
|
||||
})
|
||||
|
||||
return func(c core.Context) {
|
||||
var responses interface{}
|
||||
|
||||
defer func() {
|
||||
// 设置 core log
|
||||
c.GraphPayload(responses)
|
||||
}()
|
||||
|
||||
// 设置 core trace_id
|
||||
extensions["trace_id"] = c.Trace().ID()
|
||||
|
||||
h.AroundResponses(func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||
resp := next(ctx)
|
||||
resp.Extensions = extensions
|
||||
responses = resp
|
||||
return resp
|
||||
})
|
||||
|
||||
// 设置 core context
|
||||
coreContext := context.WithValue(c.Request().Context(), resolvers.CoreContextKey, c)
|
||||
h.ServeHTTP(c.ResponseWriter(), c.Request().WithContext(coreContext))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *gql) Playground() core.HandlerFunc {
|
||||
h := playground.Handler("GraphQL", "/graphql/query")
|
||||
return func(c core.Context) {
|
||||
h.ServeHTTP(c.ResponseWriter(), c.Request())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
|
||||
|
||||
package model
|
||||
|
||||
type User struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Sex string `json:"sex"`
|
||||
Mobile string `json:"mobile"`
|
||||
}
|
||||
|
||||
type UpdateUserMobileInput struct {
|
||||
ID string `json:"id"`
|
||||
Mobile string `json:"mobile"`
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package resolvers
|
||||
|
||||
// THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/graph/generated"
|
||||
"github.com/xinliangnote/go-gin-api/internal/graph/model"
|
||||
)
|
||||
|
||||
type Resolver struct{}
|
||||
|
||||
func (r *mutationResolver) UpdateUserMobile(ctx context.Context, data model.UpdateUserMobileInput) (*model.User, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (r *queryResolver) BySex(ctx context.Context, sex string) ([]*model.User, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
// Mutation returns generated.MutationResolver implementation.
|
||||
func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} }
|
||||
|
||||
// Query returns generated.QueryResolver implementation.
|
||||
func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} }
|
||||
|
||||
type mutationResolver struct{ *Resolver }
|
||||
type queryResolver struct{ *Resolver }
|
||||
@@ -0,0 +1,51 @@
|
||||
package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/api/service/user_service"
|
||||
"github.com/xinliangnote/go-gin-api/internal/graph/generated"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
|
||||
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type coreCtxKeyType struct{ name string }
|
||||
|
||||
var CoreContextKey = coreCtxKeyType{"_core_context"}
|
||||
|
||||
type mutationResolver struct{ *Resolver }
|
||||
|
||||
type queryResolver struct{ *Resolver }
|
||||
|
||||
type Resolver struct {
|
||||
logger *zap.Logger
|
||||
cache cache.Repo
|
||||
userService user_service.UserService
|
||||
}
|
||||
|
||||
func NewRootResolvers(logger *zap.Logger, db db.Repo, cache cache.Repo) generated.Config {
|
||||
c := generated.Config{
|
||||
Resolvers: &Resolver{
|
||||
logger: logger,
|
||||
cache: cache,
|
||||
userService: user_service.NewUserService(db, cache),
|
||||
},
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (r *Resolver) Mutation() generated.MutationResolver {
|
||||
return &mutationResolver{r}
|
||||
}
|
||||
|
||||
func (r *Resolver) Query() generated.QueryResolver {
|
||||
return &queryResolver{r}
|
||||
}
|
||||
|
||||
// getCoreContextByCtx 获取 core context
|
||||
func (r *Resolver) getCoreContextByCtx(ctx context.Context) core.Context {
|
||||
return ctx.Value(CoreContextKey).(core.Context)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package resolvers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/internal/graph/model"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (r *queryResolver) BySex(ctx context.Context, sex string) ([]*model.User, error) {
|
||||
if sex == "" {
|
||||
return nil, errors.New("sex required")
|
||||
}
|
||||
|
||||
//模拟数据
|
||||
var users []*model.User
|
||||
users = append(users, &model.User{ID: "1", Name: "Tom", Sex: sex, Mobile: "13266666666"})
|
||||
users = append(users, &model.User{ID: "1", Name: "Jack", Sex: sex, Mobile: "13288888888"})
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) UpdateUserMobile(ctx context.Context, data model.UpdateUserMobileInput) (*model.User, error) {
|
||||
if data.ID == "" {
|
||||
return nil, errors.New("id required")
|
||||
}
|
||||
|
||||
if data.Mobile == "" {
|
||||
return nil, errors.New("mobile required")
|
||||
}
|
||||
|
||||
//模拟数据
|
||||
user := new(model.User)
|
||||
user.ID = data.ID
|
||||
user.Mobile = data.Mobile
|
||||
user.Sex = "男"
|
||||
user.Name = "Jack"
|
||||
|
||||
//操作数据库
|
||||
//userData, err := r.userService.GetUserByUserName(r.getCoreContextByCtx(ctx), "test_user")
|
||||
//if err != nil {
|
||||
// return nil, err
|
||||
//}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
type User {
|
||||
id: String!
|
||||
name: String!
|
||||
sex: String!
|
||||
mobile: String!
|
||||
}
|
||||
|
||||
# 查询 集合
|
||||
type Query {
|
||||
bySex(sex: String!): [User!]
|
||||
}
|
||||
|
||||
# 输入类型: 一般用户更改资源中的输入是列表对象,完成复杂任务
|
||||
input updateUserMobileInput {
|
||||
id:ID!
|
||||
mobile: String!
|
||||
}
|
||||
|
||||
# 更改或者创建 集合
|
||||
type Mutation {
|
||||
updateUserMobile(data: updateUserMobileInput!): User
|
||||
}
|
||||
Vendored
+194
@@ -0,0 +1,194 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/configs"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/trace"
|
||||
|
||||
"github.com/go-redis/redis/v7"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Option func(*option)
|
||||
|
||||
type Trace = trace.T
|
||||
|
||||
type option struct {
|
||||
Trace *trace.Trace
|
||||
Redis *trace.Redis
|
||||
}
|
||||
|
||||
func newOption() *option {
|
||||
return &option{}
|
||||
}
|
||||
|
||||
var _ Repo = (*cacheRepo)(nil)
|
||||
|
||||
type Repo interface {
|
||||
i()
|
||||
Set(key, value string, ttl time.Duration, options ...Option) error
|
||||
Get(key string, options ...Option) (string, error)
|
||||
TTL(key string) (time.Duration, error)
|
||||
Expire(key string, ttl time.Duration) bool
|
||||
ExpireAt(key string, ttl time.Time) bool
|
||||
Del(keys ...string) bool
|
||||
Incr(key string, options ...Option) int64
|
||||
Close() error
|
||||
}
|
||||
|
||||
type cacheRepo struct {
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
func New() (Repo, error) {
|
||||
client, err := redisConnect()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cacheRepo{
|
||||
client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *cacheRepo) i() {}
|
||||
|
||||
func redisConnect() (*redis.Client, error) {
|
||||
cfg := configs.Get().Redis
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: cfg.Addr,
|
||||
Password: cfg.Pass,
|
||||
DB: cfg.Db,
|
||||
MaxRetries: cfg.MaxRetries,
|
||||
PoolSize: cfg.PoolSize,
|
||||
MinIdleConns: cfg.MinIdleConns,
|
||||
})
|
||||
|
||||
if err := client.Ping().Err(); err != nil {
|
||||
return nil, errors.Wrap(err, "ping redis err")
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Set set some <key,value> into redis
|
||||
func (c *cacheRepo) Set(key, value string, ttl time.Duration, options ...Option) error {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "set"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.Value = value
|
||||
opt.Redis.TTL = ttl.Minutes()
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
if err := c.client.Set(key, value, ttl).Err(); err != nil {
|
||||
return errors.Wrapf(err, "redis set key: %s err", key)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get get some key from redis
|
||||
func (c *cacheRepo) Get(key string, options ...Option) (string, error) {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "get"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
|
||||
value, err := c.client.Get(key).Result()
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "redis get key: %s err", key)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// TTL get some key from redis
|
||||
func (c *cacheRepo) TTL(key string) (time.Duration, error) {
|
||||
ttl, err := c.client.TTL(key).Result()
|
||||
if err != nil {
|
||||
return -1, errors.Wrapf(err, "redis get key: %s err", key)
|
||||
}
|
||||
|
||||
return ttl, nil
|
||||
}
|
||||
|
||||
// Expire expire some key
|
||||
func (c *cacheRepo) Expire(key string, ttl time.Duration) bool {
|
||||
ok, _ := c.client.Expire(key, ttl).Result()
|
||||
return ok
|
||||
}
|
||||
|
||||
// ExpireAt expire some key at some time
|
||||
func (c *cacheRepo) ExpireAt(key string, ttl time.Time) bool {
|
||||
ok, _ := c.client.ExpireAt(key, ttl).Result()
|
||||
return ok
|
||||
}
|
||||
|
||||
// Del del some key from redis
|
||||
func (c *cacheRepo) Del(keys ...string) bool {
|
||||
if len(keys) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
value, _ := c.client.Del(keys...).Result()
|
||||
return value > 0
|
||||
}
|
||||
|
||||
func (c *cacheRepo) Incr(key string, options ...Option) int64 {
|
||||
ts := time.Now()
|
||||
opt := newOption()
|
||||
defer func() {
|
||||
if opt.Trace != nil {
|
||||
opt.Redis.Timestamp = time_parse.CSTLayoutString()
|
||||
opt.Redis.Handle = "incr"
|
||||
opt.Redis.Key = key
|
||||
opt.Redis.CostSeconds = time.Since(ts).Seconds()
|
||||
opt.Trace.AppendRedis(opt.Redis)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, f := range options {
|
||||
f(opt)
|
||||
}
|
||||
value, _ := c.client.Incr(key).Result()
|
||||
return value
|
||||
}
|
||||
|
||||
// Close close redis client
|
||||
func (c *cacheRepo) Close() error {
|
||||
return c.client.Close()
|
||||
}
|
||||
|
||||
// WithTrace 设置trace信息
|
||||
func WithTrace(t Trace) Option {
|
||||
return func(opt *option) {
|
||||
if t != nil {
|
||||
opt.Trace = t.(*trace.Trace)
|
||||
opt.Redis = new(trace.Redis)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,376 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
stdctx "context"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/xinliangnote/go-gin-api/pkg/errno"
|
||||
"github.com/xinliangnote/go-gin-api/pkg/trace"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type HandlerFunc func(c Context)
|
||||
|
||||
type Trace = trace.T
|
||||
|
||||
const (
|
||||
_Alias = "_alias_"
|
||||
_TraceName = "_trace_"
|
||||
_LoggerName = "_logger_"
|
||||
_BodyName = "_body_"
|
||||
_PayloadName = "_payload_"
|
||||
_GraphPayloadName = "_graph_payload_"
|
||||
_UserID = "_user_id_"
|
||||
_UserName = "_user_name_"
|
||||
_AbortErrorName = "_abort_error_"
|
||||
)
|
||||
|
||||
var contextPool = &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new(context)
|
||||
},
|
||||
}
|
||||
|
||||
func newContext(ctx *gin.Context) Context {
|
||||
context := contextPool.Get().(*context)
|
||||
context.ctx = ctx
|
||||
return context
|
||||
}
|
||||
|
||||
func releaseContext(ctx Context) {
|
||||
c := ctx.(*context)
|
||||
c.ctx = nil
|
||||
contextPool.Put(c)
|
||||
}
|
||||
|
||||
var _ Context = (*context)(nil)
|
||||
|
||||
type Context interface {
|
||||
init()
|
||||
|
||||
// ShouldBindQuery 反序列化 querystring
|
||||
// tag: `form:"xxx"` (注:不要写成 query)
|
||||
ShouldBindQuery(obj interface{}) error
|
||||
|
||||
// ShouldBindPostForm 反序列化 postform (querystring会被忽略)
|
||||
// tag: `form:"xxx"`
|
||||
ShouldBindPostForm(obj interface{}) error
|
||||
|
||||
// ShouldBindForm 同时反序列化 querystring 和 postform;
|
||||
// 当 querystring 和 postform 存在相同字段时,postform 优先使用。
|
||||
// tag: `form:"xxx"`
|
||||
ShouldBindForm(obj interface{}) error
|
||||
|
||||
// ShouldBindJSON 反序列化 postjson
|
||||
// tag: `json:"xxx"`
|
||||
ShouldBindJSON(obj interface{}) error
|
||||
|
||||
// ShouldBindURI 反序列化 path 参数(如路由路径为 /user/:name)
|
||||
// tag: `uri:"xxx"`
|
||||
ShouldBindURI(obj interface{}) error
|
||||
|
||||
// Redirect 重定向
|
||||
Redirect(code int, location string)
|
||||
|
||||
// Trace 获取 Trace 对象
|
||||
Trace() Trace
|
||||
setTrace(trace Trace)
|
||||
disableTrace()
|
||||
|
||||
// Logger 获取 Logger 对象
|
||||
Logger() *zap.Logger
|
||||
setLogger(logger *zap.Logger)
|
||||
|
||||
// Payload 正确返回
|
||||
Payload(payload interface{})
|
||||
getPayload() interface{}
|
||||
|
||||
// GraphPayload GraphQL返回值 与 api 返回结构不同
|
||||
GraphPayload(payload interface{})
|
||||
getGraphPayload() interface{}
|
||||
|
||||
// AbortWithError 错误返回
|
||||
AbortWithError(err errno.Error)
|
||||
abortError() errno.Error
|
||||
|
||||
// Header 获取 Header 对象
|
||||
Header() http.Header
|
||||
// GetHeader 获取 Header
|
||||
GetHeader(key string) string
|
||||
// SetHeader 设置 Header
|
||||
SetHeader(key, value string)
|
||||
|
||||
// UserID 获取 JWT 中 UserID
|
||||
UserID() int64
|
||||
setUserID(userID int64)
|
||||
|
||||
// UserName 获取 JWT 中 UserName
|
||||
UserName() string
|
||||
setUserName(userName string)
|
||||
|
||||
// Alias 设置路由别名 for metrics uri
|
||||
Alias() string
|
||||
setAlias(path string)
|
||||
|
||||
// Request 获取 Request 对象
|
||||
Request() *http.Request
|
||||
// RawData 获取 Request.Body
|
||||
RawData() []byte
|
||||
// Method 获取 Request.Method
|
||||
Method() string
|
||||
// Host 获取 Request.Host
|
||||
Host() string
|
||||
// Path 获取 请求的路径 Request.URL.Path (不附带 querystring)
|
||||
Path() string
|
||||
// URI 获取 unescape 后的 Request.URL.RequestURI()
|
||||
URI() string
|
||||
// RequestContext 获取请求的 context (当 client 关闭后,会自动 canceled)
|
||||
RequestContext() StdContext
|
||||
|
||||
// ResponseWriter 获取 ResponseWriter 对象
|
||||
ResponseWriter() gin.ResponseWriter
|
||||
}
|
||||
|
||||
type context struct {
|
||||
ctx *gin.Context
|
||||
}
|
||||
|
||||
type StdContext struct {
|
||||
stdctx.Context
|
||||
Trace
|
||||
*zap.Logger
|
||||
}
|
||||
|
||||
func (c *context) init() {
|
||||
body, err := c.ctx.GetRawData()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.ctx.Set(_BodyName, body) // cache body是为了trace使用
|
||||
c.ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body)) // re-construct req body
|
||||
}
|
||||
|
||||
// ShouldBindQuery 反序列化querystring
|
||||
// tag: `form:"xxx"` (注:不要写成query)
|
||||
func (c *context) ShouldBindQuery(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.Query)
|
||||
}
|
||||
|
||||
// ShouldBindPostForm 反序列化 postform (querystring 会被忽略)
|
||||
// tag: `form:"xxx"`
|
||||
func (c *context) ShouldBindPostForm(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.FormPost)
|
||||
}
|
||||
|
||||
// ShouldBindForm 同时反序列化querystring和postform;
|
||||
// 当querystring和postform存在相同字段时,postform优先使用。
|
||||
// tag: `form:"xxx"`
|
||||
func (c *context) ShouldBindForm(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.Form)
|
||||
}
|
||||
|
||||
// ShouldBindJSON 反序列化postjson
|
||||
// tag: `json:"xxx"`
|
||||
func (c *context) ShouldBindJSON(obj interface{}) error {
|
||||
return c.ctx.ShouldBindWith(obj, binding.JSON)
|
||||
}
|
||||
|
||||
// ShouldBindURI 反序列化path参数(如路由路径为 /user/:name)
|
||||
// tag: `uri:"xxx"`
|
||||
func (c *context) ShouldBindURI(obj interface{}) error {
|
||||
return c.ctx.ShouldBindUri(obj)
|
||||
}
|
||||
|
||||
// Redirect 重定向
|
||||
func (c *context) Redirect(code int, location string) {
|
||||
c.ctx.Redirect(code, location)
|
||||
}
|
||||
|
||||
func (c *context) Trace() Trace {
|
||||
t, ok := c.ctx.Get(_TraceName)
|
||||
if !ok || t == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return t.(Trace)
|
||||
}
|
||||
|
||||
func (c *context) setTrace(trace Trace) {
|
||||
c.ctx.Set(_TraceName, trace)
|
||||
}
|
||||
|
||||
func (c *context) disableTrace() {
|
||||
c.setTrace(nil)
|
||||
}
|
||||
|
||||
func (c *context) Logger() *zap.Logger {
|
||||
logger, ok := c.ctx.Get(_LoggerName)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return logger.(*zap.Logger)
|
||||
}
|
||||
|
||||
func (c *context) setLogger(logger *zap.Logger) {
|
||||
c.ctx.Set(_LoggerName, logger)
|
||||
}
|
||||
|
||||
func (c *context) getPayload() interface{} {
|
||||
if payload, ok := c.ctx.Get(_PayloadName); ok != false {
|
||||
return payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) Payload(payload interface{}) {
|
||||
c.ctx.Set(_PayloadName, payload)
|
||||
}
|
||||
|
||||
func (c *context) getGraphPayload() interface{} {
|
||||
if payload, ok := c.ctx.Get(_GraphPayloadName); ok != false {
|
||||
return payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) GraphPayload(payload interface{}) {
|
||||
c.ctx.Set(_GraphPayloadName, payload)
|
||||
}
|
||||
|
||||
func (c *context) Header() http.Header {
|
||||
header := c.ctx.Request.Header
|
||||
|
||||
clone := make(http.Header, len(header))
|
||||
for k, v := range header {
|
||||
value := make([]string, len(v))
|
||||
copy(value, v)
|
||||
|
||||
clone[k] = value
|
||||
}
|
||||
return clone
|
||||
}
|
||||
|
||||
func (c *context) GetHeader(key string) string {
|
||||
return c.ctx.GetHeader(key)
|
||||
}
|
||||
|
||||
func (c *context) SetHeader(key, value string) {
|
||||
c.ctx.Header(key, value)
|
||||
}
|
||||
|
||||
func (c *context) UserID() int64 {
|
||||
val, ok := c.ctx.Get(_UserID)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return val.(int64)
|
||||
}
|
||||
|
||||
func (c *context) setUserID(userID int64) {
|
||||
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 {
|
||||
httpCode := err.GetHttpCode()
|
||||
if httpCode == 0 {
|
||||
httpCode = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
c.ctx.AbortWithStatus(httpCode)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// Request 获取 Request
|
||||
func (c *context) Request() *http.Request {
|
||||
return c.ctx.Request
|
||||
}
|
||||
|
||||
func (c *context) RawData() []byte {
|
||||
body, ok := c.ctx.Get(_BodyName)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return body.([]byte)
|
||||
}
|
||||
|
||||
// Method 请求的method
|
||||
func (c *context) Method() string {
|
||||
return c.ctx.Request.Method
|
||||
}
|
||||
|
||||
// Host 请求的host
|
||||
func (c *context) Host() string {
|
||||
return c.ctx.Request.Host
|
||||
}
|
||||
|
||||
// Path 请求的路径(不附带querystring)
|
||||
func (c *context) Path() string {
|
||||
return c.ctx.Request.URL.Path
|
||||
}
|
||||
|
||||
// URI unescape后的uri
|
||||
func (c *context) URI() string {
|
||||
uri, _ := url.QueryUnescape(c.ctx.Request.URL.RequestURI())
|
||||
return uri
|
||||
}
|
||||
|
||||
// RequestContext 获取请求的 context (当client关闭后,会自动canceled)
|
||||
func (c *context) RequestContext() StdContext {
|
||||
return StdContext{
|
||||
c.ctx.Request.Context(),
|
||||
c.Trace(),
|
||||
c.Logger(),
|
||||
}
|
||||
}
|
||||
|
||||
// ResponseWriter 获取 ResponseWriter
|
||||
func (c *context) ResponseWriter() gin.ResponseWriter {
|
||||
return c.ctx.Writer
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user