diff --git a/doc/wiki-cn/blademaster-quickstart.md b/doc/wiki-cn/blademaster-quickstart.md index d3437a2c0..7e842f96f 100644 --- a/doc/wiki-cn/blademaster-quickstart.md +++ b/doc/wiki-cn/blademaster-quickstart.md @@ -4,32 +4,48 @@ ``` ├── CHANGELOG.md -├── CONTRIBUTORS.md -├── LICENSE +├── OWNERS ├── README.md +├── api +│   ├── api.bm.go +│   ├── api.pb.go +│   ├── api.proto +│   └── client.go ├── cmd │   ├── cmd │   └── main.go ├── configs │   ├── application.toml +│   ├── db.toml │   ├── grpc.toml │   ├── http.toml -│   ├── log.toml │   ├── memcache.toml -│   ├── mysql.toml │   └── redis.toml ├── go.mod ├── go.sum -└── internal - ├── dao - │   └── dao.go - ├── model - │   └── model.go - ├── server - │   └── http - │   └── http.go - └── service - └── service.go +├── internal +│   ├── dao +│   │   ├── dao.bts.go +│   │   ├── dao.go +│   │   ├── db.go +│   │   ├── mc.cache.go +│   │   ├── mc.go +│   │   └── redis.go +│   ├── di +│   │   ├── app.go +│   │   ├── wire.go +│   │   └── wire_gen.go +│   ├── model +│   │   └── model.go +│   ├── server +│   │   ├── grpc +│   │   │   └── server.go +│   │   └── http +│   │   └── server.go +│   └── service +│   └── service.go +└── test + └── docker-compose.yaml ``` # 路由 diff --git a/doc/wiki-cn/cache-mc.md b/doc/wiki-cn/cache-mc.md index 4c8efcff3..86b11bda3 100644 --- a/doc/wiki-cn/cache-mc.md +++ b/doc/wiki-cn/cache-mc.md @@ -4,32 +4,48 @@ ``` ├── CHANGELOG.md -├── CONTRIBUTORS.md -├── LICENSE +├── OWNERS ├── README.md +├── api +│   ├── api.bm.go +│   ├── api.pb.go +│   ├── api.proto +│   └── client.go ├── cmd │   ├── cmd │   └── main.go ├── configs │   ├── application.toml +│   ├── db.toml │   ├── grpc.toml │   ├── http.toml -│   ├── log.toml │   ├── memcache.toml -│   ├── mysql.toml │   └── redis.toml ├── go.mod ├── go.sum -└── internal - ├── dao - │   └── dao.go - ├── model - │   └── model.go - ├── server - │   └── http - │   └── http.go - └── service - └── service.go +├── internal +│   ├── dao +│   │   ├── dao.bts.go +│   │   ├── dao.go +│   │   ├── db.go +│   │   ├── mc.cache.go +│   │   ├── mc.go +│   │   └── redis.go +│   ├── di +│   │   ├── app.go +│   │   ├── wire.go +│   │   └── wire_gen.go +│   ├── model +│   │   └── model.go +│   ├── server +│   │   ├── grpc +│   │   │   └── server.go +│   │   └── http +│   │   └── server.go +│   └── service +│   └── service.go +└── test + └── docker-compose.yaml ``` # 开始使用 @@ -39,9 +55,8 @@ 创建项目成功后,进入项目中的configs目录,打开memcache.toml,我们可以看到: ```toml -demoExpire = "24h" -[demo] - name = "kratos-demo" +[Client] + name = "abc" proto = "tcp" addr = "127.0.0.1:11211" active = 50 @@ -49,31 +64,25 @@ demoExpire = "24h" dialTimeout = "100ms" readTimeout = "200ms" writeTimeout = "300ms" - idleTimeout = "80s" + idleTimeout = "80s" ``` 在该配置文件中我们可以配置memcache的连接方式proto、连接地址addr、连接池的闲置连接数idle、最大连接数active以及各类超时。 -这里可选添加mc的过期时间设置。 - - ## 初始化 -进入项目的internal/dao目录,打开dao.go,其中: +进入项目的internal/dao目录,打开mc.go,其中: ```go -var ( - mc struct { - Demo *memcache.Config - DemoExpire xtime.Duration - } -) +var cfg struct { + Client *memcache.Config +} checkErr(paladin.Get("memcache.toml").UnmarshalTOML(&mc)) ``` 使用paladin配置管理工具将上文中的memcache.toml中的配置解析为我们需要使用的配置。 ```go -// Dao dao. -type Dao struct { +// dao dao. +type dao struct { mc *memcache.Memcache mcExpire int32 } @@ -82,7 +91,7 @@ type Dao struct { 在dao的主结构提中定义了memcache的连接池对象和过期时间。 ```go -dao = &Dao{ +d = &dao{ // memcache mc: memcache.New(mc.Demo), mcExpire: int32(time.Duration(mc.DemoExpire) / time.Second), @@ -95,11 +104,11 @@ dao = &Dao{ ```go // Ping ping the resource. -func (d *Dao) Ping(ctx context.Context) (err error) { +func (d *dao) Ping(ctx context.Context) (err error) { return d.pingMC(ctx) } -func (d *Dao) pingMC(ctx context.Context) (err error) { +func (d *dao) pingMC(ctx context.Context) (err error) { if err = d.mc.Set(ctx, &memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil { log.Error("conn.Set(PING) error(%v)", err) } diff --git a/doc/wiki-cn/cache-redis.md b/doc/wiki-cn/cache-redis.md index 8304dea0a..34ce96856 100644 --- a/doc/wiki-cn/cache-redis.md +++ b/doc/wiki-cn/cache-redis.md @@ -4,32 +4,48 @@ ``` ├── CHANGELOG.md -├── CONTRIBUTORS.md -├── LICENSE +├── OWNERS ├── README.md +├── api +│   ├── api.bm.go +│   ├── api.pb.go +│   ├── api.proto +│   └── client.go ├── cmd │   ├── cmd │   └── main.go ├── configs │   ├── application.toml +│   ├── db.toml │   ├── grpc.toml │   ├── http.toml -│   ├── log.toml │   ├── memcache.toml -│   ├── mysql.toml │   └── redis.toml ├── go.mod ├── go.sum -└── internal - ├── dao - │   └── dao.go - ├── model - │   └── model.go - ├── server - │   └── http - │   └── http.go - └── service - └── service.go +├── internal +│   ├── dao +│   │   ├── dao.bts.go +│   │   ├── dao.go +│   │   ├── db.go +│   │   ├── mc.cache.go +│   │   ├── mc.go +│   │   └── redis.go +│   ├── di +│   │   ├── app.go +│   │   ├── wire.go +│   │   └── wire_gen.go +│   ├── model +│   │   └── model.go +│   ├── server +│   │   ├── grpc +│   │   │   └── server.go +│   │   └── http +│   │   └── server.go +│   └── service +│   └── service.go +└── test + └── docker-compose.yaml ``` # 开始使用 @@ -39,9 +55,7 @@ 创建项目成功后,进入项目中的configs目录,打开redis.toml,我们可以看到: ```toml -demoExpire = "24h" - -[demo] +[Client] name = "kratos-demo" proto = "tcp" addr = "127.0.0.1:6389" @@ -55,20 +69,14 @@ demoExpire = "24h" 在该配置文件中我们可以配置redis的连接方式proto、连接地址addr、连接池的闲置连接数idle、最大连接数active以及各类超时。 -这里可选添加redis的过期时间设置。 - - ## 初始化 -进入项目的internal/dao目录,打开dao.go,其中: +进入项目的internal/dao目录,打开redis.go,其中: ```go -var ( - rc struct { - Demo *redis.Config - DemoExpire xtime.Duration - } -) +var cfg struct { + Client *memcache.Config +} checkErr(paladin.Get("redis.toml").UnmarshalTOML(&rc)) ``` 使用paladin配置管理工具将上文中的redis.toml中的配置解析为我们需要使用的配置。 @@ -84,7 +92,7 @@ type Dao struct { 在dao的主结构提中定义了redis的连接池对象和过期时间。 ```go -dao = &Dao{ +d = &dao{ // redis redis: redis.NewPool(rc.Demo), redisExpire: int32(time.Duration(rc.DemoExpire) / time.Second), @@ -97,11 +105,11 @@ dao = &Dao{ ```go // Ping ping the resource. -func (d *Dao) Ping(ctx context.Context) (err error) { +func (d *dao) Ping(ctx context.Context) (err error) { return d.pingRedis(ctx) } -func (d *Dao) pingRedis(ctx context.Context) (err error) { +func (d *dao) pingRedis(ctx context.Context) (err error) { conn := d.redis.Get(ctx) defer conn.Close() if _, err = conn.Do("SET", "ping", "pong"); err != nil { @@ -130,7 +138,7 @@ func (d *Dao) Close() { ```go // DemoIncrby . -func (d *Dao) DemoIncrby(c context.Context, pid int) (err error) { +func (d *dao) DemoIncrby(c context.Context, pid int) (err error) { cacheKey := keyDemo(pid) conn := d.redis.Get(c) defer conn.Close() @@ -149,7 +157,7 @@ kratos/pkg/cache/redis包除了支持发送单个命令,也支持批量发送 ```go // DemoIncrbys . -func (d *Dao) DemoIncrbys(c context.Context, pid int) (err error) { +func (d *dao) DemoIncrbys(c context.Context, pid int) (err error) { cacheKey := keyDemo(pid) conn := d.redis.Get(c) defer conn.Close() diff --git a/doc/wiki-cn/database-mysql-orm.md b/doc/wiki-cn/database-mysql-orm.md index 5b776034c..1e16fc771 100644 --- a/doc/wiki-cn/database-mysql-orm.md +++ b/doc/wiki-cn/database-mysql-orm.md @@ -4,32 +4,48 @@ ``` ├── CHANGELOG.md -├── CONTRIBUTORS.md -├── LICENSE +├── OWNERS ├── README.md +├── api +│   ├── api.bm.go +│   ├── api.pb.go +│   ├── api.proto +│   └── client.go ├── cmd │   ├── cmd │   └── main.go ├── configs │   ├── application.toml +│   ├── db.toml │   ├── grpc.toml │   ├── http.toml -│   ├── log.toml │   ├── memcache.toml -│   ├── mysql.toml │   └── redis.toml ├── go.mod ├── go.sum -└── internal - ├── dao - │   └── dao.go - ├── model - │   └── model.go - ├── server - │   └── http - │   └── http.go - └── service - └── service.go +├── internal +│   ├── dao +│   │   ├── dao.bts.go +│   │   ├── dao.go +│   │   ├── db.go +│   │   ├── mc.cache.go +│   │   ├── mc.go +│   │   └── redis.go +│   ├── di +│   │   ├── app.go +│   │   ├── wire.go +│   │   └── wire_gen.go +│   ├── model +│   │   └── model.go +│   ├── server +│   │   ├── grpc +│   │   │   └── server.go +│   │   └── http +│   │   └── server.go +│   └── service +│   └── service.go +└── test + └── docker-compose.yaml ``` # 开始使用 @@ -57,17 +73,15 @@ ## 初始化 -进入项目的internal/dao目录,打开dao.go,其中: +进入项目的internal/dao目录,打开db.go,其中: ```go -var ( - dc struct { - Demo *sql.Config - } -) -checkErr(paladin.Get("mysql.toml").UnmarshalTOML(&dc)) +var cfg struct { + Client *sql.Config +} +checkErr(paladin.Get("db.toml").UnmarshalTOML(&dc)) ``` -使用paladin配置管理工具将上文中的mysql.toml中的配置解析为我们需要使用mysql的相关配置。 +使用paladin配置管理工具将上文中的db.toml中的配置解析为我们需要使用db的相关配置。 # TODO:补充常用方法 diff --git a/doc/wiki-cn/database-mysql.md b/doc/wiki-cn/database-mysql.md index 3614c4e3f..2eab493bb 100644 --- a/doc/wiki-cn/database-mysql.md +++ b/doc/wiki-cn/database-mysql.md @@ -4,32 +4,48 @@ ``` ├── CHANGELOG.md -├── CONTRIBUTORS.md -├── LICENSE +├── OWNERS ├── README.md +├── api +│   ├── api.bm.go +│   ├── api.pb.go +│   ├── api.proto +│   └── client.go ├── cmd │   ├── cmd │   └── main.go ├── configs │   ├── application.toml +│   ├── db.toml │   ├── grpc.toml │   ├── http.toml -│   ├── log.toml │   ├── memcache.toml -│   ├── mysql.toml │   └── redis.toml ├── go.mod ├── go.sum -└── internal - ├── dao - │   └── dao.go - ├── model - │   └── model.go - ├── server - │   └── http - │   └── http.go - └── service - └── service.go +├── internal +│   ├── dao +│   │   ├── dao.bts.go +│   │   ├── dao.go +│   │   ├── db.go +│   │   ├── mc.cache.go +│   │   ├── mc.go +│   │   └── redis.go +│   ├── di +│   │   ├── app.go +│   │   ├── wire.go +│   │   └── wire_gen.go +│   ├── model +│   │   └── model.go +│   ├── server +│   │   ├── grpc +│   │   │   └── server.go +│   │   └── http +│   │   └── server.go +│   └── service +│   └── service.go +└── test + └── docker-compose.yaml ``` # 开始使用 @@ -57,17 +73,15 @@ ## 初始化 -进入项目的internal/dao目录,打开dao.go,其中: +进入项目的internal/dao目录,打开db.go,其中: ```go -var ( - dc struct { - Demo *sql.Config - } -) -checkErr(paladin.Get("mysql.toml").UnmarshalTOML(&dc)) +var cfg struct { + Client *sql.Config +} +checkErr(paladin.Get("db.toml").UnmarshalTOML(&dc)) ``` -使用paladin配置管理工具将上文中的mysql.toml中的配置解析为我们需要使用mysql的相关配置。 +使用paladin配置管理工具将上文中的db.toml中的配置解析为我们需要使用db的相关配置。 ```go // Dao dao. @@ -79,7 +93,7 @@ type Dao struct { 在dao的主结构提中定义了mysql的连接池对象。 ```go -dao = &Dao{ +d = &dao{ db: sql.NewMySQL(dc.Demo), } ``` @@ -90,7 +104,7 @@ dao = &Dao{ ```go // Ping ping the resource. -func (d *Dao) Ping(ctx context.Context) (err error) { +func (d *dao) Ping(ctx context.Context) (err error) { return d.db.Ping(ctx) } ``` @@ -101,7 +115,7 @@ func (d *Dao) Ping(ctx context.Context) (err error) { ```go // Close close the resource. -func (d *Dao) Close() { +func (d *dao) Close() { d.db.Close() } ``` @@ -114,7 +128,7 @@ func (d *Dao) Close() { ```go // GetDemo 用户角色 -func (d *Dao) GetDemo(c context.Context, did int64) (demo int8, err error) { +func (d *dao) GetDemo(c context.Context, did int64) (demo int8, err error) { err = d.db.QueryRow(c, _getDemoSQL, did).Scan(&demo) if err != nil && err != sql.ErrNoRows { log.Error("d.GetDemo.Query error(%v)", err) @@ -132,7 +146,7 @@ db.QueryRow方法用于返回最多一条记录的查询,在QueryRow方法后 ```go // ResourceLogs ResourceLogs. -func (d *Dao) GetDemos(c context.Context, dids []int64) (demos []int8, err error) { +func (d *dao) GetDemos(c context.Context, dids []int64) (demos []int8, err error) { rows, err := d.db.Query(c, _getDemosSQL, dids) if err != nil { log.Error("query error(%v)", err) diff --git a/doc/wiki-cn/kratos-tool.md b/doc/wiki-cn/kratos-tool.md index 68b47bc9b..312b36be4 100644 --- a/doc/wiki-cn/kratos-tool.md +++ b/doc/wiki-cn/kratos-tool.md @@ -55,10 +55,16 @@ kratos new kratos-demo kratos new kratos-demo -o YourName -d YourPath ``` -注意,`kratos new`默认是不会生成通过 protobuf 定义的`grpc`和`bm`示例代码的,如需生成请加`--proto`,如下: +注意,`kratos new`默认会生成通过 protobuf 定义的`grpc`和`bm`示例代码的,如只生成bm请加`--http`,如下: ```shell -kratos new kratos-demo -o YourName -d YourPath --proto +kratos new kratos-demo -o YourName -d YourPath --http +``` + +如只生成grpc请加`--grpc`,如下: + +```shell +kratos new kratos-demo -o YourName -d YourPath --grpc ``` > 特别注意,如果不是MacOS系统,需要自己进行手动安装protoc,用于生成的示例项目`api`目录下的`proto`文件并不会自动生成对应的`.pb.go`和`.bm.go`文件。 @@ -76,13 +82,16 @@ kratos new kratos-demo -o YourName -d YourPath --proto ``` kratos tool +protoc(已安装): 快速方便生成pb.go的protoc封装,windows、Linux请先安装protoc工具 Author(kratos) [2019/10/31] +genbts(已安装): 缓存回源逻辑代码生成器 Author(kratos) [2019/10/31] +testcli(已安装): 测试代码生成 Author(kratos) [2019/09/09] +genmc(已安装): mc缓存代码生成 Author(kratos) [2019/07/23] swagger(已安装): swagger api文档 Author(goswagger.io) [2019/05/05] -protoc(已安装): 快速方便生成pb.go和bm.go的protoc封装,windows、Linux请先安装protoc工具 Author(kratos) [2019/05/04] -kratos(已安装): Kratos工具集本体 Author(kratos) [2019/04/02] 安装工具: kratos tool install demo 执行工具: kratos tool demo 安装全部工具: kratos tool install all +全部升级: kratos tool upgrade all 详细文档: https://github.com/bilibili/kratos/blob/master/doc/wiki-cn/kratos-tool.md ``` diff --git a/doc/wiki-cn/quickstart.md b/doc/wiki-cn/quickstart.md index 19496fe60..3faed015e 100644 --- a/doc/wiki-cn/quickstart.md +++ b/doc/wiki-cn/quickstart.md @@ -11,36 +11,48 @@ kratos new kratos-demo 根据提示可以快速创建项目,如[kratos-demo](https://github.com/bilibili/kratos-demo)就是通过工具创建生成。目录结构如下: ``` -├── CHANGELOG.md # CHANGELOG -├── CONTRIBUTORS.md # CONTRIBUTORS -├── README.md # README -├── api # api目录为对外保留的proto文件及生成的pb.go文件,注:需要"--proto"参数 +├── CHANGELOG.md +├── OWNERS +├── README.md +├── api # api目录为对外保留的proto文件及生成的pb.go文件 +│   ├── api.bm.go +│   ├── api.pb.go # 通过go generate生成的pb.go文件 │   ├── api.proto -│   ├── api.pb.go # 通过go generate生成的pb.go文件 -│   └── generate.go -├── cmd # cmd目录为main所在 -│   └── main.go # main.go -├── configs # configs为配置文件目录 -│   ├── application.toml # 应用的自定义配置文件,可能是一些业务开关如:useABtest = true -│   ├── grpc.toml # grpc相关配置 -│   ├── http.toml # http相关配置 -│   ├── log.toml # log相关配置 -│   ├── memcache.toml # memcache相关配置 -│   ├── mysql.toml # mysql相关配置 -│   └── redis.toml # redis相关配置 -├── go.mod # go.mod -└── internal # internal为项目内部包,包括以下目录: - ├── dao # dao层,用于数据库、cache、MQ、依赖某业务grpc|http等资源访问 - │   └── dao.go - ├── model # model层,用于声明业务结构体 - │   └── model.go - ├── server # server层,用于初始化grpc和http server - │   └── http # http层,用于初始化http server和声明handler - │   └── http.go - │   └── grpc # grpc层,用于初始化grpc server和定义method - │   └── grpc.go - └── service # service层,用于业务逻辑处理,且为方便http和grpc共用方法,建议入参和出参保持grpc风格,且使用pb文件生成代码 - └── service.go +│   └── client.go +├── cmd +│   └── main.go # cmd目录为main所在 +├── configs # configs为配置文件目录 +│   ├── application.toml # 应用的自定义配置文件,可能是一些业务开关如:useABtest = true +│   ├── db.toml # db相关配置 +│   ├── grpc.toml # grpc相关配置 +│   ├── http.toml # http相关配置 +│   ├── memcache.toml # memcache相关配置 +│   └── redis.toml # redis相关配置 +├── go.mod +├── go.sum +└── internal # internal为项目内部包,包括以下目录: +│   ├── dao # dao层,用于数据库、cache、MQ、依赖某业务grpc|http等资源访问 +│   │   ├── dao.bts.go +│   │   ├── dao.go +│   │   ├── db.go +│   │   ├── mc.cache.go +│   │   ├── mc.go +│   │   └── redis.go +│   ├── di # 依赖注入层 采用wire静态分析依赖 +│   │   ├── app.go +│   │   ├── wire.go # wire 声明 +│   │   └── wire_gen.go # go generate 生成的代码 +│   ├── model # model层,用于声明业务结构体 +│   │   └── model.go +│   ├── server # server层,用于初始化grpc和http server +│   │   ├── grpc # grpc层,用于初始化grpc server和定义method +│   │   │   └── server.go +│   │   └── http # http层,用于初始化http server和声明handler +│   │   └── server.go +│   └── service # service层,用于业务逻辑处理,且为方便http和grpc共用方法,建议入参和出参保持grpc风格,且使用pb文件生成代码 +│   └── service.go +└── test # 测试资源层 用于存放测试相关资源数据 如docker-compose配置 数据库初始化语句等 + └── docker-compose.yaml ``` 生成后可直接运行如下: diff --git a/go.mod b/go.mod index 95dcb20b3..f6c991787 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/aristanetworks/goarista v0.0.0-20190912214011-b54698eaaca6 // indirect github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect @@ -17,16 +18,16 @@ require ( github.com/go-playground/locales v0.12.1 // indirect github.com/go-playground/universal-translator v0.16.0 // indirect github.com/go-sql-driver/mysql v1.4.1 + github.com/gobuffalo/packr/v2 v2.7.1 github.com/gogo/protobuf v1.3.0 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect github.com/golang/mock v1.3.1 // indirect github.com/golang/protobuf v1.3.2 github.com/google/uuid v1.1.1 // indirect github.com/gorilla/websocket v1.4.0 // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/leodido/go-urn v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.2 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/mattn/go-colorable v0.1.4 // indirect + github.com/mattn/go-isatty v0.0.10 // indirect github.com/montanaflynn/stats v0.5.0 github.com/openzipkin/zipkin-go v0.2.1 github.com/otokaze/mock v0.0.0-20190125081256-8282b7a7c7c3 @@ -38,17 +39,17 @@ require ( github.com/shirou/gopsutil v2.19.6+incompatible github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 github.com/sirupsen/logrus v1.4.2 - github.com/stretchr/testify v1.3.0 + github.com/stretchr/testify v1.4.0 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect github.com/tsuna/gohbase v0.0.0-20190502052937-24ffed0537aa - github.com/urfave/cli v1.20.0 + github.com/urfave/cli v1.22.1 go.etcd.io/etcd v0.0.0-20190917205325-a14579fbfb1a go.uber.org/atomic v1.4.0 // indirect go.uber.org/multierr v1.2.0 // indirect golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect golang.org/x/net v0.0.0-20191011234655-491137f69257 - golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect - golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89 + golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c // indirect + golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3 google.golang.org/appengine v1.6.1 // indirect google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03 google.golang.org/grpc v1.24.0 diff --git a/go.sum b/go.sum index d885b27d0..67c9d0247 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,7 @@ github.com/aristanetworks/glog v0.0.0-20180419172825-c15b03b3054f/go.mod h1:KASm github.com/aristanetworks/goarista v0.0.0-20190912214011-b54698eaaca6 h1:6bZNnQcA2fkzH9AhZXbp2nDqbWa4bBqFeUb70Zq1HBM= github.com/aristanetworks/goarista v0.0.0-20190912214011-b54698eaaca6/go.mod h1:Z4RTxGAuYhPzcq8+EdRM+R8M48Ssle2TsWtwRKa+vns= github.com/aristanetworks/splunk-hec-go v0.3.3/go.mod h1:1VHO9r17b0K7WmOlLb9nTk/2YanvOEnLMUgsFrxBROc= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -22,6 +23,8 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0 h1:3Jm3tLmsgAYcjC+4Up7hJrFBPr+n7rAqYeSw/SZazuY= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= @@ -32,6 +35,12 @@ github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf h1:CAKfRE2YtTUIjjh1bkBt github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +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/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8= github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= @@ -71,6 +80,15 @@ github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEK github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/logger v1.0.1 h1:ZEgyRGgAm4ZAhAO45YXMs5Fp+bzGLESFewzAVBMKuTg= +github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr/v2 v2.7.1 h1:n3CIW5T17T8v4GGK5sWXLVWJhCz7b5aNLSxW6gYim4o= +github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -113,10 +131,13 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20190809212627-fc22c7df067e/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -141,15 +162,20 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= 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/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +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= @@ -171,10 +197,9 @@ github.com/openzipkin/zipkin-go v0.2.1 h1:noL5/5Uf1HpVl3wNsfkZhIKbSWCVi5jgqkONNx github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/otokaze/mock v0.0.0-20190125081256-8282b7a7c7c3 h1:zjmNboC3QFuMdJSaZJ7Qvi3HUxWXPdj7wb3rc4jH5HI= github.com/otokaze/mock v0.0.0-20190125081256-8282b7a7c7c3/go.mod h1:pLR8n2aimFxvvDJ6n8JuQWthMGezCYMjuhlaTjPTZf0= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/philchia/agollo v0.0.0-20190728085453-a95533fccea3 h1:e/WwwXpp+h9CtbiwSdDxrgq6ymvrvLH/P+kS+8qq4v8= github.com/philchia/agollo v0.0.0-20190728085453-a95533fccea3/go.mod h1:EXNdWdQkS+QBi0nb/Xm+sBBuQ1PM7/NIPr1JDzOlt8A= -github.com/philchia/agollo v2.3.1+incompatible h1:C4zDDuOcP1Qynikz2rSJQSMjwexv4GfDpwBHJRinhPc= -github.com/philchia/agollo v2.3.1+incompatible/go.mod h1:EXNdWdQkS+QBi0nb/Xm+sBBuQ1PM7/NIPr1JDzOlt8A= github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -201,12 +226,23 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237 h1:HQagqIiBmr8YXawX/le3+O26N+vPPC1PtjaF3mwnook= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.4.0 h1:LUa41nrWTQNGhzdsZ5lTnkwbNjj6rXTdazA1cSdjkOY= +github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +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/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec h1:6ncX5ko6B9LntYM0YBRXkiSaZMmLYeZ/NWcmeB43mMY= github.com/samuel/go-zookeeper v0.0.0-20180130194729-c4fab1ac1bec/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/shirou/gopsutil v2.19.6+incompatible h1:49/Gru26Lne9Cl3IoAVDZVM09hvkSrUodgIIsCVRwbs= github.com/shirou/gopsutil v2.19.6+incompatible/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +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/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM= github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -214,15 +250,24 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +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.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc= @@ -231,12 +276,16 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tsuna/gohbase v0.0.0-20190502052937-24ffed0537aa h1:V/ABqiqsgqmpoIcLDSpJ1KqPfbxRmkcfET5+BRy9ctM= github.com/tsuna/gohbase v0.0.0-20190502052937-24ffed0537aa/go.mod h1:3HfLQly3YNLGxNv/2YOfmz30vcjG9hbuME1GpxoLlGs= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 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 v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtaci/kcp-go v5.4.5+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= @@ -253,9 +302,11 @@ go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -283,23 +334,28 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ 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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-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-20181205085412-a5c9d58dba9a/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/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8 h1:41hwlulw1prEMBxLQSlMSux1zxJf07B3WPsdjJlKZxE= golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c h1:S/FtSvpNLtFBgjTqcKsRpsa6aVsI6iztaz1bQd9BJwE= +golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -318,6 +374,8 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b h1:mSUCVIwDx4hfXJfWsOPfdzE golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89 h1:WiVZGyzQN7gPNLRkkpsNX3jC0Jx5j9GxadCZW/8eXw0= golang.org/x/tools v0.0.0-20190912185636-87d9f09c5d89/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3 h1:2AmBLzhAfXj+2HCW09VCkJtHIYgHTIPcTeYqgP7Bwt0= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= @@ -338,6 +396,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +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 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= diff --git a/tool/kratos-gen-bts/README.md b/tool/kratos-gen-bts/README.md index 3e6ef48bb..82f6b0af2 100644 --- a/tool/kratos-gen-bts/README.md +++ b/tool/kratos-gen-bts/README.md @@ -36,6 +36,7 @@ dao里面需要有cache对象 代码会调用d.cache来新增缓存 | ---------------- | ------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | -nullcache | | 空指针对象(存正常业务不会出现的内容 id的话像是-1这样的) | &Demo{ID:-1} 或-1 或"null" | | -check_null_code | | 开启空缓存并且value为指针对象时必填 用于判断是否是空缓存 $来指代对象名 | `-check_null_code=$!=nil&&$.ID==-1 或 $ == -1` | +| -cache_err |continue| 缓存出错的时候的行为 continue: 继续执行 break: 抛出错误 方法返回|break| | -batch | | (限多key模板) 批量获取数据 每组大小 | 100 | | -max_group | | (限多key模板)批量获取数据 最大组数量 | 10 | | -batch_err | break | (限多key模板)批量获取数据回源错误的时候 降级继续请求(continue)还是直接返回(break) | break 或 continue | @@ -44,3 +45,4 @@ dao里面需要有cache对象 代码会调用d.cache来新增缓存 | -paging | false | (限单key模板)分页 数据源应返回2个值 第一个为对外数据 第二个为全量数据 用于新增缓存 | false | | -ignores | | 用于依赖的三个方法参数和主方法参数不一致的情况. 忽略方法的某些参数 用\|分隔方法逗号分隔参数 | pn,ps\|pn\|origin 表示"缓存获取"方法忽略pn,ps两个参数 回源方法忽略pn参数 加缓存方法忽略origin参数 | | -custom_method | false | 自定义方法名 \|分隔 缓存获取方法名\|回源方法名\|增加缓存方法名 | d.mc.AddDemo\|d.mysql.Demo\|d.mc.AddDemo | +| -struct_name | dao | 所属结构体名称 | Dao| \ No newline at end of file diff --git a/tool/kratos-gen-bts/header_template.go b/tool/kratos-gen-bts/header_template.go index 3d5d56292..5d130b132 100644 --- a/tool/kratos-gen-bts/header_template.go +++ b/tool/kratos-gen-bts/header_template.go @@ -24,9 +24,9 @@ NEWLINE {{if .EnableSingleFlight}} "golang.org/x/sync/singleflight" {{end}} ) -var ( - _ _bts -) +{{if .UseBTS}} +var _ _bts +{{end }} {{if .EnableSingleFlight}} var cacheSingleFlights = [SFCOUNT]*singleflight.Group{SFINIT} {{end }} diff --git a/tool/kratos-gen-bts/main.go b/tool/kratos-gen-bts/main.go index 66fc161d1..415999da4 100644 --- a/tool/kratos-gen-bts/main.go +++ b/tool/kratos-gen-bts/main.go @@ -10,6 +10,7 @@ import ( "os" "path/filepath" "regexp" + "runtime" "strconv" "strings" "text/template" @@ -22,6 +23,7 @@ var ( singleFlight = flag.Bool("singleflight", false, "enable singleflight") nullCache = flag.String("nullcache", "", "null cache") checkNullCode = flag.String("check_null_code", "", "check null code") + cacheErr = flag.String("cache_err", "continue", "cache err to contine or break") batchSize = flag.Int("batch", 0, "batch size") batchErr = flag.String("batch_err", "break", "batch err to contine or break") maxGroup = flag.Int("max_group", 0, "max group size") @@ -29,18 +31,19 @@ var ( paging = flag.Bool("paging", false, "use paging in single template") ignores = flag.String("ignores", "", "ignore params") customMethod = flag.String("custom_method", "", "自定义方法名 |分隔: 缓存|回源|增加缓存") + structName = flag.String("struct_name", "dao", "struct name") numberTypes = []string{"int", "int8", "int16", "int32", "int64", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64"} simpleTypes = []string{"int", "int8", "int16", "int32", "int64", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "bool", "string", "[]byte"} - optionNames = []string{"singleflight", "nullcache", "check_null_code", "batch", "max_group", "sync", "paging", "ignores", "batch_err", "custom_method"} + optionNames = []string{"singleflight", "nullcache", "check_null_code", "batch", "max_group", "sync", "paging", "ignores", "batch_err", "custom_method", "cache_err", "struct_name"} optionNamesMap = map[string]bool{} + interfaceName string ) const ( - _interfaceName = "_bts" - _multiTpl = 1 - _singleTpl = 2 - _noneTpl = 3 + _multiTpl = 1 + _singleTpl = 2 + _noneTpl = 3 ) func resetFlag() { @@ -52,8 +55,10 @@ func resetFlag() { *sync = false *paging = false *batchErr = "break" + *cacheErr = "continue" *ignores = "" *customMethod = "" + *structName = "dao" } // options options @@ -91,6 +96,10 @@ type options struct { Comment string CustomMethod string IDName string + CacheErrContinue bool + StructName string + hasDec bool + UseBTS bool } func getOptions(opt *options, comment string) { @@ -108,6 +117,7 @@ func getOptions(opt *options, comment string) { os.Args = append(os.Args, arg) } } + opt.hasDec = true } resetFlag() flag.Parse() @@ -122,13 +132,15 @@ func getOptions(opt *options, comment string) { opt.GroupSize = *batchSize opt.MaxGroup = *maxGroup opt.CustomMethod = *customMethod + opt.CacheErrContinue = *cacheErr == "continue" + opt.StructName = *structName } func processList(s *pkg.Source, list *ast.Field) (opt options) { fset := s.Fset src := s.Src lines := strings.Split(src, "\n") - opt = options{Args: s.GetDef(_interfaceName), importPackages: s.Packages(list)} + opt = options{name: list.Names[0].Name, Args: s.GetDef(interfaceName), importPackages: s.Packages(list)} // get comment line := fset.Position(list.Pos()).Line - 3 if len(lines)-1 >= line { @@ -140,8 +152,11 @@ func processList(s *pkg.Source, list *ast.Field) (opt options) { line = fset.Position(list.Pos()).Line - 2 comment := lines[line] getOptions(&opt, comment) + if !opt.hasDec { + log.Printf("%s: 无声明 忽略此方法\n", opt.name) + return + } // get func - opt.name = list.Names[0].Name params := list.Type.(*ast.FuncType).Params.List if len(params) == 0 { log.Fatalln(opt.name + "参数不足") @@ -304,15 +319,26 @@ func processList(s *pkg.Source, list *ast.Field) (opt options) { // parse parse options func parse(s *pkg.Source) (opts []*options) { - c := s.F.Scope.Lookup(_interfaceName) - if (c == nil) || (c.Kind != ast.Typ) { + var c *ast.Object + for _, name := range []string{"_bts", "Dao"} { + c = s.F.Scope.Lookup(name) + if (c == nil) || (c.Kind != ast.Typ) { + c = nil + continue + } + interfaceName = name + break + } + if c == nil { log.Fatalln("无法找到缓存声明") } lists := c.Decl.(*ast.TypeSpec).Type.(*ast.InterfaceType).Methods.List for _, list := range lists { opt := processList(s, list) - opt.Check() - opts = append(opts, &opt) + if opt.hasDec { + opt.Check() + opts = append(opts, &opt) + } } return } @@ -339,10 +365,6 @@ func (option *options) Check() { if option.SimpleValue && option.NullCache == option.ZeroValue { log.Fatalf("%s: %s 不能作为空缓存值 \n", option.name, option.NullCache) } - if strings.Contains(option.NullCache, "{}") { - // -nullcache=[]*model.OrderMain{} 这种无效 - log.Fatalf("%s: %s 不能作为空缓存值 会导致空缓存无效 \n", option.name, option.NullCache) - } if strings.Contains(option.CheckNullCode, "len") && strings.Contains(strings.Replace(option.CheckNullCode, " ", "", -1), "==0") { // -check_null_code=len($)==0 这种无效 log.Fatalf("%s: -check_null_code=%s 错误 会有无意义的赋值\n", option.name, option.CheckNullCode) @@ -352,6 +374,7 @@ func (option *options) Check() { func genHeader(opts []*options) (src string) { option := options{PkgName: os.Getenv("GOPACKAGE")} + option.UseBTS = interfaceName == "_bts" var sfCount int var packages, sfInit []string packagesMap := map[string]bool{`"context"`: true} @@ -464,7 +487,9 @@ func main() { log.SetFlags(0) defer func() { if err := recover(); err != nil { - log.Fatalf("程序解析失败, err: %+v", err) + buf := make([]byte, 64*1024) + buf = buf[:runtime.Stack(buf, false)] + log.Fatalf("程序解析失败, err: %+v stack: %s", err, buf) } }() options := parse(pkg.NewSource(pkg.SourceText())) diff --git a/tool/kratos-gen-bts/multi_template.go b/tool/kratos-gen-bts/multi_template.go index 6d4ffcffa..7034f00af 100644 --- a/tool/kratos-gen-bts/multi_template.go +++ b/tool/kratos-gen-bts/multi_template.go @@ -2,15 +2,19 @@ package main var _multiTemplate = ` // NAME {{or .Comment "get data from cache if miss will call source method, then add to cache."}} -func (d *Dao) NAME(c context.Context, {{.IDName}} []KEY{{.ExtraArgsType}}) (res map[KEY]VALUE, err error) { +func (d *{{.StructName}}) NAME(c context.Context, {{.IDName}} []KEY{{.ExtraArgsType}}) (res map[KEY]VALUE, err error) { if len({{.IDName}}) == 0 { return } addCache := true if res, err = CACHEFUNC(c, {{.IDName}} {{.ExtraCacheArgs}});err != nil { + {{if .CacheErrContinue}} addCache = false res = nil err = nil + {{else}} + return + {{end}} } var miss []KEY for _, key := range {{.IDName}} { diff --git a/tool/kratos-gen-bts/none_template.go b/tool/kratos-gen-bts/none_template.go index dfdf53ab8..90c4063d0 100644 --- a/tool/kratos-gen-bts/none_template.go +++ b/tool/kratos-gen-bts/none_template.go @@ -2,12 +2,16 @@ package main var _noneTemplate = ` // NAME {{or .Comment "get data from cache if miss will call source method, then add to cache."}} -func (d *Dao) NAME(c context.Context) (res VALUE, err error) { +func (d *{{.StructName}}) NAME(c context.Context) (res VALUE, err error) { addCache := true res, err = CACHEFUNC(c) if err != nil { + {{if .CacheErrContinue}} addCache = false err = nil + {{else}} + return + {{end}} } {{if .EnableNullCache}} defer func() { @@ -21,7 +25,7 @@ func (d *Dao) NAME(c context.Context) (res VALUE, err error) { {{else}} if res != {{.ZeroValue}} { {{end}} - cache.MetricHits.Inc("bts:NAME") + cache.MetricHits.Inc("bts:NAME") return } {{if .EnableSingleFlight}} diff --git a/tool/kratos-gen-bts/single_template.go b/tool/kratos-gen-bts/single_template.go index 7d3219e1f..0ec2d4473 100644 --- a/tool/kratos-gen-bts/single_template.go +++ b/tool/kratos-gen-bts/single_template.go @@ -2,12 +2,16 @@ package main var _singleTemplate = ` // NAME {{or .Comment "get data from cache if miss will call source method, then add to cache."}} -func (d *Dao) NAME(c context.Context, {{.IDName}} KEY{{.ExtraArgsType}}) (res VALUE, err error) { +func (d *{{.StructName}}) NAME(c context.Context, {{.IDName}} KEY{{.ExtraArgsType}}) (res VALUE, err error) { addCache := true res, err = CACHEFUNC(c, {{.IDName}} {{.ExtraCacheArgs}}) if err != nil { + {{if .CacheErrContinue}} addCache = false err = nil + {{else}} + return + {{end}} } {{if .EnableNullCache}} defer func() { diff --git a/tool/kratos-gen-bts/testdata/dao.bts.go b/tool/kratos-gen-bts/testdata/dao.bts.go index 4b8f0096c..ced05553b 100644 --- a/tool/kratos-gen-bts/testdata/dao.bts.go +++ b/tool/kratos-gen-bts/testdata/dao.bts.go @@ -27,12 +27,10 @@ import ( "github.com/bilibili/kratos/pkg/sync/errgroup" ) -var ( - _ _bts -) +var _ _bts // Demos get data from cache if miss will call source method, then add to cache. -func (d *Dao) Demos(c context.Context, keys []int64) (res map[int64]*Demo, err error) { +func (d *dao) Demos(c context.Context, keys []int64) (res map[int64]*Demo, err error) { if len(keys) == 0 { return } @@ -111,7 +109,7 @@ func (d *Dao) Demos(c context.Context, keys []int64) (res map[int64]*Demo, err e } // Demos1 get data from cache if miss will call source method, then add to cache. -func (d *Dao) Demos1(c context.Context, keys []int64) (res map[int64]*Demo, err error) { +func (d *dao) Demos1(c context.Context, keys []int64) (res map[int64]*Demo, err error) { if len(keys) == 0 { return } @@ -190,7 +188,7 @@ func (d *Dao) Demos1(c context.Context, keys []int64) (res map[int64]*Demo, err } // Demo get data from cache if miss will call source method, then add to cache. -func (d *Dao) Demo(c context.Context, key int64) (res *Demo, err error) { +func (d *dao) Demo(c context.Context, key int64) (res *Demo, err error) { addCache := true res, err = d.CacheDemo(c, key) if err != nil { @@ -223,7 +221,7 @@ func (d *Dao) Demo(c context.Context, key int64) (res *Demo, err error) { } // Demo1 get data from cache if miss will call source method, then add to cache. -func (d *Dao) Demo1(c context.Context, key int64, pn int, ps int) (res *Demo, err error) { +func (d *dao) Demo1(c context.Context, key int64, pn int, ps int) (res *Demo, err error) { addCache := true res, err = d.CacheDemo1(c, key, pn, ps) if err != nil { @@ -250,7 +248,7 @@ func (d *Dao) Demo1(c context.Context, key int64, pn int, ps int) (res *Demo, er } // None get data from cache if miss will call source method, then add to cache. -func (d *Dao) None(c context.Context) (res *Demo, err error) { +func (d *dao) None(c context.Context) (res *Demo, err error) { addCache := true res, err = d.CacheNone(c) if err != nil { diff --git a/tool/kratos-gen-bts/testdata/dao.go b/tool/kratos-gen-bts/testdata/dao.go index 6e1f5aece..e3e68edfc 100644 --- a/tool/kratos-gen-bts/testdata/dao.go +++ b/tool/kratos-gen-bts/testdata/dao.go @@ -13,13 +13,13 @@ type Demo struct { } // Dao . -type Dao struct { +type dao struct { cache *fanout.Fanout } // New . -func New() *Dao { - return &Dao{cache: fanout.New("cache")} +func New() *dao { + return &dao{cache: fanout.New("cache")} } //go:generate kratos tool genbts diff --git a/tool/kratos-gen-bts/testdata/multi.go b/tool/kratos-gen-bts/testdata/multi.go index b398adb67..4685d37ef 100644 --- a/tool/kratos-gen-bts/testdata/multi.go +++ b/tool/kratos-gen-bts/testdata/multi.go @@ -12,37 +12,37 @@ var ( ) // CacheDemos . -func (d *Dao) CacheDemos(c context.Context, keys []int64) (map[int64]*Demo, error) { +func (d *dao) CacheDemos(c context.Context, keys []int64) (map[int64]*Demo, error) { // get data from cache return _multiCacheFunc(c, keys) } // RawDemos . -func (d *Dao) RawDemos(c context.Context, keys []int64) (map[int64]*Demo, error) { +func (d *dao) RawDemos(c context.Context, keys []int64) (map[int64]*Demo, error) { // get data from db return _multiRawFunc(c, keys) } // AddCacheDemos . -func (d *Dao) AddCacheDemos(c context.Context, values map[int64]*Demo) error { +func (d *dao) AddCacheDemos(c context.Context, values map[int64]*Demo) error { // add to cache return _multiAddCacheFunc(c, values) } // CacheDemos1 . -func (d *Dao) CacheDemos1(c context.Context, keys []int64) (map[int64]*Demo, error) { +func (d *dao) CacheDemos1(c context.Context, keys []int64) (map[int64]*Demo, error) { // get data from cache return _multiCacheFunc(c, keys) } // RawDemos . -func (d *Dao) RawDemos1(c context.Context, keys []int64) (map[int64]*Demo, error) { +func (d *dao) RawDemos1(c context.Context, keys []int64) (map[int64]*Demo, error) { // get data from db return _multiRawFunc(c, keys) } // AddCacheDemos . -func (d *Dao) AddCacheDemos1(c context.Context, values map[int64]*Demo) error { +func (d *dao) AddCacheDemos1(c context.Context, values map[int64]*Demo) error { // add to cache return _multiAddCacheFunc(c, values) } diff --git a/tool/kratos-gen-bts/testdata/none.go b/tool/kratos-gen-bts/testdata/none.go index b504c9c79..c3202613a 100644 --- a/tool/kratos-gen-bts/testdata/none.go +++ b/tool/kratos-gen-bts/testdata/none.go @@ -12,19 +12,19 @@ var ( ) // CacheNone . -func (d *Dao) CacheNone(c context.Context) (*Demo, error) { +func (d *dao) CacheNone(c context.Context) (*Demo, error) { // get data from cache return _noneCacheFunc(c) } // RawNone . -func (d *Dao) RawNone(c context.Context) (*Demo, error) { +func (d *dao) RawNone(c context.Context) (*Demo, error) { // get data from db return _noneRawFunc(c) } // AddCacheNone . -func (d *Dao) AddCacheNone(c context.Context, value *Demo) error { +func (d *dao) AddCacheNone(c context.Context, value *Demo) error { // add to cache return _noneAddCacheFunc(c, value) } diff --git a/tool/kratos-gen-bts/testdata/single.go b/tool/kratos-gen-bts/testdata/single.go index db7c13c55..fe390216a 100644 --- a/tool/kratos-gen-bts/testdata/single.go +++ b/tool/kratos-gen-bts/testdata/single.go @@ -12,37 +12,37 @@ var ( ) // CacheDemo . -func (d *Dao) CacheDemo(c context.Context, key int64) (*Demo, error) { +func (d *dao) CacheDemo(c context.Context, key int64) (*Demo, error) { // get data from cache return _singleCacheFunc(c, key) } // RawDemo . -func (d *Dao) RawDemo(c context.Context, key int64) (*Demo, error) { +func (d *dao) RawDemo(c context.Context, key int64) (*Demo, error) { // get data from db return _singleRawFunc(c, key) } // AddCacheDemo . -func (d *Dao) AddCacheDemo(c context.Context, key int64, value *Demo) error { +func (d *dao) AddCacheDemo(c context.Context, key int64, value *Demo) error { // add to cache return _singleAddCacheFunc(c, key, value) } // CacheDemo1 . -func (d *Dao) CacheDemo1(c context.Context, key int64, pn, ps int) (*Demo, error) { +func (d *dao) CacheDemo1(c context.Context, key int64, pn, ps int) (*Demo, error) { // get data from cache return nil, nil } // RawDemo1 . -func (d *Dao) RawDemo1(c context.Context, key int64, pn, ps int) (*Demo, *Demo, error) { +func (d *dao) RawDemo1(c context.Context, key int64, pn, ps int) (*Demo, *Demo, error) { // get data from db return nil, nil, nil } // AddCacheDemo1 . -func (d *Dao) AddCacheDemo1(c context.Context, key int64, value *Demo, pn, ps int) error { +func (d *dao) AddCacheDemo1(c context.Context, key int64, value *Demo, pn, ps int) error { // add to cache return nil } diff --git a/tool/kratos-gen-mc/README.md b/tool/kratos-gen-mc/README.md index f912f7198..0bc8c89ff 100644 --- a/tool/kratos-gen-mc/README.md +++ b/tool/kratos-gen-mc/README.md @@ -40,5 +40,6 @@ mc Add方法需要用注解 -type=only_add单独指定 | batch | | get(限多key模板) | 批量获取数据 每组大小 | - | 100 | | max_group | | get(限多key模板) | 批量获取数据 最大组数量 | - | 10 | | batch_err | break | get(限多key模板) | 批量获取数据回源错误的时候 降级继续请求(continue)还是直接返回(break) | break 或 continue | continue | -| struct_name | Dao | 全部 | 用户自定义Dao结构体名称 | | MemcacheDao | - +| struct_name | dao | 全部 | 用户自定义Dao结构体名称 | | MemcacheDao | +|check_null_code||add/set|(和null_expire配套使用)判断是否是空缓存的代码 用于为空缓存独立设定过期时间||$.ID==-1 或者 $=="-1"等| +|null_expire|300(5分钟)|add/set|(和check_null_code配套使用)空缓存的过期时间||d.nullExpire| \ No newline at end of file diff --git a/tool/kratos-gen-mc/header_template.go b/tool/kratos-gen-mc/header_template.go index b0237c6a6..ad53e8a17 100644 --- a/tool/kratos-gen-mc/header_template.go +++ b/tool/kratos-gen-mc/header_template.go @@ -1,7 +1,7 @@ package main var _headerTemplate = ` -// Code generated by kratos tool mcgen. DO NOT EDIT. +// Code generated by kratos tool genmc. DO NOT EDIT. NEWLINE /* @@ -25,7 +25,5 @@ NEWLINE {{.ImportPackage}} ) -var ( - _ _mc -) +var _ _mc ` diff --git a/tool/kratos-gen-mc/main.go b/tool/kratos-gen-mc/main.go index 86759cd0a..1e8bd39b3 100644 --- a/tool/kratos-gen-mc/main.go +++ b/tool/kratos-gen-mc/main.go @@ -9,26 +9,29 @@ import ( "os" "path/filepath" "regexp" + "runtime" "strconv" "strings" "text/template" - "github.com/bilibili/kratos/tool/pkg" + common "github.com/bilibili/kratos/tool/pkg" ) var ( - encode = flag.String("encode", "", "encode type: json/pb/raw/gob/gzip") - mcType = flag.String("type", "", "type: get/set/del/replace/only_add") - key = flag.String("key", "", "key name method") - expire = flag.String("expire", "", "expire time code") - structName = flag.String("struct_name", "Dao", "struct name") - batchSize = flag.Int("batch", 0, "batch size") - batchErr = flag.String("batch_err", "break", "batch err to contine or break") - maxGroup = flag.Int("max_group", 0, "max group size") + encode = flag.String("encode", "", "encode type: json/pb/raw/gob/gzip") + mcType = flag.String("type", "", "type: get/set/del/replace/only_add") + key = flag.String("key", "", "key name method") + expire = flag.String("expire", "", "expire time code") + structName = flag.String("struct_name", "dao", "struct name") + batchSize = flag.Int("batch", 0, "batch size") + batchErr = flag.String("batch_err", "break", "batch err to contine or break") + maxGroup = flag.Int("max_group", 0, "max group size") + checkNullCode = flag.String("check_null_code", "", "check null code") + nullExpire = flag.String("null_expire", "", "null cache expire time code") mcValidTypes = []string{"set", "replace", "del", "get", "only_add"} mcValidPrefix = []string{"set", "replace", "del", "get", "cache", "add"} - optionNamesMap = map[string]bool{"batch": true, "max_group": true, "encode": true, "type": true, "key": true, "expire": true, "batch_err": true, "struct_name": true} + optionNamesMap = map[string]bool{"batch": true, "max_group": true, "encode": true, "type": true, "key": true, "expire": true, "batch_err": true, "struct_name": true, "check_null_code": true, "null_expire": true} simpleTypes = []string{"int", "int8", "int16", "int32", "int64", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "bool", "string", "[]byte"} lenTypes = []string{"[]", "map"} ) @@ -51,6 +54,9 @@ func resetFlag() { *batchSize = 0 *maxGroup = 0 *batchErr = "break" + *checkNullCode = "" + *nullExpire = "" + *structName = "dao" } // options options @@ -88,17 +94,20 @@ type options struct { LenType bool PointType bool StructName string + CheckNullCode string + ExpireNullCode string + EnableNullCode bool } func getOptions(opt *options, comment string) { os.Args = []string{os.Args[0]} if regexp.MustCompile(`\s+//\s*mc:.+`).Match([]byte(comment)) { - args := strings.Split(pkg.RegexpReplace(`//\s*mc:(?P.+)`, comment, "$arg"), " ") + args := strings.Split(common.RegexpReplace(`//\s*mc:(?P.+)`, comment, "$arg"), " ") for _, arg := range args { arg = strings.TrimSpace(arg) if arg != "" { // validate option name - argName := pkg.RegexpReplace(`-(?P[\w_-]+)=.+`, arg, "$name") + argName := common.RegexpReplace(`-(?P[\w_-]+)=.+`, arg, "$name") if !optionNamesMap[argName] { log.Fatalf("选项:%s 不存在 请检查拼写\n", argName) } @@ -122,9 +131,16 @@ func getOptions(opt *options, comment string) { opt.GroupSize = *batchSize opt.MaxGroup = *maxGroup opt.StructName = *structName + opt.CheckNullCode = *checkNullCode + if *nullExpire != "" { + opt.ExpireNullCode = *nullExpire + } + if opt.CheckNullCode != "" { + opt.EnableNullCode = true + } } -func getTypeFromPrefix(opt *options, params []*ast.Field, s *pkg.Source) { +func getTypeFromPrefix(opt *options, params []*ast.Field, s *common.Source) { if opt.MCType == "" { for _, t := range mcValidPrefix { if strings.HasPrefix(strings.ToLower(opt.name), t) { @@ -160,7 +176,7 @@ func getTypeFromPrefix(opt *options, params []*ast.Field, s *pkg.Source) { } } -func processList(s *pkg.Source, list *ast.Field) (opt options) { +func processList(s *common.Source, list *ast.Field) (opt options) { src := s.Src fset := s.Fset lines := strings.Split(src, "\n") @@ -168,11 +184,12 @@ func processList(s *pkg.Source, list *ast.Field) (opt options) { opt.name = list.Names[0].Name opt.KeyMethod = "key" + opt.name opt.ExpireCode = "d.mc" + opt.name + "Expire" + opt.ExpireNullCode = "300" // 默认5分钟 // get comment line := fset.Position(list.Pos()).Line - 3 if len(lines)-1 >= line { comment := lines[line] - opt.Comment = pkg.RegexpReplace(`\s+//(?P.+)`, comment, "$name") + opt.Comment = common.RegexpReplace(`\s+//(?P.+)`, comment, "$name") opt.Comment = strings.TrimSpace(opt.Comment) } // get options @@ -235,7 +252,7 @@ func processList(s *pkg.Source, list *ast.Field) (opt options) { return } -func getKeyValueType(opt *options, params, results []*ast.Field, s *pkg.Source) { +func getKeyValueType(opt *options, params, results []*ast.Field, s *common.Source) { // check if s.ExprString(results[len(results)-1].Type) != "error" { log.Fatalln("最后返回值参数需为error") @@ -352,7 +369,7 @@ func getKeyValueType(opt *options, params, results []*ast.Field, s *pkg.Source) } } -func parse(s *pkg.Source) (opts []*options) { +func parse(s *common.Source) (opts []*options) { c := s.F.Scope.Lookup(_interfaceName) if (c == nil) || (c.Kind != ast.Typ) { log.Fatalln("无法找到缓存声明") @@ -476,6 +493,9 @@ func genBody(opts []*options) (res string) { src = strings.Replace(src, "VALUE", option.ValueType, -1) src = strings.Replace(src, "GROUPSIZE", strconv.Itoa(option.GroupSize), -1) src = strings.Replace(src, "MAXGROUP", strconv.Itoa(option.MaxGroup), -1) + if option.EnableNullCode { + option.CheckNullCode = strings.Replace(option.CheckNullCode, "$", "val", -1) + } t := template.Must(template.New("cache").Parse(src)) var buffer bytes.Buffer err := t.Execute(&buffer, option) @@ -494,13 +514,15 @@ func main() { log.SetFlags(0) defer func() { if err := recover(); err != nil { - log.Fatalf("程序解析失败, err: %+v", err) + buf := make([]byte, 64*1024) + buf = buf[:runtime.Stack(buf, false)] + log.Fatalf("程序解析失败, err: %+v stack: %s", err, buf) } }() - options := parse(pkg.NewSource(pkg.SourceText())) + options := parse(common.NewSource(common.SourceText())) header := genHeader(options) body := genBody(options) - code := pkg.FormatCode(header + "\n" + body) + code := common.FormatCode(header + "\n" + body) // Write to file. dir := filepath.Dir(".") outputName := filepath.Join(dir, "mc.cache.go") diff --git a/tool/kratos-gen-mc/multi_template.go b/tool/kratos-gen-mc/multi_template.go index 214adad76..db02358cc 100644 --- a/tool/kratos-gen-mc/multi_template.go +++ b/tool/kratos-gen-mc/multi_template.go @@ -167,6 +167,11 @@ func (d *{{.StructName}}) NAME(c context.Context, values map[KEY]VALUE {{.ExtraA {{else}} item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}} {{end}} + {{if .EnableNullCode}} + if {{.CheckNullCode}} { + item.Expiration = {{.ExpireNullCode}} + } + {{end}} if err = d.mc.Set(c, item); err != nil { log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key)) return diff --git a/tool/kratos-gen-mc/none_template.go b/tool/kratos-gen-mc/none_template.go index fb7a28353..65ec1de63 100644 --- a/tool/kratos-gen-mc/none_template.go +++ b/tool/kratos-gen-mc/none_template.go @@ -72,6 +72,11 @@ func (d *{{.StructName}}) NAME(c context.Context, val VALUE) (err error) { {{else}} item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}} {{end}} + {{if .EnableNullCode}} + if {{.CheckNullCode}} { + item.Expiration = {{.ExpireNullCode}} + } + {{end}} if err = d.mc.Set(c, item); err != nil { log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key)) return diff --git a/tool/kratos-gen-mc/single_template.go b/tool/kratos-gen-mc/single_template.go index b7a111cc4..850a4ba12 100644 --- a/tool/kratos-gen-mc/single_template.go +++ b/tool/kratos-gen-mc/single_template.go @@ -71,6 +71,11 @@ func (d *{{.StructName}}) NAME(c context.Context, id KEY, val VALUE {{.ExtraArgs {{else}} item := &memcache.Item{Key: key, Object: val, Expiration: {{.ExpireCode}}, Flags: {{.Encode}}} {{end}} + {{if .EnableNullCode}} + if {{.CheckNullCode}} { + item.Expiration = {{.ExpireNullCode}} + } + {{end}} if err = d.mc.Set(c, item); err != nil { log.Errorv(c, log.KV("NAME", fmt.Sprintf("%+v", err)), log.KV("key", key)) return diff --git a/tool/kratos-gen-mc/testdata/mc.cache.go b/tool/kratos-gen-mc/testdata/mc.cache.go index 22bf6e793..ff058c509 100644 --- a/tool/kratos-gen-mc/testdata/mc.cache.go +++ b/tool/kratos-gen-mc/testdata/mc.cache.go @@ -1,4 +1,4 @@ -// Code generated by kratos tool mcgen. DO NOT EDIT. +// Code generated by kratos tool genmc. DO NOT EDIT. /* Package testdata is a generated mc cache package. diff --git a/tool/kratos-gen-project/main-packr.go b/tool/kratos-gen-project/main-packr.go new file mode 100644 index 000000000..7fbe0329b --- /dev/null +++ b/tool/kratos-gen-project/main-packr.go @@ -0,0 +1,8 @@ +// +build !skippackr +// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT. + +// You can use the "packr clean" command to clean up this, +// and any other packr generated files. +package main + +import _ "github.com/bilibili/kratos/tool/kratos-gen-project/packrd" diff --git a/tool/kratos-gen-project/main.go b/tool/kratos-gen-project/main.go new file mode 100644 index 000000000..af27c6ee6 --- /dev/null +++ b/tool/kratos-gen-project/main.go @@ -0,0 +1,76 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/urfave/cli" +) + +var appHelpTemplate = `{{if .Usage}}{{.Usage}}{{end}} + +USAGE: + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + +VERSION: + {{.Version}}{{end}}{{end}}{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if len .Authors}} + +AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: + {{range $index, $author := .Authors}}{{if $index}} + {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} + +OPTIONS: + {{range $index, $option := .VisibleFlags}}{{if $index}} + {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} + +COPYRIGHT: + {{.Copyright}}{{end}} +` + +func main() { + app := cli.NewApp() + app.Name = "" + app.Usage = "kratos 新项目创建工具" + app.UsageText = "name [options]" + app.HideVersion = true + app.CustomAppHelpTemplate = appHelpTemplate + app.Flags = []cli.Flag{ + cli.StringFlag{ + Name: "d", + Value: "", + Usage: "指定项目所在目录", + Destination: &p.path, + }, + cli.BoolFlag{ + Name: "http", + Usage: "只使用http 不使用grpc", + Destination: &p.onlyHTTP, + }, + cli.BoolFlag{ + Name: "grpc", + Usage: "只使用grpc 不使用http", + Destination: &p.onlyHTTP, + }, + cli.BoolFlag{ + Name: "proto", + Usage: "废弃参数 无作用", + Destination: &p.none, + Hidden: true, + }, + } + if len(os.Args) < 2 || strings.HasPrefix(os.Args[1], "-") { + fmt.Fprintf(os.Stderr, "未填写项目名称\n") + os.Exit(-1) + } + p.Name = os.Args[1] + app.Action = runNew + args := append([]string{os.Args[0]}, os.Args[2:]...) + err := app.Run(args) + if err != nil { + panic(err) + } +} diff --git a/tool/kratos-gen-project/new.go b/tool/kratos-gen-project/new.go new file mode 100644 index 000000000..643043edc --- /dev/null +++ b/tool/kratos-gen-project/new.go @@ -0,0 +1,55 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/bilibili/kratos/tool/pkg" + "github.com/urfave/cli" +) + +func runNew(ctx *cli.Context) (err error) { + if p.onlyGRPC && p.onlyHTTP { + p.onlyGRPC = false + p.onlyHTTP = false + } + if p.path != "" { + if p.path, err = filepath.Abs(p.path); err != nil { + return + } + p.path = filepath.Join(p.path, p.Name) + } else { + pwd, _ := os.Getwd() + p.path = filepath.Join(pwd, p.Name) + } + p.ModPrefix = modPath(p.path) + // creata a project + if err := create(); err != nil { + return err + } + fmt.Printf("Project: %s\n", p.Name) + fmt.Printf("OnlyGRPC: %t\n", p.onlyGRPC) + fmt.Printf("OnlyHTTP: %t\n", p.onlyHTTP) + fmt.Printf("Directory: %s\n\n", p.path) + fmt.Println("项目创建成功.") + return nil +} + +func modPath(p string) string { + dir := filepath.Dir(p) + for { + if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil { + content, _ := ioutil.ReadFile(filepath.Join(dir, "go.mod")) + mod := pkg.RegexpReplace(`module\s+(?P[\S]+)`, string(content), "$name") + return fmt.Sprintf("%s/%s/", mod, strings.TrimPrefix(filepath.Dir(p), dir+string(os.PathSeparator))) + } + parent := filepath.Dir(dir) + if dir == parent { + return "" + } + dir = parent + } +} diff --git a/tool/kratos-gen-project/packrd/packed-packr.go b/tool/kratos-gen-project/packrd/packed-packr.go new file mode 100644 index 000000000..aa99f97f1 --- /dev/null +++ b/tool/kratos-gen-project/packrd/packed-packr.go @@ -0,0 +1,174 @@ +// +build !skippackr +// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT. + +// You can use the "packr2 clean" command to clean up this, +// and any other packr generated files. +package packrd + +import ( + "github.com/gobuffalo/packr/v2" + "github.com/gobuffalo/packr/v2/file/resolver" +) + +var _ = func() error { + const gk = "314eeeb23d475df0cf6cd2642a1621a3" + g := packr.New(gk, "") + hgr, err := resolver.NewHexGzip(map[string]string{ + "14b27f88168b4f08f9d703f2a9b5027c": "1f8b08000000000000ffa492516bdb3010c7dff3290ebde42572e384259b200f657d5cc9d614c6564250e55b7cd4d279d2c550d8871f72dd242bdda0ece54efef9eff3fdef04d0614cc4c1809a174b350248183b7298cc0800a0ba7fca00e4ed1e0df8c7f4b331ef8ac5805b8e929e351ae6f3e9c2e430100c1d450e1e839c44d7df365f3eed6ed6ebdbdde7cbcde6ebfae66a1599e528b8fdbeba4c642f36b50dfbdad2f0a2e3e6e0f1ec6f85b9a8d83d60d418243eb64c41340592eabea8069563ef6da80cdc0d0060acb5ab6db44e30ea84a2b3678cab83fc783f9efc21e3a6b1421cce25bb4320c715ee1c8d07f176c835da466a57a37b30c73a82490cdca98fd7576a02aa9fa0ad3c050513d552d867aa751b59d871b312d7aaede96bf2c80731309ba623a420183bdb18284f30a244c294952380d113aa28bdd860cf5edb5e9ee862befc60727883a1bea0760da9c1cef6953ecfbb3f5afa77f31ebdb3aec6eae5157ce67f335196b3b2347d8437f8405773ce49aca47cf8a526002ab87c2e67cb625a4c8bb27fc8a5ffdbe6ef000000ffff0987409f7d030000", + "1769e4a13f3ecbd1dbb3698b5f8cae8a": "1f8b08000000000000ff4ccc310ec2300c05d0d93e859503547611022131710536c4109a0c969aa64a0d5c1f1918b2f9bfafefdb65d6bcd81d618925d399427c4c01616dd5aa479bd68010536a9e643c0c3cf020279151c49bc9f4e5c33d23689afd1446481ae7ab965c9ff61d32972d20b41c53c7e39fdf4d2d77befb391191ffec9a236f013f010000ffff1bfc1755b6000000", + "1794b30bcdd9584d5877963a3cb28504": "1f8b08000000000000ff8c535b6b1b3b107e5efd8a3982046d70b4e7e1701e5cfc10dc10426b3790b62fa504453bab08ebb2c8e3c4c6ec7f2f922f4dd2d2e66159edf25de69b19f54a2f9441685564ccfa3e2602c12aae63205c136715ef3c71c62abeddca596c6f1276763d0cdbad9c2b8fc3d0d8409882728d8f2dbacc30961e56f75247dfdc5b67f3d32c92a2b86cfa8569b4d20fd878f4e5f016420c5dd32ba75a1bde0077d1705633d634268e0d064c8a107600a0181d180c5e33daf408775e4349d0298db06555d380d763385fe066b2c0cd452238cfc8894162d534977c91c86a8742c3be4d72ba7b8fc0b659edffff6a1067a51f720f1e01a61453fd7b035cf736e1a4952dfa78593e5875d1b66fb51b814a042f1d6b1098d21f6c59f51e1dd241bf78fd25d333c181b16e1534ccf16936153508afe1ec305439db1f4aec3d2577f75125d09d8125a595a6fca79a3a8b819e71a73174d6b06a6095ed0a7f02fbe9cb2b24c18f488adef15a7e095ea5e583729f3fcd3e8a53dd99fa5de1fd3381605d714948ab148aa8d73001388accf149e8cec85d1d353b400f01450b67ad8a35dcd8606653a169fdba472f3a93ed8e75b7d26b798b945923383d9a5e13faed07dc8c81f736183e82afcaad700cdfbedf6f0805ef6330bc1e41590645368631fc3bfc9acb45232fb3afc8773614af9bebf955bdab469c3cd6bc0ca12ed95f65db2d82f839e125251b4c56de21a1f3246ffb64037582ab4477272dcf2b9117e047000000ffffe48ced133d040000", + "225361cfe91f8a3ee02db98f64637aa4": "1f8b08000000000000ffa492516bdb3010c7dff3290ebde42572e384259b200f657d5cc9d614c6564250e55b7cd4d279d2c550d8871f72dd242bdda0ece54efef9eff3fdef04d0614cc4c1809a174b350248183b7298cc0800a0ba7fca00e4ed1e0df8c7f4b331ef8ac5805b8e929e351ae6f3e9c2e430100c1d450e1e839c44d7df365f3eed6ed6ebdbdde7cbcde6ebfae66a1599e528b8fdbeba4c642f36b50dfbdad2f0a2e3e6e0f1ec6f85b9a8d83d60d418243eb64c41340592eabea8069563ef6da80cdc0d0060acb5ab6db44e30ea84a2b3678cab83fc783f9efc21e3a6b1421cce25bb4320c715ee1c8d07f176c835da466a57a37b30c73a82490cdca98fd7576a02aa9fa0ad3c050513d552d867aa751b59d871b312d7aaede96bf2c80731309ba623a420183bdb18284f30a244c294952380d113aa28bdd860cf5edb5e9ee862befc60727883a1bea0760da9c1cef6953ecfbb3f5afa77f31ebdb3aec6eae5157ce67f335196b3b2347d8437f8405773ce49aca47cf8a526002ab87c2e67cb625a4c8bb27fc8a5ffdbe6ef000000ffff0987409f7d030000", + "236ab314cd41c9b7b2c5194c0eb72bb1": "1f8b08000000000000ff52567049cdcde7e252565678b970e7f3d9eb9eaf6b78b2bb9bcb508f0b100000ffff24c85b041b000000", + "2f762fe51f2becdb8677b17926a52f03": "1f8b08000000000000ff849141ebd43010c5cf994f3116947629cd41bc547a58456ffe1156f09c4d67b361db244cd3ee4ac97797b4ab82081e8696c7bc97df6382d23765087b0b60c7e0396209a2d0de457ac4024411ed48058028d6b5f9e2fbaf4c17fb48695d9b1735524ad2ba48ecd42027e2c5ea7dd9d8789dcf8df6a33cdbc1e6913756d14f32dc8c1cbc29febfe5284a0e5ade15f7e40aa800a434be35e4885524bc5b26883f02e131049c22cf3ae20a625a341e9e38cd69ff82301c341ef6b04d25860470999dc617ba1f4328ff65acd1fce5aab05421e0e118428d7af0137dce1939a8ac6a24e63c9eab15445eecf0cd31841544066b715a740d62c369d1d42012883f29dd3327f7103a3e6ad4ca691ab0edf07996e6bb8dd76f76243fc7f297f641e99b613fbb3e33bc7d77c8876b4ea4bdeb2b10c25e36b0b643d39cae73ecfddd953a3eaaf79bfeaa436787ed513178d37cca05ca22439e78f9edd88b95af97aad88ae6e4b4176b3ee60e655676e2fc9b4030c5991d24f8190000ffffb30c321d6c020000", + "33550cc0d0a7c442ee2f7ef103747430": "1f8b08000000000000ff94525d6b1341147deefc8acbbe34817697ea5b421ea4162a88865a9f44c26473b35ddddd99ce4c164308d454a84a35554a4b3f1eaa54e98bad20546a2dfd31c926e9bf90d9ec2682ed83f3321ff79c7bce3dbb9605d1f16ef7eccdd5a7b3fede31dc29de83feee2be0822906bdadb5eef92944ed93eef9976863bdb77dda6bb70797dfc15928ce42f4711de617178b9a452c6b482ad7aa092f6ab7062bab395d816958528acb9c655530448f7114d27418733c346de65b31d566de74b956ada2901691f540d117500023aedd36f284b83e674281e1b86aa9568e890e7398950ac7b7f8129fccf868e4c7bc58700c479fabfa4d28ca5d8b06015354b92c9023583c29b59f530721fa70116dbceb5e5cf6378fa04139772b4db311a2902e0b9a3ac9ded659f4bb3d05c91b44179fa3af2d0867a620bc05a649d25615f499295184ae8d663833d479f070712e07bdfd9568e3fde0e467f4fae06ae77070b9d3fdb5d7db3ee86f1e69851f47576b6f21d369ed4f775afbd9cecbc3ceea372084716d1c1c564a350a6050ee1af9b49419e565267bc941a550c812f5bc2c14a04a3d897942126370177d060d020020b80d45377020937ec83457734ee79a0581aa26027923204f26749347b43e8f9ec720136f0bb8fcdfd4c70bf7af23274f926713cf7a8d678f1b53ee9afadfd4d38e417a39a8728645cbb62569bdb4a47b192340334f92ad49888f52ea7c530bd0201352091d4e407d9dfb0c3cf92b6c9f0954d491d9c26495093f6768940121f5dc0a559833042ed75c811563f2e9750292275613915916280cd43f3acf240b1475f46893f610336cf8270000ffff68dc4476f7030000", + "336d416ed5faa95a29de7b6afd385568": "1f8b08000000000000ff9452c18adb30103d6bbe626a285890daf41a9a43296d37870d69939ccb441e3b4364c94832ddc5f8df8b9ca56c4a0fedc1467af39ee6e98d063257ea187b120720fde043c21254d15aea0a50858fb77f1da57364f3263e4743765926e9b90050c534558fbed9076ee5699ea7a9da51cff35c8b4b1c1cd9ba91ccef245dc673657c5f9fc54afeea6ba0e4633d5cbbda78d7d603596ac4fd03ddfaae000dd08ece2c3728354ea0b2f56a4f2172a94159df555b27a9746235d635367c1e3bcca435e6622361330d942e33a8865b0e0bfac9fad7fad697059d0dc64421151ad48bcbdbd11ad48f159a2cf9323ab3420e01d71b6c64a97f1c864c9176c1df6cd089cd46d5404e4cc9216850332893353d5db9341772e8637558425fe17b0dea36806ae793b4cfa559e1cb1caac3f6ebc3697fb7ff76da1eef80e3e7ef8f77c07677d4a05a1f16233177fef0ce807a75df8e1312dedae2db58ac30568714c475a5d659f45392b9605c4e3014f9bf1dac4129f53bb69c91fa236f7e92256ea5f253ab0e9679286f4b36de354b29701a83fb8b8987d33eb768b8a5d1a6f51d77ce91cff02b0000ffff37cebd8001030000", + "348f254eb8f48eaf3d0330c83c18324c": "1f8b08000000000000ff9451c18ea3300c3de3afb038255d44be600fedf6b28756d5767f2010173c85240aa18c84f8f711d0a9462355ea9c78f8bd3cdbcf4ae1afa2e7c6e0c081d8be51194129fc5f13aef5a82b6cf5953aecfa40186bc22ef6057287d6c5451491ed425cd8ea667d9703785d5e75456818805bef424401892f301dc7fce0cc29d085dfa7691cf3a36e699a94f69c42f294661b2958dd28a3dd4bba8ec28d82aa822f7fa2af63f42febb9a41420492b8e755fe4a56b55e55cd5909a134d4102dc7440a3dd29b81b1b0af87b093b3fd270a6288c7633ccf00ef6bb07fc4786bbc7dfe18f5cacee5d9fd8ddd9d57221766c8db034085fe47b6add79d9526638d7369ffaf3fa9552025c7a5be25fcb71ebbd9028365bef339cab42664821b8207184c46bcba5589bcc47175fb6ccbecf99e19ceb3ad77c91151d69d87a2f254cf0110000ffffb4884e698c020000", + "359dcf82ea381d6901e53f88ff235896": "1f8b08000000000000ff94525d6b1341147deefc8acbbe34817697ea5b421ea4162a88865a9f44c26473b35ddddd99ce4c164308d454a84a35554a4b3f1eaa54e98bad20546a2dfd31c926e9bf90d9ec2682ed83f3321ff79c7bce3dbb9605d1f16ef7eccdd5a7b3fede31dc29de83feee2be0822906bdadb5eef92944ed93eef9976863bdb77dda6bb70797dfc15928ce42f4711de617178b9a452c6b482ad7aa092f6ab7062bab395d816958528acb9c655530448f7114d27418733c346de65b31d566de74b956ada2901691f540d117500023aedd36f284b83e674281e1b86aa9568e890e7398950ac7b7f8129fccf868e4c7bc58700c479fabfa4d28ca5d8b06015354b92c9023583c29b59f530721fa70116dbceb5e5cf6378fa04139772b4db311a2902e0b9a3ac9ded659f4bb3d05c91b44179fa3af2d0867a620bc05a649d25615f499295184ae8d663833d479f070712e07bdfd9568e3fde0e467f4fae06ae77070b9d3fdb5d7db3ee86f1e69851f47576b6f21d369ed4f775afbd9cecbc3ceea372084716d1c1c564a350a6050ee1af9b49419e565267bc941a550c812f5bc2c14a04a3d897942126370177d060d020020b80d45377020937ec83457734ee79a0581aa26027923204f26749347b43e8f9ec720136f0bb8fcdfd4c70bf7af23274f926713cf7a8d678f1b53ee9afadfd4d38e417a39a8728645cbb62569bdb4a47b192340334f92ad49888f52ea7c530bd0201352091d4e407d9dfb0c3cf92b6c9f0954d491d9c26495093f6768940121f5dc0a559833042ed75c811563f2e9750292275613915916280cd43f3acf240b1475f46893f610336cf8270000ffff68dc4476f7030000", + "39a955dfabc5df68502b59574724045e": "1f8b08000000000000ff5256567049cdcde7e2525656562833d433d033e032d45378b2a3ebf9aefd4fbbe6bf68de5b5151c105080000ffff79fbc41327000000", + "40aa45750f8397d706e3d8fdd82fa11f": "1f8b08000000000000ff5ccc410a02310c85e175728a210728ad8283822bafe04e5cc4268b40673a74a25e5f2a0832cbff83f76e97623afb1d61e64987f340fcc884b0b4eab5a7e7851058a4f54abb31c410433a1df6e391104c4a5fa588c0d9edf50b312e579bb43efdbb5b09a129cbd6decd5cb7d84fff2dae849f000000ffffe1039f77a9000000", + "43befbfad04c8efdf57be993ceb9e432": "1f8b08000000000000ff8a0e4e2d2a4b2d8ae552505050484c492952b0555032d003432b4b03030325b04c49666e6a7e690948d2b058890b100000ffffb9f9177936000000", + "46713bf4406bd2896c32e5778efb1eb5": "1f8b08000000000000ff8c53516e133110fdb64f31b144e54591f7bf281fd0464140d3aa69c527f23ab3bb56bcf6e2f5a691a21c831b803800df1ca79c03d9bb698b2a041f96ecf1cc7bf39ec7ad541b5921d421b494eaa6753e00a784590c790c324a495b00dbefc5855b5f792cf5ee70d8efc552367838e4b2d58c92bf5e6b1bd05b69f2c6add1c4cc4a87ba2f84724d5e68a3e3ca375e06d7e5eda6ca95b365de4a23d7dafe47ba7115a3a468e05f89473d7961e41a1bd905f48c66946ea5876eaba02dc439366e857e8b9ed23c8725de81c53b905034d0a5b8a0656f55bce1dd9f151970b495b6082f8b46ccd3760ae87d5cce67b0a72452714a48ada00bbe57210609190052ddb03d73b6d41525e4404946892e13ce0c465bc4020367518c08ae312c13b7b691beaba5b9b9bcf8c04f6a95bd4a259319586d12cb08327944997bbf7461bed3ddd887c7d07b3bd09281d16a43e3311a34838e9251e30c8a469c63297b13869e79adc6eeb33830e21a2b1d3d8e0ebdb9187370b4a58baaac0ed7ae0f0fe18c8ea4c351ac82f48167f4d8d7810ee63f2d7c62767218c595b6156fb5ad324a2a389d018a85777dcb592e0bc5324aa2d64a2ce6379ce55de46053a8dddd8d4b8459d47ba48a385c855da2397336e02e241e5dc2a7e1754f67717a065a1576d368d973f78daba2dfce7316318799e02fb6194b28192544859d785d381f3eea50af820c7dc7d31b0ffbe8a056786be5566a230b83c74ef31c70279bd62094cea79f0c1e3ff7d805a8a55d9b87b17d54c9d533499b28e5247d53f13efd9bd8f85b34c69d025b38236d05f75fbffffaf1e5fedb4f984c266c9a66438977abcb25df0cd2e9e177000000ffffb265211b53040000", + "468e50d126ac1e7c1a9ea44dde207990": "1f8b08000000000000ff8c53516e133110fdb64f31b144e54591f7bf281fd0464140d3aa69c527f23ab3bb56bcf6e2f5a691a21c831b803800df1ca79c03d9bb698b2a041f96ecf1cc7bf39ec7ad541b5921d421b494eaa6753e00a784590c790c324a495b00dbefc5855b5f792cf5ee70d8efc552367838e4b2d58c92bf5e6b1bd05b69f2c6add1c4cc4a87ba2f84724d5e68a3e3ca375e06d7e5eda6ca95b365de4a23d7dafe47ba7115a3a468e05f89473d7961e41a1bd905f48c66946ea5876eaba02dc439366e857e8b9ed23c8725de81c53b905034d0a5b8a0656f55bce1dd9f151970b495b6082f8b46ccd3760ae87d5cce67b0a72452714a48ada00bbe57210609190052ddb03d73b6d41525e4404946892e13ce0c465bc4020367518c08ae312c13b7b691beaba5b9b9bcf8c04f6a95bd4a259319586d12cb08327944997bbf7461bed3ddd887c7d07b3bd09281d16a43e3311a34838e9251e30c8a469c63297b13869e79adc6eeb33830e21a2b1d3d8e0ebdb9187370b4a58baaac0ed7ae0f0fe18c8ea4c351ac82f48167f4d8d7810ee63f2d7c62767218c595b6156fb5ad324a2a389d018a85777dcb592e0bc5324aa2d64a2ce6379ce55de46053a8dddd8d4b8459d47ba48a385c855da2397336e02e241e5dc2a7e1754f67717a065a1576d368d973f78daba2dfce7316318799e02fb6194b28192544859d785d381f3eea50af820c7dc7d31b0ffbe8a056786be5566a230b83c74ef31c70279bd62094cea79f0c1e3ff7d805a8a55d9b87b17d54c9d533499b28e5247d53f13efd9bd8f85b34c69d025b38236d05f75fbffffaf1e5fedb4f984c266c9a66438977abcb25df0cd2e9e177000000ffffb265211b53040000", + "470fd5cab5c7a57cec62609827d2c84f": "1f8b08000000000000ff8a0e4e2d2a4b2d8ae552505050484c492952b0555032d003432b4b03030325b04c49666e6a7e690948d2b058890b100000ffffb9f9177936000000", + "473893d607815c5c27cec94e0e78e437": "1f8b08000000000000ff52567049cdcde7e252565678b970e7f3d9eb9eaf6b78b2bb9bcb508f0b100000ffff24c85b041b000000", + "48e53a59007a8dda61d904d989943a09": "1f8b08000000000000ff5ccdc14ec3300cc6f1f3fc143ec2614e9c32525e827748db6022927964c98434f5dd51e15238f862fdfefa8a2e3d47bcdfe93594b8ae00a2c8c40ea0c6cf9e6ac407404494d4defb44b31633a59cb6331f3534bd6209d7162b1c764454d45caa369dfa1bde981cf13f90c359fe90811c1c7effa455cc9739c786374b96ecd1597eb1cf6ee4f1343c9d8e4be0c1cf7ef4bcf82d52c99176add4cbfc33ebc8c2237c070000ffff34bdd5b6e6000000", + "49d0cdb7406397b8e77616d290bcd94f": "1f8b08000000000000ff5492b18ed4301086ebcc530c96901294b5fb95b65836cd35b72be005bc5ec7589b782c674240e80a3a4a0a7a90780c5e0771af81622f3a5d916226ffffcdf8b7a33657ed2ceae8c18f9112630d953014d87e640195e847160095709edfcf67696854673ff8f553d7a4992615af4e05cb2a45a3169d2e361407911bac7434e8e02425a75c8a464003a014ee63bceb5082a130f1addaa17877ec8e5bdc771dee4f27bceb4416dfdbe530781b18835d70c5a0c935f473304fbf6bd33b7c557690a575a0d07bd722459e504ab99a65e7f5708cec2934587776a4a26dd1a644a9c1cf50153e6e7778c33d1b527852ca062a63b26f951653c6d7b70ce56b6dae2ed11c2e75d3623fb27c1b930fdcd7e2e227431f6cfab455ea627b3d0fac5e4ea22d71340d54becfe8173b0c7e58d7aa92e53985b5cc53a17a80ffbd7bbb3c9da536a66957193ce4081fbffff8fbf51bba37a703fef9fdebf1e71750cad1d6d96093668be5329189068c89980c6e3639eacde63cae2f44e636fc0b0000ffff940f602534020000", + "4ee76ca4d3f34ada842b90d87762fe26": "1f8b08000000000000ffbc91bd4a04311485ebe429428a416118333fa82c04052dc546bbc5229b5cd9c0fc7973e32ac3bcbb44071dabadb4ca395fc2e1836c6f5a0f3d3d71669c43a1852cab8b4215aa283775adce25672ef4894f3100ce9b6934211c0674f335d9f1e4f7ebd3b3c919323b1360be22dfc1104997214330eef1a71ed013acfa68307c764d18216b07abef066bdacceed30de948cf97ddaec9d329394b73b70ff7428bed11adeaffb4f2232af59fabe48b8f4cbf69c9bf82d0a2529c79d7a6582e71d9155a367bc9d94b047cff6642564a754172066f6057b85e30a1e957b8f9c21f010000ffff57d7944148020000", + "518b74b34be782fd3abced06105dfdf1": "1f8b08000000000000ff5256567049cdcde7e2525656562833d433d033e032d45378b2a3ebf9aefd4fbbe6bf68de5b5151c105080000ffff79fbc41327000000", + "532d363951d4f0d0c18e620c67cb7b40": "1f8b08000000000000ff94924d8fdb2c1485d7f02bae2cbd919d3782fd48594d2b75914ca34c475d5f63eca0606030ee24b2fcdf2bfc91499ba61f0bb004c7f79c877b1d8a2356121ae9bf29212955b5b33e404a4922ac09f214124a92b20e09a5c4e590741ddbda62e765a94e7ddf75ec096bd9f71c9d8aca7bd7ca04e90d6a5ea08dba4a85439b33616b9e2bade2e2478fc136dc1d2b2eac29b9438d8532d1f95a5f598da6e2cedb60f3b6e42e9c9d6cb8ac5d382734a39473781e79662e46a3e6fd34f85604e8284101b09c7cd8161d25055a28d0b20f68693fd47a926f60e41be05c0dd014e06568bd61b46c8d8892b4987fcb206d603979ad407a1f97f559346c600d8be9aea384a0780058cc09be7cde6eba7e45498cf100c58a929e9258610db3e62b06714813744e2b814159c382ad75b28286a1c82819934de19ff1fc496a6da1f24e40216b0b31f194fb2a687691a6229c606a3e7b1cbf2bf0f215962e6783642f5f3348bd74fa0ccbe1e1d9c7b8ff4c3b2ad6f1f9d22b5946495907b6f3ca84324d0e43c0ff9a64701926e61ec6cb7e0379fd771c2ffbcdbfa2bc1f36ee1ecbe25a145b38d435e101269004febf708c0dbc856dbdfe3df04e990a5cdcc24182978d6d7d9ce35bdca8fc35a7fca13719a437adbaa04567585c5d777d9ca738d173fd6c4af6a86d23410cfb9fb20dda741cfca1d874407bfa3d0000ffff0c06c20f7a040000", + "56d831af18f731847e4733aa321128cb": "1f8b08000000000000ff84914fcb9c3c14c5d7b99fe2bec25b74906451bab1b89896a7bb3e14a6d0758c77348c26215e9d29e2772fd1e99f45a18b8b7239e7e477b8419b9bee085b0b60c7e023630e2233de313d380391b11d290310d9bacacfbefd12e96a1fdbb6aef2558fb46dca3aa6e8f4a0268a8b3587b8b3dccf8d347e548d1d6c1a758b9afda4c2ad5383ef3210cd88ff123a62d53307d50cbaa5514f4c31830240a9ce571d398a9a09ef3612f0f740780e01278eb3615c414c8bc1d3934b5e8e2f881488a766942faeb38e6003b8cecee02bddcf21e47f3395d8ffe12830d721e0e91c428966f0137d4afe14921725528c697c2c56104958e39b73082b880454e1b49812c48e51615f82d840fc4ea99f39895f187e9468b433346055e3f32ef29be5feab1dc9cf9cffdc7dd0e6d6453fbb3631bc7d774a97931732deb5050861af3b5855632f2ffdccadbfbbdcf0a378bfefffabd1d9617f540cbe932fa9409e25c84b5c7e398e62f9ff4b91ed4553f27614931f53873c6d0ee2f4bb8188c47374b0c18f000000ffffadf6f33a6d020000", + "5d243c2aa906cb9527df41e508cda83d": "1f8b08000000000000ffa492516bdb3010c7dff3290ebde42572e384259b200f657d5cc9d614c6564250e55b7cd4d279d2c550d8871f72dd242bdda0ece54efef9eff3fdef04d0614cc4c1809a174b350248183b7298cc0800a0ba7fca00e4ed1e0df8c7f4b331ef8ac5805b8e929e351ae6f3e9c2e430100c1d450e1e839c44d7df365f3eed6ed6ebdbdde7cbcde6ebfae66a1599e528b8fdbeba4c642f36b50dfbdad2f0a2e3e6e0f1ec6f85b9a8d83d60d418243eb64c41340592eabea8069563ef6da80cdc0d0060acb5ab6db44e30ea84a2b3678cab83fc783f9efc21e3a6b1421cce25bb4320c715ee1c8d07f176c835da466a57a37b30c73a82490cdca98fd7576a02aa9fa0ad3c050513d552d867aa751b59d871b312d7aaede96bf2c80731309ba623a420183bdb18284f30a244c294952380d113aa28bdd860cf5edb5e9ee862befc60727883a1bea0760da9c1cef6953ecfbb3f5afa77f31ebdb3aec6eae5157ce67f335196b3b2347d8437f8405773ce49aca47cf8a526002ab87c2e67cb625a4c8bb27fc8a5ffdbe6ef000000ffff0987409f7d030000", + "5d2e61f4f8ab5957f172a990d9fb3baf": "1f8b08000000000000ff5256702c2dc9c82fe25256084a2dcb4c2d4f2de202040000ffffbe75c21514000000", + "5e8471dec0685b7154cd71dcf0444643": "1f8b08000000000000ff94525d6b1341147deefc8acbbe34817697ea5b421ea4162a88865a9f44c26473b35ddddd99ce4c164308d454a84a35554a4b3f1eaa54e98bad20546a2dfd31c926e9bf90d9ec2682ed83f3321ff79c7bce3dbb9605d1f16ef7eccdd5a7b3fede31dc29de83feee2be0822906bdadb5eef92944ed93eef9976863bdb77dda6bb70797dfc15928ce42f4711de617178b9a452c6b482ad7aa092f6ab7062bab395d816958528acb9c655530448f7114d27418733c346de65b31d566de74b956ada2901691f540d117500023aedd36f284b83e674281e1b86aa9568e890e7398950ac7b7f8129fccf868e4c7bc58700c479fabfa4d28ca5d8b06015354b92c9023583c29b59f530721fa70116dbceb5e5cf6378fa04139772b4db311a2902e0b9a3ac9ded659f4bb3d05c91b44179fa3af2d0867a620bc05a649d25615f499295184ae8d663833d479f070712e07bdfd9568e3fde0e467f4fae06ae77070b9d3fdb5d7db3ee86f1e69851f47576b6f21d369ed4f775afbd9cecbc3ceea372084716d1c1c564a350a6050ee1af9b49419e565267bc941a550c812f5bc2c14a04a3d897942126370177d060d020020b80d45377020937ec83457734ee79a0581aa26027923204f26749347b43e8f9ec720136f0bb8fcdfd4c70bf7af23274f926713cf7a8d678f1b53ee9afadfd4d38e417a39a8728645cbb62569bdb4a47b192340334f92ad49888f52ea7c530bd0201352091d4e407d9dfb0c3cf92b6c9f0954d491d9c26495093f6768940121f5dc0a559833042ed75c811563f2e9750292275613915916280cd43f3acf240b1475f46893f610336cf8270000ffff68dc4476f7030000", + "64f157c0a5aaef8684ce174785fdb08b": "1f8b08000000000000ff5256702c2dc9c82fe25256084a2dcb4c2d4f2de202040000ffffbe75c21514000000", + "65c9c5ceead4379a32ef56fe8044a9a7": "1f8b08000000000000ff8451cb8adc30103cabbfa2f121486191be604ec9924b7612f2f8008da6ed15634ba2255b0bc6ff1e641b1672d9435fbaaabaaae864ddc30e84032707e0a714b9a004916ed8adab7e89f79f4cbd7fdbb675d5573bd1b6199b7c0720bac197d7f9a65d9ccccd8fbe8d79b02d319bf4188c8ba137c98ef6ee43f7313d50319c9ca996ef143a5000c6e0952a06aa68f784988917620dfd1c5cc3645e1ca69bfe4a53fcbd630a65cdf8f9b8a28fdd1312739bc80a57108b656487b9f0ec4a5b8883f79fec4b0cbd1f406c209afe826719fd8d8aec5a1e5de234764aff0d93e5fc6ac73f3f5ebecb4fec1408dfefae9777d933f33596e7379f0fd3e368f0e36e51335ef0f4bf523d2248766718d57ea27fd1e073217eef2b6b3e19523d615e9a75cd47e30b36b0582e5281602a3307d8e05f000000ffff90051aa3f4010000", + "6640f2771831eddce9f1132a8ffa02b1": "1f8b08000000000000ff8c90cd8adb3010c7cfd6534c75285258a44be9a5e4d0dd855e36e9f7038cf515115972e4719362fceec58e0ba5a73d0c0231bff97ff468ce181c582c8cc5ae2f9540b0869b92c9dd8833d6f069528762bf54e7e36d9ea7491db173f3ac6326573326dd15eb12670d0f914e63ab4ce9741b535c469f2b5219747f0eda94ec758f096dccaf58b748d8e2e0f470499c49c6fc980d1cddf5f9514810b685dd7049eaf9f1015cadcb942a6162cd2fac607c8081ea6868f9699e527499eec053c93e06d6ccac897e45f7b0b9529f1c096e5b45a54b5caa9fb9c33a9c30fdf87c78116f8d0ff2c34abcd9438e693d5d1d8d35afe76c0b7b58248eee7af8fdfdeb8b303ea8bbb6647f37e72d89b0b0b358247cc3ebc74ad124270cdd60eb7ef1b9bc0f102dc44cefdf49105809766bdf6a43fe0faf350447b09407be960e6cfb8ff29f000000ffffed2515fbf0010000", + "676482aadd24e9539226c67ebd8b5d04": "1f8b08000000000000ff8c90cd8adb3010c7cfd6534c75285258a44be9a5e4d0dd855e36e9f7038cf515115972e4719362fceec58e0ba5a73d0c0231bff97ff468ce181c582c8cc5ae2f9540b0869b92c9dd8833d6f069528762bf54e7e36d9ea7491db173f3ac6326573326dd15eb12670d0f914e63ab4ce9741b535c469f2b5219747f0eda94ec758f096dccaf58b748d8e2e0f470499c49c6fc980d1cddf5f9514810b685dd7049eaf9f1015cadcb942a6162cd2fac607c8081ea6868f9699e527499eec053c93e06d6ccac897e45f7b0b9529f1c096e5b45a54b5caa9fb9c33a9c30fdf87c78116f8d0ff2c34abcd9438e693d5d1d8d35afe76c0b7b58248eee7af8fdfdeb8b303ea8bbb6647f37e72d89b0b0b358247cc3ebc74ad124270cdd60eb7ef1b9bc0f102dc44cefdf49105809766bdf6a43fe0faf350447b09407be960e6cfb8ff29f000000ffffed2515fbf0010000", + "6cc24b961eaafa6a5726c5e875dd92ae": "1f8b08000000000000ff4ccc310ec2300c05d0d93e859503547611022131710536c4109a0c969aa64a0d5c1f1918b2f9bfafefdb65d6bcd81d618925d399427c4c01616dd5aa479bd68010536a9e643c0c3cf020279151c49bc9f4e5c33d23689afd1446481ae7ab965c9ff61d32972d20b41c53c7e39fdf4d2d77befb391191ffec9a236f013f010000ffff1bfc1755b6000000", + "7a53e746d0de690c8b20ca83292508c5": "1f8b08000000000000ff8a0e4e2d2a4b2d8ae552505050484c492952b0555032d003432b0b03030325b04c49666e6a7e690948d2b058890b100000ffffb7699cdc36000000", + "80a49866e2154ebe00c57fd7c80a4cab": "1f8b08000000000000ff8c51416e8330103cb3af5871b253845fd043d25c7a481435fd80c11bb20dd89631a112e2ef15904655a54839793d339edd1d2b852f45c7b5c19e03b1fda2328252f879265cf0a82b6cf4855a6cbb4018cf846dec0ae416ad8bb32822db9938b1d5f5f22e07f0babce88ad0300037de858802125f603a0cf9ce9943a0137f8fe330e47bddd0382aed3985e421cd3652b0ba5646bba7742d852b0555055f3eade792528024ad389ebb222f5da32ae7aa9ad494500a12e0aa031aed0ec15dd950c0d739bc7c4ffd91a230da4d6586b762bbb9971f64b8bddf766f72b6ba757d60776317cb99d8b035c2522f7c916fa971c7794b99e184ad7ef5c7e59452029c3a5be2bbe5b8f65e4814abb5f7194ea8901952082e481c20f1da72299626d3278a3f5b66ffe7cc70ca75996b4ffdda7b2961849f000000ffff98b3536b52020000", + "885a5148286f0720126cd2a540b56564": "1f8b08000000000000ff4ccc310ec2300c05d0d93e859503547611022131710536c4109a0c969aa64a0d5c1f1918b2f9bfafefdb65d6bcd81d618925d399427c4c01616dd5aa479bd68010536a9e643c0c3cf020279151c49bc9f4e5c33d23689afd1446481ae7ab965c9ff61d32972d20b41c53c7e39fdf4d2d77befb391191ffec9a236f013f010000ffff1bfc1755b6000000", + "89e787ea2b6d77d3061b5e56a50c6e36": "1f8b08000000000000ff8c91cd6ae33010c7cfd653cc0a769182911f60c9291bc2c26e1a9af45c14595244648d91e53450f2ee45b25328bde42004c3ffe3374c2fd5595a0dad44425cd7634cc048451586a4af89125251ebd2693c0a855d7374dee5d79ca34c3834fdd9364aaa936ea26edd401f5063304d2fbd6c5d7840eed152c209316350b0d56fcfb98671601116a55294490d3ac6fc30727827d5454650c6c290e2a8529e542bef744877d70a8371965437523953cc4b98a9c44627462759c2ce532e5e4227e37092fef0f4ff1ffba58ce5bf8be9c71282f3253fea34c6501273d8e4ff2456c68a898093bbf436afc55a58b41239ec5cb0b33c5d613e4146cd3f07f6754767e0b59ed15b31f5fdc16cad81eed7075a03ed5db0e5c760e977668f56ac7320cb070f62af13dbfddd6ef854c37e5e382d157cda6be6fe080000ffffb73c6a1735020000", + "8f2519501a642ae50acf464ad3acb9f9": "1f8b08000000000000ff8c51c16eab30103cb35fb1e264e721fc05ef90bc5cde2151d4f4070cdec036605bc6844a887faf8034aa2a45cac9eb99f1ecee5829fc53f4dc181c3810db0f2a232885ef35e18a475d61abafd461d707c2581376b12f903bb42e2ea2886c17e2c25637ebbb1cc0ebf2aa2b42c300dc7a17220a487c81e938e607674e812efc394de3981f754bd3a4b4e71492a734db48c1ea4619ed5ed275146e14541da37f59cf25a500495a71acfb222f5dab2ae7aa86d49c500a12e0a6031aed4ec1ddd850c0bf4b78f99186334561b49bcb0cefc57ef728dfc870f7b81dfec9c5eadef589dd9d5d2d1762c7d6084b83f045bea7d69d972d658633b6f9d69fd7534a0970e96d89ff2dc7adf742a2d86cbdcf704685cc90427041e20889d7964bb136993f51fcd832fb3d678673aeeb5c471ab6de4b09137c050000ffffe1cf2bb052020000", + "959fd518960ea8b397538a6f7b1bdd3a": "1f8b08000000000000ffe2525608c9c82c56c82c56485408f1f7f55148c94f2ecd4dcd2bd15370cacfcfade34a49cdcd77ad28c82c4a55b055503232c950e202040000ffffc36ed62935000000", + "95d28ebee82ae43dfc0c8b16b6088b2d": "1f8b08000000000000ff5ccdc14ec3300cc6f1f3fc143ec2614e9c32525e827748db6022927964c98434f5dd51e15238f862fdfefa8a2e3d47bcdfe93594b8ae00a2c8c40ea0c6cf9e6ac407404494d4defb44b31633a59cb6331f3534bd6209d7162b1c764454d45caa369dfa1bde981cf13f90c359fe90811c1c7effa455cc9739c786374b96ecd1597eb1cf6ee4f1343c9d8e4be0c1cf7ef4bcf82d52c99176add4cbfc33ebc8c2237c070000ffff34bdd5b6e6000000", + "97e4f2cf9f4ad4fc842f20a7fb124f91": "1f8b08000000000000ff94924f8bdb3010c5cf9a4f3135b4d8c14887d28b4b0e69d9deba1452e859916765115b12f2d84931feee454efa97c2b687c1c3f0e6e7f7c68eda9cb5256c1d801b62488c2588c204cf74e50244c16ea0024014cb223f86f653a227775dd765918f7aa07555ce3325af7b35529a9db989ade36e3a4913067572bdcba5ce497318553c5bd5075b80380df89cd013ab8e39aa53af5b1af4c8948ae7f9792d45a32e3ab5e40ba80094b2a1b1e4296926bcb844c05f23e121461c394d86710131ce0677f720f2787b82c80e70771ae483b7ce13089ba2c1dd8dbec928c10af03479838f7439c458fe8d5463f70ba646fb07a3c252c788bb438c359a3e8cf4211333b6ac6aa4947285542d20b2708faf0e312e20b2ef06c7d9d42036b70d76b9cd3e1bb4358815c44fe0fe8ecc8985e16b8d467b433d367bbc7f7af9c571f7d90d14262ebfcfde6973b6294cbecd765ebfd9e59f431ec904df5620847bda3c367bb4f2d84ddc868b2f0d5fabb7dbfcc51ebdebb7978a3e58f990b3944536794cf38f8d5bc6f2e55c155be64c5e7fa377ff41cfd7f817fa381bf93e5fa8cc93db3d72bb8248c453f2b0c2b7000000ffff73be5e8b2e030000", + "984dd6df0bfb1684d6d188b40962ca7b": "1f8b08000000000000ff8451cb8adc30103cabbfa2f121486191be604ec9924b7612f2f8008da6ed15634ba2255b0bc6ff1e641b1672d9435fbaaabaaae864ddc30e84032707e0a714b9a004916ed8adab7e89f79f4cbd7fdbb675d5573bd1b6199b7c0720bac197d7f9a65d9ccccd8fbe8d79b02d319bf4188c8ba137c98ef6ee43f7313d50319c9ca996ef143a5000c6e0952a06aa68f784988917620dfd1c5cc3645e1ca69bfe4a53fcbd630a65cdf8f9b8a28fdd1312739bc80a57108b656487b9f0ec4a5b8883f79fec4b0cbd1f406c209afe826719fd8d8aec5a1e5de234764aff0d93e5fc6ac73f3f5ebecb4fec1408dfefae9777d933f33596e7379f0fd3e368f0e36e51335ef0f4bf523d2248766718d57ea27fd1e073217eef2b6b3e19523d615e9a75cd47e30b36b0582e5281602a3307d8e05f000000ffff90051aa3f4010000", + "a17964c54f014a0dd59c42b49123a941": "1f8b08000000000000ff5492b18ed4301086ebcc530c96901294b5fb95b65836cd35b72be005bc5ec7589b782c674240e80a3a4a0a7a90780c5e0771af81622f3a5d916226ffffcdf8b7a33657ed2ceae8c18f9112630d953014d87e640195e847160095709edfcf67696854673ff8f553d7a4992615af4e05cb2a45a3169d2e361407911bac7434e8e02425a75c8a464003a014ee63bceb5082a130f1addaa17877ec8e5bdc771dee4f27bceb4416dfdbe530781b18835d70c5a0c935f473304fbf6bd33b7c557690a575a0d07bd722459e504ab99a65e7f5708cec2934587776a4a26dd1a644a9c1cf50153e6e7778c33d1b527852ca062a63b26f951653c6d7b70ce56b6dae2ed11c2e75d3623fb27c1b930fdcd7e2e227431f6cfab455ea627b3d0fac5e4ea22d71340d54becfe8173b0c7e58d7aa92e53985b5cc53a17a80ffbd7bbb3c9da536a66957193ce4081fbffff8fbf51bba37a703fef9fdebf1e71750cad1d6d96093668be5329189068c89980c6e3639eacde63cae2f44e636fc0b0000ffff940f602534020000", + "a2cb44570c3d3285165729786d5f1def": "1f8b08000000000000ff9452c18adb30103d6bbe626a285890daf41a9a43296d37870d69939ccb441e3b4364c94832ddc5f8df8b9ca56c4a0fedc1467af39ee6e98d063257ea187b120720fde043c21254d15aea0a50858fb77f1da57364f3263e4743765926e9b90050c534558fbed9076ee5699ea7a9da51cff35c8b4b1c1cd9ba91ccef245dc673657c5f9fc54afeea6ba0e4633d5cbbda78d7d603596ac4fd03ddfaae000dd08ece2c3728354ea0b2f56a4f2172a94159df555b27a9746235d635367c1e3bcca435e6622361330d942e33a8865b0e0bfac9fad7fad697059d0dc64421151ad48bcbdbd11ad48f159a2cf9323ab3420e01d71b6c64a97f1c864c9176c1df6cd089cd46d5404e4cc9216850332893353d5db9341772e8637558425fe17b0dea36806ae793b4cfa559e1cb1caac3f6ebc3697fb7ff76da1eef80e3e7ef8f77c07677d4a05a1f16233177fef0ce807a75df8e1312dedae2db58ac30568714c475a5d659f45392b9605c4e3014f9bf1dac4129f53bb69c91fa236f7e92256ea5f253ab0e9679286f4b36de354b29701a83fb8b8987d33eb768b8a5d1a6f51d77ce91cff02b0000ffff37cebd8001030000", + "a416686e4cfcf5ed8366cfcf264e48e0": "1f8b08000000000000ff8c53dd6ef3360cbd969e82358ac00e1209dd865d78f0c5d66c4381b52bf6735dc812ed0891255796d71481df7d90ecf46718be2f01624914299e7348f6421e448ba084a35477bdf301724a32e96cc063c828c982ee30a39464a713bb77ead163a38fd3743ab107d1e134716d037a2b0cef9c4213435a1df663cda4eb78ad8d8e7f7ef022b881f787964b21f7c83becd2e6e2008f4a0f97783bdbf05e18a1b4bdc05d89206a31201f9e2f013fbc5ac97bdda3d1167923ac1ba34cc728137c2d78d6b2a094f3d6952d5af42220cc1e109c33d0a2adc34039879d70b12e90f46d84441a5e7b4ce637139c28b9356ec0bca0e451db3697e1084bf5d8edbc1690a3f780de3b5f50c239d46128616b476392b4d52a958efde88396064f77bb727b33c156ee511e9ea2db93740aabebabca6ab35a5db3bb5d556d6f28592272f9df9c1bd02ac2fcfebb02f2f5a7e737672453d4215154c2b1995d3c0dc18f32446aaa86b7df7a78366cf71325a90fcec674607fc42f259dfce07eee2f76bf6c28490bace7a2b15fd24289c2cefd7cecb5c708f8db6f165c0ff802165f40244cc22af018466f196d462be375ee3fe5df4027ff27ed06547d065f40ae620193048b0c91e73fc2836cda85f98912b27b07955a8bed462f827696928912dda4072a58da9cfd8a21cf44df1b2d93170bae3359c1feb69df0c35e98bf7ebfff2d5fc9a62d7e48a15715586d626e32d34aef2aa860a5848b665597a0ea4d72507a28c1c77d274be864dc2572252c624639b2799e8b78fb2e6a39ab9a7f6291cba665ef1c0be090eeff44e9ac8a2f4cf40c6c2e47ea7290e91bf6081e07377a894b3972056b255c01cb34a4ee619d646fd3a1d85cab0f06557f3ccd653b1be6ac71a4a08f9f2fe5bc68f022a29951549e4ef4df000000ffff20759cb67c050000", + "a7f82d82b0fbcd0d7a86744fc49b7173": "1f8b08000000000000ffbc91bd4a04311485ebe429428a416118333fa82c04052dc546bbc5229b5cd9c0fc7973e32ac3bcbb44071dabadb4ca395fc2e1836c6f5a0f3d3d71669c43a1852cab8b4215aa283775adce25672ef4894f3100ce9b6934211c0674f335d9f1e4f7ebd3b3c919323b1360be22dfc1104997214330eef1a71ed013acfa68307c764d18216b07abef066bdacceed30de948cf97ddaec9d329394b73b70ff7428bed11adeaffb4f2232af59fabe48b8f4cbf69c9bf82d0a2529c79d7a6582e71d9155a367bc9d94b047cff6642564a754172066f6057b85e30a1e957b8f9c21f010000ffff57d7944148020000", + "a833afd1c2dfd51f0ba59a8bf977cc1b": "1f8b08000000000000ffbc91bd4a04311485ebe429428a416118333fa82c04052dc546bbc5229b5cd9c0fc7973e32ac3bcbb44071dabadb4ca395fc2e1836c6f5a0f3d3d71669c43a1852cab8b4215aa283775adce25672ef4894f3100ce9b6934211c0674f335d9f1e4f7ebd3b3c919323b1360be22dfc1104997214330eef1a71ed013acfa68307c764d18216b07abef066bdacceed30de948cf97ddaec9d329394b73b70ff7428bed11adeaffb4f2232af59fabe48b8f4cbf69c9bf82d0a2529c79d7a6582e71d9155a367bc9d94b047cff6642564a754172066f6057b85e30a1e957b8f9c21f010000ffff57d7944148020000", + "aa6f74a5b61f4cf11f0d49914680fd21": "1f8b08000000000000ff8c91cd6ae33010c7cfd653cc0a769182911f60c9291bc2c26e1a9af45c14595244648d91e53450f2ee45b25328bde42004c3ffe3374c2fd5595a0dad44425cd7634cc048451586a4af89125251ebd2693c0a855d7374dee5d79ca34c3834fdd9364aaa936ea26edd401f5063304d2fbd6c5d7840eed152c209316350b0d56fcfb98671601116a55294490d3ac6fc30727827d5454650c6c290e2a8529e542bef744877d70a8371965437523953cc4b98a9c44627462759c2ce532e5e4227e37092fef0f4ff1ffba58ce5bf8be9c71282f3253fea34c6501273d8e4ff2456c68a898093bbf436afc55a58b41239ec5cb0b33c5d613e4146cd3f07f6754767e0b59ed15b31f5fdc16cad81eed7075a03ed5db0e5c760e977668f56ac7320cb070f62af13dbfddd6ef854c37e5e382d157cda6be6fe080000ffffb73c6a1735020000", + "aaa0e84aef1077c2699e21ba05d51c7f": "1f8b08000000000000ff5ccc410a02310c85e175728a210728ad8283822bafe04e5cc4268b40673a74a25e5f2a0832cbff83f76e97623afb1d61e64987f340fcc884b0b4eab5a7e7851058a4f54abb31c410433a1df6e391104c4a5fa588c0d9edf50b312e579bb43efdbb5b09a129cbd6decd5cb7d84fff2dae849f000000ffffe1039f77a9000000", + "aaf0b28d854f8d677257bc26f4a6e22d": "1f8b08000000000000ff94924d8fdb2c1485d7f02bae2cbd919d3782fd48594d2b75914ca34c475d5f63eca0606030ee24b2fcdf2bfc91499ba61f0bb004c7f79c877b1d8a2356121ae9bf29212955b5b33e404a4922ac09f214124a92b20e09a5c4e590741ddbda62e765a94e7ddf75ec096bd9f71c9d8aca7bd7ca04e90d6a5ea08dba4a85439b33616b9e2bade2e2478fc136dc1d2b2eac29b9438d8532d1f95a5f598da6e2cedb60f3b6e42e9c9d6cb8ac5d382734a39473781e79662e46a3e6fd34f85604e8284101b09c7cd8161d25055a28d0b20f68693fd47a926f60e41be05c0dd014e06568bd61b46c8d8892b4987fcb206d603979ad407a1f97f559346c600d8be9aea384a0780058cc09be7cde6eba7e45498cf100c58a929e9258610db3e62b06714813744e2b814159c382ad75b28286a1c82819934de19ff1fc496a6da1f24e40216b0b31f194fb2a687691a6229c606a3e7b1cbf2bf0f215962e6783642f5f3348bd74fa0ccbe1e1d9c7b8ff4c3b2ad6f1f9d22b5946495907b6f3ca84324d0e43c0ff9a64701926e61ec6cb7e0379fd771c2ffbcdbfa2bc1f36ee1ecbe25a145b38d435e101269004febf708c0dbc856dbdfe3df04e990a5cdcc24182978d6d7d9ce35bdca8fc35a7fca13719a437adbaa04567585c5d777d9ca738d173fd6c4af6a86d23410cfb9fb20dda741cfca1d874407bfa3d0000ffff0c06c20f7a040000", + "aeab2b2b2dab4699657654469ca5b02b": "1f8b08000000000000ff5ccc410a02310c85e175728a210728ad8283822bafe04e5cc4268b40673a74a25e5f2a0832cbff83f76e97623afb1d61e64987f340fcc884b0b4eab5a7e7851058a4f54abb31c410433a1df6e391104c4a5fa588c0d9edf50b312e579bb43efdbb5b09a129cbd6decd5cb7d84fff2dae849f000000ffffe1039f77a9000000", + "b07da232bbd50bea80db83a2cb2ca45e": "1f8b08000000000000ff2a484cce4e4c4f55c8cd4f49cde1e2d2d757f02e4a2cc92f56c848cdc9c957c80673f4b84a2a0b526132c52545a5c9250ad55c9c1e6035c525459979e95cb55c10558e452599c939a948ca3c5d1432f34acc4cb8389df3f34a52f34a605a381d4b4b32f28be02600020000ffffcb8696638d000000", + "c20ee81720733a2f96a9b0df3a23a7a2": "1f8b08000000000000ff2a484cce4e4c4f55c8cd4f49cde1e2d2d757f02e4a2cc92f56c848cdc9c957c80673f4b84a2a0b526132c52545a5c9250ad55c9c1e6035c525459979e95cb55c10558e452599c939a948ca3c5d1432f34acc4cb8389df3f34a52f34a605a381d4b4b32f28be02600020000ffffcb8696638d000000", + "caf71f0f0cbb53c27c2bbcd00a648fd9": "1f8b08000000000000ff9452c18adb30103d6bbe626a285890daf41a9a43296d37870d69939ccb441e3b4364c94832ddc5f8df8b9ca56c4a0fedc1467af39ee6e98d063257ea187b120720fde043c21254d15aea0a50858fb77f1da57364f3263e4743765926e9b90050c534558fbed9076ee5699ea7a9da51cff35c8b4b1c1cd9ba91ccef245dc673657c5f9fc54afeea6ba0e4633d5cbbda78d7d603596ac4fd03ddfaae000dd08ece2c3728354ea0b2f56a4f2172a94159df555b27a9746235d635367c1e3bcca435e6622361330d942e33a8865b0e0bfac9fad7fad697059d0dc64421151ad48bcbdbd11ad48f159a2cf9323ab3420e01d71b6c64a97f1c864c9176c1df6cd089cd46d5404e4cc9216850332893353d5db9341772e8637558425fe17b0dea36806ae793b4cfa559e1cb1caac3f6ebc3697fb7ff76da1eef80e3e7ef8f77c07677d4a05a1f16233177fef0ce807a75df8e1312dedae2db58ac30568714c475a5d659f45392b9605c4e3014f9bf1dac4129f53bb69c91fa236f7e92256ea5f253ab0e9679286f4b36de354b29701a83fb8b8987d33eb768b8a5d1a6f51d77ce91cff02b0000ffff37cebd8001030000", + "cbfa81bf4d53c8a610fcbb7932ed95a3": "1f8b08000000000000ffe2525608c9c82c56c82c56485408f1f7f55148c94f2ecd4dcd2bd15370cacfcfade34a49cdcd77ad28c82c4a55b055503232c950e202040000ffffc36ed62935000000", + "cca1a28dc237a0b1a6d7768c4454036a": "1f8b08000000000000ff5491b18ed4301086ebcc530c96901294b3fb95b65836cd35b72be0057cde89b136f158ce8405a12be82829e841e231781dc4bd064abce874858b19ffff37e3dfc9bab3f58436050863e22c5843a51c47a18fa2a052fd280aa0523ec8fbf95e3b1ecd7d18c272cc395be1c9a4b33791c4e4e4ccc5e613c5e260f60369cf838d5e73f6c6e7e4143400c6e02ea5db0e35388e935cab2daa7787eeb0c15dd7e1ee78c4db4eade23bbaec87405130d205170cbab5867e8eeee9ba76bdc75765075d5a7b8e7df02d729209b5d68b5977c10e8724816383754723176d8b9433e7063f4355f8b8d9e215f76c48e169ad1ba89c5b7d8bb498567c7dcd50bfb6eeec33cff154372df6a3e8b72987287dad4e6172fc81f2a78d3127eaed3c887939a9b6c4d13450857e45bfd8620cc3b2569549e61c97729d0ad503fcefddd1e5e92db5734dbbc8e0618df0f1fb8fbf5fbfa17f73dce39fdfbf1e7f7e01633c6f3c45ca5608cb67a2300f98320b3bbcb959a3b629e8b503ff020000ffffb1117d162f020000", + "cdc9702cf3b30ddc315510a28df1ff83": "1f8b08000000000000ff8c535b6b1b3b107e5efd8a3982046d70b4e7e1701e5cfc10dc10426b3790b62fa504453bab08ebb2c8e3c4c6ec7f2f922f4dd2d2e66159edf25de69b19f54a2f9441685564ccfa3e2602c12aae63205c136715ef3c71c62abeddca596c6f1276763d0cdbad9c2b8fc3d0d8409882728d8f2dbacc30961e56f75247dfdc5b67f3d32c92a2b86cfa8569b4d20fd878f4e5f016420c5dd32ba75a1bde0077d1705633d634268e0d064c8a107600a0181d180c5e33daf408775e4349d0298db06555d380d763385fe066b2c0cd452238cfc8894162d534977c91c86a8742c3be4d72ba7b8fc0b659edffff6a1067a51f720f1e01a61453fd7b035cf736e1a4952dfa78593e5875d1b66fb51b814a042f1d6b1098d21f6c59f51e1dd241bf78fd25d333c181b16e1534ccf16936153508afe1ec305439db1f4aec3d2577f75125d09d8125a595a6fca79a3a8b819e71a73174d6b06a6095ed0a7f02fbe9cb2b24c18f488adef15a7e095ea5e583729f3fcd3e8a53dd99fa5de1fd3381605d714948ab148aa8d73001388accf149e8cec85d1d353b400f01450b67ad8a35dcd8606653a169fdba472f3a93ed8e75b7d26b798b945923383d9a5e13faed07dc8c81f736183e82afcaad700cdfbedf6f0805ef6330bc1e41590645368631fc3bfc9acb45232fb3afc8773614af9bebf955bdab469c3cd6bc0ca12ed95f65db2d82f839e125251b4c56de21a1f3246ffb64037582ab4477272dcf2b9117e047000000ffffe48ced133d040000", + "d1ce3e717c8a1e9830e9e1626ff88fa8": "1f8b08000000000000ff8c53dd6ef3360cbd969e82358ac00e1209dd865d78f0c5d66c4381b52bf6735dc812ed0891255796d71481df7d90ecf46718be2f01624914299e7348f6421e448ba084a35477bdf301724a32e96cc063c828c982ee30a39464a713bb77ead163a38fd3743ab107d1e134716d037a2b0cef9c4213435a1df663cda4eb78ad8d8e7f7ef022b881f787964b21f7c83becd2e6e2008f4a0f97783bdbf05e18a1b4bdc05d89206a31201f9e2f013fbc5ac97bdda3d1167923ac1ba34cc728137c2d78d6b2a094f3d6952d5af42220cc1e109c33d0a2adc34039879d70b12e90f46d84441a5e7b4ce637139c28b9356ec0bca0e451db3697e1084bf5d8edbc1690a3f780de3b5f50c239d46128616b476392b4d52a958efde88396064f77bb727b33c156ee511e9ea2db93740aabebabca6ab35a5db3bb5d556d6f28592272f9df9c1bd02ac2fcfebb02f2f5a7e737672453d4215154c2b1995d3c0dc18f32446aaa86b7df7a78366cf71325a90fcec674607fc42f259dfce07eee2f76bf6c28490bace7a2b15fd24289c2cefd7cecb5c708f8db6f165c0ff802165f40244cc22af018466f196d462be375ee3fe5df4027ff27ed06547d065f40ae620193048b0c91e73fc2836cda85f98912b27b07955a8bed462f827696928912dda4072a58da9cfd8a21cf44df1b2d93170bae3359c1feb69df0c35e98bf7ebfff2d5fc9a62d7e48a15715586d626e32d34aef2aa860a5848b665597a0ea4d72507a28c1c77d274be864dc2572252c624639b2799e8b78fb2e6a39ab9a7f6291cba665ef1c0be090eeff44e9ac8a2f4cf40c6c2e47ea7290e91bf6081e07377a894b3972056b255c01cb34a4ee619d646fd3a1d85cab0f06557f3ccd653b1be6ac71a4a08f9f2fe5bc68f022a29951549e4ef4df000000ffff20759cb67c050000", + "d34aa8c5fcb453998edcaa9594393f70": "1f8b08000000000000ff8c535b6b1b3b107e5efd8a3982046d70b4e7e1701e5cfc10dc10426b3790b62fa504453bab08ebb2c8e3c4c6ec7f2f922f4dd2d2e66159edf25de69b19f54a2f9441685564ccfa3e2602c12aae63205c136715ef3c71c62abeddca596c6f1276763d0cdbad9c2b8fc3d0d8409882728d8f2dbacc30961e56f75247dfdc5b67f3d32c92a2b86cfa8569b4d20fd878f4e5f016420c5dd32ba75a1bde0077d1705633d634268e0d064c8a107600a0181d180c5e33daf408775e4349d0298db06555d380d763385fe066b2c0cd452238cfc8894162d534977c91c86a8742c3be4d72ba7b8fc0b659edffff6a1067a51f720f1e01a61453fd7b035cf736e1a4952dfa78593e5875d1b66fb51b814a042f1d6b1098d21f6c59f51e1dd241bf78fd25d333c181b16e1534ccf16936153508afe1ec305439db1f4aec3d2577f75125d09d8125a595a6fca79a3a8b819e71a73174d6b06a6095ed0a7f02fbe9cb2b24c18f488adef15a7e095ea5e583729f3fcd3e8a53dd99fa5de1fd3381605d714948ab148aa8d73001388accf149e8cec85d1d353b400f01450b67ad8a35dcd8606653a169fdba472f3a93ed8e75b7d26b798b945923383d9a5e13faed07dc8c81f736183e82afcaad700cdfbedf6f0805ef6330bc1e41590645368631fc3bfc9acb45232fb3afc8773614af9bebf955bdab469c3cd6bc0ca12ed95f65db2d82f839e125251b4c56de21a1f3246ffb64037582ab4477272dcf2b9117e047000000ffffe48ced133d040000", + "d3a9bc220c8ae2d4e01680157e65d694": "1f8b08000000000000ffe2525608c9c82c56c82c56485408f1f7f55148c94f2ecd4dcd2bd15370cacfcfade34a49cdcd77ad28c82c4a55b055503232c950e202040000ffffc36ed62935000000", + "d5f9b4870ad447f7ef808033db2803ad": "1f8b08000000000000ff94924d8fdb2c1485d7f02bae2cbd919d3782fd48594d2b75914ca34c475d5f63eca0606030ee24b2fcdf2bfc91499ba61f0bb004c7f79c877b1d8a2356121ae9bf29212955b5b33e404a4922ac09f214124a92b20e09a5c4e590741ddbda62e765a94e7ddf75ec096bd9f71c9d8aca7bd7ca04e90d6a5ea08dba4a85439b33616b9e2bade2e2478fc136dc1d2b2eac29b9438d8532d1f95a5f598da6e2cedb60f3b6e42e9c9d6cb8ac5d382734a39473781e79662e46a3e6fd34f85604e8284101b09c7cd8161d25055a28d0b20f68693fd47a926f60e41be05c0dd014e06568bd61b46c8d8892b4987fcb206d603979ad407a1f97f559346c600d8be9aea384a0780058cc09be7cde6eba7e45498cf100c58a929e9258610db3e62b06714813744e2b814159c382ad75b28286a1c82819934de19ff1fc496a6da1f24e40216b0b31f194fb2a687691a6229c606a3e7b1cbf2bf0f215962e6783642f5f3348bd74fa0ccbe1e1d9c7b8ff4c3b2ad6f1f9d22b5946495907b6f3ca84324d0e43c0ff9a64701926e61ec6cb7e0379fd771c2ffbcdbfa2bc1f36ee1ecbe25a145b38d435e101269004febf708c0dbc856dbdfe3df04e990a5cdcc24182978d6d7d9ce35bdca8fc35a7fca13719a437adbaa04567585c5d777d9ca738d173fd6c4af6a86d23410cfb9fb20dda741cfca1d874407bfa3d0000ffff0c06c20f7a040000", + "d81923e98881c369f957c7d15decf26f": "1f8b08000000000000ff8c91cd6ae33010c7cfd653cc0a769182911f60c9291bc2c26e1a9af45c14595244648d91e53450f2ee45b25328bde42004c3ffe3374c2fd5595a0dad44425cd7634cc048451586a4af89125251ebd2693c0a855d7374dee5d79ca34c3834fdd9364aaa936ea26edd401f5063304d2fbd6c5d7840eed152c209316350b0d56fcfb98671601116a55294490d3ac6fc30727827d5454650c6c290e2a8529e542bef744877d70a8371965437523953cc4b98a9c44627462759c2ce532e5e4227e37092fef0f4ff1ffba58ce5bf8be9c71282f3253fea34c6501273d8e4ff2456c68a898093bbf436afc55a58b41239ec5cb0b33c5d613e4146cd3f07f6754767e0b59ed15b31f5fdc16cad81eed7075a03ed5db0e5c760e977668f56ac7320cb070f62af13dbfddd6ef854c37e5e382d157cda6be6fe080000ffffb73c6a1735020000", + "de469d397e894ad53241ccaa67354d77": "1f8b08000000000000ff5256702c2dc9c82fe25256084a2dcb4c2d4f2d02040000ffff7187321713000000", + "e507552ddfbcbf9862edb00a6a06942e": "1f8b08000000000000ff8c53dd6ef3360cbd969e82358ac00e1209dd865d78f0c5d66c4381b52bf6735dc812ed0891255796d71481df7d90ecf46718be2f01624914299e7348f6421e448ba084a35477bdf301724a32e96cc063c828c982ee30a39464a713bb77ead163a38fd3743ab107d1e134716d037a2b0cef9c4213435a1df663cda4eb78ad8d8e7f7ef022b881f787964b21f7c83becd2e6e2008f4a0f97783bdbf05e18a1b4bdc05d89206a31201f9e2f013fbc5ac97bdda3d1167923ac1ba34cc728137c2d78d6b2a094f3d6952d5af42220cc1e109c33d0a2adc34039879d70b12e90f46d84441a5e7b4ce637139c28b9356ec0bca0e451db3697e1084bf5d8edbc1690a3f780de3b5f50c239d46128616b476392b4d52a958efde88396064f77bb727b33c156ee511e9ea2db93740aabebabca6ab35a5db3bb5d556d6f28592272f9df9c1bd02ac2fcfebb02f2f5a7e737672453d4215154c2b1995d3c0dc18f32446aaa86b7df7a78366cf71325a90fcec674607fc42f259dfce07eee2f76bf6c28490bace7a2b15fd24289c2cefd7cecb5c708f8db6f165c0ff802165f40244cc22af018466f196d462be375ee3fe5df4027ff27ed06547d065f40ae620193048b0c91e73fc2836cda85f98912b27b07955a8bed462f827696928912dda4072a58da9cfd8a21cf44df1b2d93170bae3359c1feb69df0c35e98bf7ebfff2d5fc9a62d7e48a15715586d626e32d34aef2aa860a5848b665597a0ea4d72507a28c1c77d274be864dc2572252c624639b2799e8b78fb2e6a39ab9a7f6291cba665ef1c0be090eeff44e9ac8a2f4cf40c6c2e47ea7290e91bf6081e07377a894b3972056b255c01cb34a4ee619d646fd3a1d85cab0f06557f3ccd653b1be6ac71a4a08f9f2fe5bc68f022a29951549e4ef4df000000ffff20759cb67c050000", + "ee89e1856fc911f261533efa462e6867": "1f8b08000000000000ff8c90cd8adb3010c7cfd6534c75285258a44be9a5e4d0dd855e36e9f7038cf515115972e4719362fceec58e0ba5a73d0c0231bff97ff468ce181c582c8cc5ae2f9540b0869b92c9dd8833d6f069528762bf54e7e36d9ea7491db173f3ac6326573326dd15eb12670d0f914e63ab4ce9741b535c469f2b5219747f0eda94ec758f096dccaf58b748d8e2e0f470499c49c6fc980d1cddf5f9514810b685dd7049eaf9f1015cadcb942a6162cd2fac607c8081ea6868f9699e527499eec053c93e06d6ccac897e45f7b0b9529f1c096e5b45a54b5caa9fb9c33a9c30fdf87c78116f8d0ff2c34abcd9438e693d5d1d8d35afe76c0b7b58248eee7af8fdfdeb8b303ea8bbb6647f37e72d89b0b0b358247cc3ebc74ad124270cdd60eb7ef1b9bc0f102dc44cefdf49105809766bdf6a43fe0faf350447b09407be960e6cfb8ff29f000000ffffed2515fbf0010000", + "f14888b9e73b4709f9f661ca025578a5": "1f8b08000000000000ff52567049cdcde7e252565678b970e7f3d9eb9eaf6b78b2bb9bcb508f0b100000ffff24c85b041b000000", + "f6819875960d317b08fedcef244fc640": "1f8b08000000000000ff5256567049cdcde7e2525656562833d433d033e032d45378b2a3ebf9aefd4fbbe6bf68de5b5151c105080000ffff79fbc41327000000", + "f6e84ad3fd70355fca59f33e23639704": "1f8b08000000000000ff5ccdc14ec3300cc6f1f3fc143ec2614e9c32525e827748db6022927964c98434f5dd51e15238f862fdfefa8a2e3d47bcdfe93594b8ae00a2c8c40ea0c6cf9e6ac407404494d4defb44b31633a59cb6331f3534bd6209d7162b1c764454d45caa369dfa1bde981cf13f90c359fe90811c1c7effa455cc9739c786374b96ecd1597eb1cf6ee4f1343c9d8e4be0c1cf7ef4bcf82d52c99176add4cbfc33ebc8c2237c070000ffff34bdd5b6e6000000", + "faef00ce61dfdd11dc5b0198e8cb4d24": "1f8b08000000000000ff8a0e4e2d2a4b2d8ae552505050484c492952b0555032d003432b0b03030325b04c49666e6a7e690948d2b058890b100000ffffb7699cdc36000000", + "fe2a9fe5f84f01e208243862890c2182": "1f8b08000000000000ff2a484cce4e4c4f55c8cd4f49cde1e2d2d757f02e4a2cc92f56c848cdc9c957c80673f4b84a2a0b526132c52545a5c9250ad55c9c1e6035c525459979e95cb55c10558e452599c939a948ca3c5d1432f34acc4cb8389df3f34a52f34a605a381d4b4b32f28be02600020000ffffcb8696638d000000", + }) + if err != nil { + panic(err) + } + g.DefaultResolver = hgr + + func() { + b := packr.New("all", "./templates/all") + b.SetResolver("CHANGELOG.md", packr.Pointer{ForwardBox: gk, ForwardPath: "518b74b34be782fd3abced06105dfdf1"}) + b.SetResolver("OWNERS", packr.Pointer{ForwardBox: gk, ForwardPath: "5d2e61f4f8ab5957f172a990d9fb3baf"}) + b.SetResolver("README.md", packr.Pointer{ForwardBox: gk, ForwardPath: "f14888b9e73b4709f9f661ca025578a5"}) + b.SetResolver("api/api.proto", packr.Pointer{ForwardBox: gk, ForwardPath: "5e8471dec0685b7154cd71dcf0444643"}) + b.SetResolver("api/client.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "a17964c54f014a0dd59c42b49123a941"}) + b.SetResolver("cmd/main.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "336d416ed5faa95a29de7b6afd385568"}) + b.SetResolver("configs/application.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "cbfa81bf4d53c8a610fcbb7932ed95a3"}) + b.SetResolver("configs/db.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "4ee76ca4d3f34ada842b90d87762fe26"}) + b.SetResolver("configs/grpc.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "470fd5cab5c7a57cec62609827d2c84f"}) + b.SetResolver("configs/http.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "7a53e746d0de690c8b20ca83292508c5"}) + b.SetResolver("configs/memcache.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "6cc24b961eaafa6a5726c5e875dd92ae"}) + b.SetResolver("configs/redis.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "aeab2b2b2dab4699657654469ca5b02b"}) + b.SetResolver("go.mod.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "95d28ebee82ae43dfc0c8b16b6088b2d"}) + b.SetResolver("internal/dao/dao.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "a416686e4cfcf5ed8366cfcf264e48e0"}) + b.SetResolver("internal/dao/db.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "ee89e1856fc911f261533efa462e6867"}) + b.SetResolver("internal/dao/mc.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "d34aa8c5fcb453998edcaa9594393f70"}) + b.SetResolver("internal/dao/redis.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "89e787ea2b6d77d3061b5e56a50c6e36"}) + b.SetResolver("internal/di/app.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "97e4f2cf9f4ad4fc842f20a7fb124f91"}) + b.SetResolver("internal/di/wire.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "348f254eb8f48eaf3d0330c83c18324c"}) + b.SetResolver("internal/model/model.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "b07da232bbd50bea80db83a2cb2ca45e"}) + b.SetResolver("internal/server/grpc/server.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "984dd6df0bfb1684d6d188b40962ca7b"}) + b.SetResolver("internal/server/http/server.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "468e50d126ac1e7c1a9ea44dde207990"}) + b.SetResolver("internal/service/service.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "aaf0b28d854f8d677257bc26f4a6e22d"}) + b.SetResolver("test/docker-compose.yaml", packr.Pointer{ForwardBox: gk, ForwardPath: "5d243c2aa906cb9527df41e508cda83d"}) + }() + + + func() { + b := packr.New("grpc", "./templates/grpc") + b.SetResolver("CHANGELOG.md", packr.Pointer{ForwardBox: gk, ForwardPath: "39a955dfabc5df68502b59574724045e"}) + b.SetResolver("OWNERS", packr.Pointer{ForwardBox: gk, ForwardPath: "de469d397e894ad53241ccaa67354d77"}) + b.SetResolver("README.md", packr.Pointer{ForwardBox: gk, ForwardPath: "473893d607815c5c27cec94e0e78e437"}) + b.SetResolver("api/api.proto", packr.Pointer{ForwardBox: gk, ForwardPath: "359dcf82ea381d6901e53f88ff235896"}) + b.SetResolver("api/client.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "cca1a28dc237a0b1a6d7768c4454036a"}) + b.SetResolver("cmd/main.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "a2cb44570c3d3285165729786d5f1def"}) + b.SetResolver("configs/application.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "959fd518960ea8b397538a6f7b1bdd3a"}) + b.SetResolver("configs/db.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "a7f82d82b0fbcd0d7a86744fc49b7173"}) + b.SetResolver("configs/grpc.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "43befbfad04c8efdf57be993ceb9e432"}) + b.SetResolver("configs/memcache.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "885a5148286f0720126cd2a540b56564"}) + b.SetResolver("configs/redis.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "aaa0e84aef1077c2699e21ba05d51c7f"}) + b.SetResolver("go.mod.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "48e53a59007a8dda61d904d989943a09"}) + b.SetResolver("internal/dao/dao.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "e507552ddfbcbf9862edb00a6a06942e"}) + b.SetResolver("internal/dao/db.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "6640f2771831eddce9f1132a8ffa02b1"}) + b.SetResolver("internal/dao/mc.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "1794b30bcdd9584d5877963a3cb28504"}) + b.SetResolver("internal/dao/redis.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "d81923e98881c369f957c7d15decf26f"}) + b.SetResolver("internal/di/app.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "2f762fe51f2becdb8677b17926a52f03"}) + b.SetResolver("internal/di/wire.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "80a49866e2154ebe00c57fd7c80a4cab"}) + b.SetResolver("internal/model/model.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "c20ee81720733a2f96a9b0df3a23a7a2"}) + b.SetResolver("internal/server/grpc/server.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "65c9c5ceead4379a32ef56fe8044a9a7"}) + b.SetResolver("internal/service/service.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "532d363951d4f0d0c18e620c67cb7b40"}) + b.SetResolver("test/docker-compose.yaml", packr.Pointer{ForwardBox: gk, ForwardPath: "225361cfe91f8a3ee02db98f64637aa4"}) + }() + + + func() { + b := packr.New("http", "./templates/http") + b.SetResolver("CHANGELOG.md", packr.Pointer{ForwardBox: gk, ForwardPath: "f6819875960d317b08fedcef244fc640"}) + b.SetResolver("OWNERS", packr.Pointer{ForwardBox: gk, ForwardPath: "64f157c0a5aaef8684ce174785fdb08b"}) + b.SetResolver("README.md", packr.Pointer{ForwardBox: gk, ForwardPath: "236ab314cd41c9b7b2c5194c0eb72bb1"}) + b.SetResolver("api/api.proto", packr.Pointer{ForwardBox: gk, ForwardPath: "33550cc0d0a7c442ee2f7ef103747430"}) + b.SetResolver("api/client.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "49d0cdb7406397b8e77616d290bcd94f"}) + b.SetResolver("cmd/main.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "caf71f0f0cbb53c27c2bbcd00a648fd9"}) + b.SetResolver("configs/application.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "d3a9bc220c8ae2d4e01680157e65d694"}) + b.SetResolver("configs/db.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "a833afd1c2dfd51f0ba59a8bf977cc1b"}) + b.SetResolver("configs/http.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "faef00ce61dfdd11dc5b0198e8cb4d24"}) + b.SetResolver("configs/memcache.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "1769e4a13f3ecbd1dbb3698b5f8cae8a"}) + b.SetResolver("configs/redis.toml", packr.Pointer{ForwardBox: gk, ForwardPath: "40aa45750f8397d706e3d8fdd82fa11f"}) + b.SetResolver("go.mod.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "f6e84ad3fd70355fca59f33e23639704"}) + b.SetResolver("internal/dao/dao.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "d1ce3e717c8a1e9830e9e1626ff88fa8"}) + b.SetResolver("internal/dao/db.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "676482aadd24e9539226c67ebd8b5d04"}) + b.SetResolver("internal/dao/mc.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "cdc9702cf3b30ddc315510a28df1ff83"}) + b.SetResolver("internal/dao/redis.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "aa6f74a5b61f4cf11f0d49914680fd21"}) + b.SetResolver("internal/di/app.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "56d831af18f731847e4733aa321128cb"}) + b.SetResolver("internal/di/wire.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "8f2519501a642ae50acf464ad3acb9f9"}) + b.SetResolver("internal/model/model.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "fe2a9fe5f84f01e208243862890c2182"}) + b.SetResolver("internal/server/http/server.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "46713bf4406bd2896c32e5778efb1eb5"}) + b.SetResolver("internal/service/service.go.tmpl", packr.Pointer{ForwardBox: gk, ForwardPath: "d5f9b4870ad447f7ef808033db2803ad"}) + b.SetResolver("test/docker-compose.yaml", packr.Pointer{ForwardBox: gk, ForwardPath: "14b27f88168b4f08f9d703f2a9b5027c"}) + }() + + return nil +}() diff --git a/tool/kratos-gen-project/project.go b/tool/kratos-gen-project/project.go new file mode 100644 index 000000000..c9dc547a6 --- /dev/null +++ b/tool/kratos-gen-project/project.go @@ -0,0 +1,93 @@ +package main + +import ( + "bytes" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "text/template" + + "github.com/gobuffalo/packr/v2" +) + +// project project config +type project struct { + // project name + Name string + // mod prefix + ModPrefix string + // project dir + path string + none bool + onlyGRPC bool + onlyHTTP bool +} + +var p project + +//go:generate packr2 +func create() (err error) { + box := packr.New("all", "./templates/all") + if p.onlyHTTP { + box = packr.New("http", "./templates/http") + } else if p.onlyGRPC { + box = packr.New("grpc", "./templates/grpc") + } + if err = os.MkdirAll(p.path, 0755); err != nil { + return + } + for _, name := range box.List() { + if p.ModPrefix != "" && name == "go.mod.tmpl" { + continue + } + tmpl, _ := box.FindString(name) + i := strings.LastIndex(name, string(os.PathSeparator)) + if i > 0 { + dir := name[:i] + if err = os.MkdirAll(filepath.Join(p.path, dir), 0755); err != nil { + return + } + } + if strings.HasSuffix(name, ".tmpl") { + name = strings.TrimSuffix(name, ".tmpl") + } + if err = write(filepath.Join(p.path, name), tmpl); err != nil { + return + } + } + + if err = generate(); err != nil { + return + } + return +} + +func generate() error { + cmd := exec.Command("go", "generate", "./...") + cmd.Dir = p.path + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() +} + +func write(path, tpl string) (err error) { + data, err := parse(tpl) + if err != nil { + return + } + return ioutil.WriteFile(path, data, 0644) +} + +func parse(s string) ([]byte, error) { + t, err := template.New("").Parse(s) + if err != nil { + return nil, err + } + var buf bytes.Buffer + if err = t.Execute(&buf, p); err != nil { + return nil, err + } + return buf.Bytes(), nil +} diff --git a/tool/kratos-gen-project/templates/all/CHANGELOG.md b/tool/kratos-gen-project/templates/all/CHANGELOG.md new file mode 100644 index 000000000..c39acc0e2 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/CHANGELOG.md @@ -0,0 +1,4 @@ +## Demo + +### v1.0.0 +1. 上线功能xxx diff --git a/tool/kratos-gen-project/templates/all/OWNERS b/tool/kratos-gen-project/templates/all/OWNERS new file mode 100644 index 000000000..c1e28c554 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/OWNERS @@ -0,0 +1,2 @@ +# Author +# Reviewer diff --git a/tool/kratos-gen-project/templates/all/README.md b/tool/kratos-gen-project/templates/all/README.md new file mode 100644 index 000000000..e43f93fc3 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/README.md @@ -0,0 +1,4 @@ +# Demo + +## 项目简介 +1. diff --git a/tool/kratos-gen-project/templates/all/api/api.proto b/tool/kratos-gen-project/templates/all/api/api.proto new file mode 100644 index 000000000..98612eb9c --- /dev/null +++ b/tool/kratos-gen-project/templates/all/api/api.proto @@ -0,0 +1,34 @@ +// 定义项目 API 的 proto 文件 可以同时描述 gRPC 和 HTTP API +// protobuf 文件参考: +// - https://developers.google.com/protocol-buffers/ +syntax = "proto3"; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; +import "google/protobuf/empty.proto"; +import "google/api/annotations.proto"; + +// package 命名使用 {appid}.{version} 的方式, version 形如 v1, v2 .. +package demo.service.v1; + +// NOTE: 最后请删除这些无用的注释 (゜-゜)つロ + +option go_package = "api"; +option (gogoproto.goproto_getters_all) = false; + +service Demo { + rpc Ping (.google.protobuf.Empty) returns (.google.protobuf.Empty); + rpc SayHello (HelloReq) returns (.google.protobuf.Empty); + rpc SayHelloURL(HelloReq) returns (HelloResp) { + option (google.api.http) = { + get:"/abc/say_hello" + }; + }; +} + +message HelloReq { + string name = 1 [(gogoproto.moretags)='form:"name" validate:"required"']; +} + +message HelloResp { + string Content = 1 [(gogoproto.jsontag) = 'content']; +} diff --git a/tool/kratos-gen-project/templates/all/api/client.go.tmpl b/tool/kratos-gen-project/templates/all/api/client.go.tmpl new file mode 100644 index 000000000..2b0875e89 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/api/client.go.tmpl @@ -0,0 +1,25 @@ +package api +import ( + "context" + "fmt" + + "github.com/bilibili/kratos/pkg/net/rpc/warden" + + "google.golang.org/grpc" +) + +// AppID . +const AppID = "TODO: ADD APP ID" + +// NewClient new grpc client +func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (DemoClient, error) { + client := warden.NewClient(cfg, opts...) + cc, err := client.Dial(context.Background(), fmt.Sprintf("discovery://default/%s", AppID)) + if err != nil { + return nil, err + } + return NewDemoClient(cc), nil +} + +// 生成 gRPC 代码 +//go:generate kratos tool protoc --grpc --bm api.proto diff --git a/tool/kratos-gen-project/templates/all/cmd/main.go.tmpl b/tool/kratos-gen-project/templates/all/cmd/main.go.tmpl new file mode 100644 index 000000000..9427562f0 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/cmd/main.go.tmpl @@ -0,0 +1,41 @@ +package main + +import ( + "flag" + "os" + "os/signal" + "syscall" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/di" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +func main() { + flag.Parse() + log.Init(nil) // debug flag: log.dir={path} + defer log.Close() + log.Info("abc start") + paladin.Init() + _, closeFunc, err := di.InitApp() + if err != nil { + panic(err) + } + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) + for { + s := <-c + log.Info("get a signal %s", s.String()) + switch s { + case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT: + closeFunc() + log.Info("abc exit") + time.Sleep(time.Second) + return + case syscall.SIGHUP: + default: + return + } + } +} diff --git a/tool/kratos-gen-project/templates/all/configs/application.toml b/tool/kratos-gen-project/templates/all/configs/application.toml new file mode 100644 index 000000000..a42ca6e63 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/configs/application.toml @@ -0,0 +1,3 @@ + +# This is a TOML document. Boom~ +demoExpire = "24h" diff --git a/tool/kratos-gen-project/templates/all/configs/db.toml b/tool/kratos-gen-project/templates/all/configs/db.toml new file mode 100644 index 000000000..840bd2e78 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/configs/db.toml @@ -0,0 +1,10 @@ +[Client] + addr = "127.0.0.1:3306" + dsn = "{user}:{password}@tcp(127.0.0.1:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8" + readDSN = ["{user}:{password}@tcp(127.0.0.2:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8","{user}:{password}@tcp(127.0.0.3:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"] + active = 20 + idle = 10 + idleTimeout ="4h" + queryTimeout = "200ms" + execTimeout = "300ms" + tranTimeout = "400ms" diff --git a/tool/kratos-gen-project/templates/all/configs/grpc.toml b/tool/kratos-gen-project/templates/all/configs/grpc.toml new file mode 100644 index 000000000..40339cecc --- /dev/null +++ b/tool/kratos-gen-project/templates/all/configs/grpc.toml @@ -0,0 +1,3 @@ +[Server] + addr = "0.0.0.0:9000" + timeout = "1s" diff --git a/tool/kratos-gen-project/templates/all/configs/http.toml b/tool/kratos-gen-project/templates/all/configs/http.toml new file mode 100644 index 000000000..951a03197 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/configs/http.toml @@ -0,0 +1,3 @@ +[Server] + addr = "0.0.0.0:8000" + timeout = "1s" diff --git a/tool/kratos-gen-project/templates/all/configs/memcache.toml b/tool/kratos-gen-project/templates/all/configs/memcache.toml new file mode 100644 index 000000000..c8a1d101c --- /dev/null +++ b/tool/kratos-gen-project/templates/all/configs/memcache.toml @@ -0,0 +1,10 @@ +[Client] + name = "abc" + proto = "tcp" + addr = "127.0.0.1:11211" + active = 50 + idle = 10 + dialTimeout = "100ms" + readTimeout = "200ms" + writeTimeout = "300ms" + idleTimeout = "80s" diff --git a/tool/kratos-gen-project/templates/all/configs/redis.toml b/tool/kratos-gen-project/templates/all/configs/redis.toml new file mode 100644 index 000000000..294c23743 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/configs/redis.toml @@ -0,0 +1,10 @@ +[Client] + name = "abc" + proto = "tcp" + addr = "127.0.0.1:6379" + idle = 10 + active = 10 + dialTimeout = "1s" + readTimeout = "1s" + writeTimeout = "1s" + idleTimeout = "10s" diff --git a/tool/kratos-gen-project/templates/all/go.mod.tmpl b/tool/kratos-gen-project/templates/all/go.mod.tmpl new file mode 100644 index 000000000..3e2e8cb53 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/go.mod.tmpl @@ -0,0 +1,11 @@ +module {{.Name}} + +go 1.12 + +require ( + github.com/bilibili/kratos master + github.com/gogo/protobuf v1.2.1 + github.com/golang/protobuf v1.3.2 + golang.org/x/net v0.0.0-20190628185345-da137c7871d7 + google.golang.org/grpc v1.22.0 +) diff --git a/tool/kratos-gen-project/templates/all/internal/dao/dao.go.tmpl b/tool/kratos-gen-project/templates/all/internal/dao/dao.go.tmpl new file mode 100644 index 000000000..cd9f5a03d --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/dao/dao.go.tmpl @@ -0,0 +1,63 @@ +package dao + +import ( + "context" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/cache/memcache" + "github.com/bilibili/kratos/pkg/cache/redis" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/database/sql" + "github.com/bilibili/kratos/pkg/sync/pipeline/fanout" + xtime "github.com/bilibili/kratos/pkg/time" +) + +//go:generate kratos tool genbts +// Dao dao interface +type Dao interface { + Close() + Ping(ctx context.Context) (err error) + // bts: -nullcache=&model.Article{ID:-1} -check_null_code=$!=nil&&$.ID==-1 + Article(c context.Context, id int64) (*model.Article, error) +} + +// dao dao. +type dao struct { + db *sql.DB + redis *redis.Redis + mc *memcache.Memcache + cache *fanout.Fanout + demoExpire int32 +} + +// New new a dao and return. +func New(r *redis.Redis, mc *memcache.Memcache, db *sql.DB) (d Dao, err error) { + var cfg struct{ + DemoExpire xtime.Duration + } + if err = paladin.Get("application.toml").UnmarshalTOML(&cfg); err != nil { + return + } + d = &dao{ + db: db, + redis: r, + mc: mc, + cache: fanout.New("cache"), + demoExpire: int32(time.Duration(cfg.DemoExpire) / time.Second), + } + return +} + +// Close close the resource. +func (d *dao) Close() { + d.mc.Close() + d.redis.Close() + d.db.Close() + d.cache.Close() +} + +// Ping ping the resource. +func (d *dao) Ping(ctx context.Context) (err error) { + return nil +} diff --git a/tool/kratos-gen-project/templates/all/internal/dao/db.go.tmpl b/tool/kratos-gen-project/templates/all/internal/dao/db.go.tmpl new file mode 100644 index 000000000..e5bf726e5 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/dao/db.go.tmpl @@ -0,0 +1,25 @@ +package dao + +import ( + "context" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/database/sql" +) + +func NewDB() (db *sql.DB, err error) { + var cfg struct { + Client *sql.Config + } + if err = paladin.Get("db.toml").UnmarshalTOML(&cfg); err != nil { + return + } + db = sql.NewMySQL(cfg.Client) + return +} + +func (d *dao) RawArticle(ctx context.Context, id int64) (art *model.Article, err error) { + // get data from db + return +} diff --git a/tool/kratos-gen-project/templates/all/internal/dao/mc.go.tmpl b/tool/kratos-gen-project/templates/all/internal/dao/mc.go.tmpl new file mode 100644 index 000000000..7990a7067 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/dao/mc.go.tmpl @@ -0,0 +1,43 @@ +package dao + +import ( + "context" + "fmt" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/cache/memcache" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +//go:generate kratos tool genmc +type _mc interface { + // mc: -key=keyArt -type=get + CacheArticle(c context.Context, id int64) (*model.Article, error) + // mc: -key=keyArt -expire=d.demoExpire + AddCacheArticle(c context.Context, id int64, art *model.Article) (err error) + // mc: -key=keyArt + DeleteArticleCache(c context.Context, id int64) (err error) +} + +func NewMC() (mc *memcache.Memcache, err error) { + var cfg struct { + Client *memcache.Config + } + if err = paladin.Get("memcache.toml").UnmarshalTOML(&cfg); err != nil { + return + } + mc = memcache.New(cfg.Client) + return +} + +func (d *dao) PingMC(ctx context.Context) (err error) { + if err = d.mc.Set(ctx, &memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil { + log.Error("conn.Set(PING) error(%v)", err) + } + return +} + +func keyArt(id int64) string { + return fmt.Sprintf("art_%d", id) +} diff --git a/tool/kratos-gen-project/templates/all/internal/dao/redis.go.tmpl b/tool/kratos-gen-project/templates/all/internal/dao/redis.go.tmpl new file mode 100644 index 000000000..063b999ce --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/dao/redis.go.tmpl @@ -0,0 +1,27 @@ +package dao + +import ( + "context" + + "github.com/bilibili/kratos/pkg/cache/redis" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +func NewRedis() (r *redis.Redis, err error) { + var cfg struct { + Client *redis.Config + } + if err = paladin.Get("redis.toml").UnmarshalTOML(&cfg); err != nil { + return + } + r = redis.NewRedis(cfg.Client) + return +} + +func (d *dao) PingRedis(ctx context.Context) (err error) { + if _, err = d.redis.Do(ctx, "SET", "ping", "pong"); err != nil { + log.Error("conn.Set(PING) error(%v)", err) + } + return +} \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/all/internal/di/app.go.tmpl b/tool/kratos-gen-project/templates/all/internal/di/app.go.tmpl new file mode 100644 index 000000000..ecf983daf --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/di/app.go.tmpl @@ -0,0 +1,39 @@ +package di + +import ( + "context" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/service" + + "github.com/bilibili/kratos/pkg/log" + bm "github.com/bilibili/kratos/pkg/net/http/blademaster" + "github.com/bilibili/kratos/pkg/net/rpc/warden" +) + +//go:generate wire +type App struct { + svc *service.Service + http *bm.Engine + grpc *warden.Server +} + +func NewApp(svc *service.Service, h *bm.Engine, g *warden.Server) (app *App, closeFunc func(), err error){ + app = &App{ + svc: svc, + http: h, + grpc: g, + } + closeFunc = func() { + ctx, cancel := context.WithTimeout(context.Background(), 35*time.Second) + if err := g.Shutdown(ctx); err != nil { + log.Error("grpcSrv.Shutdown error(%v)", err) + } + if err := h.Shutdown(ctx); err != nil { + log.Error("httpSrv.Shutdown error(%v)", err) + } + svc.Close() + cancel() + } + return +} diff --git a/tool/kratos-gen-project/templates/all/internal/di/wire.go.tmpl b/tool/kratos-gen-project/templates/all/internal/di/wire.go.tmpl new file mode 100644 index 000000000..c3f8a9df6 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/di/wire.go.tmpl @@ -0,0 +1,21 @@ +// +build wireinject +// The build tag makes sure the stub is not built in the final build. + +package di + +import ( + pb "{{.ModPrefix}}{{.Name}}/api" + "{{.ModPrefix}}{{.Name}}/internal/dao" + "{{.ModPrefix}}{{.Name}}/internal/server/grpc" + "{{.ModPrefix}}{{.Name}}/internal/server/http" + "{{.ModPrefix}}{{.Name}}/internal/service" + + "github.com/google/wire" +) + +var daoProvider = wire.NewSet(dao.New, dao.NewDB, dao.NewRedis, dao.NewMC) +var serviceProvider = wire.NewSet(service.New, wire.Bind(new(pb.DemoServer), new(*service.Service))) + +func InitApp() (*App, func(), error) { + panic(wire.Build(daoProvider, serviceProvider, http.New, grpc.New, NewApp)) +} diff --git a/tool/kratos-gen-project/templates/all/internal/model/model.go.tmpl b/tool/kratos-gen-project/templates/all/internal/model/model.go.tmpl new file mode 100644 index 000000000..b3fcf7985 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/model/model.go.tmpl @@ -0,0 +1,12 @@ +package model + +// Kratos hello kratos. +type Kratos struct { + Hello string +} + +type Article struct { + ID int64 + Content string + Author string +} \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/all/internal/server/grpc/server.go.tmpl b/tool/kratos-gen-project/templates/all/internal/server/grpc/server.go.tmpl new file mode 100644 index 000000000..c1814e36d --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/server/grpc/server.go.tmpl @@ -0,0 +1,23 @@ +package grpc + +import ( + pb "{{.ModPrefix}}{{.Name}}/api" + + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/net/rpc/warden" +) + +// New new a grpc server. +func New(svc pb.DemoServer) (ws *warden.Server, err error) { + var rc struct { + Server *warden.ServerConfig + } + err = paladin.Get("grpc.toml").UnmarshalTOML(&rc) + if err == paladin.ErrNotExist { + err = nil + } + ws = warden.NewServer(rc.Server) + pb.RegisterDemoServer(ws.Server(), svc) + ws, err = ws.Start() + return +} diff --git a/tool/kratos-gen-project/templates/all/internal/server/http/server.go.tmpl b/tool/kratos-gen-project/templates/all/internal/server/http/server.go.tmpl new file mode 100644 index 000000000..2917e8499 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/server/http/server.go.tmpl @@ -0,0 +1,57 @@ +package http + +import ( + "net/http" + + pb "{{.ModPrefix}}{{.Name}}/api" + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" + bm "github.com/bilibili/kratos/pkg/net/http/blademaster" +) + +var svc pb.DemoServer + +// New new a bm server. +func New(s pb.DemoServer) (engine *bm.Engine, err error) { + var ( + hc struct { + Server *bm.ServerConfig + } + ) + if err = paladin.Get("http.toml").UnmarshalTOML(&hc); err != nil { + if err != paladin.ErrNotExist { + return + } + err = nil + } + svc = s + engine = bm.DefaultServer(hc.Server) + pb.RegisterDemoBMServer(engine, s) + initRouter(engine) + err = engine.Start() + return +} + +func initRouter(e *bm.Engine) { + e.Ping(ping) + g := e.Group("/abc") + { + g.GET("/start", howToStart) + } +} + +func ping(ctx *bm.Context) { + if _, err := svc.Ping(ctx, nil); err != nil { + log.Error("ping error(%v)", err) + ctx.AbortWithStatus(http.StatusServiceUnavailable) + } +} + +// example for http request handler. +func howToStart(c *bm.Context) { + k := &model.Kratos{ + Hello: "Golang 大法好 !!!", + } + c.JSON(k, nil) +} \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/all/internal/service/service.go.tmpl b/tool/kratos-gen-project/templates/all/internal/service/service.go.tmpl new file mode 100644 index 000000000..34b27d6fa --- /dev/null +++ b/tool/kratos-gen-project/templates/all/internal/service/service.go.tmpl @@ -0,0 +1,54 @@ +package service + +import ( + "context" + "fmt" + + pb "{{.ModPrefix}}{{.Name}}/api" + "{{.ModPrefix}}{{.Name}}/internal/dao" + "github.com/bilibili/kratos/pkg/conf/paladin" + + "github.com/golang/protobuf/ptypes/empty" +) + +// Service service. +type Service struct { + ac *paladin.Map + dao dao.Dao +} + +// New new a service and return. +func New(d dao.Dao) (s *Service, err error) { + s = &Service{ + ac: &paladin.TOML{}, + dao: d, + } + err = paladin.Watch("application.toml", s.ac) + return +} + +// SayHello grpc demo func. +func (s *Service) SayHello(ctx context.Context, req *pb.HelloReq) (reply *empty.Empty, err error) { + reply = new(empty.Empty) + fmt.Printf("hello %s", req.Name) + return +} + +// SayHelloURL bm demo func. +func (s *Service) SayHelloURL(ctx context.Context, req *pb.HelloReq) (reply *pb.HelloResp, err error) { + reply = &pb.HelloResp{ + Content: "hello " + req.Name, + } + fmt.Printf("hello url %s", req.Name) + return +} + +// Ping ping the resource. +func (s *Service) Ping(ctx context.Context, e *empty.Empty) (*empty.Empty, error) { + return &empty.Empty{}, s.dao.Ping(ctx) +} + +// Close close the resource. +func (s *Service) Close() { + s.dao.Close() +} diff --git a/tool/kratos-gen-project/templates/all/test/docker-compose.yaml b/tool/kratos-gen-project/templates/all/test/docker-compose.yaml new file mode 100644 index 000000000..481f18d51 --- /dev/null +++ b/tool/kratos-gen-project/templates/all/test/docker-compose.yaml @@ -0,0 +1,40 @@ + version: "3.7" + services: + db: + image: mysql:5.6 + ports: + - 3306:3306 + environment: + - MYSQL_ROOT_PASSWORD=root + - TZ=Asia/Shanghai + volumes: + - .:/docker-entrypoint-initdb.d + command: [ + '--character-set-server=utf8', + '--collation-server=utf8_unicode_ci' + ] + healthcheck: + test: ["CMD", "mysqladmin" ,"ping", "--protocol=tcp"] + timeout: 20s + interval: 1s + retries: 20 + + redis: + image: redis + ports: + - 6379:6379 + healthcheck: + test: ["CMD", "redis-cli","ping"] + interval: 20s + timeout: 1s + retries: 20 + + memcached: + image: memcached + ports: + - 11211:11211 + healthcheck: + test: ["CMD", "echo", "stats", "|", "nc", "127.0.0.1", "11211"] + interval: 20s + timeout: 1s + retries: 20 diff --git a/tool/kratos-gen-project/templates/grpc/CHANGELOG.md b/tool/kratos-gen-project/templates/grpc/CHANGELOG.md new file mode 100644 index 000000000..c39acc0e2 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/CHANGELOG.md @@ -0,0 +1,4 @@ +## Demo + +### v1.0.0 +1. 上线功能xxx diff --git a/tool/kratos-gen-project/templates/grpc/OWNERS b/tool/kratos-gen-project/templates/grpc/OWNERS new file mode 100644 index 000000000..42d4bf1e5 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/OWNERS @@ -0,0 +1,2 @@ +# Author +# Reviewer \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/grpc/README.md b/tool/kratos-gen-project/templates/grpc/README.md new file mode 100644 index 000000000..e43f93fc3 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/README.md @@ -0,0 +1,4 @@ +# Demo + +## 项目简介 +1. diff --git a/tool/kratos-gen-project/templates/grpc/api/api.proto b/tool/kratos-gen-project/templates/grpc/api/api.proto new file mode 100644 index 000000000..98612eb9c --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/api/api.proto @@ -0,0 +1,34 @@ +// 定义项目 API 的 proto 文件 可以同时描述 gRPC 和 HTTP API +// protobuf 文件参考: +// - https://developers.google.com/protocol-buffers/ +syntax = "proto3"; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; +import "google/protobuf/empty.proto"; +import "google/api/annotations.proto"; + +// package 命名使用 {appid}.{version} 的方式, version 形如 v1, v2 .. +package demo.service.v1; + +// NOTE: 最后请删除这些无用的注释 (゜-゜)つロ + +option go_package = "api"; +option (gogoproto.goproto_getters_all) = false; + +service Demo { + rpc Ping (.google.protobuf.Empty) returns (.google.protobuf.Empty); + rpc SayHello (HelloReq) returns (.google.protobuf.Empty); + rpc SayHelloURL(HelloReq) returns (HelloResp) { + option (google.api.http) = { + get:"/abc/say_hello" + }; + }; +} + +message HelloReq { + string name = 1 [(gogoproto.moretags)='form:"name" validate:"required"']; +} + +message HelloResp { + string Content = 1 [(gogoproto.jsontag) = 'content']; +} diff --git a/tool/kratos-gen-project/templates/grpc/api/client.go.tmpl b/tool/kratos-gen-project/templates/grpc/api/client.go.tmpl new file mode 100644 index 000000000..b738a7a0c --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/api/client.go.tmpl @@ -0,0 +1,25 @@ +package api +import ( + "context" + "fmt" + + "github.com/bilibili/kratos/pkg/net/rpc/warden" + + "google.golang.org/grpc" +) + +// AppID . +const AppID = "TODO: ADD APP ID" + +// NewClient new grpc client +func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (DemoClient, error) { + client := warden.NewClient(cfg, opts...) + cc, err := client.Dial(context.Background(), fmt.Sprintf("discovery://default/%s", AppID)) + if err != nil { + return nil, err + } + return NewDemoClient(cc), nil +} + +// 生成 gRPC 代码 +//go:generate kratos tool protoc --grpc api.proto diff --git a/tool/kratos-gen-project/templates/grpc/cmd/main.go.tmpl b/tool/kratos-gen-project/templates/grpc/cmd/main.go.tmpl new file mode 100644 index 000000000..9427562f0 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/cmd/main.go.tmpl @@ -0,0 +1,41 @@ +package main + +import ( + "flag" + "os" + "os/signal" + "syscall" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/di" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +func main() { + flag.Parse() + log.Init(nil) // debug flag: log.dir={path} + defer log.Close() + log.Info("abc start") + paladin.Init() + _, closeFunc, err := di.InitApp() + if err != nil { + panic(err) + } + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) + for { + s := <-c + log.Info("get a signal %s", s.String()) + switch s { + case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT: + closeFunc() + log.Info("abc exit") + time.Sleep(time.Second) + return + case syscall.SIGHUP: + default: + return + } + } +} diff --git a/tool/kratos-gen-project/templates/grpc/configs/application.toml b/tool/kratos-gen-project/templates/grpc/configs/application.toml new file mode 100644 index 000000000..a42ca6e63 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/configs/application.toml @@ -0,0 +1,3 @@ + +# This is a TOML document. Boom~ +demoExpire = "24h" diff --git a/tool/kratos-gen-project/templates/grpc/configs/db.toml b/tool/kratos-gen-project/templates/grpc/configs/db.toml new file mode 100644 index 000000000..840bd2e78 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/configs/db.toml @@ -0,0 +1,10 @@ +[Client] + addr = "127.0.0.1:3306" + dsn = "{user}:{password}@tcp(127.0.0.1:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8" + readDSN = ["{user}:{password}@tcp(127.0.0.2:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8","{user}:{password}@tcp(127.0.0.3:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"] + active = 20 + idle = 10 + idleTimeout ="4h" + queryTimeout = "200ms" + execTimeout = "300ms" + tranTimeout = "400ms" diff --git a/tool/kratos-gen-project/templates/grpc/configs/grpc.toml b/tool/kratos-gen-project/templates/grpc/configs/grpc.toml new file mode 100644 index 000000000..40339cecc --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/configs/grpc.toml @@ -0,0 +1,3 @@ +[Server] + addr = "0.0.0.0:9000" + timeout = "1s" diff --git a/tool/kratos-gen-project/templates/grpc/configs/memcache.toml b/tool/kratos-gen-project/templates/grpc/configs/memcache.toml new file mode 100644 index 000000000..c8a1d101c --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/configs/memcache.toml @@ -0,0 +1,10 @@ +[Client] + name = "abc" + proto = "tcp" + addr = "127.0.0.1:11211" + active = 50 + idle = 10 + dialTimeout = "100ms" + readTimeout = "200ms" + writeTimeout = "300ms" + idleTimeout = "80s" diff --git a/tool/kratos-gen-project/templates/grpc/configs/redis.toml b/tool/kratos-gen-project/templates/grpc/configs/redis.toml new file mode 100644 index 000000000..294c23743 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/configs/redis.toml @@ -0,0 +1,10 @@ +[Client] + name = "abc" + proto = "tcp" + addr = "127.0.0.1:6379" + idle = 10 + active = 10 + dialTimeout = "1s" + readTimeout = "1s" + writeTimeout = "1s" + idleTimeout = "10s" diff --git a/tool/kratos-gen-project/templates/grpc/go.mod.tmpl b/tool/kratos-gen-project/templates/grpc/go.mod.tmpl new file mode 100644 index 000000000..3e2e8cb53 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/go.mod.tmpl @@ -0,0 +1,11 @@ +module {{.Name}} + +go 1.12 + +require ( + github.com/bilibili/kratos master + github.com/gogo/protobuf v1.2.1 + github.com/golang/protobuf v1.3.2 + golang.org/x/net v0.0.0-20190628185345-da137c7871d7 + google.golang.org/grpc v1.22.0 +) diff --git a/tool/kratos-gen-project/templates/grpc/internal/dao/dao.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/dao/dao.go.tmpl new file mode 100644 index 000000000..cd9f5a03d --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/dao/dao.go.tmpl @@ -0,0 +1,63 @@ +package dao + +import ( + "context" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/cache/memcache" + "github.com/bilibili/kratos/pkg/cache/redis" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/database/sql" + "github.com/bilibili/kratos/pkg/sync/pipeline/fanout" + xtime "github.com/bilibili/kratos/pkg/time" +) + +//go:generate kratos tool genbts +// Dao dao interface +type Dao interface { + Close() + Ping(ctx context.Context) (err error) + // bts: -nullcache=&model.Article{ID:-1} -check_null_code=$!=nil&&$.ID==-1 + Article(c context.Context, id int64) (*model.Article, error) +} + +// dao dao. +type dao struct { + db *sql.DB + redis *redis.Redis + mc *memcache.Memcache + cache *fanout.Fanout + demoExpire int32 +} + +// New new a dao and return. +func New(r *redis.Redis, mc *memcache.Memcache, db *sql.DB) (d Dao, err error) { + var cfg struct{ + DemoExpire xtime.Duration + } + if err = paladin.Get("application.toml").UnmarshalTOML(&cfg); err != nil { + return + } + d = &dao{ + db: db, + redis: r, + mc: mc, + cache: fanout.New("cache"), + demoExpire: int32(time.Duration(cfg.DemoExpire) / time.Second), + } + return +} + +// Close close the resource. +func (d *dao) Close() { + d.mc.Close() + d.redis.Close() + d.db.Close() + d.cache.Close() +} + +// Ping ping the resource. +func (d *dao) Ping(ctx context.Context) (err error) { + return nil +} diff --git a/tool/kratos-gen-project/templates/grpc/internal/dao/db.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/dao/db.go.tmpl new file mode 100644 index 000000000..e5bf726e5 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/dao/db.go.tmpl @@ -0,0 +1,25 @@ +package dao + +import ( + "context" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/database/sql" +) + +func NewDB() (db *sql.DB, err error) { + var cfg struct { + Client *sql.Config + } + if err = paladin.Get("db.toml").UnmarshalTOML(&cfg); err != nil { + return + } + db = sql.NewMySQL(cfg.Client) + return +} + +func (d *dao) RawArticle(ctx context.Context, id int64) (art *model.Article, err error) { + // get data from db + return +} diff --git a/tool/kratos-gen-project/templates/grpc/internal/dao/mc.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/dao/mc.go.tmpl new file mode 100644 index 000000000..7990a7067 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/dao/mc.go.tmpl @@ -0,0 +1,43 @@ +package dao + +import ( + "context" + "fmt" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/cache/memcache" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +//go:generate kratos tool genmc +type _mc interface { + // mc: -key=keyArt -type=get + CacheArticle(c context.Context, id int64) (*model.Article, error) + // mc: -key=keyArt -expire=d.demoExpire + AddCacheArticle(c context.Context, id int64, art *model.Article) (err error) + // mc: -key=keyArt + DeleteArticleCache(c context.Context, id int64) (err error) +} + +func NewMC() (mc *memcache.Memcache, err error) { + var cfg struct { + Client *memcache.Config + } + if err = paladin.Get("memcache.toml").UnmarshalTOML(&cfg); err != nil { + return + } + mc = memcache.New(cfg.Client) + return +} + +func (d *dao) PingMC(ctx context.Context) (err error) { + if err = d.mc.Set(ctx, &memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil { + log.Error("conn.Set(PING) error(%v)", err) + } + return +} + +func keyArt(id int64) string { + return fmt.Sprintf("art_%d", id) +} diff --git a/tool/kratos-gen-project/templates/grpc/internal/dao/redis.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/dao/redis.go.tmpl new file mode 100644 index 000000000..063b999ce --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/dao/redis.go.tmpl @@ -0,0 +1,27 @@ +package dao + +import ( + "context" + + "github.com/bilibili/kratos/pkg/cache/redis" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +func NewRedis() (r *redis.Redis, err error) { + var cfg struct { + Client *redis.Config + } + if err = paladin.Get("redis.toml").UnmarshalTOML(&cfg); err != nil { + return + } + r = redis.NewRedis(cfg.Client) + return +} + +func (d *dao) PingRedis(ctx context.Context) (err error) { + if _, err = d.redis.Do(ctx, "SET", "ping", "pong"); err != nil { + log.Error("conn.Set(PING) error(%v)", err) + } + return +} \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/grpc/internal/di/app.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/di/app.go.tmpl new file mode 100644 index 000000000..29a0eff1f --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/di/app.go.tmpl @@ -0,0 +1,33 @@ +package di + +import ( + "context" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/service" + + "github.com/bilibili/kratos/pkg/log" + "github.com/bilibili/kratos/pkg/net/rpc/warden" +) + +//go:generate wire +type App struct { + svc *service.Service + grpc *warden.Server +} + +func NewApp(svc *service.Service, g *warden.Server) (app *App, closeFunc func(), err error){ + app = &App{ + svc: svc, + grpc: g, + } + closeFunc = func() { + ctx, cancel := context.WithTimeout(context.Background(), 35*time.Second) + if err := g.Shutdown(ctx); err != nil { + log.Error("grpcSrv.Shutdown error(%v)", err) + } + svc.Close() + cancel() + } + return +} diff --git a/tool/kratos-gen-project/templates/grpc/internal/di/wire.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/di/wire.go.tmpl new file mode 100644 index 000000000..5c644f42f --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/di/wire.go.tmpl @@ -0,0 +1,20 @@ +// +build wireinject +// The build tag makes sure the stub is not built in the final build. + +package di + +import ( + pb "{{.ModPrefix}}{{.Name}}/api" + "{{.ModPrefix}}{{.Name}}/internal/dao" + "{{.ModPrefix}}{{.Name}}/internal/server/grpc" + "{{.ModPrefix}}{{.Name}}/internal/service" + + "github.com/google/wire" +) + +var daoProvider = wire.NewSet(dao.New, dao.NewDB, dao.NewRedis, dao.NewMC) +var serviceProvider = wire.NewSet(service.New, wire.Bind(new(pb.DemoServer), new(*service.Service))) + +func InitApp() (*App, func(), error) { + panic(wire.Build(daoProvider, serviceProvider, grpc.New, NewApp)) +} diff --git a/tool/kratos-gen-project/templates/grpc/internal/model/model.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/model/model.go.tmpl new file mode 100644 index 000000000..b3fcf7985 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/model/model.go.tmpl @@ -0,0 +1,12 @@ +package model + +// Kratos hello kratos. +type Kratos struct { + Hello string +} + +type Article struct { + ID int64 + Content string + Author string +} \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/grpc/internal/server/grpc/server.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/server/grpc/server.go.tmpl new file mode 100644 index 000000000..c1814e36d --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/server/grpc/server.go.tmpl @@ -0,0 +1,23 @@ +package grpc + +import ( + pb "{{.ModPrefix}}{{.Name}}/api" + + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/net/rpc/warden" +) + +// New new a grpc server. +func New(svc pb.DemoServer) (ws *warden.Server, err error) { + var rc struct { + Server *warden.ServerConfig + } + err = paladin.Get("grpc.toml").UnmarshalTOML(&rc) + if err == paladin.ErrNotExist { + err = nil + } + ws = warden.NewServer(rc.Server) + pb.RegisterDemoServer(ws.Server(), svc) + ws, err = ws.Start() + return +} diff --git a/tool/kratos-gen-project/templates/grpc/internal/service/service.go.tmpl b/tool/kratos-gen-project/templates/grpc/internal/service/service.go.tmpl new file mode 100644 index 000000000..34b27d6fa --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/internal/service/service.go.tmpl @@ -0,0 +1,54 @@ +package service + +import ( + "context" + "fmt" + + pb "{{.ModPrefix}}{{.Name}}/api" + "{{.ModPrefix}}{{.Name}}/internal/dao" + "github.com/bilibili/kratos/pkg/conf/paladin" + + "github.com/golang/protobuf/ptypes/empty" +) + +// Service service. +type Service struct { + ac *paladin.Map + dao dao.Dao +} + +// New new a service and return. +func New(d dao.Dao) (s *Service, err error) { + s = &Service{ + ac: &paladin.TOML{}, + dao: d, + } + err = paladin.Watch("application.toml", s.ac) + return +} + +// SayHello grpc demo func. +func (s *Service) SayHello(ctx context.Context, req *pb.HelloReq) (reply *empty.Empty, err error) { + reply = new(empty.Empty) + fmt.Printf("hello %s", req.Name) + return +} + +// SayHelloURL bm demo func. +func (s *Service) SayHelloURL(ctx context.Context, req *pb.HelloReq) (reply *pb.HelloResp, err error) { + reply = &pb.HelloResp{ + Content: "hello " + req.Name, + } + fmt.Printf("hello url %s", req.Name) + return +} + +// Ping ping the resource. +func (s *Service) Ping(ctx context.Context, e *empty.Empty) (*empty.Empty, error) { + return &empty.Empty{}, s.dao.Ping(ctx) +} + +// Close close the resource. +func (s *Service) Close() { + s.dao.Close() +} diff --git a/tool/kratos-gen-project/templates/grpc/test/docker-compose.yaml b/tool/kratos-gen-project/templates/grpc/test/docker-compose.yaml new file mode 100644 index 000000000..481f18d51 --- /dev/null +++ b/tool/kratos-gen-project/templates/grpc/test/docker-compose.yaml @@ -0,0 +1,40 @@ + version: "3.7" + services: + db: + image: mysql:5.6 + ports: + - 3306:3306 + environment: + - MYSQL_ROOT_PASSWORD=root + - TZ=Asia/Shanghai + volumes: + - .:/docker-entrypoint-initdb.d + command: [ + '--character-set-server=utf8', + '--collation-server=utf8_unicode_ci' + ] + healthcheck: + test: ["CMD", "mysqladmin" ,"ping", "--protocol=tcp"] + timeout: 20s + interval: 1s + retries: 20 + + redis: + image: redis + ports: + - 6379:6379 + healthcheck: + test: ["CMD", "redis-cli","ping"] + interval: 20s + timeout: 1s + retries: 20 + + memcached: + image: memcached + ports: + - 11211:11211 + healthcheck: + test: ["CMD", "echo", "stats", "|", "nc", "127.0.0.1", "11211"] + interval: 20s + timeout: 1s + retries: 20 diff --git a/tool/kratos-gen-project/templates/http/CHANGELOG.md b/tool/kratos-gen-project/templates/http/CHANGELOG.md new file mode 100644 index 000000000..c39acc0e2 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/CHANGELOG.md @@ -0,0 +1,4 @@ +## Demo + +### v1.0.0 +1. 上线功能xxx diff --git a/tool/kratos-gen-project/templates/http/OWNERS b/tool/kratos-gen-project/templates/http/OWNERS new file mode 100644 index 000000000..c1e28c554 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/OWNERS @@ -0,0 +1,2 @@ +# Author +# Reviewer diff --git a/tool/kratos-gen-project/templates/http/README.md b/tool/kratos-gen-project/templates/http/README.md new file mode 100644 index 000000000..e43f93fc3 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/README.md @@ -0,0 +1,4 @@ +# Demo + +## 项目简介 +1. diff --git a/tool/kratos-gen-project/templates/http/api/api.proto b/tool/kratos-gen-project/templates/http/api/api.proto new file mode 100644 index 000000000..98612eb9c --- /dev/null +++ b/tool/kratos-gen-project/templates/http/api/api.proto @@ -0,0 +1,34 @@ +// 定义项目 API 的 proto 文件 可以同时描述 gRPC 和 HTTP API +// protobuf 文件参考: +// - https://developers.google.com/protocol-buffers/ +syntax = "proto3"; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; +import "google/protobuf/empty.proto"; +import "google/api/annotations.proto"; + +// package 命名使用 {appid}.{version} 的方式, version 形如 v1, v2 .. +package demo.service.v1; + +// NOTE: 最后请删除这些无用的注释 (゜-゜)つロ + +option go_package = "api"; +option (gogoproto.goproto_getters_all) = false; + +service Demo { + rpc Ping (.google.protobuf.Empty) returns (.google.protobuf.Empty); + rpc SayHello (HelloReq) returns (.google.protobuf.Empty); + rpc SayHelloURL(HelloReq) returns (HelloResp) { + option (google.api.http) = { + get:"/abc/say_hello" + }; + }; +} + +message HelloReq { + string name = 1 [(gogoproto.moretags)='form:"name" validate:"required"']; +} + +message HelloResp { + string Content = 1 [(gogoproto.jsontag) = 'content']; +} diff --git a/tool/kratos-gen-project/templates/http/api/client.go.tmpl b/tool/kratos-gen-project/templates/http/api/client.go.tmpl new file mode 100644 index 000000000..2b0875e89 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/api/client.go.tmpl @@ -0,0 +1,25 @@ +package api +import ( + "context" + "fmt" + + "github.com/bilibili/kratos/pkg/net/rpc/warden" + + "google.golang.org/grpc" +) + +// AppID . +const AppID = "TODO: ADD APP ID" + +// NewClient new grpc client +func NewClient(cfg *warden.ClientConfig, opts ...grpc.DialOption) (DemoClient, error) { + client := warden.NewClient(cfg, opts...) + cc, err := client.Dial(context.Background(), fmt.Sprintf("discovery://default/%s", AppID)) + if err != nil { + return nil, err + } + return NewDemoClient(cc), nil +} + +// 生成 gRPC 代码 +//go:generate kratos tool protoc --grpc --bm api.proto diff --git a/tool/kratos-gen-project/templates/http/cmd/main.go.tmpl b/tool/kratos-gen-project/templates/http/cmd/main.go.tmpl new file mode 100644 index 000000000..9427562f0 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/cmd/main.go.tmpl @@ -0,0 +1,41 @@ +package main + +import ( + "flag" + "os" + "os/signal" + "syscall" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/di" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +func main() { + flag.Parse() + log.Init(nil) // debug flag: log.dir={path} + defer log.Close() + log.Info("abc start") + paladin.Init() + _, closeFunc, err := di.InitApp() + if err != nil { + panic(err) + } + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) + for { + s := <-c + log.Info("get a signal %s", s.String()) + switch s { + case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT: + closeFunc() + log.Info("abc exit") + time.Sleep(time.Second) + return + case syscall.SIGHUP: + default: + return + } + } +} diff --git a/tool/kratos-gen-project/templates/http/configs/application.toml b/tool/kratos-gen-project/templates/http/configs/application.toml new file mode 100644 index 000000000..a42ca6e63 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/configs/application.toml @@ -0,0 +1,3 @@ + +# This is a TOML document. Boom~ +demoExpire = "24h" diff --git a/tool/kratos-gen-project/templates/http/configs/db.toml b/tool/kratos-gen-project/templates/http/configs/db.toml new file mode 100644 index 000000000..840bd2e78 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/configs/db.toml @@ -0,0 +1,10 @@ +[Client] + addr = "127.0.0.1:3306" + dsn = "{user}:{password}@tcp(127.0.0.1:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8" + readDSN = ["{user}:{password}@tcp(127.0.0.2:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8mb4,utf8","{user}:{password}@tcp(127.0.0.3:3306)/{database}?timeout=1s&readTimeout=1s&writeTimeout=1s&parseTime=true&loc=Local&charset=utf8,utf8mb4"] + active = 20 + idle = 10 + idleTimeout ="4h" + queryTimeout = "200ms" + execTimeout = "300ms" + tranTimeout = "400ms" diff --git a/tool/kratos-gen-project/templates/http/configs/http.toml b/tool/kratos-gen-project/templates/http/configs/http.toml new file mode 100644 index 000000000..951a03197 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/configs/http.toml @@ -0,0 +1,3 @@ +[Server] + addr = "0.0.0.0:8000" + timeout = "1s" diff --git a/tool/kratos-gen-project/templates/http/configs/memcache.toml b/tool/kratos-gen-project/templates/http/configs/memcache.toml new file mode 100644 index 000000000..c8a1d101c --- /dev/null +++ b/tool/kratos-gen-project/templates/http/configs/memcache.toml @@ -0,0 +1,10 @@ +[Client] + name = "abc" + proto = "tcp" + addr = "127.0.0.1:11211" + active = 50 + idle = 10 + dialTimeout = "100ms" + readTimeout = "200ms" + writeTimeout = "300ms" + idleTimeout = "80s" diff --git a/tool/kratos-gen-project/templates/http/configs/redis.toml b/tool/kratos-gen-project/templates/http/configs/redis.toml new file mode 100644 index 000000000..294c23743 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/configs/redis.toml @@ -0,0 +1,10 @@ +[Client] + name = "abc" + proto = "tcp" + addr = "127.0.0.1:6379" + idle = 10 + active = 10 + dialTimeout = "1s" + readTimeout = "1s" + writeTimeout = "1s" + idleTimeout = "10s" diff --git a/tool/kratos-gen-project/templates/http/go.mod.tmpl b/tool/kratos-gen-project/templates/http/go.mod.tmpl new file mode 100644 index 000000000..3e2e8cb53 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/go.mod.tmpl @@ -0,0 +1,11 @@ +module {{.Name}} + +go 1.12 + +require ( + github.com/bilibili/kratos master + github.com/gogo/protobuf v1.2.1 + github.com/golang/protobuf v1.3.2 + golang.org/x/net v0.0.0-20190628185345-da137c7871d7 + google.golang.org/grpc v1.22.0 +) diff --git a/tool/kratos-gen-project/templates/http/internal/dao/dao.go.tmpl b/tool/kratos-gen-project/templates/http/internal/dao/dao.go.tmpl new file mode 100644 index 000000000..cd9f5a03d --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/dao/dao.go.tmpl @@ -0,0 +1,63 @@ +package dao + +import ( + "context" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/cache/memcache" + "github.com/bilibili/kratos/pkg/cache/redis" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/database/sql" + "github.com/bilibili/kratos/pkg/sync/pipeline/fanout" + xtime "github.com/bilibili/kratos/pkg/time" +) + +//go:generate kratos tool genbts +// Dao dao interface +type Dao interface { + Close() + Ping(ctx context.Context) (err error) + // bts: -nullcache=&model.Article{ID:-1} -check_null_code=$!=nil&&$.ID==-1 + Article(c context.Context, id int64) (*model.Article, error) +} + +// dao dao. +type dao struct { + db *sql.DB + redis *redis.Redis + mc *memcache.Memcache + cache *fanout.Fanout + demoExpire int32 +} + +// New new a dao and return. +func New(r *redis.Redis, mc *memcache.Memcache, db *sql.DB) (d Dao, err error) { + var cfg struct{ + DemoExpire xtime.Duration + } + if err = paladin.Get("application.toml").UnmarshalTOML(&cfg); err != nil { + return + } + d = &dao{ + db: db, + redis: r, + mc: mc, + cache: fanout.New("cache"), + demoExpire: int32(time.Duration(cfg.DemoExpire) / time.Second), + } + return +} + +// Close close the resource. +func (d *dao) Close() { + d.mc.Close() + d.redis.Close() + d.db.Close() + d.cache.Close() +} + +// Ping ping the resource. +func (d *dao) Ping(ctx context.Context) (err error) { + return nil +} diff --git a/tool/kratos-gen-project/templates/http/internal/dao/db.go.tmpl b/tool/kratos-gen-project/templates/http/internal/dao/db.go.tmpl new file mode 100644 index 000000000..e5bf726e5 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/dao/db.go.tmpl @@ -0,0 +1,25 @@ +package dao + +import ( + "context" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/database/sql" +) + +func NewDB() (db *sql.DB, err error) { + var cfg struct { + Client *sql.Config + } + if err = paladin.Get("db.toml").UnmarshalTOML(&cfg); err != nil { + return + } + db = sql.NewMySQL(cfg.Client) + return +} + +func (d *dao) RawArticle(ctx context.Context, id int64) (art *model.Article, err error) { + // get data from db + return +} diff --git a/tool/kratos-gen-project/templates/http/internal/dao/mc.go.tmpl b/tool/kratos-gen-project/templates/http/internal/dao/mc.go.tmpl new file mode 100644 index 000000000..7990a7067 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/dao/mc.go.tmpl @@ -0,0 +1,43 @@ +package dao + +import ( + "context" + "fmt" + + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/cache/memcache" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +//go:generate kratos tool genmc +type _mc interface { + // mc: -key=keyArt -type=get + CacheArticle(c context.Context, id int64) (*model.Article, error) + // mc: -key=keyArt -expire=d.demoExpire + AddCacheArticle(c context.Context, id int64, art *model.Article) (err error) + // mc: -key=keyArt + DeleteArticleCache(c context.Context, id int64) (err error) +} + +func NewMC() (mc *memcache.Memcache, err error) { + var cfg struct { + Client *memcache.Config + } + if err = paladin.Get("memcache.toml").UnmarshalTOML(&cfg); err != nil { + return + } + mc = memcache.New(cfg.Client) + return +} + +func (d *dao) PingMC(ctx context.Context) (err error) { + if err = d.mc.Set(ctx, &memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil { + log.Error("conn.Set(PING) error(%v)", err) + } + return +} + +func keyArt(id int64) string { + return fmt.Sprintf("art_%d", id) +} diff --git a/tool/kratos-gen-project/templates/http/internal/dao/redis.go.tmpl b/tool/kratos-gen-project/templates/http/internal/dao/redis.go.tmpl new file mode 100644 index 000000000..063b999ce --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/dao/redis.go.tmpl @@ -0,0 +1,27 @@ +package dao + +import ( + "context" + + "github.com/bilibili/kratos/pkg/cache/redis" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" +) + +func NewRedis() (r *redis.Redis, err error) { + var cfg struct { + Client *redis.Config + } + if err = paladin.Get("redis.toml").UnmarshalTOML(&cfg); err != nil { + return + } + r = redis.NewRedis(cfg.Client) + return +} + +func (d *dao) PingRedis(ctx context.Context) (err error) { + if _, err = d.redis.Do(ctx, "SET", "ping", "pong"); err != nil { + log.Error("conn.Set(PING) error(%v)", err) + } + return +} \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/http/internal/di/app.go.tmpl b/tool/kratos-gen-project/templates/http/internal/di/app.go.tmpl new file mode 100644 index 000000000..7a5852329 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/di/app.go.tmpl @@ -0,0 +1,33 @@ +package di + +import ( + "context" + "time" + + "{{.ModPrefix}}{{.Name}}/internal/service" + + "github.com/bilibili/kratos/pkg/log" + bm "github.com/bilibili/kratos/pkg/net/http/blademaster" +) + +//go:generate wire +type App struct { + svc *service.Service + http *bm.Engine +} + +func NewApp(svc *service.Service, h *bm.Engine) (app *App, closeFunc func(), err error){ + app = &App{ + svc: svc, + http: h, + } + closeFunc = func() { + ctx, cancel := context.WithTimeout(context.Background(), 35*time.Second) + if err := h.Shutdown(ctx); err != nil { + log.Error("httpSrv.Shutdown error(%v)", err) + } + svc.Close() + cancel() + } + return +} diff --git a/tool/kratos-gen-project/templates/http/internal/di/wire.go.tmpl b/tool/kratos-gen-project/templates/http/internal/di/wire.go.tmpl new file mode 100644 index 000000000..2bbd5edbc --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/di/wire.go.tmpl @@ -0,0 +1,20 @@ +// +build wireinject +// The build tag makes sure the stub is not built in the final build. + +package di + +import ( + pb "{{.ModPrefix}}{{.Name}}/api" + "{{.ModPrefix}}{{.Name}}/internal/dao" + "{{.ModPrefix}}{{.Name}}/internal/server/http" + "{{.ModPrefix}}{{.Name}}/internal/service" + + "github.com/google/wire" +) + +var daoProvider = wire.NewSet(dao.New, dao.NewDB, dao.NewRedis, dao.NewMC) +var serviceProvider = wire.NewSet(service.New, wire.Bind(new(pb.DemoServer), new(*service.Service))) + +func InitApp() (*App, func(), error) { + panic(wire.Build(daoProvider, serviceProvider, http.New, NewApp)) +} diff --git a/tool/kratos-gen-project/templates/http/internal/model/model.go.tmpl b/tool/kratos-gen-project/templates/http/internal/model/model.go.tmpl new file mode 100644 index 000000000..b3fcf7985 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/model/model.go.tmpl @@ -0,0 +1,12 @@ +package model + +// Kratos hello kratos. +type Kratos struct { + Hello string +} + +type Article struct { + ID int64 + Content string + Author string +} \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/http/internal/server/http/server.go.tmpl b/tool/kratos-gen-project/templates/http/internal/server/http/server.go.tmpl new file mode 100644 index 000000000..2917e8499 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/server/http/server.go.tmpl @@ -0,0 +1,57 @@ +package http + +import ( + "net/http" + + pb "{{.ModPrefix}}{{.Name}}/api" + "{{.ModPrefix}}{{.Name}}/internal/model" + "github.com/bilibili/kratos/pkg/conf/paladin" + "github.com/bilibili/kratos/pkg/log" + bm "github.com/bilibili/kratos/pkg/net/http/blademaster" +) + +var svc pb.DemoServer + +// New new a bm server. +func New(s pb.DemoServer) (engine *bm.Engine, err error) { + var ( + hc struct { + Server *bm.ServerConfig + } + ) + if err = paladin.Get("http.toml").UnmarshalTOML(&hc); err != nil { + if err != paladin.ErrNotExist { + return + } + err = nil + } + svc = s + engine = bm.DefaultServer(hc.Server) + pb.RegisterDemoBMServer(engine, s) + initRouter(engine) + err = engine.Start() + return +} + +func initRouter(e *bm.Engine) { + e.Ping(ping) + g := e.Group("/abc") + { + g.GET("/start", howToStart) + } +} + +func ping(ctx *bm.Context) { + if _, err := svc.Ping(ctx, nil); err != nil { + log.Error("ping error(%v)", err) + ctx.AbortWithStatus(http.StatusServiceUnavailable) + } +} + +// example for http request handler. +func howToStart(c *bm.Context) { + k := &model.Kratos{ + Hello: "Golang 大法好 !!!", + } + c.JSON(k, nil) +} \ No newline at end of file diff --git a/tool/kratos-gen-project/templates/http/internal/service/service.go.tmpl b/tool/kratos-gen-project/templates/http/internal/service/service.go.tmpl new file mode 100644 index 000000000..34b27d6fa --- /dev/null +++ b/tool/kratos-gen-project/templates/http/internal/service/service.go.tmpl @@ -0,0 +1,54 @@ +package service + +import ( + "context" + "fmt" + + pb "{{.ModPrefix}}{{.Name}}/api" + "{{.ModPrefix}}{{.Name}}/internal/dao" + "github.com/bilibili/kratos/pkg/conf/paladin" + + "github.com/golang/protobuf/ptypes/empty" +) + +// Service service. +type Service struct { + ac *paladin.Map + dao dao.Dao +} + +// New new a service and return. +func New(d dao.Dao) (s *Service, err error) { + s = &Service{ + ac: &paladin.TOML{}, + dao: d, + } + err = paladin.Watch("application.toml", s.ac) + return +} + +// SayHello grpc demo func. +func (s *Service) SayHello(ctx context.Context, req *pb.HelloReq) (reply *empty.Empty, err error) { + reply = new(empty.Empty) + fmt.Printf("hello %s", req.Name) + return +} + +// SayHelloURL bm demo func. +func (s *Service) SayHelloURL(ctx context.Context, req *pb.HelloReq) (reply *pb.HelloResp, err error) { + reply = &pb.HelloResp{ + Content: "hello " + req.Name, + } + fmt.Printf("hello url %s", req.Name) + return +} + +// Ping ping the resource. +func (s *Service) Ping(ctx context.Context, e *empty.Empty) (*empty.Empty, error) { + return &empty.Empty{}, s.dao.Ping(ctx) +} + +// Close close the resource. +func (s *Service) Close() { + s.dao.Close() +} diff --git a/tool/kratos-gen-project/templates/http/test/docker-compose.yaml b/tool/kratos-gen-project/templates/http/test/docker-compose.yaml new file mode 100644 index 000000000..481f18d51 --- /dev/null +++ b/tool/kratos-gen-project/templates/http/test/docker-compose.yaml @@ -0,0 +1,40 @@ + version: "3.7" + services: + db: + image: mysql:5.6 + ports: + - 3306:3306 + environment: + - MYSQL_ROOT_PASSWORD=root + - TZ=Asia/Shanghai + volumes: + - .:/docker-entrypoint-initdb.d + command: [ + '--character-set-server=utf8', + '--collation-server=utf8_unicode_ci' + ] + healthcheck: + test: ["CMD", "mysqladmin" ,"ping", "--protocol=tcp"] + timeout: 20s + interval: 1s + retries: 20 + + redis: + image: redis + ports: + - 6379:6379 + healthcheck: + test: ["CMD", "redis-cli","ping"] + interval: 20s + timeout: 1s + retries: 20 + + memcached: + image: memcached + ports: + - 11211:11211 + healthcheck: + test: ["CMD", "echo", "stats", "|", "nc", "127.0.0.1", "11211"] + interval: 20s + timeout: 1s + retries: 20 diff --git a/tool/kratos-gen-project/testdata/test_in_gomod.sh b/tool/kratos-gen-project/testdata/test_in_gomod.sh new file mode 100755 index 000000000..79bc1a6d6 --- /dev/null +++ b/tool/kratos-gen-project/testdata/test_in_gomod.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -e + +rm -rf ./a +kratos new a +cd ./a/cmd && go build +if [ $? -ne 0 ] +then + echo "Failed: all" + exit 1 +fi +rm -rf ./b +kratos new b --grpc +cd ./b/cmd && go build +if [ $? -ne 0 ] +then + echo "Failed: --grpc" + exit 1 +fi +rm -rf ./c +kratos new c --http +cd ./c/cmd && go build +if [ $? -ne 0 ] +then + echo "Failed: --http" + exit 1 +fi diff --git a/tool/kratos-gen-project/testdata/test_not_in_gomod.sh b/tool/kratos-gen-project/testdata/test_not_in_gomod.sh new file mode 100755 index 000000000..154d68c4a --- /dev/null +++ b/tool/kratos-gen-project/testdata/test_not_in_gomod.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -e + +rm -rf /tmp/test-kratos +mkdir /tmp/test-kratos +kratos new a -d /tmp/test-kratos +cd /tmp/test-kratos/a/cmd && go build +if [ $? -ne 0 ] +then + echo "Failed: all" + exit 1 +fi +kratos new b -d /tmp/test-kratos --grpc +cd /tmp/test-kratos/b/cmd && go build +if [ $? -ne 0 ] +then + echo "Failed: --grpc" + exit 1 +fi +kratos new c -d /tmp/test-kratos --http +cd /tmp/test-kratos/c/cmd && go build +if [ $? -ne 0 ] +then + echo "Failed: --http" + exit 1 +fi diff --git a/tool/kratos/main.go b/tool/kratos/main.go index ec71239cc..e79c2f8d7 100644 --- a/tool/kratos/main.go +++ b/tool/kratos/main.go @@ -14,34 +14,11 @@ func main() { app.Version = Version app.Commands = []cli.Command{ { - Name: "new", - Aliases: []string{"n"}, - Usage: "create new project", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "o", - Value: "", - Usage: "project owner for create project", - Destination: &p.Owner, - }, - cli.StringFlag{ - Name: "d", - Value: "", - Usage: "project directory for create project", - Destination: &p.Path, - }, - cli.BoolFlag{ - Name: "proto", - Usage: "whether to use protobuf for create project", - Destination: &p.WithGRPC, - }, - cli.StringFlag{ - Name: "m", - Usage: "project module name for create project, for `go mod init`", - Destination: &p.ModuleName, - }, - }, - Action: runNew, + Name: "new", + Aliases: []string{"n"}, + Usage: "创建新项目", + Action: runNew, + SkipFlagParsing: true, }, { Name: "build", @@ -82,3 +59,7 @@ func main() { panic(err) } } + +func runNew(ctx *cli.Context) error { + return installAndRun("genproject", ctx.Args()) +} diff --git a/tool/kratos/new.go b/tool/kratos/new.go deleted file mode 100644 index 2b2b08ad7..000000000 --- a/tool/kratos/new.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "os" - "path" - "path/filepath" - - "github.com/urfave/cli" -) - -func runNew(ctx *cli.Context) error { - if len(ctx.Args()) == 0 { - return errors.New("project name required, please enter a project name you want to create") - } - p.Name = ctx.Args()[0] - - if p.ModuleName == "" { - p.ModuleName = p.Name - } - - if p.Path != "" { - p.Path = path.Join(p.Path, p.Name) - } else { - pwd, _ := os.Getwd() - p.Path = path.Join(pwd, p.Name) - } - p.Path = filepath.FromSlash(p.Path) - // Create a project - if err := create(); err != nil { - return err - } - fmt.Printf("Project: %s\n", p.Name) - fmt.Printf("Owner: %s\n", p.Owner) - fmt.Printf("Module Name: %s\n", p.ModuleName) - fmt.Printf("WithGRPC: %t\n", p.WithGRPC) - fmt.Printf("Directory: %s\n\n", p.Path) - fmt.Println("The application has been created.") - return nil -} diff --git a/tool/kratos/project.go b/tool/kratos/project.go deleted file mode 100644 index 670b70400..000000000 --- a/tool/kratos/project.go +++ /dev/null @@ -1,146 +0,0 @@ -package main - -import ( - "bytes" - "io/ioutil" - "os" - "os/exec" - "strings" - "text/template" -) - -// project project config -type project struct { - Name string - Owner string - Path string - WithGRPC bool - Here bool - ModuleName string // 支持项目的自定义module名 (go.mod init) -} - -const ( - _tplTypeDao = iota - _tplTypeHTTPServer - _tplTypeAPIProto - _tplTypeService - _tplTypeMain - _tplTypeChangeLog - _tplTypeContributors - _tplTypeReadme - _tplTypeAppToml - _tplTypeMySQLToml - _tplTypeMCToml - _tplTypeRedisToml - _tplTypeHTTPToml - _tplTypeGRPCToml - _tplTypeModel - _tplTypeGRPCServer - _tplTypeGomod - _tplTypeAPIGogen -) - -var ( - p project - // files type => path - files = map[int]string{ - // init doc - _tplTypeChangeLog: "/CHANGELOG.md", - _tplTypeContributors: "/CONTRIBUTORS.md", - _tplTypeReadme: "/README.md", - // init project - _tplTypeGomod: "/go.mod", - _tplTypeMain: "/cmd/main.go", - _tplTypeDao: "/internal/dao/dao.go", - _tplTypeHTTPServer: "/internal/server/http/server.go", - _tplTypeService: "/internal/service/service.go", - _tplTypeModel: "/internal/model/model.go", - // init config - _tplTypeAppToml: "/configs/application.toml", - _tplTypeMySQLToml: "/configs/mysql.toml", - _tplTypeMCToml: "/configs/memcache.toml", - _tplTypeRedisToml: "/configs/redis.toml", - _tplTypeHTTPToml: "/configs/http.toml", - _tplTypeGRPCToml: "/configs/grpc.toml", - } - // tpls type => content - tpls = map[int]string{ - _tplTypeDao: _tplDao, - _tplTypeHTTPServer: _tplHTTPServer, - _tplTypeAPIProto: _tplAPIProto, - _tplTypeMain: _tplMain, - _tplTypeService: _tplService, - _tplTypeChangeLog: _tplChangeLog, - _tplTypeContributors: _tplContributors, - _tplTypeReadme: _tplReadme, - _tplTypeMySQLToml: _tplMySQLToml, - _tplTypeMCToml: _tplMCToml, - _tplTypeRedisToml: _tplRedisToml, - _tplTypeAppToml: _tplAppToml, - _tplTypeHTTPToml: _tplHTTPToml, - _tplTypeModel: _tplModel, - _tplTypeGomod: _tplGoMod, - _tplTypeAPIGogen: _tplGogen, - } -) - -func create() (err error) { - if p.WithGRPC { - files[_tplTypeGRPCServer] = "/internal/server/grpc/server.go" - files[_tplTypeAPIProto] = "/api/api.proto" - files[_tplTypeAPIGogen] = "/api/generate.go" - tpls[_tplTypeHTTPServer] = _tplPBHTTPServer - tpls[_tplTypeGRPCServer] = _tplGRPCServer - tpls[_tplTypeGRPCToml] = _tplGRPCToml - tpls[_tplTypeService] = _tplGPRCService - tpls[_tplTypeMain] = _tplGRPCMain - } - if err = os.MkdirAll(p.Path, 0755); err != nil { - return - } - for t, v := range files { - i := strings.LastIndex(v, "/") - if i > 0 { - dir := v[:i] - if err = os.MkdirAll(p.Path+dir, 0755); err != nil { - return - } - } - if err = write(p.Path+v, tpls[t]); err != nil { - return - } - } - if p.WithGRPC { - if err = genpb(); err != nil { - return - } - } - return -} - -func genpb() error { - cmd := exec.Command("kratos", "tool", "protoc", p.Name+"/api/api.proto") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() -} - -func write(name, tpl string) (err error) { - data, err := parse(tpl) - if err != nil { - return - } - return ioutil.WriteFile(name, data, 0644) -} - -func parse(s string) ([]byte, error) { - t, err := template.New("").Parse(s) - if err != nil { - return nil, err - } - var buf bytes.Buffer - if err = t.Execute(&buf, p); err != nil { - return nil, err - } - return buf.Bytes(), nil -} diff --git a/tool/kratos/tool.go b/tool/kratos/tool.go index cc7f0c258..7cfea9aab 100644 --- a/tool/kratos/tool.go +++ b/tool/kratos/tool.go @@ -20,20 +20,44 @@ const ( toolDoc = "https://github.com/bilibili/kratos/blob/master/doc/wiki-cn/kratos-tool.md" ) +type Tool struct { + Name string `json:"name"` + Alias string `json:"alias"` + BuildTime time.Time `json:"build_time"` + Install string `json:"install"` + Requirements []string `json:"requirements"` + Dir string `json:"dir"` + Summary string `json:"summary"` + Platform []string `json:"platform"` + Author string `json:"author"` + URL string `json:"url"` + Hidden bool `json:"hidden"` + requires []*Tool +} + func toolAction(c *cli.Context) (err error) { if c.NArg() == 0 { sort.Slice(toolIndexs, func(i, j int) bool { return toolIndexs[i].BuildTime.After(toolIndexs[j].BuildTime) }) for _, t := range toolIndexs { + if t.Hidden { + continue + } updateTime := t.BuildTime.Format("2006/01/02") fmt.Printf("%s%s: %s Author(%s) [%s]\n", color.HiMagentaString(t.Name), getNotice(t), color.HiCyanString(t.Summary), t.Author, updateTime) } fmt.Println("\n安装工具: kratos tool install demo") fmt.Println("执行工具: kratos tool demo") fmt.Println("安装全部工具: kratos tool install all") + fmt.Println("全部升级: kratos tool upgrade all") fmt.Println("\n详细文档:", toolDoc) return } - if c.Args().First() == "install" { + commond := c.Args().First() + switch commond { + case "upgrade": + upgradeAll() + return + case "install": name := c.Args().Get(1) if name == "all" { installAll() @@ -41,24 +65,42 @@ func toolAction(c *cli.Context) (err error) { install(name) } return + case "check_install": + if e := checkInstall(c.Args().Get(1)); e != nil { + fmt.Fprintf(os.Stderr, fmt.Sprintf("%v\n", e)) + } + return } - name := c.Args().First() - for _, t := range toolIndexs { + if e := installAndRun(commond, c.Args()[1:]); e != nil { + fmt.Fprintf(os.Stderr, fmt.Sprintf("%v\n", e)) + } + return +} + +func installAndRun(name string, args []string) (err error) { + for _, t := range toolList() { if name == t.Name { - if !t.installed() || t.updated() { - install(name) + if !t.installed() || t.needUpdated() { + t.install() } pwd, _ := os.Getwd() - var args []string - if c.NArg() > 1 { - args = []string(c.Args())[1:] + err = runTool(t.Name, pwd, t.toolPath(), args) + return + } + } + return fmt.Errorf("找不到%s", name) +} + +func checkInstall(name string) (err error) { + for _, t := range toolList() { + if name == t.Name { + if !t.installed() || t.needUpdated() { + t.install() } - runTool(t.Name, pwd, t.toolPath(), args) return } } - fmt.Fprintf(os.Stderr, "还未安装 %s\n", name) - return + return fmt.Errorf("找不到%s", name) } func upgradeAction(c *cli.Context) error { @@ -71,7 +113,7 @@ func install(name string) { fmt.Fprintf(os.Stderr, color.HiRedString("请填写要安装的工具名称\n")) return } - for _, t := range toolIndexs { + for _, t := range toolList() { if name == t.Name { t.install() return @@ -82,60 +124,70 @@ func install(name string) { } func installAll() { - for _, t := range toolIndexs { + for _, t := range toolList() { if t.Install != "" { t.install() } } } +func upgradeAll() { + for _, t := range toolList() { + if t.needUpdated() { + t.install() + } + } +} + +func toolList() (tools []*Tool) { + return toolIndexs +} + func getNotice(t *Tool) (notice string) { if !t.supportOS() || t.Install == "" { return } notice = color.HiGreenString("(未安装)") - if f, err := os.Stat(t.toolPath()); err == nil { + if t.installed() { notice = color.HiBlueString("(已安装)") - if t.BuildTime.After(f.ModTime()) { + if t.needUpdated() { notice = color.RedString("(有更新)") } } return } -func runTool(name, dir, cmd string, args []string) (err error) { - toolCmd := &exec.Cmd{ - Path: cmd, - Args: append([]string{cmd}, args...), - Dir: dir, - Stdin: os.Stdin, - Stdout: os.Stdout, - Stderr: os.Stderr, - Env: os.Environ(), - } - if filepath.Base(cmd) == cmd { - var lp string - if lp, err = exec.LookPath(cmd); err == nil { - toolCmd.Path = lp +func (t Tool) needUpdated() bool { + for _, r := range t.requires { + if r.needUpdated() { + return true } } - if err = toolCmd.Run(); err != nil { - if e, ok := err.(*exec.ExitError); !ok || !e.Exited() { - fmt.Fprintf(os.Stderr, "运行 %s 出错: %v\n", name, err) + if !t.supportOS() || t.Install == "" { + return false + } + if f, err := os.Stat(t.toolPath()); err == nil { + if t.BuildTime.After(f.ModTime()) { + return true } } - return + return false } -// Tool . -type Tool struct { - Name string `json:"name"` - Alias string `json:"alias"` - BuildTime time.Time `json:"build_time"` - Install string `json:"install"` - Summary string `json:"summary"` - Platform []string `json:"platform"` - Author string `json:"author"` +func (t Tool) toolPath() string { + name := t.Alias + if name == "" { + name = t.Name + } + if gobin := os.Getenv("GOBIN"); len(gobin) > 0 { + return filepath.Join(gobin, t.Alias) + } + return filepath.Join(gopath(), "bin", t.Alias) +} + +func (t Tool) installed() bool { + _, err := os.Stat(t.toolPath()) + return err == nil } func (t Tool) supportOS() bool { @@ -173,18 +225,6 @@ func (t Tool) updated() bool { return false } -func (t Tool) toolPath() string { - if gobin := os.Getenv("GOBIN"); len(gobin) > 0 { - return filepath.Join(gobin, t.Alias) - } - return filepath.Join(gopath(), "bin", t.Alias) -} - -func (t Tool) installed() bool { - _, err := os.Stat(t.toolPath()) - return err == nil -} - func gopath() (gp string) { gopaths := strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator)) @@ -213,3 +253,27 @@ func gopath() (gp string) { } return build.Default.GOPATH } + +func runTool(name, dir, cmd string, args []string) (err error) { + toolCmd := &exec.Cmd{ + Path: cmd, + Args: append([]string{cmd}, args...), + Dir: dir, + Stdin: os.Stdin, + Stdout: os.Stdout, + Stderr: os.Stderr, + Env: os.Environ(), + } + if filepath.Base(cmd) == cmd { + var lp string + if lp, err = exec.LookPath(cmd); err == nil { + toolCmd.Path = lp + } + } + if err = toolCmd.Run(); err != nil { + if e, ok := err.(*exec.ExitError); !ok || !e.Exited() { + fmt.Fprintf(os.Stderr, "运行 %s 出错: %v\n", name, err) + } + } + return +} diff --git a/tool/kratos/tool_index.go b/tool/kratos/tool_index.go index 1a5edb73b..c3e9d4782 100644 --- a/tool/kratos/tool_index.go +++ b/tool/kratos/tool_index.go @@ -3,7 +3,7 @@ package main import "time" var toolIndexs = []*Tool{ - &Tool{ + { Name: "kratos", Alias: "kratos", BuildTime: time.Date(2019, 6, 21, 0, 0, 0, 0, time.Local), @@ -11,17 +11,18 @@ var toolIndexs = []*Tool{ Summary: "Kratos工具集本体", Platform: []string{"darwin", "linux", "windows"}, Author: "kratos", + Hidden: true, }, - &Tool{ + { Name: "protoc", Alias: "kratos-protoc", - BuildTime: time.Date(2019, 6, 21, 0, 0, 0, 0, time.Local), + BuildTime: time.Date(2019, 10, 31, 0, 0, 0, 0, time.Local), Install: "go get -u github.com/bilibili/kratos/tool/kratos-protoc", Summary: "快速方便生成pb.go的protoc封装,windows、Linux请先安装protoc工具", Platform: []string{"darwin", "linux", "windows"}, Author: "kratos", }, - &Tool{ + { Name: "swagger", Alias: "swagger", BuildTime: time.Date(2019, 5, 5, 0, 0, 0, 0, time.Local), @@ -30,16 +31,16 @@ var toolIndexs = []*Tool{ Platform: []string{"darwin", "linux", "windows"}, Author: "goswagger.io", }, - &Tool{ + { Name: "genbts", Alias: "kratos-gen-bts", - BuildTime: time.Date(2019, 7, 23, 0, 0, 0, 0, time.Local), + BuildTime: time.Date(2019, 10, 31, 0, 0, 0, 0, time.Local), Install: "go get -u github.com/bilibili/kratos/tool/kratos-gen-bts", Summary: "缓存回源逻辑代码生成器", Platform: []string{"darwin", "linux", "windows"}, Author: "kratos", }, - &Tool{ + { Name: "genmc", Alias: "kratos-gen-mc", BuildTime: time.Date(2019, 7, 23, 0, 0, 0, 0, time.Local), @@ -48,4 +49,29 @@ var toolIndexs = []*Tool{ Platform: []string{"darwin", "linux", "windows"}, Author: "kratos", }, + { + Name: "wire", + BuildTime: time.Date(2019, 8, 20, 0, 0, 0, 0, time.Local), + Install: "go get -u github.com/google/wire/cmd/wire", + Platform: []string{"darwin", "linux", "windows"}, + Hidden: true, + }, + { + Name: "genproject", + Alias: "kratos-gen-project", + Install: "go get -u github.com/bilibili/kratos/tool/kratos-gen-project", + BuildTime: time.Date(2019, 11, 3, 0, 0, 0, 0, time.Local), + Platform: []string{"darwin", "linux", "windows"}, + Hidden: true, + Requirements: []string{"wire"}, + }, + { + Name: "testcli", + Alias: "testcli", + BuildTime: time.Date(2019, 9, 9, 0, 0, 0, 0, time.Local), + Install: "go get -u github.com/bilibili/kratos/tool/testcli", + Summary: "测试代码生成", + Platform: []string{"darwin", "linux", "windows"}, + Author: "kratos", + }, } diff --git a/tool/pkg/common.go b/tool/pkg/common.go index 9103ee1d0..0941203f1 100644 --- a/tool/pkg/common.go +++ b/tool/pkg/common.go @@ -118,7 +118,9 @@ func FormatCode(source string) string { // Packages get import packages func (s *Source) Packages(f *ast.Field) (res []string) { fs := f.Type.(*ast.FuncType).Params.List - fs = append(fs, f.Type.(*ast.FuncType).Results.List...) + if f.Type.(*ast.FuncType).Results != nil { + fs = append(fs, f.Type.(*ast.FuncType).Results.List...) + } var types []string resMap := make(map[string]bool) for _, field := range fs {