From 2fb321df9030227633b36eead8ad29078cb85c5f Mon Sep 17 00:00:00 2001 From: iczc Date: Tue, 6 Aug 2019 16:50:36 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=A4=BA=E4=BE=8B?= =?UTF-8?q?=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/wiki-cn/warden-quickstart.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/wiki-cn/warden-quickstart.md b/doc/wiki-cn/warden-quickstart.md index ae3a712f7..3ca32bd9c 100644 --- a/doc/wiki-cn/warden-quickstart.md +++ b/doc/wiki-cn/warden-quickstart.md @@ -1,6 +1,10 @@ # 准备工作 -推荐使用[kratos工具](kratos-tool.md)快速生成带`--grpc`的项目,如我们生成一个叫`kratos-demo`的项目。 +推荐使用[kratos工具](kratos-tool.md)快速生成带`grpc`的项目,如我们生成一个叫`kratos-demo`的项目。 + +``` +kratos new kratos-demo --proto +``` # pb文件 From 7f1b59077737a9f355dfe5da0665a6d54eaadde5 Mon Sep 17 00:00:00 2001 From: colstuwjx Date: Fri, 9 Aug 2019 17:54:58 +0800 Subject: [PATCH 02/15] Add bm timeout doc. --- doc/wiki-cn/blademaster-mod.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/wiki-cn/blademaster-mod.md b/doc/wiki-cn/blademaster-mod.md index 8e90c466b..e72f1eb52 100644 --- a/doc/wiki-cn/blademaster-mod.md +++ b/doc/wiki-cn/blademaster-mod.md @@ -26,6 +26,7 @@ type Context struct { ``` * 首先可以看到 blademaster 的 Context 结构体中会 embed 一个标准库中的 Context 实例,bm 中的 Context 也是直接通过该实例来实现标准库中的 Context 接口。 +* blademaster 会使用配置的 server timeout (默认1s) 作为一次请求整个过程中的超时时间,使用该context调用dao做数据库、缓存操作查询时均会将该超时时间传递下去,一旦抵达deadline,后续相关操作均会返回`context deadline exceeded`。 * Request 和 Writer 字段用于获取当前请求的与输出响应。 * index 和 handlers 用于 handler 的流程控制;handlers 中存储了当前请求需要执行的所有 handler,index 用于标记当前正在执行的 handler 的索引位。 * Keys 用于在 handler 之间传递一些额外的信息。 From 3e92753a1b7bfb29321ada87e1fc91504ccf1b04 Mon Sep 17 00:00:00 2001 From: wuxingzhong <330332812@qq.com> Date: Wed, 14 Aug 2019 09:04:41 +0800 Subject: [PATCH 03/15] judge if interface is up (#256) --- pkg/net/ip/ip.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/net/ip/ip.go b/pkg/net/ip/ip.go index 54e241d1a..386d7e23f 100644 --- a/pkg/net/ip/ip.go +++ b/pkg/net/ip/ip.go @@ -48,6 +48,9 @@ func InternalIP() string { return "" } for _, inter := range inters { + if !isUp(inter.Flags) { + continue + } if !strings.HasPrefix(inter.Name, "lo") { addrs, err := inter.Addrs() if err != nil { @@ -64,3 +67,8 @@ func InternalIP() string { } return "" } + +// isUp Interface is up +func isUp(v net.Flags) bool { + return v&net.FlagUp == net.FlagUp +} From ecb0c6104c91fe40f077f1d25a51f309e59bd4ed Mon Sep 17 00:00:00 2001 From: felixhao Date: Wed, 14 Aug 2019 02:23:24 +0000 Subject: [PATCH 04/15] use real ip in trace and metrics. --- pkg/database/sql/CHANGELOG.md | 24 +++++++++++ pkg/database/sql/sql.go | 79 ++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 38 deletions(-) create mode 100755 pkg/database/sql/CHANGELOG.md diff --git a/pkg/database/sql/CHANGELOG.md b/pkg/database/sql/CHANGELOG.md new file mode 100755 index 000000000..054bc765f --- /dev/null +++ b/pkg/database/sql/CHANGELOG.md @@ -0,0 +1,24 @@ +### database/sql + +##### Version 1.3.1 +> 1. trace、metric 区别不同数据库实例(主、从) + +##### Version 1.3.0 +> 1. add slow log + +##### Version 1.2.1 +> 1.支持上报熔断错误 + +##### Version 1.2.0 +> 1.添加数据库读写分离 + +##### Version 1.1.1 +> 1.修复部分函数中的context cancel leak + +##### Version 1.1.0 +> 1.添加context和timeout支持 +> 2.添加breaker支持 +> 3.更新driver,支持context/pool timeout + +##### Version 1.0.0 +> 1.支持trace/stats diff --git a/pkg/database/sql/sql.go b/pkg/database/sql/sql.go index 60e813410..5f8220d4d 100644 --- a/pkg/database/sql/sql.go +++ b/pkg/database/sql/sql.go @@ -8,10 +8,10 @@ import ( "sync/atomic" "time" - "github.com/bilibili/kratos/pkg/ecode" - "github.com/bilibili/kratos/pkg/log" - "github.com/bilibili/kratos/pkg/net/netutil/breaker" - "github.com/bilibili/kratos/pkg/net/trace" + "go-common/library/ecode" + "go-common/library/log" + "go-common/library/net/netutil/breaker" + "go-common/library/net/trace" "github.com/pkg/errors" ) @@ -38,7 +38,7 @@ var ( type DB struct { write *conn read []*conn - idx uint64 + idx int64 master *DB } @@ -47,6 +47,7 @@ type conn struct { *sql.DB breaker breaker.Breaker conf *Config + addr string } // Tx transaction. @@ -130,17 +131,19 @@ func Open(c *Config) (*DB, error) { if err != nil { return nil, err } + addr := parseDSNAddr(c.DSN) brkGroup := breaker.NewGroup(c.Breaker) - brk := brkGroup.Get(c.Addr) - w := &conn{DB: d, breaker: brk, conf: c} + brk := brkGroup.Get(addr) + w := &conn{DB: d, breaker: brk, conf: c, addr: addr} rs := make([]*conn, 0, len(c.ReadDSN)) for _, rd := range c.ReadDSN { d, err := connect(c, rd) if err != nil { return nil, err } - brk := brkGroup.Get(parseDSNAddr(rd)) - r := &conn{DB: d, breaker: brk, conf: c} + addr = parseDSNAddr(rd) + brk := brkGroup.Get(addr) + r := &conn{DB: d, breaker: brk, conf: c, addr: addr} rs = append(rs, r) } db.write = w @@ -217,8 +220,8 @@ func (db *DB) readIndex() int { if len(db.read) == 0 { return 0 } - v := atomic.AddUint64(&db.idx, 1) - return int(v % uint64(len(db.read))) + v := atomic.AddInt64(&db.idx, 1) + return int(v) % len(db.read) } // Close closes the write and read database, releasing any open resources. @@ -271,7 +274,7 @@ func (db *conn) begin(c context.Context) (tx *Tx, err error) { t, ok := trace.FromContext(c) if ok { t = t.Fork(_family, "begin") - t.SetTag(trace.String(trace.TagAddress, db.conf.Addr), trace.String(trace.TagComment, "")) + t.SetTag(trace.String(trace.TagAddress, db.addr), trace.String(trace.TagComment, "")) defer func() { if err != nil { t.Finish(&err) @@ -279,12 +282,12 @@ func (db *conn) begin(c context.Context) (tx *Tx, err error) { }() } if err = db.breaker.Allow(); err != nil { - _metricReqErr.Inc(db.conf.Addr, db.conf.Addr, "begin", "breaker") + _metricReqErr.Inc(db.addr, db.addr, "begin", "breaker") return } _, c, cancel := db.conf.TranTimeout.Shrink(c) rtx, err := db.BeginTx(c, nil) - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.conf.Addr, db.conf.Addr, "begin") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.addr, db.addr, "begin") if err != nil { err = errors.WithStack(err) cancel() @@ -299,18 +302,18 @@ func (db *conn) exec(c context.Context, query string, args ...interface{}) (res defer slowLog(fmt.Sprintf("Exec query(%s) args(%+v)", query, args), now) if t, ok := trace.FromContext(c); ok { t = t.Fork(_family, "exec") - t.SetTag(trace.String(trace.TagAddress, db.conf.Addr), trace.String(trace.TagComment, query)) + t.SetTag(trace.String(trace.TagAddress, db.addr), trace.String(trace.TagComment, query)) defer t.Finish(&err) } if err = db.breaker.Allow(); err != nil { - _metricReqErr.Inc(db.conf.Addr, db.conf.Addr, "exec", "breaker") + _metricReqErr.Inc(db.addr, db.addr, "exec", "breaker") return } _, c, cancel := db.conf.ExecTimeout.Shrink(c) res, err = db.ExecContext(c, query, args...) cancel() db.onBreaker(&err) - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.conf.Addr, db.conf.Addr, "exec") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.addr, db.addr, "exec") if err != nil { err = errors.Wrapf(err, "exec:%s, args:%+v", query, args) } @@ -322,18 +325,18 @@ func (db *conn) ping(c context.Context) (err error) { defer slowLog("Ping", now) if t, ok := trace.FromContext(c); ok { t = t.Fork(_family, "ping") - t.SetTag(trace.String(trace.TagAddress, db.conf.Addr), trace.String(trace.TagComment, "")) + t.SetTag(trace.String(trace.TagAddress, db.addr), trace.String(trace.TagComment, "")) defer t.Finish(&err) } if err = db.breaker.Allow(); err != nil { - _metricReqErr.Inc(db.conf.Addr, db.conf.Addr, "ping", "breaker") + _metricReqErr.Inc(db.addr, db.addr, "ping", "breaker") return } _, c, cancel := db.conf.ExecTimeout.Shrink(c) err = db.PingContext(c) cancel() db.onBreaker(&err) - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.conf.Addr, db.conf.Addr, "ping") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.addr, db.addr, "ping") if err != nil { err = errors.WithStack(err) } @@ -379,17 +382,17 @@ func (db *conn) query(c context.Context, query string, args ...interface{}) (row defer slowLog(fmt.Sprintf("Query query(%s) args(%+v)", query, args), now) if t, ok := trace.FromContext(c); ok { t = t.Fork(_family, "query") - t.SetTag(trace.String(trace.TagAddress, db.conf.Addr), trace.String(trace.TagComment, query)) + t.SetTag(trace.String(trace.TagAddress, db.addr), trace.String(trace.TagComment, query)) defer t.Finish(&err) } if err = db.breaker.Allow(); err != nil { - _metricReqErr.Inc(db.conf.Addr, db.conf.Addr, "query", "breaker") + _metricReqErr.Inc(db.addr, db.addr, "query", "breaker") return } _, c, cancel := db.conf.QueryTimeout.Shrink(c) rs, err := db.DB.QueryContext(c, query, args...) db.onBreaker(&err) - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.conf.Addr, db.conf.Addr, "query") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.addr, db.addr, "query") if err != nil { err = errors.Wrapf(err, "query:%s, args:%+v", query, args) cancel() @@ -405,15 +408,15 @@ func (db *conn) queryRow(c context.Context, query string, args ...interface{}) * t, ok := trace.FromContext(c) if ok { t = t.Fork(_family, "queryrow") - t.SetTag(trace.String(trace.TagAddress, db.conf.Addr), trace.String(trace.TagComment, query)) + t.SetTag(trace.String(trace.TagAddress, db.addr), trace.String(trace.TagComment, query)) } if err := db.breaker.Allow(); err != nil { - _metricReqErr.Inc(db.conf.Addr, db.conf.Addr, "queryRow", "breaker") + _metricReqErr.Inc(db.addr, db.addr, "queryRow", "breaker") return &Row{db: db, t: t, err: err} } _, c, cancel := db.conf.QueryTimeout.Shrink(c) r := db.DB.QueryRowContext(c, query, args...) - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.conf.Addr, db.conf.Addr, "queryrow") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), db.addr, db.addr, "queryrow") return &Row{db: db, Row: r, query: query, args: args, t: t, cancel: cancel} } @@ -445,11 +448,11 @@ func (s *Stmt) Exec(c context.Context, args ...interface{}) (res sql.Result, err } } else if t, ok := trace.FromContext(c); ok { t = t.Fork(_family, "exec") - t.SetTag(trace.String(trace.TagAddress, s.db.conf.Addr), trace.String(trace.TagComment, s.query)) + t.SetTag(trace.String(trace.TagAddress, s.db.addr), trace.String(trace.TagComment, s.query)) defer t.Finish(&err) } if err = s.db.breaker.Allow(); err != nil { - _metricReqErr.Inc(s.db.conf.Addr, s.db.conf.Addr, "stmt:exec", "breaker") + _metricReqErr.Inc(s.db.addr, s.db.addr, "stmt:exec", "breaker") return } stmt, ok := s.stmt.Load().(*sql.Stmt) @@ -461,7 +464,7 @@ func (s *Stmt) Exec(c context.Context, args ...interface{}) (res sql.Result, err res, err = stmt.ExecContext(c, args...) cancel() s.db.onBreaker(&err) - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), s.db.conf.Addr, s.db.conf.Addr, "stmt:exec") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), s.db.addr, s.db.addr, "stmt:exec") if err != nil { err = errors.Wrapf(err, "exec:%s, args:%+v", s.query, args) } @@ -483,11 +486,11 @@ func (s *Stmt) Query(c context.Context, args ...interface{}) (rows *Rows, err er } } else if t, ok := trace.FromContext(c); ok { t = t.Fork(_family, "query") - t.SetTag(trace.String(trace.TagAddress, s.db.conf.Addr), trace.String(trace.TagComment, s.query)) + t.SetTag(trace.String(trace.TagAddress, s.db.addr), trace.String(trace.TagComment, s.query)) defer t.Finish(&err) } if err = s.db.breaker.Allow(); err != nil { - _metricReqErr.Inc(s.db.conf.Addr, s.db.conf.Addr, "stmt:query", "breaker") + _metricReqErr.Inc(s.db.addr, s.db.addr, "stmt:query", "breaker") return } stmt, ok := s.stmt.Load().(*sql.Stmt) @@ -498,7 +501,7 @@ func (s *Stmt) Query(c context.Context, args ...interface{}) (rows *Rows, err er _, c, cancel := s.db.conf.QueryTimeout.Shrink(c) rs, err := stmt.QueryContext(c, args...) s.db.onBreaker(&err) - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), s.db.conf.Addr, s.db.conf.Addr, "stmt:query") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), s.db.addr, s.db.addr, "stmt:query") if err != nil { err = errors.Wrapf(err, "query:%s, args:%+v", s.query, args) cancel() @@ -527,11 +530,11 @@ func (s *Stmt) QueryRow(c context.Context, args ...interface{}) (row *Row) { } } else if t, ok := trace.FromContext(c); ok { t = t.Fork(_family, "queryrow") - t.SetTag(trace.String(trace.TagAddress, s.db.conf.Addr), trace.String(trace.TagComment, s.query)) + t.SetTag(trace.String(trace.TagAddress, s.db.addr), trace.String(trace.TagComment, s.query)) row.t = t } if row.err = s.db.breaker.Allow(); row.err != nil { - _metricReqErr.Inc(s.db.conf.Addr, s.db.conf.Addr, "stmt:queryrow", "breaker") + _metricReqErr.Inc(s.db.addr, s.db.addr, "stmt:queryrow", "breaker") return } stmt, ok := s.stmt.Load().(*sql.Stmt) @@ -541,7 +544,7 @@ func (s *Stmt) QueryRow(c context.Context, args ...interface{}) (row *Row) { _, c, cancel := s.db.conf.QueryTimeout.Shrink(c) row.Row = stmt.QueryRowContext(c, args...) row.cancel = cancel - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), s.db.conf.Addr, s.db.conf.Addr, "stmt:queryrow") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), s.db.addr, s.db.addr, "stmt:queryrow") return } @@ -582,7 +585,7 @@ func (tx *Tx) Exec(query string, args ...interface{}) (res sql.Result, err error tx.t.SetTag(trace.String(trace.TagAnnotation, fmt.Sprintf("exec %s", query))) } res, err = tx.tx.ExecContext(tx.c, query, args...) - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), tx.db.conf.Addr, tx.db.conf.Addr, "tx:exec") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), tx.db.addr, tx.db.addr, "tx:exec") if err != nil { err = errors.Wrapf(err, "exec:%s, args:%+v", query, args) } @@ -597,7 +600,7 @@ func (tx *Tx) Query(query string, args ...interface{}) (rows *Rows, err error) { now := time.Now() defer slowLog(fmt.Sprintf("Query query(%s) args(%+v)", query, args), now) defer func() { - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), tx.db.conf.Addr, tx.db.conf.Addr, "tx:query") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), tx.db.addr, tx.db.addr, "tx:query") }() rs, err := tx.tx.QueryContext(tx.c, query, args...) if err == nil { @@ -618,7 +621,7 @@ func (tx *Tx) QueryRow(query string, args ...interface{}) *Row { now := time.Now() defer slowLog(fmt.Sprintf("QueryRow query(%s) args(%+v)", query, args), now) defer func() { - _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), tx.db.conf.Addr, tx.db.conf.Addr, "tx:queryrow") + _metricReqDur.Observe(int64(time.Since(now)/time.Millisecond), tx.db.addr, tx.db.addr, "tx:queryrow") }() r := tx.tx.QueryRowContext(tx.c, query, args...) return &Row{Row: r, db: tx.db, query: query, args: args} From 16c346eba40dfb30001afb74d5abc0ea8bd42865 Mon Sep 17 00:00:00 2001 From: longXboy Date: Wed, 14 Aug 2019 10:26:05 +0800 Subject: [PATCH 05/15] fix resolver bug --- pkg/net/rpc/warden/CHANGELOG.md | 3 +++ pkg/net/rpc/warden/resolver/resolver.go | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/pkg/net/rpc/warden/CHANGELOG.md b/pkg/net/rpc/warden/CHANGELOG.md index 7bd96bbc7..10965198c 100644 --- a/pkg/net/rpc/warden/CHANGELOG.md +++ b/pkg/net/rpc/warden/CHANGELOG.md @@ -1,5 +1,8 @@ ### net/rpc/warden +##### Version 1.1.21 +1. fix resolver bug + ##### Version 1.1.20 1. client增加timeoutCallOpt强制覆盖每次请求的timeout diff --git a/pkg/net/rpc/warden/resolver/resolver.go b/pkg/net/rpc/warden/resolver/resolver.go index 06b0bf8e5..a8039a646 100644 --- a/pkg/net/rpc/warden/resolver/resolver.go +++ b/pkg/net/rpc/warden/resolver/resolver.go @@ -128,19 +128,24 @@ func (r *Resolver) updateproc() { return } } - if ins, ok := r.nr.Fetch(context.Background()); ok { - instances, ok := ins.Instances[r.zone] - if !ok { - for _, value := range ins.Instances { + if insMap, ok := r.nr.Fetch(context.Background()); ok { + instances, _ := insMap[r.zone] + res := r.filter(instances) + if len(res) == 0 { + for _, value := range insMap { instances = append(instances, value...) } + res = r.filter(instances) } - r.newAddress(r.filter(instances)) + r.newAddress(res) } } } func (r *Resolver) filter(backends []*naming.Instance) (instances []*naming.Instance) { + if len(backends) == 0 { + return + } for _, ins := range backends { //如果r.clusters的长度大于0说明需要进行集群选择 if _, ok := r.clusters[ins.Metadata[naming.MetaCluster]]; !ok && len(r.clusters) > 0 { From 46402f77568efa536c5db3701a62db94deb60894 Mon Sep 17 00:00:00 2001 From: shunza Date: Thu, 15 Aug 2019 10:01:12 +0800 Subject: [PATCH 06/15] fix sql import package. --- pkg/database/sql/sql.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/database/sql/sql.go b/pkg/database/sql/sql.go index 5f8220d4d..282fe8469 100644 --- a/pkg/database/sql/sql.go +++ b/pkg/database/sql/sql.go @@ -8,10 +8,10 @@ import ( "sync/atomic" "time" - "go-common/library/ecode" - "go-common/library/log" - "go-common/library/net/netutil/breaker" - "go-common/library/net/trace" + "github.com/bilibili/kratos/pkg/ecode" + "github.com/bilibili/kratos/pkg/log" + "github.com/bilibili/kratos/pkg/net/netutil/breaker" + "github.com/bilibili/kratos/pkg/net/trace" "github.com/pkg/errors" ) From 0c6f0227088b993babbbcb3f9e7219a2c33b4305 Mon Sep 17 00:00:00 2001 From: longXboy Date: Thu, 15 Aug 2019 10:37:50 +0800 Subject: [PATCH 07/15] fix test for resolver --- pkg/net/rpc/warden/resolver/resolver.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/net/rpc/warden/resolver/resolver.go b/pkg/net/rpc/warden/resolver/resolver.go index a8039a646..4804e148e 100644 --- a/pkg/net/rpc/warden/resolver/resolver.go +++ b/pkg/net/rpc/warden/resolver/resolver.go @@ -128,11 +128,11 @@ func (r *Resolver) updateproc() { return } } - if insMap, ok := r.nr.Fetch(context.Background()); ok { - instances, _ := insMap[r.zone] + if ins, ok := r.nr.Fetch(context.Background()); ok { + instances, _ := ins.Instances[r.zone] res := r.filter(instances) if len(res) == 0 { - for _, value := range insMap { + for _, value := range ins.Instances { instances = append(instances, value...) } res = r.filter(instances) From d9cee15ef6288c246b9a3bbfabe84439eecb11fc Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Thu, 15 Aug 2019 11:08:58 +0800 Subject: [PATCH 08/15] doc and example (#267) * add doc and example * rm deprecated ecode.Equal --- doc/wiki-cn/cache-redis.md | 2 +- doc/wiki-cn/database-mysql-orm.md | 81 +++++++++++++++++++ doc/wiki-cn/database.md | 3 +- doc/wiki-cn/kratos-genbts.md | 2 +- doc/wiki-cn/ratelimit.md | 20 ++--- doc/wiki-cn/summary.md | 1 + .../blademaster/middleware/auth/README.md | 0 .../blademaster/middleware/auth/auth.go | 0 .../middleware/auth/example_test.go | 2 +- pkg/database/sql/sql.go | 4 +- pkg/ecode/ecode.go | 6 +- pkg/ecode/status.go | 6 -- pkg/ecode/status_test.go | 3 - pkg/naming/discovery/discovery.go | 18 ++--- pkg/net/rpc/warden/client.go | 19 +++-- pkg/net/rpc/warden/server_test.go | 10 +-- 16 files changed, 125 insertions(+), 52 deletions(-) create mode 100644 doc/wiki-cn/database-mysql-orm.md rename {pkg/net/http => example}/blademaster/middleware/auth/README.md (100%) rename {pkg/net/http => example}/blademaster/middleware/auth/auth.go (100%) rename {pkg/net/http => example}/blademaster/middleware/auth/example_test.go (93%) diff --git a/doc/wiki-cn/cache-redis.md b/doc/wiki-cn/cache-redis.md index a6c08e052..8304dea0a 100644 --- a/doc/wiki-cn/cache-redis.md +++ b/doc/wiki-cn/cache-redis.md @@ -180,7 +180,7 @@ func (d *Dao) DemoIncrbys(c context.Context, pid int) (err error) { ## 返回值转换 -与[memcache包](cache-mc.md)类似地,kratos/pkg/cache/redis包中也提供了Scan方法将redis server的返回值转换为golang类型。 +kratos/pkg/cache/redis包中也提供了Scan方法将redis server的返回值转换为golang类型。 除此之外,kratos/pkg/cache/redis包提供了大量返回值转换的快捷方式: diff --git a/doc/wiki-cn/database-mysql-orm.md b/doc/wiki-cn/database-mysql-orm.md new file mode 100644 index 000000000..5b776034c --- /dev/null +++ b/doc/wiki-cn/database-mysql-orm.md @@ -0,0 +1,81 @@ +# 准备工作 + +推荐使用[kratos工具](kratos-tool.md)快速生成项目,如我们生成一个叫`kratos-demo`的项目。目录结构如下: + +``` +├── CHANGELOG.md +├── CONTRIBUTORS.md +├── LICENSE +├── README.md +├── cmd +│   ├── cmd +│   └── main.go +├── configs +│   ├── application.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 +``` + +# 开始使用 + +## 配置 + +创建项目成功后,进入项目中的configs目录,mysql.toml,我们可以看到: + +```toml +[demo] + 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" +``` + +在该配置文件中我们可以配置mysql的读和写的dsn、连接地址addr、连接池的闲置连接数idle、最大连接数active以及各类超时。 + +如果配置了readDSN,在进行读操作的时候会优先使用readDSN的连接。 + +## 初始化 + +进入项目的internal/dao目录,打开dao.go,其中: + +```go +var ( + dc struct { + Demo *sql.Config + } +) +checkErr(paladin.Get("mysql.toml").UnmarshalTOML(&dc)) +``` +使用paladin配置管理工具将上文中的mysql.toml中的配置解析为我们需要使用mysql的相关配置。 + +# TODO:补充常用方法 + +# 扩展阅读 + +[tidb模块说明](database-tidb.md) +[hbase模块说明](database-hbase.md) + +------------- + +[文档目录树](summary.md) diff --git a/doc/wiki-cn/database.md b/doc/wiki-cn/database.md index 1939bccaa..61d9f81d6 100644 --- a/doc/wiki-cn/database.md +++ b/doc/wiki-cn/database.md @@ -6,7 +6,8 @@ ## MySQL MySQL数据库驱动,支持读写分离、context、timeout、trace和统计功能,以及错误熔断防止数据库雪崩。 -[mysql client](database-mysql.md) +[mysql client](database-mysql.md) +[mysql client orm](database-mysql-orm.md) ## HBase HBase客户端,支持trace、slowlog和统计功能。 diff --git a/doc/wiki-cn/kratos-genbts.md b/doc/wiki-cn/kratos-genbts.md index f9e5803d9..7c889ddc4 100644 --- a/doc/wiki-cn/kratos-genbts.md +++ b/doc/wiki-cn/kratos-genbts.md @@ -2,7 +2,7 @@ > 缓存回源代码生成 -在internal/dao/dao.go中添加mc缓存interface定义,可以指定对应的[注解参数](../../tool/kratos-gen-mc/README.md); +在internal/dao/dao.go中添加mc缓存interface定义,可以指定对应的[注解参数](../../tool/kratos-gen-bts/README.md); 并且在接口前面添加`go:generate kratos tool genbts`; 然后在当前目录执行`go generate`,可以看到自动生成的dao.bts.go代码。 diff --git a/doc/wiki-cn/ratelimit.md b/doc/wiki-cn/ratelimit.md index d6a875537..51d28a76d 100644 --- a/doc/wiki-cn/ratelimit.md +++ b/doc/wiki-cn/ratelimit.md @@ -11,17 +11,17 @@ kratos 借鉴了 Sentinel 项目的自适应限流系统,通过综合分析服 ## 限流规则 -1,指标介绍 +### 指标介绍 -|指标名称|指标含义| -|---|---| -|cpu|最近 1s 的 CPU 使用率均值,使用滑动平均计算,采样周期是 250ms| -|inflight|当前处理中正在处理的请求数量| -|pass|请求处理成功的量| -|rt|请求成功的响应耗时| +| 指标名称 | 指标含义 | +| -------- | ------------------------------------------------------------- | +| cpu | 最近 1s 的 CPU 使用率均值,使用滑动平均计算,采样周期是 250ms | +| inflight | 当前处理中正在处理的请求数量 | +| pass | 请求处理成功的量 | +| rt | 请求成功的响应耗时 | -2,滑动窗口 +### 滑动窗口 在自适应限流保护中,采集到的指标的时效性非常强,系统只需要采集最近一小段时间内的 qps、rt 即可,对于较老的数据,会自动丢弃。为了实现这个效果,kratos 使用了滑动窗口来保存采样数据。 @@ -31,7 +31,7 @@ kratos 借鉴了 Sentinel 项目的自适应限流系统,通过综合分析服 当时间流动之后,过期的桶会自动被新桶的数据覆盖掉,在图中,在 1000-1500ms 时,bucket 1 的数据因为过期而被丢弃,之后 bucket 3 的数据填到了窗口的头部。 -3,限流公式 +### 限流公式 判断是否丢弃当前请求的算法如下: @@ -51,7 +51,7 @@ windows 表示一秒内采样窗口的数量,默认配置中是 5s 50 个采 可以看到,没有限流的场景里,系统在 700qps 时开始抖动,在 1k qps 时被拖垮,几乎没有新的请求能被放行,然而在使用限流之后,系统请求能够稳定在 600 qps 左右,rt 没有暴增,服务也没有被打垮,可见,限流有效的保护了服务。 -参考资料: +## 参考资料 [Sentinel 系统自适应限流](https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81) diff --git a/doc/wiki-cn/summary.md b/doc/wiki-cn/summary.md index 5fc3d0356..4b6940647 100644 --- a/doc/wiki-cn/summary.md +++ b/doc/wiki-cn/summary.md @@ -21,6 +21,7 @@ * [log-agent](log-agent.md) * [database](database.md) * [mysql](database-mysql.md) + * [mysql-orm](database-mysql-orm.md) * [hbase](database-hbase.md) * [tidb](database-tidb.md) * [cache](cache.md) diff --git a/pkg/net/http/blademaster/middleware/auth/README.md b/example/blademaster/middleware/auth/README.md similarity index 100% rename from pkg/net/http/blademaster/middleware/auth/README.md rename to example/blademaster/middleware/auth/README.md diff --git a/pkg/net/http/blademaster/middleware/auth/auth.go b/example/blademaster/middleware/auth/auth.go similarity index 100% rename from pkg/net/http/blademaster/middleware/auth/auth.go rename to example/blademaster/middleware/auth/auth.go diff --git a/pkg/net/http/blademaster/middleware/auth/example_test.go b/example/blademaster/middleware/auth/example_test.go similarity index 93% rename from pkg/net/http/blademaster/middleware/auth/example_test.go rename to example/blademaster/middleware/auth/example_test.go index f1e20ea21..b97e22276 100644 --- a/pkg/net/http/blademaster/middleware/auth/example_test.go +++ b/example/blademaster/middleware/auth/example_test.go @@ -4,7 +4,7 @@ import ( "fmt" bm "github.com/bilibili/kratos/pkg/net/http/blademaster" - "github.com/bilibili/kratos/pkg/net/http/blademaster/middleware/auth" + "github.com/bilibili/kratos/example/blademaster/middleware/auth" "github.com/bilibili/kratos/pkg/net/metadata" ) diff --git a/pkg/database/sql/sql.go b/pkg/database/sql/sql.go index 282fe8469..a59997264 100644 --- a/pkg/database/sql/sql.go +++ b/pkg/database/sql/sql.go @@ -196,7 +196,7 @@ func (db *DB) Prepared(query string) (stmt *Stmt) { func (db *DB) Query(c context.Context, query string, args ...interface{}) (rows *Rows, err error) { idx := db.readIndex() for i := range db.read { - if rows, err = db.read[(idx+i)%len(db.read)].query(c, query, args...); !ecode.ServiceUnavailable.Equal(err) { + if rows, err = db.read[(idx+i)%len(db.read)].query(c, query, args...); !ecode.EqualError(ecode.ServiceUnavailable, err) { return } } @@ -209,7 +209,7 @@ func (db *DB) Query(c context.Context, query string, args ...interface{}) (rows func (db *DB) QueryRow(c context.Context, query string, args ...interface{}) *Row { idx := db.readIndex() for i := range db.read { - if row := db.read[(idx+i)%len(db.read)].queryRow(c, query, args...); !ecode.ServiceUnavailable.Equal(row.err) { + if row := db.read[(idx+i)%len(db.read)].queryRow(c, query, args...); !ecode.EqualError(ecode.ServiceUnavailable, row.err) { return row } } diff --git a/pkg/ecode/ecode.go b/pkg/ecode/ecode.go index 3e627970f..259424cf4 100644 --- a/pkg/ecode/ecode.go +++ b/pkg/ecode/ecode.go @@ -9,7 +9,7 @@ import ( ) var ( - _messages atomic.Value // NOTE: stored map[string]map[int]string + _messages atomic.Value // NOTE: stored map[int]string _codes = map[int]struct{}{} // register codes. ) @@ -71,10 +71,6 @@ func (e Code) Message() string { // Details return details. func (e Code) Details() []interface{} { return nil } -// Equal for compatible. -// Deprecated: please use ecode.EqualError. -func (e Code) Equal(err error) bool { return EqualError(e, err) } - // Int parse code int to error. func Int(i int) Code { return Code(i) } diff --git a/pkg/ecode/status.go b/pkg/ecode/status.go index 79e0f2a0d..e690e79d0 100644 --- a/pkg/ecode/status.go +++ b/pkg/ecode/status.go @@ -74,12 +74,6 @@ func (s *Status) WithDetails(pbs ...proto.Message) (*Status, error) { return s, nil } -// Equal for compatible. -// Deprecated: please use ecode.EqualError. -func (s *Status) Equal(err error) bool { - return EqualError(s, err) -} - // Proto return origin protobuf message func (s *Status) Proto() *types.Status { return s.s diff --git a/pkg/ecode/status_test.go b/pkg/ecode/status_test.go index c1fec659c..78bf6c158 100644 --- a/pkg/ecode/status_test.go +++ b/pkg/ecode/status_test.go @@ -16,9 +16,6 @@ func TestEqual(t *testing.T) { err2 = Errorf(RequestErr, "test") ) assert.Equal(t, err1, err2) - assert.True(t, OK.Equal(nil)) - assert.True(t, err1.Equal(err2)) - assert.False(t, err1.Equal(nil)) assert.True(t, Equal(nil, nil)) } diff --git a/pkg/naming/discovery/discovery.go b/pkg/naming/discovery/discovery.go index 1030d32c4..635229ce4 100644 --- a/pkg/naming/discovery/discovery.go +++ b/pkg/naming/discovery/discovery.go @@ -338,7 +338,7 @@ func (d *Discovery) Register(ctx context.Context, ins *naming.Instance) (cancelF for { select { case <-ticker.C: - if err := d.renew(ctx, ins); err != nil && ecode.NothingFound.Equal(err) { + if err := d.renew(ctx, ins); err != nil && ecode.EqualError(ecode.NothingFound, err) { _ = d.register(ctx, ins) } case <-ctx.Done(): @@ -380,7 +380,7 @@ func (d *Discovery) register(ctx context.Context, ins *naming.Instance) (err err uri, c.Zone, c.Env, ins.AppID, ins.Addrs, err) return } - if ec := ecode.Int(res.Code); !ec.Equal(ecode.OK) { + if ec := ecode.Int(res.Code); !ecode.Equal(ecode.OK, ec) { log.Warn("discovery: register client.Get(%v) env(%s) appid(%s) addrs(%v) code(%v)", uri, c.Env, ins.AppID, ins.Addrs, res.Code) err = ec return @@ -408,9 +408,9 @@ func (d *Discovery) renew(ctx context.Context, ins *naming.Instance) (err error) uri, c.Env, ins.AppID, c.Host, err) return } - if ec := ecode.Int(res.Code); !ec.Equal(ecode.OK) { + if ec := ecode.Int(res.Code); !ecode.Equal(ecode.OK, ec) { err = ec - if ec.Equal(ecode.NothingFound) { + if ecode.Equal(ecode.NothingFound, ec) { return } log.Error("discovery: renew client.Get(%v) env(%s) appid(%s) hostname(%s) code(%v)", @@ -440,7 +440,7 @@ func (d *Discovery) cancel(ins *naming.Instance) (err error) { uri, c.Env, ins.AppID, c.Host, err) return } - if ec := ecode.Int(res.Code); !ec.Equal(ecode.OK) { + if ec := ecode.Int(res.Code); !ecode.Equal(ecode.OK, ec) { log.Warn("discovery cancel client.Get(%v) env(%s) appid(%s) hostname(%s) code(%v)", uri, c.Env, ins.AppID, c.Host, res.Code) err = ec @@ -484,7 +484,7 @@ func (d *Discovery) set(ctx context.Context, ins *naming.Instance) (err error) { uri, conf.Zone, conf.Env, ins.AppID, ins.Addrs, err) return } - if ec := ecode.Int(res.Code); !ec.Equal(ecode.OK) { + if ec := ecode.Int(res.Code); !ecode.Equal(ecode.OK, ec) { log.Warn("discovery: set client.Get(%v) env(%s) appid(%s) addrs(%v) code(%v)", uri, conf.Env, ins.AppID, ins.Addrs, res.Code) err = ec @@ -587,8 +587,8 @@ func (d *Discovery) polls(ctx context.Context) (apps map[string]*naming.Instance log.Error("discovery: client.Get(%s) error(%+v)", uri+"?"+params.Encode(), err) return } - if ec := ecode.Int(res.Code); !ec.Equal(ecode.OK) { - if !ec.Equal(ecode.NotModified) { + if ec := ecode.Int(res.Code); !ecode.Equal(ecode.OK, ec) { + if !ecode.Equal(ecode.NotModified, ec) { log.Error("discovery: client.Get(%s) get error code(%d)", uri+"?"+params.Encode(), res.Code) err = ec } @@ -611,7 +611,7 @@ func (d *Discovery) broadcast(apps map[string]*naming.InstancesInfo) { for appID, v := range apps { var count int // v maybe nil in old version(less than v1.1) discovery,check incase of panic - if v==nil { + if v == nil { continue } for zone, ins := range v.Instances { diff --git a/pkg/net/rpc/warden/client.go b/pkg/net/rpc/warden/client.go index f8ae1d2b8..07cdad77c 100644 --- a/pkg/net/rpc/warden/client.go +++ b/pkg/net/rpc/warden/client.go @@ -3,8 +3,6 @@ package warden import ( "context" "fmt" - "github.com/bilibili/kratos/pkg/net/rpc/warden/resolver" - "github.com/bilibili/kratos/pkg/net/rpc/warden/resolver/direct" "net/url" "os" "strconv" @@ -12,6 +10,9 @@ import ( "sync" "time" + "github.com/bilibili/kratos/pkg/net/rpc/warden/resolver" + "github.com/bilibili/kratos/pkg/net/rpc/warden/resolver/direct" + "github.com/bilibili/kratos/pkg/conf/env" "github.com/bilibili/kratos/pkg/conf/flagvar" "github.com/bilibili/kratos/pkg/ecode" @@ -84,14 +85,15 @@ type Client struct { handlers []grpc.UnaryClientInterceptor } -type TimeOutCallOption struct { +// TimeoutCallOption timeout option. +type TimeoutCallOption struct { *grpc.EmptyCallOption Timeout time.Duration } // WithTimeoutCallOption can override the timeout in ctx and the timeout in the configuration file -func WithTimeoutCallOption(timeout time.Duration) *TimeOutCallOption { - return &TimeOutCallOption{&grpc.EmptyCallOption{}, timeout} +func WithTimeoutCallOption(timeout time.Duration) *TimeoutCallOption { + return &TimeoutCallOption{&grpc.EmptyCallOption{}, timeout} } // handle returns a new unary client interceptor for OpenTracing\Logging\LinkTimeout. @@ -127,10 +129,10 @@ func (c *Client) handle() grpc.UnaryClientInterceptor { return } defer onBreaker(brk, &err) - var timeOpt *TimeOutCallOption + var timeOpt *TimeoutCallOption for _, opt := range opts { var tok bool - timeOpt, tok = opt.(*TimeOutCallOption) + timeOpt, tok = opt.(*TimeoutCallOption) if tok { break } @@ -173,9 +175,10 @@ func (c *Client) handle() grpc.UnaryClientInterceptor { func onBreaker(breaker breaker.Breaker, err *error) { if err != nil && *err != nil { - if ecode.ServerErr.Equal(*err) || ecode.ServiceUnavailable.Equal(*err) || ecode.Deadline.Equal(*err) || ecode.LimitExceed.Equal(*err) { + if ecode.EqualError(ecode.ServerErr, *err) || ecode.EqualError(ecode.ServiceUnavailable, *err) || ecode.EqualError(ecode.Deadline, *err) || ecode.EqualError(ecode.LimitExceed, *err) { breaker.MarkFailed() return + } } breaker.MarkSuccess() diff --git a/pkg/net/rpc/warden/server_test.go b/pkg/net/rpc/warden/server_test.go index 72f479ac7..248caff4e 100644 --- a/pkg/net/rpc/warden/server_test.go +++ b/pkg/net/rpc/warden/server_test.go @@ -220,7 +220,7 @@ func Test_Warden(t *testing.T) { func testValidation(t *testing.T) { _, err := runClient(context.Background(), &clientConfig, t, "", 0) - if !ecode.RequestErr.Equal(err) { + if !ecode.EqualError(ecode.RequestErr, err) { t.Fatalf("testValidation should return ecode.RequestErr,but is %v", err) } } @@ -296,7 +296,7 @@ func testBreaker(t *testing.T) { for i := 0; i < 50; i++ { _, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "breaker_test"}) if err != nil { - if ecode.ServiceUnavailable.Equal(err) { + if ecode.EqualError(ecode.ServiceUnavailable, err) { return } } @@ -334,7 +334,7 @@ func testLinkTimeout(t *testing.T) { if err == nil { t.Fatalf("testLinkTimeout must return error") } - if !ecode.Deadline.Equal(err) { + if !ecode.EqualError(ecode.Deadline, err) { t.Fatalf("testLinkTimeout must return error RPCDeadline,err:%v", err) } @@ -344,7 +344,7 @@ func testClientConfig(t *testing.T) { if err == nil { t.Fatalf("testLinkTimeout must return error") } - if !ecode.Deadline.Equal(err) { + if !ecode.EqualError(ecode.Deadline, err) { t.Fatalf("testLinkTimeout must return error RPCDeadline,err:%v", err) } } @@ -397,7 +397,7 @@ func testClientRecovery(t *testing.T) { t.Fatalf("recovery must return ecode error") } - if !ecode.ServerErr.Equal(e) { + if !ecode.EqualError(ecode.ServerErr, e) { t.Fatalf("recovery must return ecode.RPCClientErr") } } From d09f8e2d51ca18d2b1e3bf36e53d7c551ebf77f0 Mon Sep 17 00:00:00 2001 From: shunza Date: Thu, 15 Aug 2019 11:21:37 +0800 Subject: [PATCH 09/15] 1. delete database/sql changelog file. 2. delete database/sql config addr param. 3. add stat/metric business metric help. --- pkg/database/sql/CHANGELOG.md | 24 ------------------------ pkg/database/sql/mysql.go | 1 - pkg/stat/metric/metric.go | 8 +++++++- 3 files changed, 7 insertions(+), 26 deletions(-) delete mode 100755 pkg/database/sql/CHANGELOG.md diff --git a/pkg/database/sql/CHANGELOG.md b/pkg/database/sql/CHANGELOG.md deleted file mode 100755 index 054bc765f..000000000 --- a/pkg/database/sql/CHANGELOG.md +++ /dev/null @@ -1,24 +0,0 @@ -### database/sql - -##### Version 1.3.1 -> 1. trace、metric 区别不同数据库实例(主、从) - -##### Version 1.3.0 -> 1. add slow log - -##### Version 1.2.1 -> 1.支持上报熔断错误 - -##### Version 1.2.0 -> 1.添加数据库读写分离 - -##### Version 1.1.1 -> 1.修复部分函数中的context cancel leak - -##### Version 1.1.0 -> 1.添加context和timeout支持 -> 2.添加breaker支持 -> 3.更新driver,支持context/pool timeout - -##### Version 1.0.0 -> 1.支持trace/stats diff --git a/pkg/database/sql/mysql.go b/pkg/database/sql/mysql.go index eb2e7c52a..29a1f6e4d 100644 --- a/pkg/database/sql/mysql.go +++ b/pkg/database/sql/mysql.go @@ -11,7 +11,6 @@ import ( // Config mysql config. type Config struct { - Addr string // for trace DSN string // write data source name. ReadDSN []string // read data source name. Active int // pool diff --git a/pkg/stat/metric/metric.go b/pkg/stat/metric/metric.go index 812ca7626..9ea08ca72 100644 --- a/pkg/stat/metric/metric.go +++ b/pkg/stat/metric/metric.go @@ -1,6 +1,9 @@ package metric -import "errors" +import ( + "errors" + "fmt" +) // Opts contains the common arguments for creating Metric. type Opts struct { @@ -62,6 +65,7 @@ func NewBusinessMetricCount(name string, labels ...string) CounterVec { Subsystem: _businessSubsystemCount, Name: name, Labels: labels, + Help: fmt.Sprintf("business metric count %s", name), }) } @@ -76,6 +80,7 @@ func NewBusinessMetricGauge(name string, labels ...string) GaugeVec { Subsystem: _businessSubSystemGauge, Name: name, Labels: labels, + Help: fmt.Sprintf("business metric gauge %s", name), }) } @@ -94,5 +99,6 @@ func NewBusinessMetricHistogram(name string, buckets []float64, labels ...string Name: name, Labels: labels, Buckets: buckets, + Help: fmt.Sprintf("business metric histogram %s", name), }) } From 85b9d677b76788802229bc543a474f25023120be Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Thu, 15 Aug 2019 17:42:51 +0800 Subject: [PATCH 10/15] fix bm router USE (#271) --- pkg/net/http/blademaster/routergroup.go | 2 -- pkg/net/http/blademaster/server.go | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/net/http/blademaster/routergroup.go b/pkg/net/http/blademaster/routergroup.go index 9859539fc..281796b12 100644 --- a/pkg/net/http/blademaster/routergroup.go +++ b/pkg/net/http/blademaster/routergroup.go @@ -134,7 +134,6 @@ func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRo return group.handle("HEAD", relativePath, handlers...) } - func (group *RouterGroup) combineHandlers(handlerGroups ...[]HandlerFunc) []HandlerFunc { finalSize := len(group.Handlers) for _, handlers := range handlerGroups { @@ -190,4 +189,3 @@ func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRou group.handle("TRACE", relativePath, handlers...) return group.returnObj() } - diff --git a/pkg/net/http/blademaster/server.go b/pkg/net/http/blademaster/server.go index ee629c6af..5cd2bc6f4 100644 --- a/pkg/net/http/blademaster/server.go +++ b/pkg/net/http/blademaster/server.go @@ -383,6 +383,8 @@ func (engine *Engine) UseFunc(middleware ...HandlerFunc) IRoutes { // For example, this is the right place for a logger or error management middleware. func (engine *Engine) Use(middleware ...Handler) IRoutes { engine.RouterGroup.Use(middleware...) + engine.rebuild404Handlers() + engine.rebuild405Handlers() return engine } From f06cafc8dd852ff91d24e096266a98a6d8c43e58 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Thu, 15 Aug 2019 20:52:09 +0800 Subject: [PATCH 11/15] add bm middleware doc (#272) --- doc/wiki-cn/blademaster-mid.md | 76 +++++++++++++++++++++++------- pkg/net/http/blademaster/server.go | 2 +- 2 files changed, 59 insertions(+), 19 deletions(-) diff --git a/doc/wiki-cn/blademaster-mid.md b/doc/wiki-cn/blademaster-mid.md index 5e0a4c3c4..8f32944d3 100644 --- a/doc/wiki-cn/blademaster-mid.md +++ b/doc/wiki-cn/blademaster-mid.md @@ -105,28 +105,68 @@ func Example() { # 内置中间件 +## Recovery + +代码位于`pkg/net/http/blademaster/recovery.go`内,用于recovery panic。会被`DefaultServer`默认注册,建议使用`NewServer`的话也将其作为首个中间件注册。 + +## Trace + +代码位于`pkg/net/http/blademaster/trace.go`内,用于trace设置,并且实现了`net/http/httptrace`的接口,能够收集官方库内的调用栈详情。会被`DefaultServer`默认注册,建议使用`NewServer`的话也将其作为第二个中间件注册。 + +## Logger + +代码位于`pkg/net/http/blademaster/logger.go`内,用于请求日志记录。会被`DefaultServer`默认注册,建议使用`NewServer`的话也将其作为第三个中间件注册。 + +## CSRF + +代码位于`pkg/net/http/blademaster/csrf.go`内,用于防跨站请求。如要使用如下: + +```go +e := bm.DefaultServer(nil) +// 挂载自适应限流中间件到 bm engine,使用默认配置 +csrf := bm.CSRF([]string{"bilibili.com"}, []string{"/a/api"}) +e.Use(csrf) +// 或者 +e.GET("/api", csrf, myHandler) +``` + +## CORS + +代码位于`pkg/net/http/blademaster/cors.go`内,用于跨域允许请求。请注意该: +1. 使用该中间件进行全局注册后,可"省略"单独为`OPTIONS`请求注册路由,如示例一。 +2. 使用该中间单独为某路由注册,需要为该路由再注册一个`OPTIONS`方法的同路径路由,如示例二。 + +示例一: +```go +e := bm.DefaultServer(nil) +// 挂载自适应限流中间件到 bm engine,使用默认配置 +cors := bm.CORS([]string{"github.com"}) +e.Use(cors) +// 该路由可以默认针对 OPTIONS /api 的跨域请求支持 +e.POST("/api", myHandler) +``` + +示例二: +```go +e := bm.DefaultServer(nil) +// 挂载自适应限流中间件到 bm engine,使用默认配置 +cors := bm.CORS([]string{"github.com"}) +// e.Use(cors) 不进行全局注册 +e.OPTIONS("/api", cors, myHandler) // 需要单独为/api进行OPTIONS方法注册 +e.POST("/api", cors, myHandler) +``` + ## 自适应限流 -更多关于自适应限流的信息,请参考:[kratos 自适应限流](/doc/wiki-cn/ratelimit.md) +更多关于自适应限流的信息可参考:[kratos 自适应限流](/doc/wiki-cn/ratelimit.md)。如要使用如下: ```go -func Example() { - myHandler := func(ctx *bm.Context) { - mid := metadata.Int64(ctx, metadata.Mid) - ctx.JSON(fmt.Sprintf("%d", mid), nil) - } - - - e := bm.DefaultServer(nil) - - // 挂载自适应限流中间件到 bm engine,使用默认配置 - limiter := bm.NewRateLimiter(nil) - e.Use(limiter.Limit()) - - e.GET("/user", myHandler) - - e.Start() -} +e := bm.DefaultServer(nil) +// 挂载自适应限流中间件到 bm engine,使用默认配置 +limiter := bm.NewRateLimiter(nil) +e.Use(limiter.Limit()) +// 或者 +e.GET("/api", csrf, myHandler) ``` # 扩展阅读 diff --git a/pkg/net/http/blademaster/server.go b/pkg/net/http/blademaster/server.go index 5cd2bc6f4..f934dabcd 100644 --- a/pkg/net/http/blademaster/server.go +++ b/pkg/net/http/blademaster/server.go @@ -206,7 +206,7 @@ func (engine *Engine) SetMethodConfig(path string, mc *MethodConfig) { engine.pcLock.Unlock() } -// DefaultServer returns an Engine instance with the Recovery, Logger and CSRF middleware already attached. +// DefaultServer returns an Engine instance with the Recovery and Logger middleware already attached. func DefaultServer(conf *ServerConfig) *Engine { engine := NewServer(conf) engine.Use(Recovery(), Trace(), Logger()) From c1f9b5ca81d8b26e80b166cb87047026f4fd67b1 Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Thu, 15 Aug 2019 21:24:50 +0800 Subject: [PATCH 12/15] fix bm middleware doc (#273) --- doc/wiki-cn/blademaster-mid.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/wiki-cn/blademaster-mid.md b/doc/wiki-cn/blademaster-mid.md index 8f32944d3..0c2d8257e 100644 --- a/doc/wiki-cn/blademaster-mid.md +++ b/doc/wiki-cn/blademaster-mid.md @@ -4,7 +4,8 @@ # 写自己的中间件 -middleware本质上就是一个handler,如下代码: +middleware本质上就是一个handler,接口和方法声明如下代码: + ```go // Handler responds to an HTTP request. type Handler interface { @@ -21,7 +22,7 @@ func (f HandlerFunc) ServeHTTP(c *Context) { ``` 1. 实现了`Handler`接口,可以作为engine的全局中间件使用:`engine.Use(YourHandler)` -2. 声明为`HandlerFunc`方法,可以作为router的局部中间件使用:`e.GET("/path", YourHandlerFunc)` +2. 声明为`HandlerFunc`方法,可以作为engine的全局中间件使用:`engine.UseFunc(YourHandlerFunc)`,也可以作为router的局部中间件使用:`e.GET("/path", YourHandlerFunc)` 简单示例代码如下: @@ -42,16 +43,17 @@ d := &Demo{} e.Use(d) // HandlerFunc使用如下: +e.UseFunc(d.ServeHTTP) e.GET("/path", d.ServeHTTP) // 或者只有方法 myHandler := func(ctx *bm.Context) { // some code } +e.UseFunc(myHandler) e.GET("/path", myHandler) ``` - # 全局中间件 在blademaster的`server.go`代码中,有以下代码: @@ -64,19 +66,17 @@ func DefaultServer(conf *ServerConfig) *Engine { } ``` -会默认创建一个bm engine,并注册`Recovery(), Trace(), Logger()`三个middlerware,用于全局handler处理。优先级从前到后。 -如果需要自定义默认全局执行的middleware,可以使用`NewServer`方法创建一个无middleware的engine对象。 -如果想要将自定义的middleware注册进全局,可以继续调用Use方法如下: +会默认创建一个`bm engine`,并注册`Recovery(), Trace(), Logger()`三个middlerware用于全局handler处理,优先级从前到后。如果想要将自定义的middleware注册进全局,可以继续调用Use方法如下: ```go engine.Use(YourMiddleware()) ``` -此方法会将`YourMiddleware`追加到已有的全局middleware后执行。 +此方法会将`YourMiddleware`追加到已有的全局middleware后执行。如果需要全部自定义全局执行的middleware,可以使用`NewServer`方法创建一个无middleware的engine对象,然后使用`engine.Use/UseFunc`进行注册。 # 局部中间件 -先来看一段示例(代码再pkg/net/http/blademaster/middleware/auth模块下): +先来看一段鉴权伪代码示例([auth示例代码位置](https://github.com/bilibili/kratos/tree/master/example/blademaster/middleware/auth)): ```go func Example() { From 1481e14c1227fc72de7be47ead26a8e6707b321f Mon Sep 17 00:00:00 2001 From: Felix Hao Date: Fri, 16 Aug 2019 11:15:38 +0800 Subject: [PATCH 13/15] add protoc gen ecode (#274) * add protoc gen ecode * add protobuf example --- .gitignore | 1 + doc/wiki-cn/kratos-protoc.md | 37 +- example/protobuf/api.bm.go | 40 + example/protobuf/api.ecode.go | 17 + example/protobuf/api.pb.go | 1000 +++++++++++++++++ example/protobuf/api.proto | 33 + example/protobuf/api.swagger.json | 96 ++ example/protobuf/gen.sh | 3 + tool/kratos-protoc/bm.go | 2 +- tool/kratos-protoc/ecode.go | 25 + tool/kratos-protoc/main.go | 5 + tool/kratos-protoc/protoc.go | 12 +- tool/kratos-protoc/swagger.go | 2 +- tool/protobuf/pkg/naming/naming.go | 11 + .../protoc-gen-bm/generator/generator.go | 28 +- .../protobuf/protoc-gen-bswagger/generator.go | 2 +- .../protoc-gen-ecode/generator/generator.go | 117 ++ .../generator/generator_test.go | 27 + tool/protobuf/protoc-gen-ecode/main.go | 23 + 19 files changed, 1438 insertions(+), 43 deletions(-) create mode 100644 example/protobuf/api.bm.go create mode 100644 example/protobuf/api.ecode.go create mode 100644 example/protobuf/api.pb.go create mode 100644 example/protobuf/api.proto create mode 100644 example/protobuf/api.swagger.json create mode 100644 example/protobuf/gen.sh create mode 100644 tool/kratos-protoc/ecode.go create mode 100644 tool/protobuf/protoc-gen-ecode/generator/generator.go create mode 100644 tool/protobuf/protoc-gen-ecode/generator/generator_test.go create mode 100644 tool/protobuf/protoc-gen-ecode/main.go diff --git a/.gitignore b/.gitignore index 3ccbd8e00..f9f02aeb8 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ tool/kratos-gen-bts/kratos-gen-bts tool/kratos-gen-mc/kratos-gen-mc tool/kratos/kratos-protoc/kratos-protoc tool/kratos/protobuf/protoc-gen-bm/protoc-gen-bm +tool/kratos/protobuf/protoc-gen-ecode/protoc-gen-ecode tool/kratos/protobuf/protoc-gen-bswagger/protoc-gen-bswagger diff --git a/doc/wiki-cn/kratos-protoc.md b/doc/wiki-cn/kratos-protoc.md index 817b16373..dd416d196 100644 --- a/doc/wiki-cn/kratos-protoc.md +++ b/doc/wiki-cn/kratos-protoc.md @@ -1,38 +1,31 @@ ### kratos tool protoc -``` -// generate all +```shell +# generate all kratos tool protoc api.proto -// generate gRPC +# generate gRPC kratos tool protoc --grpc api.proto -// generate BM HTTP +# generate BM HTTP kratos tool protoc --bm api.proto -// generate swagger +# generate ecode +kratos tool protoc --ecode api.proto +# generate swagger kratos tool protoc --swagger api.proto ``` -执行对应生成 `api.pb.go/api.bm.go/api.swagger.json` 源文档。 - -> 该工具在Windows/Linux下运行,需提前安装好 protobuf 工具 - -该工具实际是一段`shell`脚本,其中自动将`protoc`命令进行了拼接,识别了需要的`*.proto`文件和当前目录下的`proto`文件,最终会拼接为如下命令进行执行: -```shell -export $KRATOS_HOME = kratos路径 -export $KRATOS_DEMO = 项目路径 +执行生成如 `api.pb.go/api.bm.go/api.swagger.json/api.ecode.go` 的对应文件,需要注意的是:`ecode`生成有固定规则,需要首先是`enum`类型,且`enum`名字要以`ErrCode`结尾,如`enum UserErrCode`。详情可见:[example](https://github.com/bilibili/kratos/tree/master/example/protobuf) -// 生成:api.pb.go -protoc -I$GOPATH/src:$KRATOS_HOME/third_party:$KRATOS_DEMO/api --gofast_out=plugins=grpc:$KRATOS_DEMO/api $KRATOS_DEMO/api/api.proto +> 该工具在Windows/Linux下运行,需提前安装好 [protobuf](https://github.com/google/protobuf) 工具 -// 生成:api.bm.go -protoc -I$GOPATH/src:$KRATOS_HOME/third_party:$KRATOS_DEMO/api --bm_out=$KRATOS_DEMO/api $KRATOS_DEMO/api/api.proto +`kratos tool protoc`本质上是拼接好了`protoc`命令然后进行执行,在执行时会打印出对应执行的`protoc`命令,如下可见: -// 生成:api.swagger.json -protoc -I$GOPATH/src:$KRATOS_HOME/third_party:$KRATOS_DEMO/api --bswagger_out=$KRATOS_DEMO/api $KRATOS_DEMO/api/api.proto +```shell +protoc --proto_path=$GOPATH --proto_path=$GOPATH/github.com/bilibili/kratos/third_party --proto_path=. --bm_out=:. api.proto +protoc --proto_path=$GOPATH --proto_path=$GOPATH/github.com/bilibili/kratos/third_party --proto_path=. --gofast_out=plugins=grpc:. api.proto +protoc --proto_path=$GOPATH --proto_path=$GOPATH/github.com/bilibili/kratos/third_party --proto_path=. --bswagger_out=:. api.proto +protoc --proto_path=$GOPATH --proto_path=$GOPATH/github.com/bilibili/kratos/third_party --proto_path=. --ecode_out=:. api.proto ``` -大家也可以参考该命令进行`proto`生成,也可以参考 [protobuf](https://github.com/google/protobuf) 官方参数。 - - ------------- [文档目录树](summary.md) diff --git a/example/protobuf/api.bm.go b/example/protobuf/api.bm.go new file mode 100644 index 000000000..4e29bad26 --- /dev/null +++ b/example/protobuf/api.bm.go @@ -0,0 +1,40 @@ +// Code generated by protoc-gen-bm v0.1, DO NOT EDIT. +// source: api.proto + +package api + +import ( + "context" + + bm "github.com/bilibili/kratos/pkg/net/http/blademaster" + "github.com/bilibili/kratos/pkg/net/http/blademaster/binding" +) + +// to suppressed 'imported but not used warning' +var _ *bm.Context +var _ context.Context +var _ binding.StructValidator + +var PathUserInfo = "/user.api.User/Info" + +// UserBMServer is the server API for User service. +type UserBMServer interface { + Info(ctx context.Context, req *UserReq) (resp *InfoReply, err error) +} + +var UserSvc UserBMServer + +func userInfo(c *bm.Context) { + p := new(UserReq) + if err := c.BindWith(p, binding.Default(c.Request.Method, c.Request.Header.Get("Content-Type"))); err != nil { + return + } + resp, err := UserSvc.Info(c, p) + c.JSON(resp, err) +} + +// RegisterUserBMServer Register the blademaster route +func RegisterUserBMServer(e *bm.Engine, server UserBMServer) { + UserSvc = server + e.GET("/user.api.User/Info", userInfo) +} diff --git a/example/protobuf/api.ecode.go b/example/protobuf/api.ecode.go new file mode 100644 index 000000000..dfed755c1 --- /dev/null +++ b/example/protobuf/api.ecode.go @@ -0,0 +1,17 @@ +// Code generated by protoc-gen-ecode v0.1, DO NOT EDIT. +// source: api.proto + +package api + +import ( + "github.com/bilibili/kratos/pkg/ecode" +) + +// to suppressed 'imported but not used warning' +var _ ecode.Codes + +// UserErrCode ecode +var ( + UserNotExist = ecode.New(-404) + UserUpdateNameFailed = ecode.New(10000) +) diff --git a/example/protobuf/api.pb.go b/example/protobuf/api.pb.go new file mode 100644 index 000000000..3cdf09b00 --- /dev/null +++ b/example/protobuf/api.pb.go @@ -0,0 +1,1000 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: api.proto + +package api + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + io "io" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type UserErrCode int32 + +const ( + UserErrCode_OK UserErrCode = 0 + UserErrCode_UserNotExist UserErrCode = -404 + UserErrCode_UserUpdateNameFailed UserErrCode = 10000 +) + +var UserErrCode_name = map[int32]string{ + 0: "OK", + -404: "UserNotExist", + 10000: "UserUpdateNameFailed", +} + +var UserErrCode_value = map[string]int32{ + "OK": 0, + "UserNotExist": -404, + "UserUpdateNameFailed": 10000, +} + +func (x UserErrCode) String() string { + return proto.EnumName(UserErrCode_name, int32(x)) +} + +func (UserErrCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_00212fb1f9d3bf1c, []int{0} +} + +type Info struct { + Mid int64 `protobuf:"varint,1,opt,name=mid,proto3" json:"mid"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name"` + Sex string `protobuf:"bytes,3,opt,name=sex,proto3" json:"sex"` + Face string `protobuf:"bytes,4,opt,name=face,proto3" json:"face"` + Sign string `protobuf:"bytes,5,opt,name=sign,proto3" json:"sign"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Info) Reset() { *m = Info{} } +func (m *Info) String() string { return proto.CompactTextString(m) } +func (*Info) ProtoMessage() {} +func (*Info) Descriptor() ([]byte, []int) { + return fileDescriptor_00212fb1f9d3bf1c, []int{0} +} +func (m *Info) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Info) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Info.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Info) XXX_Merge(src proto.Message) { + xxx_messageInfo_Info.Merge(m, src) +} +func (m *Info) XXX_Size() int { + return m.Size() +} +func (m *Info) XXX_DiscardUnknown() { + xxx_messageInfo_Info.DiscardUnknown(m) +} + +var xxx_messageInfo_Info proto.InternalMessageInfo + +func (m *Info) GetMid() int64 { + if m != nil { + return m.Mid + } + return 0 +} + +func (m *Info) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Info) GetSex() string { + if m != nil { + return m.Sex + } + return "" +} + +func (m *Info) GetFace() string { + if m != nil { + return m.Face + } + return "" +} + +func (m *Info) GetSign() string { + if m != nil { + return m.Sign + } + return "" +} + +type UserReq struct { + Mid int64 `protobuf:"varint,1,opt,name=mid,proto3" json:"mid,omitempty" validate:"gt=0,required"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UserReq) Reset() { *m = UserReq{} } +func (m *UserReq) String() string { return proto.CompactTextString(m) } +func (*UserReq) ProtoMessage() {} +func (*UserReq) Descriptor() ([]byte, []int) { + return fileDescriptor_00212fb1f9d3bf1c, []int{1} +} +func (m *UserReq) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UserReq) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UserReq.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UserReq) XXX_Merge(src proto.Message) { + xxx_messageInfo_UserReq.Merge(m, src) +} +func (m *UserReq) XXX_Size() int { + return m.Size() +} +func (m *UserReq) XXX_DiscardUnknown() { + xxx_messageInfo_UserReq.DiscardUnknown(m) +} + +var xxx_messageInfo_UserReq proto.InternalMessageInfo + +func (m *UserReq) GetMid() int64 { + if m != nil { + return m.Mid + } + return 0 +} + +type InfoReply struct { + Info *Info `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *InfoReply) Reset() { *m = InfoReply{} } +func (m *InfoReply) String() string { return proto.CompactTextString(m) } +func (*InfoReply) ProtoMessage() {} +func (*InfoReply) Descriptor() ([]byte, []int) { + return fileDescriptor_00212fb1f9d3bf1c, []int{2} +} +func (m *InfoReply) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InfoReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InfoReply.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *InfoReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_InfoReply.Merge(m, src) +} +func (m *InfoReply) XXX_Size() int { + return m.Size() +} +func (m *InfoReply) XXX_DiscardUnknown() { + xxx_messageInfo_InfoReply.DiscardUnknown(m) +} + +var xxx_messageInfo_InfoReply proto.InternalMessageInfo + +func (m *InfoReply) GetInfo() *Info { + if m != nil { + return m.Info + } + return nil +} + +func init() { + proto.RegisterEnum("user.api.UserErrCode", UserErrCode_name, UserErrCode_value) + proto.RegisterType((*Info)(nil), "user.api.Info") + proto.RegisterType((*UserReq)(nil), "user.api.UserReq") + proto.RegisterType((*InfoReply)(nil), "user.api.InfoReply") +} + +func init() { proto.RegisterFile("api.proto", fileDescriptor_00212fb1f9d3bf1c) } + +var fileDescriptor_00212fb1f9d3bf1c = []byte{ + // 366 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x51, 0x4d, 0x4b, 0xeb, 0x40, + 0x14, 0xed, 0x34, 0x79, 0xfd, 0x98, 0x3e, 0x1e, 0x7d, 0xf3, 0x9e, 0x90, 0x96, 0x92, 0x96, 0xac, + 0x8a, 0x68, 0x2a, 0x15, 0x04, 0x05, 0x37, 0x95, 0x0a, 0x52, 0xa8, 0x10, 0xe8, 0xc6, 0xdd, 0xb4, + 0x99, 0xc4, 0x81, 0x26, 0x93, 0xe6, 0x43, 0xea, 0xbf, 0x70, 0x25, 0xfe, 0x24, 0x97, 0xfe, 0x82, + 0x22, 0x75, 0x57, 0x5c, 0xb9, 0x16, 0x94, 0x7b, 0x5b, 0xa9, 0x38, 0x8b, 0xc3, 0x9c, 0x39, 0xf7, + 0x70, 0xcf, 0xbd, 0x43, 0xcb, 0x3c, 0x92, 0x76, 0x14, 0xab, 0x54, 0xb1, 0x52, 0x96, 0x88, 0xd8, + 0xe6, 0x91, 0xac, 0xef, 0xfb, 0x32, 0xbd, 0xce, 0xc6, 0xf6, 0x44, 0x05, 0x1d, 0x5f, 0xf9, 0xaa, + 0x83, 0x05, 0xe3, 0xcc, 0x43, 0x86, 0x04, 0x6f, 0x6b, 0xa3, 0x75, 0x4f, 0xa8, 0x7e, 0x11, 0x7a, + 0x8a, 0xd5, 0xa8, 0x16, 0x48, 0xd7, 0x20, 0x2d, 0xd2, 0xd6, 0x7a, 0xc5, 0xd5, 0xa2, 0x09, 0xd4, + 0x01, 0x60, 0x0d, 0xaa, 0x87, 0x3c, 0x10, 0x46, 0xbe, 0x45, 0xda, 0xe5, 0x5e, 0x69, 0xb5, 0x68, + 0x22, 0x77, 0x10, 0xc1, 0x98, 0x88, 0xb9, 0xa1, 0xa1, 0x88, 0xc6, 0x44, 0xcc, 0x1d, 0x00, 0x30, + 0x7a, 0x7c, 0x22, 0x0c, 0x7d, 0x6b, 0x04, 0xee, 0x20, 0x82, 0x9a, 0x48, 0x3f, 0x34, 0x7e, 0x6d, + 0x55, 0xe0, 0x0e, 0xa2, 0x75, 0x4c, 0x8b, 0xa3, 0x44, 0xc4, 0x8e, 0x98, 0x31, 0xfb, 0x7b, 0xb4, + 0xc6, 0xdb, 0xa2, 0x69, 0xdc, 0xf0, 0xa9, 0x74, 0x79, 0x2a, 0x4e, 0x2c, 0x3f, 0x3d, 0x3d, 0xd8, + 0x8b, 0xc5, 0x2c, 0x93, 0xb1, 0x70, 0x2d, 0xcc, 0x6b, 0x75, 0x68, 0x19, 0x46, 0x72, 0x44, 0x34, + 0xbd, 0x65, 0x16, 0xd5, 0x65, 0xe8, 0x29, 0x74, 0x57, 0xba, 0x7f, 0xec, 0xaf, 0x45, 0xd9, 0x58, + 0x82, 0xda, 0xee, 0x80, 0x56, 0xa0, 0x57, 0x3f, 0x8e, 0xcf, 0x94, 0x2b, 0x58, 0x81, 0xe6, 0x2f, + 0x07, 0xd5, 0x1c, 0xab, 0xd1, 0xdf, 0xf0, 0x3c, 0x54, 0x69, 0x7f, 0x2e, 0x93, 0xb4, 0xfa, 0xfa, + 0xfe, 0xb1, 0x3e, 0x84, 0xd5, 0xe8, 0x7f, 0x90, 0x46, 0x11, 0xa4, 0x18, 0xf2, 0x40, 0x9c, 0x73, + 0x39, 0x15, 0x6e, 0xf5, 0x6e, 0xd8, 0x3d, 0xa2, 0x3a, 0x48, 0xcc, 0xde, 0x2c, 0xf6, 0xef, 0xb6, + 0xe5, 0x66, 0xa0, 0xfa, 0xbf, 0x1f, 0x29, 0x20, 0x68, 0x6f, 0xe7, 0x71, 0x69, 0x92, 0xa7, 0xa5, + 0x49, 0x9e, 0x97, 0x26, 0x79, 0x78, 0x31, 0x73, 0x57, 0x1a, 0x8f, 0xe4, 0xb8, 0x80, 0xff, 0x74, + 0xf8, 0x19, 0x00, 0x00, 0xff, 0xff, 0x9d, 0xa7, 0xb7, 0x22, 0xed, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// UserClient is the client API for User service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type UserClient interface { + Info(ctx context.Context, in *UserReq, opts ...grpc.CallOption) (*InfoReply, error) +} + +type userClient struct { + cc *grpc.ClientConn +} + +func NewUserClient(cc *grpc.ClientConn) UserClient { + return &userClient{cc} +} + +func (c *userClient) Info(ctx context.Context, in *UserReq, opts ...grpc.CallOption) (*InfoReply, error) { + out := new(InfoReply) + err := c.cc.Invoke(ctx, "/user.api.User/Info", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// UserServer is the server API for User service. +type UserServer interface { + Info(context.Context, *UserReq) (*InfoReply, error) +} + +func RegisterUserServer(s *grpc.Server, srv UserServer) { + s.RegisterService(&_User_serviceDesc, srv) +} + +func _User_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UserServer).Info(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/user.api.User/Info", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UserServer).Info(ctx, req.(*UserReq)) + } + return interceptor(ctx, in, info, handler) +} + +var _User_serviceDesc = grpc.ServiceDesc{ + ServiceName: "user.api.User", + HandlerType: (*UserServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Info", + Handler: _User_Info_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "api.proto", +} + +func (m *Info) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Info) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Mid != 0 { + dAtA[i] = 0x8 + i++ + i = encodeVarintApi(dAtA, i, uint64(m.Mid)) + } + if len(m.Name) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintApi(dAtA, i, uint64(len(m.Name))) + i += copy(dAtA[i:], m.Name) + } + if len(m.Sex) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintApi(dAtA, i, uint64(len(m.Sex))) + i += copy(dAtA[i:], m.Sex) + } + if len(m.Face) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintApi(dAtA, i, uint64(len(m.Face))) + i += copy(dAtA[i:], m.Face) + } + if len(m.Sign) > 0 { + dAtA[i] = 0x2a + i++ + i = encodeVarintApi(dAtA, i, uint64(len(m.Sign))) + i += copy(dAtA[i:], m.Sign) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *UserReq) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UserReq) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Mid != 0 { + dAtA[i] = 0x8 + i++ + i = encodeVarintApi(dAtA, i, uint64(m.Mid)) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *InfoReply) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *InfoReply) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Info != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintApi(dAtA, i, uint64(m.Info.Size())) + n1, err := m.Info.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func encodeVarintApi(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *Info) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Mid != 0 { + n += 1 + sovApi(uint64(m.Mid)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + l = len(m.Sex) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + l = len(m.Face) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + l = len(m.Sign) + if l > 0 { + n += 1 + l + sovApi(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *UserReq) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Mid != 0 { + n += 1 + sovApi(uint64(m.Mid)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *InfoReply) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Info != nil { + l = m.Info.Size() + n += 1 + l + sovApi(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovApi(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozApi(x uint64) (n int) { + return sovApi(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Info) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Info: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Info: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType) + } + m.Mid = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Mid |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sex", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sex = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Face", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Face = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sign", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sign = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipApi(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UserReq) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UserReq: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UserReq: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType) + } + m.Mid = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Mid |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipApi(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InfoReply) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InfoReply: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InfoReply: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApi + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthApi + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthApi + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Info == nil { + m.Info = &Info{} + } + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipApi(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthApi + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipApi(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthApi + } + iNdEx += length + if iNdEx < 0 { + return 0, ErrInvalidLengthApi + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowApi + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipApi(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + if iNdEx < 0 { + return 0, ErrInvalidLengthApi + } + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthApi = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowApi = fmt.Errorf("proto: integer overflow") +) diff --git a/example/protobuf/api.proto b/example/protobuf/api.proto new file mode 100644 index 000000000..ef3d04abd --- /dev/null +++ b/example/protobuf/api.proto @@ -0,0 +1,33 @@ +syntax = "proto3"; + +package user.api; + +import "github.com/gogo/protobuf/gogoproto/gogo.proto"; + +option go_package = "api"; + +enum UserErrCode { + OK = 0; + UserNotExist = -404; + UserUpdateNameFailed = 10000; +} + +message Info { + int64 mid = 1 [(gogoproto.jsontag) = "mid"]; + string name = 2 [(gogoproto.jsontag) = "name"]; + string sex = 3 [(gogoproto.jsontag) = "sex"]; + string face = 4 [(gogoproto.jsontag) = "face"]; + string sign = 5 [(gogoproto.jsontag) = "sign"]; +} + +message UserReq { + int64 mid = 1 [(gogoproto.moretags) = "validate:\"gt=0,required\""]; +} + +message InfoReply { + Info info = 1; +} + +service User { + rpc Info(UserReq) returns (InfoReply); +} diff --git a/example/protobuf/api.swagger.json b/example/protobuf/api.swagger.json new file mode 100644 index 000000000..32266a239 --- /dev/null +++ b/example/protobuf/api.swagger.json @@ -0,0 +1,96 @@ +{ + "swagger": "2.0", + "info": { + "title": "api.proto", + "version": "" + }, + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json", + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "paths": { + "/user.api.User/Info": { + "get": { + "summary": "/user.api.User/Info", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "type": "object", + "properties": { + "code": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "data": { + "$ref": "#/definitions/.user.api.InfoReply" + } + } + } + } + }, + "parameters": [ + { + "name": "mid", + "in": "query", + "required": true, + "type": "integer" + } + ], + "tags": [ + "user.api.User" + ] + } + } + }, + "definitions": { + ".user.api.Info": { + "type": "object", + "properties": { + "mid": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "sex": { + "type": "string" + }, + "face": { + "type": "string" + }, + "sign": { + "type": "string" + } + } + }, + ".user.api.InfoReply": { + "type": "object", + "properties": { + "info": { + "$ref": "#/definitions/.user.api.Info" + } + } + }, + ".user.api.UserReq": { + "type": "object", + "properties": { + "mid": { + "type": "integer" + } + }, + "required": [ + "mid" + ] + } + } +} \ No newline at end of file diff --git a/example/protobuf/gen.sh b/example/protobuf/gen.sh new file mode 100644 index 000000000..96984776c --- /dev/null +++ b/example/protobuf/gen.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +kratos tool protoc api.proto diff --git a/tool/kratos-protoc/bm.go b/tool/kratos-protoc/bm.go index 638e99876..2c6b4e13f 100644 --- a/tool/kratos-protoc/bm.go +++ b/tool/kratos-protoc/bm.go @@ -8,7 +8,7 @@ import ( const ( _getBMGen = "go get -u github.com/bilibili/kratos/tool/protobuf/protoc-gen-bm" - _bmProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --bm_out=explicit_http=true:." + _bmProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --bm_out=:." ) func installBMGen() error { diff --git a/tool/kratos-protoc/ecode.go b/tool/kratos-protoc/ecode.go new file mode 100644 index 000000000..22966e121 --- /dev/null +++ b/tool/kratos-protoc/ecode.go @@ -0,0 +1,25 @@ +package main + +import ( + "os/exec" + + "github.com/urfave/cli" +) + +const ( + _getEcodeGen = "go get -u github.com/bilibili/kratos/tool/protobuf/protoc-gen-ecode" + _ecodeProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --ecode_out=:." +) + +func installEcodeGen() error { + if _, err := exec.LookPath("protoc-gen-ecode"); err != nil { + if err := goget(_getEcodeGen); err != nil { + return err + } + } + return nil +} + +func genEcode(ctx *cli.Context) error { + return generate(ctx, _ecodeProtoc) +} diff --git a/tool/kratos-protoc/main.go b/tool/kratos-protoc/main.go index 3b379f726..7279b39d1 100644 --- a/tool/kratos-protoc/main.go +++ b/tool/kratos-protoc/main.go @@ -27,6 +27,11 @@ func main() { Usage: "whether to use swagger for generation", Destination: &withSwagger, }, + cli.BoolFlag{ + Name: "ecode", + Usage: "whether to use ecode for generation", + Destination: &withEcode, + }, } app.Action = func(c *cli.Context) error { return protocAction(c) diff --git a/tool/kratos-protoc/protoc.go b/tool/kratos-protoc/protoc.go index 5d1058213..af96ad91b 100644 --- a/tool/kratos-protoc/protoc.go +++ b/tool/kratos-protoc/protoc.go @@ -20,16 +20,18 @@ var ( withBM bool withGRPC bool withSwagger bool + withEcode bool ) func protocAction(ctx *cli.Context) (err error) { if err = checkProtoc(); err != nil { return err } - if !withGRPC && !withBM && !withSwagger { + if !withGRPC && !withBM && !withSwagger && !withEcode { withBM = true withGRPC = true withSwagger = true + withEcode = true } if withBM { if err = installBMGen(); err != nil { @@ -55,6 +57,14 @@ func protocAction(ctx *cli.Context) (err error) { return } } + if withEcode { + if err = installEcodeGen(); err != nil { + return + } + if err = genEcode(ctx); err != nil { + return + } + } log.Printf("generate %v success.\n", ctx.Args()) return nil } diff --git a/tool/kratos-protoc/swagger.go b/tool/kratos-protoc/swagger.go index 5559cb7e9..7d1b61aaf 100644 --- a/tool/kratos-protoc/swagger.go +++ b/tool/kratos-protoc/swagger.go @@ -8,7 +8,7 @@ import ( const ( _getSwaggerGen = "go get -u github.com/bilibili/kratos/tool/protobuf/protoc-gen-bswagger" - _swaggerProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --bswagger_out=explicit_http=true:." + _swaggerProtoc = "protoc --proto_path=%s --proto_path=%s --proto_path=%s --bswagger_out=:." ) func installSwaggerGen() error { diff --git a/tool/protobuf/pkg/naming/naming.go b/tool/protobuf/pkg/naming/naming.go index 7dc615c1c..37176116f 100644 --- a/tool/protobuf/pkg/naming/naming.go +++ b/tool/protobuf/pkg/naming/naming.go @@ -2,6 +2,7 @@ package naming import ( "os" + "path" "path/filepath" "strings" @@ -25,6 +26,16 @@ func GetVersionPrefix(pkg string) string { return "" } +// GenFileName returns the output name for the generated Go file. +func GenFileName(f *descriptor.FileDescriptorProto, suffix string) string { + name := *f.Name + if ext := path.Ext(name); ext == ".pb" || ext == ".proto" || ext == ".protodevel" { + name = name[:len(name)-len(ext)] + } + name += suffix + return name +} + func ServiceName(service *descriptor.ServiceDescriptorProto) string { return utils.CamelCase(service.GetName()) } diff --git a/tool/protobuf/protoc-gen-bm/generator/generator.go b/tool/protobuf/protoc-gen-bm/generator/generator.go index 149ccbc63..ca9a06b50 100644 --- a/tool/protobuf/protoc-gen-bm/generator/generator.go +++ b/tool/protobuf/protoc-gen-bm/generator/generator.go @@ -44,9 +44,6 @@ func (t *bm) Generate(in *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorResp func (t *bm) generateForFile(file *descriptor.FileDescriptorProto) *plugin.CodeGeneratorResponse_File { resp := new(plugin.CodeGeneratorResponse_File) - //if len(file.Service) == 0 { - // return nil - //} t.generateFileHeader(file, t.GenPkgName) t.generateImports(file) @@ -56,11 +53,8 @@ func (t *bm) generateForFile(file *descriptor.FileDescriptorProto) *plugin.CodeG count += t.generateBMInterface(file, service) t.generateBMRoute(file, service, i) } - //if count == 0 { - // return nil - //} - resp.Name = proto.String(naming.GoFileName(file, ".bm.go")) + resp.Name = proto.String(naming.GenFileName(file, ".bm.go")) resp.Content = proto.String(t.FormattedOutput()) t.Output.Reset() @@ -88,13 +82,13 @@ func (t *bm) generateFileHeader(file *descriptor.FileDescriptorProto, pkgName st t.P("// source: ", file.GetName()) t.P() if t.filesHandled == 0 { - // doc for the first file - t.P("/*") - t.P("Package ", t.GenPkgName, " is a generated blademaster stub package.") - t.P("This code was generated with kratos/tool/protobuf/protoc-gen-bm ", generator.Version, ".") - t.P() comment, err := t.Reg.FileComments(file) if err == nil && comment.Leading != "" { + // doc for the first file + t.P("/*") + t.P("Package ", t.GenPkgName, " is a generated blademaster stub package.") + t.P("This code was generated with kratos/tool/protobuf/protoc-gen-bm ", generator.Version, ".") + t.P() for _, line := range strings.Split(comment.Leading, "\n") { line = strings.TrimPrefix(line, " ") // ensure we don't escape from the block comment @@ -102,12 +96,12 @@ func (t *bm) generateFileHeader(file *descriptor.FileDescriptorProto, pkgName st t.P(line) } t.P() + t.P("It is generated from these files:") + for _, f := range t.GenFiles { + t.P("\t", f.GetName()) + } + t.P("*/") } - t.P("It is generated from these files:") - for _, f := range t.GenFiles { - t.P("\t", f.GetName()) - } - t.P("*/") } t.P(`package `, pkgName) t.P() diff --git a/tool/protobuf/protoc-gen-bswagger/generator.go b/tool/protobuf/protoc-gen-bswagger/generator.go index ec1a9d71b..b39fe16f2 100644 --- a/tool/protobuf/protoc-gen-bswagger/generator.go +++ b/tool/protobuf/protoc-gen-bswagger/generator.go @@ -66,7 +66,7 @@ func (t *swaggerGen) generateSwagger(file *descriptor.FileDescriptorProto) *plug t.defsMap = map[string]*typemap.MessageDefinition{} out := &plugin.CodeGeneratorResponse_File{} - name := naming.GoFileName(file, ".swagger.json") + name := naming.GenFileName(file, ".swagger.json") for _, svc := range file.Service { for _, meth := range svc.Method { if !t.ShouldGenForMethod(file, svc, meth) { diff --git a/tool/protobuf/protoc-gen-ecode/generator/generator.go b/tool/protobuf/protoc-gen-ecode/generator/generator.go new file mode 100644 index 000000000..0aa88cab1 --- /dev/null +++ b/tool/protobuf/protoc-gen-ecode/generator/generator.go @@ -0,0 +1,117 @@ +package generator + +import ( + "strconv" + "strings" + + "github.com/bilibili/kratos/tool/protobuf/pkg/generator" + "github.com/bilibili/kratos/tool/protobuf/pkg/naming" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/protoc-gen-go/descriptor" + plugin "github.com/golang/protobuf/protoc-gen-go/plugin" +) + +type ecode struct { + generator.Base + filesHandled int +} + +// EcodeGenerator ecode generator. +func EcodeGenerator() *ecode { + t := &ecode{} + return t +} + +// Generate ... +func (t *ecode) Generate(in *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorResponse { + t.Setup(in) + + // Showtime! Generate the response. + resp := new(plugin.CodeGeneratorResponse) + for _, f := range t.GenFiles { + respFile := t.generateForFile(f) + if respFile != nil { + resp.File = append(resp.File, respFile) + } + } + return resp +} + +func (t *ecode) generateForFile(file *descriptor.FileDescriptorProto) *plugin.CodeGeneratorResponse_File { + var enums []*descriptor.EnumDescriptorProto + for _, enum := range file.EnumType { + if strings.HasSuffix(*enum.Name, "ErrCode") { + enums = append(enums, enum) + } + } + if len(enums) == 0 { + return nil + } + resp := new(plugin.CodeGeneratorResponse_File) + t.generateFileHeader(file, t.GenPkgName) + t.generateImports(file) + for _, enum := range enums { + t.generateEcode(file, enum) + } + + resp.Name = proto.String(naming.GenFileName(file, ".ecode.go")) + resp.Content = proto.String(t.FormattedOutput()) + t.Output.Reset() + + t.filesHandled++ + return resp +} + +func (t *ecode) generateFileHeader(file *descriptor.FileDescriptorProto, pkgName string) { + t.P("// Code generated by protoc-gen-ecode ", generator.Version, ", DO NOT EDIT.") + t.P("// source: ", file.GetName()) + t.P() + if t.filesHandled == 0 { + comment, err := t.Reg.FileComments(file) + if err == nil && comment.Leading != "" { + // doc for the first file + t.P("/*") + t.P("Package ", t.GenPkgName, " is a generated ecode package.") + t.P("This code was generated with kratos/tool/protobuf/protoc-gen-ecode ", generator.Version, ".") + t.P() + for _, line := range strings.Split(comment.Leading, "\n") { + line = strings.TrimPrefix(line, " ") + // ensure we don't escape from the block comment + line = strings.Replace(line, "*/", "* /", -1) + t.P(line) + } + t.P() + t.P("It is generated from these files:") + for _, f := range t.GenFiles { + t.P("\t", f.GetName()) + } + t.P("*/") + } + } + t.P(`package `, pkgName) + t.P() +} + +func (t *ecode) generateImports(file *descriptor.FileDescriptorProto) { + t.P(`import (`) + t.P(` "github.com/bilibili/kratos/pkg/ecode"`) + t.P(`)`) + t.P() + t.P(`// to suppressed 'imported but not used warning'`) + t.P(`var _ ecode.Codes`) +} + +func (t *ecode) generateEcode(file *descriptor.FileDescriptorProto, enum *descriptor.EnumDescriptorProto) { + t.P("// ", *enum.Name, " ecode") + t.P("var (") + + for _, item := range enum.Value { + if *item.Number == 0 { + continue + } + // NOTE: eg: t.P("UserNotExist = New(-404) ") + t.P(*item.Name, " = ", "ecode.New(", strconv.Itoa(int(*item.Number)), ")") + } + + t.P(")") +} diff --git a/tool/protobuf/protoc-gen-ecode/generator/generator_test.go b/tool/protobuf/protoc-gen-ecode/generator/generator_test.go new file mode 100644 index 000000000..35e1a9240 --- /dev/null +++ b/tool/protobuf/protoc-gen-ecode/generator/generator_test.go @@ -0,0 +1,27 @@ +package generator + +import ( + "os" + "os/exec" + "testing" + + "github.com/golang/protobuf/proto" + plugin "github.com/golang/protobuf/protoc-gen-go/plugin" +) + +func TestGenerateParseCommandLineParamsError(t *testing.T) { + if os.Getenv("BE_CRASHER") == "1" { + g := &ecode{} + g.Generate(&plugin.CodeGeneratorRequest{ + Parameter: proto.String("invalid"), + }) + return + } + cmd := exec.Command(os.Args[0], "-test.run=TestGenerateParseCommandLineParamsError") + cmd.Env = append(os.Environ(), "BE_CRASHER=1") + err := cmd.Run() + if e, ok := err.(*exec.ExitError); ok && !e.Success() { + return + } + t.Fatalf("process ran with err %v, want exit status 1", err) +} diff --git a/tool/protobuf/protoc-gen-ecode/main.go b/tool/protobuf/protoc-gen-ecode/main.go new file mode 100644 index 000000000..0ce35e37a --- /dev/null +++ b/tool/protobuf/protoc-gen-ecode/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/bilibili/kratos/tool/protobuf/pkg/gen" + "github.com/bilibili/kratos/tool/protobuf/pkg/generator" + ecodegen "github.com/bilibili/kratos/tool/protobuf/protoc-gen-ecode/generator" +) + +func main() { + versionFlag := flag.Bool("version", false, "print version and exit") + flag.Parse() + if *versionFlag { + fmt.Println(generator.Version) + os.Exit(0) + } + + g := ecodegen.EcodeGenerator() + gen.Main(g) +} From 624d898caadbe39ae7cf253d51d2075fb7875ee9 Mon Sep 17 00:00:00 2001 From: longxboy Date: Fri, 16 Aug 2019 15:10:58 +0800 Subject: [PATCH 14/15] fix return (#275) --- pkg/stat/sys/cpu/cgroupCPU.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/stat/sys/cpu/cgroupCPU.go b/pkg/stat/sys/cpu/cgroupCPU.go index 2d7402acd..dda467ee7 100644 --- a/pkg/stat/sys/cpu/cgroupCPU.go +++ b/pkg/stat/sys/cpu/cgroupCPU.go @@ -56,6 +56,7 @@ func newCgroupCPU() (cpu *cgroupCPU, err error) { preTotal, err := totalCPUUsage() if err != nil { err = errors.Errorf("totalCPUUsage() failed!err:=%v", err) + return } cpu = &cgroupCPU{ frequency: maxFreq, From e95a0db456d548a080c0c41c9d910bc7da216587 Mon Sep 17 00:00:00 2001 From: Tony Date: Mon, 19 Aug 2019 10:40:53 +0800 Subject: [PATCH 15/15] update kratos to v0.2.2 --- tool/kratos/template.go | 2 +- tool/kratos/version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tool/kratos/template.go b/tool/kratos/template.go index 59c015a4b..06a2c8b83 100644 --- a/tool/kratos/template.go +++ b/tool/kratos/template.go @@ -546,7 +546,7 @@ type Kratos struct { go 1.12 require ( - github.com/bilibili/kratos v0.2.1 + github.com/bilibili/kratos v0.2.2 github.com/gogo/protobuf v1.2.1 github.com/golang/protobuf v1.3.2 golang.org/x/net v0.0.0-20190628185345-da137c7871d7 diff --git a/tool/kratos/version.go b/tool/kratos/version.go index bf74bfee5..1aac093c3 100644 --- a/tool/kratos/version.go +++ b/tool/kratos/version.go @@ -8,7 +8,7 @@ import ( var ( // Version is version - Version = "0.2.1" + Version = "0.2.2" // BuildTime is BuildTime BuildTime = "2019/07/24" )