From c407c755a0c104a32e173b8cfb2b5fb7e951f5d3 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Thu, 28 Sep 2023 20:26:44 +0800 Subject: [PATCH 01/26] feat: add all dependency --- chat.log | 5 ----- go.mod | 11 ++++++----- go.sum | 9 ++++----- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/chat.log b/chat.log index fc32448..e69de29 100644 --- a/chat.log +++ b/chat.log @@ -1,5 +0,0 @@ -me: hello -logic: hello -me: 你好! plato -logic: 你好! plato - diff --git a/go.mod b/go.mod index f769a93..3a6fbba 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,17 @@ module github.com/hardcore-os/plato go 1.18 require ( - github.com/gookit/color v1.5.1 // indirect + github.com/gookit/color v1.5.1 + github.com/rocket049/gocui v0.3.2 + github.com/spf13/cobra v1.5.0 +) + +require ( github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/nsf/termbox-go v1.1.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/rocket049/gocui v0.3.2 // indirect - github.com/spf13/cobra v1.5.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - golang.org/x/net v0.0.0-20220725212005-46097bf591d3 // indirect golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect - gopkg.in/sorcix/irc.v2 v2.0.0-20200812151606-3f15758ea8c7 // indirect ) diff --git a/go.sum b/go.sum index db01c39..5ab3621 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ= github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM= @@ -9,6 +10,7 @@ github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4 github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -20,17 +22,14 @@ github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= -golang.org/x/net v0.0.0-20220725212005-46097bf591d3 h1:2yWTtPWWRcISTw3/o+s/Y4UOMnQL71DWyToOANFusCg= -golang.org/x/net v0.0.0-20220725212005-46097bf591d3/go.mod h1:AaygXjzTFtRAg2ttMY5RMuhpJ3cNnI0XpyFJD1iQRSM= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/sorcix/irc.v2 v2.0.0-20200812151606-3f15758ea8c7 h1:XS4tmz0w7EYviIrBpFVww8IyKJQiIX5SU/1ptPVtBWI= -gopkg.in/sorcix/irc.v2 v2.0.0-20200812151606-3f15758ea8c7/go.mod h1:PmJkUcwbuPi1FiZ9Rarr6wzVMvzkO7uWqH1jwrMkgW0= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 67c1f3da9e14a4c00737d3c9785c2d3509e9fd91 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sat, 30 Sep 2023 15:45:05 +0800 Subject: [PATCH 02/26] feat: add discovery and endport calculate --- cmd/ipconf.go | 19 +++ common/discovery/discovery.go | 68 ++++++++ common/discovery/discovery_test.go | 21 +++ common/discovery/model.go | 27 +++ common/discovery/register.go | 94 +++++++++++ common/discovery/register_test.go | 26 +++ go.mod | 57 ++++++- go.sum | 263 ++++++++++++++++++++++++++++- ipconf/api.go | 29 ++++ ipconf/domain/context.go | 25 +++ ipconf/domain/dispatcher.go | 84 +++++++++ ipconf/domain/endport.go | 44 +++++ ipconf/domain/stat.go | 67 ++++++++ ipconf/domain/window.go | 36 ++++ ipconf/server.go | 19 +++ ipconf/source/data.go | 46 +++++ ipconf/source/event.go | 62 +++++++ ipconf/source/mock.go | 1 + ipconf/utils.go | 18 ++ 19 files changed, 1001 insertions(+), 5 deletions(-) create mode 100644 cmd/ipconf.go create mode 100644 common/discovery/discovery.go create mode 100644 common/discovery/discovery_test.go create mode 100644 common/discovery/model.go create mode 100644 common/discovery/register.go create mode 100644 common/discovery/register_test.go create mode 100644 ipconf/api.go create mode 100644 ipconf/domain/context.go create mode 100644 ipconf/domain/dispatcher.go create mode 100644 ipconf/domain/endport.go create mode 100644 ipconf/domain/stat.go create mode 100644 ipconf/domain/window.go create mode 100644 ipconf/server.go create mode 100644 ipconf/source/data.go create mode 100644 ipconf/source/event.go create mode 100644 ipconf/source/mock.go create mode 100644 ipconf/utils.go diff --git a/cmd/ipconf.go b/cmd/ipconf.go new file mode 100644 index 0000000..af281e0 --- /dev/null +++ b/cmd/ipconf.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "github.com/hardcore-os/plato/ipconf" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(ipConfCmd) +} + +var ipConfCmd = &cobra.Command{ + Use: "ipconf", + Run: IpConfHandle, +} + +func IpConfHandle(cmd *cobra.Command, args []string) { + ipconf.RunMain() +} diff --git a/common/discovery/discovery.go b/common/discovery/discovery.go new file mode 100644 index 0000000..0eb8e00 --- /dev/null +++ b/common/discovery/discovery.go @@ -0,0 +1,68 @@ +package discovery + +import ( + "context" + "github.com/bytedance/gopkg/util/logger" + "github.com/coreos/etcd/mvcc/mvccpb" + "sync" + "time" + + "go.etcd.io/etcd/clientv3" +) + +// ServiceDiscovery 服务发现 +type ServiceDiscovery struct { + cli *clientv3.Client //etcd client + lock sync.Mutex + ctx *context.Context +} + +// NewServiceDiscovery 新建发现服务 +func NewServiceDiscovery(ctx *context.Context, endpoints []string) *ServiceDiscovery { + cli, err := clientv3.New(clientv3.Config{ + Endpoints: endpoints, + DialTimeout: 5 * time.Second, + }) + if err != nil { + // log.error and then exist with 1 + logger.Fatal(err) + } + return &ServiceDiscovery{ + cli: cli, + ctx: ctx, + } +} + +func (s *ServiceDiscovery) WatchService(prefix string, set, del func(key, value string)) error { + // 根据前缀获取现有的key + resp, err := s.cli.Get(*s.ctx, prefix, clientv3.WithPrefix()) + if err != nil { + return err + } + + for _, kv := range resp.Kvs { + set(string(kv.Key), string(kv.Value)) + } + // 监视前缀,修改变更的server + s.watcher(prefix, set, del) + return nil +} + +func (s *ServiceDiscovery) watcher(prefix string, set, del func(key, value string)) { + rch := s.cli.Watch(*s.ctx, prefix, clientv3.WithPrefix()) + logger.CtxInfof(*s.ctx, "watching prefix:%s now...", prefix) + for wresp := range rch { + for _, ev := range wresp.Events { + switch ev.Type { + case mvccpb.PUT: //修改或者新增 + set(string(ev.Kv.Key), string(ev.Kv.Key)) + case mvccpb.DELETE: //删除 + del(string(ev.Kv.Key), string(ev.Kv.Key)) + } + } + } +} + +func (s *ServiceDiscovery) Close() error { + return s.cli.Close() +} diff --git a/common/discovery/discovery_test.go b/common/discovery/discovery_test.go new file mode 100644 index 0000000..9e94660 --- /dev/null +++ b/common/discovery/discovery_test.go @@ -0,0 +1,21 @@ +package discovery + +import ( + "context" + "testing" + "time" +) + +func TestServiceDiscovery(t *testing.T) { + var endpoints = []string{"localhost:2379"} + ctx := context.Background() + ser := NewServiceDiscovery(&ctx, endpoints) + defer ser.Close() + ser.WatchService("/web/", func(key, value string) {}, func(key, value string) {}) + ser.WatchService("/gRPC/", func(key, value string) {}, func(key, value string) {}) + for { + select { + case <-time.Tick(10 * time.Second): + } + } +} diff --git a/common/discovery/model.go b/common/discovery/model.go new file mode 100644 index 0000000..3539236 --- /dev/null +++ b/common/discovery/model.go @@ -0,0 +1,27 @@ +package discovery + +import "encoding/json" + +type EndpointInfo struct { + IP string `json:"ip"` + Port string `json:"port"` + MetaData map[string]interface{} `json:"meta"` +} + +func UnMarshal(data []byte) (*EndpointInfo, error) { + var ed EndpointInfo + err := json.Unmarshal(data, &ed) + if err != nil { + return nil, err + } + return &ed, nil +} + +func (ed *EndpointInfo) Marshal() string { + data, err := json.Marshal(ed) + if err != nil { + // TODO zt 为什么不是返回""? + panic(err) + } + return string(data) +} diff --git a/common/discovery/register.go b/common/discovery/register.go new file mode 100644 index 0000000..65c2e68 --- /dev/null +++ b/common/discovery/register.go @@ -0,0 +1,94 @@ +package discovery + +import ( + "context" + "github.com/bytedance/gopkg/util/logger" + "go.etcd.io/etcd/clientv3" + "time" +) + +type ServiceRegister struct { + cli *clientv3.Client + leaseID clientv3.LeaseID + // 租约keepAlive响应chan + KeepAliveChan <-chan *clientv3.LeaseKeepAliveResponse + Key string + Value string + ctx *context.Context +} + +func NewServiceRegister(ctx *context.Context, endpoints []string, key string, info *EndpointInfo, lease int64) (*ServiceRegister, error) { + cli, err := clientv3.New(clientv3.Config{ + Endpoints: endpoints, + DialTimeout: 5 * time.Second, + }) + if err != nil { + logger.Fatal(err) + } + + ser := &ServiceRegister{ + cli: cli, + Key: key, + Value: info.Marshal(), + ctx: ctx, + } + + // 申请租约设置时间keepalive + if err := ser.putKeyWithLease(lease); err != nil { + return nil, err + } + + return ser, nil +} + +// putKeyWithLease 设置族月 +func (ser *ServiceRegister) putKeyWithLease(lease int64) error { + // 设置租约时间 + resp, err := ser.cli.Grant(*ser.ctx, lease) + if err != nil { + return err + } + // 注册服务并绑定租约 + _, err = ser.cli.Put(*ser.ctx, ser.Key, ser.Value, clientv3.WithLease(resp.ID)) + if err != nil { + return err + } + // 设置续租 定期发送需求请求 + leaseRespChan, err := ser.cli.KeepAlive(*ser.ctx, resp.ID) + if err != nil { + return err + } + ser.leaseID = resp.ID + ser.KeepAliveChan = leaseRespChan + return nil +} + +func (ser *ServiceRegister) UpdateValue(value *EndpointInfo) error { + val := value.Marshal() + _, err := ser.cli.Put(*ser.ctx, ser.Key, val, clientv3.WithLease(ser.leaseID)) + if err != nil { + return err + } + ser.Value = val + logger.CtxInfof(*ser.ctx, "ServiceRegister.updateValue leaseID=%d Put key=%s,val=%s, success!", ser.leaseID, ser.Key, ser.Value) + return nil +} + +// ListenLeaseRespChan 监听 续租情况 +func (ser *ServiceRegister) ListenLeaseRespChan() { + for leaseKeepResp := range ser.KeepAliveChan { + logger.CtxInfof(*ser.ctx, "lease success leaseID:%d, Put key:%s,val:%s reps:+%v", + ser.leaseID, ser.Key, ser.Value, leaseKeepResp) + } + logger.CtxInfof(*ser.ctx, "lease failed !!! leaseID:%d, Put key:%s,val:%s", ser.leaseID, ser.Key, ser.Value) +} + +// Close 注销服务 +func (ser *ServiceRegister) Close() error { + // 撤销租约 + if _, err := ser.cli.Revoke(*ser.ctx, ser.leaseID); err != nil { + return err + } + logger.CtxInfof(*ser.ctx, "lease close !!! leaseID:%d, Put key:%s,val:%s success!", ser.leaseID, ser.Key, ser.Value) + return ser.cli.Close() +} diff --git a/common/discovery/register_test.go b/common/discovery/register_test.go new file mode 100644 index 0000000..9fb624c --- /dev/null +++ b/common/discovery/register_test.go @@ -0,0 +1,26 @@ +package discovery + +import ( + "context" + "log" + "testing" + "time" +) + +func TestServiceRegiste(t *testing.T) { + var endpoints = []string{"localhost:2379"} + ctx := context.Background() + ser, err := NewServiceRegister(&ctx, endpoints, "/web/node1", &EndpointInfo{ + IP: "127.0.0.1", + Port: "9999", + }, 5) + if err != nil { + log.Fatalln(err) + } + //监听续租相应chan + go ser.ListenLeaseRespChan() + select { + case <-time.After(20 * time.Second): + ser.Close() + } +} diff --git a/go.mod b/go.mod index 3a6fbba..525b261 100644 --- a/go.mod +++ b/go.mod @@ -2,18 +2,73 @@ module github.com/hardcore-os/plato go 1.18 +replace github.com/coreos/bbolt v1.3.7 => go.etcd.io/bbolt v1.3.7 + +replace google.golang.org/grpc => google.golang.org/grpc v1.25.1 + require ( + github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b + github.com/cloudwego/hertz v0.7.0 github.com/gookit/color v1.5.1 github.com/rocket049/gocui v0.3.2 github.com/spf13/cobra v1.5.0 ) require ( + github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect + github.com/bytedance/sonic v1.8.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/cloudwego/netpoll v0.5.0 // indirect + github.com/coreos/bbolt v1.3.7 // indirect + github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/btree v1.1.2 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/henrylee2cn/ameda v1.4.10 // indirect + github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect + github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/nyaruka/phonenumbers v1.0.55 // indirect + github.com/prometheus/client_golang v1.17.0 // indirect + github.com/soheilhy/cmux v0.1.5 // indirect + github.com/tidwall/gjson v1.14.4 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect + golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/grpc v1.56.2 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + +require ( + github.com/coreos/etcd v3.3.27+incompatible + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect + github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/nsf/termbox-go v1.1.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + go.etcd.io/etcd v3.3.27+incompatible + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.11.0 // indirect + google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/protobuf v1.31.0 // indirect ) diff --git a/go.sum b/go.sum index 5ab3621..8039f04 100644 --- a/go.sum +++ b/go.sum @@ -1,35 +1,290 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= +github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= +github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= +github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b h1:R6PWoQtxEMpWJPHnpci+9LgFxCS7iJCfOGBvCgZeTKI= +github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= +github.com/bytedance/mockey v1.2.1 h1:g84ngI88hz1DR4wZTL3yOuqlEcq67MretBfQUdXwrmw= +github.com/bytedance/mockey v1.2.1/go.mod h1:+Jm/fzWZAuhEDrPXVjDf/jLM2BlLXJkwk94zf2JZ3X4= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.1 h1:NqAHCaGaTzro0xMmnTCLUyRlbEP6r8MCA1cJUrH3Pu4= +github.com/bytedance/sonic v1.8.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/cloudwego/hertz v0.7.0 h1:9LFXPqHkGBNH/k/Y1h3udEloS5LVPNOUWekDfH0bQNM= +github.com/cloudwego/hertz v0.7.0/go.mod h1:WliNtVbwihWHHgAaIQEbVXl0O3aWj0ks1eoPrcEAnjs= +github.com/cloudwego/netpoll v0.5.0 h1:oRrOp58cPCvK2QbMozZNDESvrxQaEHW2dCimmwH1lcU= +github.com/cloudwego/netpoll v0.5.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= +github.com/coreos/etcd v3.3.27+incompatible h1:QIudLb9KeBsE5zyYxd1mjzRSkzLg9Wf9QlRwFgd6oTA= +github.com/coreos/etcd v3.3.27+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= +github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8 h1:NrLmX9HDyGvQhyZdrDx89zCvPdxQ/EHCo+xGNrjNmHc= +github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ= github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= +github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk= +github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= +github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhYIrO6sdV/FPe0xQM6fNHkVQW2IAymfM0= +github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= +github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= +github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= +github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= +github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rocket049/gocui v0.3.2 h1:6QEaEX85VheVRLwA5FjAe2tswlIkIg0mgoeBHEguRzA= github.com/rocket049/gocui v0.3.2/go.mod h1:oKkm50/BFqMgu7hwBRMs7/uketHe9hRMoo29X1gxK9A= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= +github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= +github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/etcd v3.3.27+incompatible h1:5hMrpf6REqTHV2LW2OclNpRtxI0k9ZplMemJsMSWju0= +go.etcd.io/etcd v3.3.27+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/ipconf/api.go b/ipconf/api.go new file mode 100644 index 0000000..e7dfc7c --- /dev/null +++ b/ipconf/api.go @@ -0,0 +1,29 @@ +package ipconf + +import ( + "context" + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hardcore-os/plato/ipconf/domain" +) + +type Response struct { + Message string `json:"message"` + Code int `json:"code"` + Data interface{} `json:"data"` +} + +func GetIpInfoList(ctx context.Context, appCtx *app.RequestContext) { + defer func() { + if r := recover(); r != nil { + appCtx.JSON(consts.StatusBadRequest, utils.H{"err": r}) + } + }() + // 构建客户端请求 + ipConfCtx := domain.BuildIpConfContext(&ctx, appCtx) + // ip调度 + eds := domain.Dispatch(ipConfCtx) + //获取分数top5返回 + ipConfCtx.AppCtx.JSON(consts.StatusOK, packRes(top5Endports(eds))) +} diff --git a/ipconf/domain/context.go b/ipconf/domain/context.go new file mode 100644 index 0000000..421c3f0 --- /dev/null +++ b/ipconf/domain/context.go @@ -0,0 +1,25 @@ +package domain + +import ( + "context" + "github.com/cloudwego/hertz/pkg/app" +) + +type IpConfContext struct { + Ctx *context.Context + AppCtx *app.RequestContext + ClientCtx *ClientContext +} + +type ClientContext struct { + IP string `json:"ip"` +} + +func BuildIpConfContext(c *context.Context, ctx *app.RequestContext) *IpConfContext { + ipConfConext := &IpConfContext{ + Ctx: c, + AppCtx: ctx, + ClientCtx: &ClientContext{}, + } + return ipConfConext +} diff --git a/ipconf/domain/dispatcher.go b/ipconf/domain/dispatcher.go new file mode 100644 index 0000000..6836abf --- /dev/null +++ b/ipconf/domain/dispatcher.go @@ -0,0 +1,84 @@ +package domain + +import ( + "github.com/hardcore-os/plato/ipconf/source" + "sort" + "sync" +) + +type Dispatcher struct { + candidatePool map[string]*Endport + sync.RWMutex +} + +var dp *Dispatcher + +func Init() { + dp = &Dispatcher{} + dp.candidatePool = make(map[string]*Endport) + go func() { + for event := range source.EventChan() { + switch event.Type { + case source.AddEvent: + dp.AddNode(event) + case source.DelEvent: + dp.DelNode(event) + } + } + }() +} + +func Dispatch(ctx *IpConfContext) []*Endport { + // 获取候选candidate + eds := dp.getCandidateEndPort(ctx) + // 计算分数 + for _, ed := range eds { + ed.CalculateScore(ctx) + } + // 全局排序,返回排序策略 + sort.Slice(eds, func(i, j int) bool { + // 优先基于活跃分数进行排序 + if eds[i].ActiveScore > eds[j].ActiveScore { + return true + } + // 如果活跃分数相同,则使用静态分数排序 + if eds[i].ActiveScore == eds[j].ActiveScore { + return eds[i].StaticScore > eds[j].StaticScore + } + return false + }) + return eds +} + +func (d *Dispatcher) getCandidateEndPort(ctx *IpConfContext) []*Endport { + dp.RLock() + defer dp.RUnlock() + candidateList := make([]*Endport, 0, len(dp.candidatePool)) + for _, ed := range dp.candidatePool { + candidateList = append(candidateList, ed) + } + return candidateList +} + +func (d *Dispatcher) DelNode(event *source.Event) { + dp.Lock() + delete(dp.candidatePool, event.Key()) + dp.Unlock() +} + +func (d *Dispatcher) AddNode(event *source.Event) { + dp.Lock() + defer dp.Unlock() + var ( + ed *Endport + ok bool + ) + if ed, ok = d.candidatePool[event.Key()]; !ok { // not exist, then create EndPort + ed = NewEndport(event.IP, event.Port) + } + ed.UpdateStat(&Stat{ + ConnectNum: event.ConnectNum, + MessageBytes: event.MessageBytes, + }) + dp.candidatePool[event.Key()] = ed +} diff --git a/ipconf/domain/endport.go b/ipconf/domain/endport.go new file mode 100644 index 0000000..557f605 --- /dev/null +++ b/ipconf/domain/endport.go @@ -0,0 +1,44 @@ +package domain + +import ( + "sync/atomic" + "unsafe" +) + +type Endport struct { + IP string `json:"ip"` + Port string `json:"port"` + ActiveScore float64 `json:"-"` + StaticScore float64 `json:"-"` + Stats *Stat `json:"-"` + window *stateWindow `json:"-"` +} + +func NewEndport(ip string, port string) *Endport { + ed := &Endport{ + IP: ip, + Port: port, + } + ed.window = newStateWindow() + ed.Stats = ed.window.getStat() + go func() { + for stat := range ed.window.statChan { + ed.window.appendStat(stat) + newStat := ed.window.getStat() + atomic.SwapPointer((*unsafe.Pointer)((unsafe.Pointer)(ed.Stats)), unsafe.Pointer(newStat)) + } + }() + return ed +} + +func (ed *Endport) UpdateStat(s *Stat) { + ed.window.statChan <- s +} + +func (ed *Endport) CalculateScore(ctx *IpConfContext) { + // 如果 stats 字段是空的,则直接使用上一次计算的结果,此次不更新 + if ed.Stats != nil { + ed.ActiveScore = ed.Stats.CalculateActiveScore() + ed.StaticScore = ed.Stats.CalculateStaticScore() + } +} diff --git a/ipconf/domain/stat.go b/ipconf/domain/stat.go new file mode 100644 index 0000000..ae9c785 --- /dev/null +++ b/ipconf/domain/stat.go @@ -0,0 +1,67 @@ +package domain + +import "math" + +// Stat +// 对于gateway网关机来说,存在不同时期加入进来的物理机,所以机器的配置是不同的,使用负载来衡量会导致偏差。 +// 为更好的应对动态的机器配置变化,我们统计其剩余资源值,来衡量一个机器其是否更适合增加其负载。 +// 这里的数值代表的是,此endpoint对应的机器其,自身剩余的资源指标。 +type Stat struct { + ConnectNum float64 // 业务上,im gateway 总体持有的长连接数量 的剩余值 + MessageBytes float64 // 业务上,im gateway 每秒收发消息的总字节数 的剩余值 +} + +// CalculateActiveScore +// 因此假设网络带宽将是系统瓶颈所在,那么哪台机器富余的带宽资源多,哪台机器的负载就是最轻的。 +// TODO: 如何预估他的数量级?何时使用静态值衡量 +// TODO: json 的解析失效 +func (s *Stat) CalculateActiveScore() float64 { + return getGB(s.MessageBytes) +} + +func (s *Stat) Avg(num float64) { + s.ConnectNum /= num + s.MessageBytes /= num +} +func (s *Stat) Clone() *Stat { + newStat := &Stat{ + MessageBytes: s.MessageBytes, + ConnectNum: s.ConnectNum, + } + return newStat +} + +func (s *Stat) Add(st *Stat) { + if st == nil { + return + } + s.ConnectNum += st.ConnectNum + s.MessageBytes += st.MessageBytes +} + +func (s *Stat) Sub(st *Stat) { + if st == nil { + return + } + s.ConnectNum -= st.ConnectNum + s.MessageBytes -= st.MessageBytes +} + +func getGB(m float64) float64 { + return decimal(m / (1 << 30)) +} +func decimal(value float64) float64 { + return math.Trunc(value*1e2+0.5) * 1e-2 +} +func min(a, b, c float64) float64 { + m := func(k, j float64) float64 { + if k > j { + return j + } + return k + } + return m(a, m(b, c)) +} +func (s *Stat) CalculateStaticScore() float64 { + return s.ConnectNum +} diff --git a/ipconf/domain/window.go b/ipconf/domain/window.go new file mode 100644 index 0000000..114411e --- /dev/null +++ b/ipconf/domain/window.go @@ -0,0 +1,36 @@ +package domain + +const ( + windowSize = 5 +) + +type stateWindow struct { + stateQueue []*Stat + statChan chan *Stat + sumStat *Stat + idx int64 +} + +func newStateWindow() *stateWindow { + return &stateWindow{ + stateQueue: make([]*Stat, windowSize), + statChan: make(chan *Stat), + sumStat: &Stat{}, + } +} + +func (sw *stateWindow) getStat() *Stat { + res := sw.sumStat.Clone() + res.Avg(windowSize) + return res +} + +func (sw *stateWindow) appendStat(s *Stat) { + // 减去即将被删除的state(循环数组充当队列) + sw.sumStat.Sub(sw.stateQueue[sw.idx%windowSize]) + // 更新最新的stat + sw.stateQueue[sw.idx%windowSize] = s + // 计算最新的窗口和 + sw.sumStat.Add(s) + sw.idx++ +} diff --git a/ipconf/server.go b/ipconf/server.go new file mode 100644 index 0000000..257bbcb --- /dev/null +++ b/ipconf/server.go @@ -0,0 +1,19 @@ +package ipconf + +import ( + "github.com/hardcore-os/plato/ipconf/domain" + "github.com/hardcore-os/plato/ipconf/source" + + "github.com/cloudwego/hertz/pkg/app/server" +) + +func RunMain() { + // 启动数据源 + source.Init() + // 初始化调度层 + domain.Init() + // 启动web容器 + s := server.Default(server.WithHostPorts(":6789")) + s.GET("/ip/list", GetIpInfoList) + s.Spin() +} diff --git a/ipconf/source/data.go b/ipconf/source/data.go new file mode 100644 index 0000000..ba9e5b3 --- /dev/null +++ b/ipconf/source/data.go @@ -0,0 +1,46 @@ +package source + +import ( + "context" + + "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/common/discovery" +) + +func Init() { + eventChan = make(chan *Event) + ctx := context.Background() + go DataHandler(&ctx) +} + +// DataHandler 服务发现处理 +func DataHandler(ctx *context.Context) { + dis := discovery.NewServiceDiscovery(ctx, []string{"localhost:2379"}) + defer dis.Close() + setFunc := func(key string, value string) { + if ed, err := discovery.UnMarshal([]byte(value)); err == nil { + if event := NewEvent(ed); event != nil { // 原文是ed != nil,应该是bug,应该是现在这样写 + event.Type = AddEvent + eventChan <- event + } + } else { + logger.CtxErrorf(*ctx, "DataHandler.setFunc.err :%s", err.Error()) + } + } + + delFunc := func(key string, value string) { + if ed, err := discovery.UnMarshal([]byte(value)); err == nil { + if event := NewEvent(ed); event != nil { + event.Type = DelEvent + eventChan <- event + } + } else { + logger.CtxErrorf(*ctx, "DataHandler.delFunc.err :%s", err.Error()) + } + } + + err := dis.WatchService("/plato/ip_dispatcher", setFunc, delFunc) + if err != nil { + panic(err) + } +} diff --git a/ipconf/source/event.go b/ipconf/source/event.go new file mode 100644 index 0000000..ea4ee9f --- /dev/null +++ b/ipconf/source/event.go @@ -0,0 +1,62 @@ +package source + +import ( + "fmt" + "github.com/hardcore-os/plato/common/discovery" +) + +var eventChan chan *Event + +func EventChan() chan *Event { + return eventChan +} + +type EventType string + +const ( + AddEvent EventType = "addNode" + DelEvent EventType = "delNode" + + connectNum string = "connect_num" + messageBytes string = "message_bytes" +) + +type Event struct { + Type EventType + IP string + Port string + ConnectNum float64 // 连接数量 + MessageBytes float64 // 接收的字节数量 +} + +func NewEvent(ed *discovery.EndpointInfo) *Event { + if ed == nil || ed.MetaData == nil { + return nil + } + var connNum, msgBytes float64 + if data, ok := ed.MetaData[connectNum]; ok { + connNum, ok = data.(float64) + if !ok { + panic("connNum transfer failed") + } + } + + if data, ok := ed.MetaData[messageBytes]; ok { + msgBytes, ok = data.(float64) + if !ok { + panic("messageBytes transfer failed") + } + } + + return &Event{ + Type: AddEvent, + IP: ed.IP, + Port: ed.Port, + ConnectNum: connNum, + MessageBytes: msgBytes, + } +} + +func (e *Event) Key() string { + return fmt.Sprintf("%s:%s", e.IP, e.Port) +} diff --git a/ipconf/source/mock.go b/ipconf/source/mock.go new file mode 100644 index 0000000..d150341 --- /dev/null +++ b/ipconf/source/mock.go @@ -0,0 +1 @@ +package source diff --git a/ipconf/utils.go b/ipconf/utils.go new file mode 100644 index 0000000..e39fe13 --- /dev/null +++ b/ipconf/utils.go @@ -0,0 +1,18 @@ +package ipconf + +import "github.com/hardcore-os/plato/ipconf/domain" + +func top5Endports(eds []*domain.Endport) []*domain.Endport { + if len(eds) < 5 { + return eds + } + return eds[:5] +} + +func packRes(ed []*domain.Endport) Response { + return Response{ + Message: "ok", + Code: 0, + Data: ed, + } +} From f7602a27d533981b6c4d344d4378fe63a27e4015 Mon Sep 17 00:00:00 2001 From: vagrantZero <750437163@qq.com> Date: Sat, 30 Sep 2023 17:10:01 +0800 Subject: [PATCH 03/26] feat: ipconf dispatch server --- cmd/ipconf.go | 2 +- cmd/plato.go | 10 + common/config/config.go | 34 +++ common/discovery/discovery.go | 15 +- common/discovery/discovery_test.go | 3 +- common/discovery/register.go | 8 +- common/discovery/register_test.go | 3 +- go.mod | 14 +- go.sum | 357 ++++++++++++++++++++++++++++- ipconf/server.go | 4 +- ipconf/source/data.go | 11 +- ipconf/source/mock.go | 41 ++++ plato.yaml | 8 + 13 files changed, 485 insertions(+), 25 deletions(-) create mode 100644 common/config/config.go create mode 100644 plato.yaml diff --git a/cmd/ipconf.go b/cmd/ipconf.go index af281e0..961d6e3 100644 --- a/cmd/ipconf.go +++ b/cmd/ipconf.go @@ -15,5 +15,5 @@ var ipConfCmd = &cobra.Command{ } func IpConfHandle(cmd *cobra.Command, args []string) { - ipconf.RunMain() + ipconf.RunMain(ConfigPath) } diff --git a/cmd/plato.go b/cmd/plato.go index 411bbb2..0bb6a17 100644 --- a/cmd/plato.go +++ b/cmd/plato.go @@ -7,8 +7,18 @@ import ( "github.com/spf13/cobra" ) +var ( + ConfigPath string +) + func init() { cobra.OnInitialize(initConfig) + rootCmd.PersistentFlags().StringVar( + &ConfigPath, + "config", + "./plato.yaml", + "config file (default is ./plato.yaml)", + ) } var rootCmd = &cobra.Command{ diff --git a/common/config/config.go b/common/config/config.go new file mode 100644 index 0000000..b0352c8 --- /dev/null +++ b/common/config/config.go @@ -0,0 +1,34 @@ +package config + +import ( + "github.com/spf13/viper" + "time" +) + +func Init(path string) { + viper.SetConfigFile(path) + viper.SetConfigType("yaml") + if err := viper.ReadInConfig(); err != nil { + panic(err) + } +} + +// GetEndpointsForDiscovery 获取服务发现地 址 +func GetEndpointsForDiscovery() []string { + return viper.GetStringSlice("discovery.endpoints") +} + +// GetTimeoutForDiscovery 获取连接服务发现集群的超时时间 单位微秒 +func GetTimeoutForDiscovery() time.Duration { + return viper.GetDuration("discovery.timeout") * time.Second +} + +func GetServicePathForIPConf() string { + return viper.GetString("ip_conf.service_path") +} + +// IsDebug 判断是不是debug环境 +func IsDebug() bool { + env := viper.GetString("global.env") + return env == "debug" +} diff --git a/common/discovery/discovery.go b/common/discovery/discovery.go index 0eb8e00..9dcc174 100644 --- a/common/discovery/discovery.go +++ b/common/discovery/discovery.go @@ -4,10 +4,9 @@ import ( "context" "github.com/bytedance/gopkg/util/logger" "github.com/coreos/etcd/mvcc/mvccpb" - "sync" - "time" - + "github.com/hardcore-os/plato/common/config" "go.etcd.io/etcd/clientv3" + "sync" ) // ServiceDiscovery 服务发现 @@ -18,10 +17,10 @@ type ServiceDiscovery struct { } // NewServiceDiscovery 新建发现服务 -func NewServiceDiscovery(ctx *context.Context, endpoints []string) *ServiceDiscovery { +func NewServiceDiscovery(ctx *context.Context) *ServiceDiscovery { cli, err := clientv3.New(clientv3.Config{ - Endpoints: endpoints, - DialTimeout: 5 * time.Second, + Endpoints: config.GetEndpointsForDiscovery(), + DialTimeout: config.GetTimeoutForDiscovery(), }) if err != nil { // log.error and then exist with 1 @@ -55,9 +54,9 @@ func (s *ServiceDiscovery) watcher(prefix string, set, del func(key, value strin for _, ev := range wresp.Events { switch ev.Type { case mvccpb.PUT: //修改或者新增 - set(string(ev.Kv.Key), string(ev.Kv.Key)) + set(string(ev.Kv.Key), string(ev.Kv.Value)) case mvccpb.DELETE: //删除 - del(string(ev.Kv.Key), string(ev.Kv.Key)) + del(string(ev.Kv.Key), string(ev.Kv.Value)) } } } diff --git a/common/discovery/discovery_test.go b/common/discovery/discovery_test.go index 9e94660..7cb5487 100644 --- a/common/discovery/discovery_test.go +++ b/common/discovery/discovery_test.go @@ -7,9 +7,8 @@ import ( ) func TestServiceDiscovery(t *testing.T) { - var endpoints = []string{"localhost:2379"} ctx := context.Background() - ser := NewServiceDiscovery(&ctx, endpoints) + ser := NewServiceDiscovery(&ctx) defer ser.Close() ser.WatchService("/web/", func(key, value string) {}, func(key, value string) {}) ser.WatchService("/gRPC/", func(key, value string) {}, func(key, value string) {}) diff --git a/common/discovery/register.go b/common/discovery/register.go index 65c2e68..41ba593 100644 --- a/common/discovery/register.go +++ b/common/discovery/register.go @@ -3,8 +3,8 @@ package discovery import ( "context" "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/common/config" "go.etcd.io/etcd/clientv3" - "time" ) type ServiceRegister struct { @@ -17,10 +17,10 @@ type ServiceRegister struct { ctx *context.Context } -func NewServiceRegister(ctx *context.Context, endpoints []string, key string, info *EndpointInfo, lease int64) (*ServiceRegister, error) { +func NewServiceRegister(ctx *context.Context, key string, info *EndpointInfo, lease int64) (*ServiceRegister, error) { cli, err := clientv3.New(clientv3.Config{ - Endpoints: endpoints, - DialTimeout: 5 * time.Second, + Endpoints: config.GetEndpointsForDiscovery(), + DialTimeout: config.GetTimeoutForDiscovery(), }) if err != nil { logger.Fatal(err) diff --git a/common/discovery/register_test.go b/common/discovery/register_test.go index 9fb624c..d563c69 100644 --- a/common/discovery/register_test.go +++ b/common/discovery/register_test.go @@ -8,9 +8,8 @@ import ( ) func TestServiceRegiste(t *testing.T) { - var endpoints = []string{"localhost:2379"} ctx := context.Background() - ser, err := NewServiceRegister(&ctx, endpoints, "/web/node1", &EndpointInfo{ + ser, err := NewServiceRegister(&ctx, "/web/node1", &EndpointInfo{ IP: "127.0.0.1", Port: "9999", }, 5) diff --git a/go.mod b/go.mod index 525b261..516d44c 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/gookit/color v1.5.1 github.com/rocket049/gocui v0.3.2 github.com/spf13/cobra v1.5.0 + github.com/spf13/viper v1.16.0 ) require ( @@ -22,19 +23,26 @@ require ( github.com/coreos/bbolt v1.3.7 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/google/btree v1.1.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/henrylee2cn/ameda v1.4.10 // indirect github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect github.com/jonboulle/clockwork v0.4.0 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/nyaruka/phonenumbers v1.0.55 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/prometheus/client_golang v1.17.0 // indirect github.com/soheilhy/cmux v0.1.5 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect github.com/tidwall/gjson v1.14.4 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect @@ -44,6 +52,8 @@ require ( golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/grpc v1.56.2 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 8039f04..f635ffe 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,42 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -17,6 +55,9 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cloudwego/hertz v0.7.0 h1:9LFXPqHkGBNH/k/Y1h3udEloS5LVPNOUWekDfH0bQNM= github.com/cloudwego/hertz v0.7.0/go.mod h1:WliNtVbwihWHHgAaIQEbVXl0O3aWj0ks1eoPrcEAnjs= github.com/cloudwego/netpoll v0.5.0 h1:oRrOp58cPCvK2QbMozZNDESvrxQaEHW2dCimmwH1lcU= @@ -39,9 +80,14 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -49,22 +95,68 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ= github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= @@ -77,16 +169,24 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/henrylee2cn/ameda v1.4.8/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= github.com/henrylee2cn/ameda v1.4.10 h1:JdvI2Ekq7tapdPsuhrc4CaFiqw6QXFvZIULWJgQyCAk= github.com/henrylee2cn/ameda v1.4.10/go.mod h1:liZulR8DgHxdK+MEwvZIylGnmcjzQ6N6f2PlWe7nEO4= github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 h1:yE9ULgp02BhYIrO6sdV/FPe0xQM6fNHkVQW2IAymfM0= github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8/go.mod h1:Nhe/DM3671a5udlv2AdV2ni/MZzgfv2qrPL5nIi3EGQ= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -94,13 +194,20 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= @@ -108,7 +215,11 @@ github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpo github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= @@ -122,6 +233,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rocket049/gocui v0.3.2 h1:6QEaEX85VheVRLwA5FjAe2tswlIkIg0mgoeBHEguRzA= github.com/rocket049/gocui v0.3.2/go.mod h1:oKkm50/BFqMgu7hwBRMs7/uketHe9hRMoo29X1gxK9A= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= @@ -132,10 +245,18 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -148,8 +269,11 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -165,12 +289,20 @@ github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chq github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.etcd.io/etcd v3.3.27+incompatible h1:5hMrpf6REqTHV2LW2OclNpRtxI0k9ZplMemJsMSWju0= go.etcd.io/etcd v3.3.27+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= @@ -184,81 +316,278 @@ golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5P golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= @@ -267,13 +596,27 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -284,7 +627,15 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/ipconf/server.go b/ipconf/server.go index 257bbcb..5abe474 100644 --- a/ipconf/server.go +++ b/ipconf/server.go @@ -1,13 +1,15 @@ package ipconf import ( + "github.com/hardcore-os/plato/common/config" "github.com/hardcore-os/plato/ipconf/domain" "github.com/hardcore-os/plato/ipconf/source" "github.com/cloudwego/hertz/pkg/app/server" ) -func RunMain() { +func RunMain(path string) { + config.Init(path) // 启动数据源 source.Init() // 初始化调度层 diff --git a/ipconf/source/data.go b/ipconf/source/data.go index ba9e5b3..18d5663 100644 --- a/ipconf/source/data.go +++ b/ipconf/source/data.go @@ -2,6 +2,7 @@ package source import ( "context" + "github.com/hardcore-os/plato/common/config" "github.com/bytedance/gopkg/util/logger" "github.com/hardcore-os/plato/common/discovery" @@ -11,11 +12,17 @@ func Init() { eventChan = make(chan *Event) ctx := context.Background() go DataHandler(&ctx) + if config.IsDebug() { + ctx := context.Background() + testServiceRegister(&ctx, "7896", "node1") + testServiceRegister(&ctx, "7897", "node2") + testServiceRegister(&ctx, "7898", "node3") + } } // DataHandler 服务发现处理 func DataHandler(ctx *context.Context) { - dis := discovery.NewServiceDiscovery(ctx, []string{"localhost:2379"}) + dis := discovery.NewServiceDiscovery(ctx) defer dis.Close() setFunc := func(key string, value string) { if ed, err := discovery.UnMarshal([]byte(value)); err == nil { @@ -39,7 +46,7 @@ func DataHandler(ctx *context.Context) { } } - err := dis.WatchService("/plato/ip_dispatcher", setFunc, delFunc) + err := dis.WatchService(config.GetServicePathForIPConf(), setFunc, delFunc) if err != nil { panic(err) } diff --git a/ipconf/source/mock.go b/ipconf/source/mock.go index d150341..efd3aac 100644 --- a/ipconf/source/mock.go +++ b/ipconf/source/mock.go @@ -1 +1,42 @@ package source + +import ( + "context" + "fmt" + "math/rand" + "time" + + "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/discovery" +) + +func testServiceRegister(ctx *context.Context, port, node string) { + // 模拟服务发现 + go func() { + ed := discovery.EndpointInfo{ + IP: "127.0.0.1", + Port: port, + MetaData: map[string]interface{}{ + "connect_num": float64(rand.Int63n(12312321231231131)), + "message_bytes": float64(rand.Int63n(1231232131556)), + }, + } + sr, err := discovery.NewServiceRegister(ctx, fmt.Sprintf("%s/%s", config.GetServicePathForIPConf(), node), &ed, time.Now().Unix()) + if err != nil { + panic(err) + } + go sr.ListenLeaseRespChan() + for { + ed = discovery.EndpointInfo{ + IP: "127.0.0.1", + Port: port, + MetaData: map[string]interface{}{ + "connect_num": float64(rand.Int63n(12312321231231131)), + "message_bytes": float64(rand.Int63n(1231232131556)), + }, + } + sr.UpdateValue(&ed) + time.Sleep(1 * time.Second) + } + }() +} diff --git a/plato.yaml b/plato.yaml new file mode 100644 index 0000000..52599ac --- /dev/null +++ b/plato.yaml @@ -0,0 +1,8 @@ +global: + env: debug +discovery: + endpoints: + - localhost:2379 + timeout: 5 +ip_conf: + service_path: /plato/ip_dispatcher \ No newline at end of file From f217ea3b1be0e61eb6af38d5f6ab68c808eae03d Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Fri, 6 Oct 2023 12:35:56 +0800 Subject: [PATCH 04/26] gateway epoll server --- client/cui.go | 5 +- client/sdk/api.go | 10 +- client/sdk/net.go | 52 ++++++-- cmd/gateway.go | 19 +++ common/config/gateway.go | 23 ++++ common/tcp/coder.go | 17 +++ common/tcp/read.go | 47 ++++++++ common/tcp/write.go | 19 +++ gateway/epoll.go | 231 ++++++++++++++++++++++++++++++++++++ gateway/server.go | 42 +++++++ gateway/table.go | 17 +++ gateway/workpool.go | 17 +++ go.mod | 3 +- go.sum | 2 + ipconf/domain/dispatcher.go | 2 +- plato.yaml | 19 ++- 16 files changed, 508 insertions(+), 17 deletions(-) create mode 100644 cmd/gateway.go create mode 100644 common/config/gateway.go create mode 100644 common/tcp/coder.go create mode 100644 common/tcp/read.go create mode 100644 common/tcp/write.go create mode 100644 gateway/epoll.go create mode 100644 gateway/server.go create mode 100644 gateway/table.go create mode 100644 gateway/workpool.go diff --git a/client/cui.go b/client/cui.go index 5129dab..627f67a 100644 --- a/client/cui.go +++ b/client/cui.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "log" "math/rand" + "net" "time" "github.com/gookit/color" @@ -59,7 +60,7 @@ func viewPrint(g *gocui.Gui, name, msg string, newline bool) { g.Update(out.Show) } -//doRecv work in goroutine +// doRecv work in goroutine func doRecv(g *gocui.Gui) { recvChannel := chat.Recv() for msg := range recvChannel { @@ -223,7 +224,7 @@ func pasteDown(g *gocui.Gui, cv *gocui.View) error { func RunMain() { // step1 创建caht的核心对象 - chat = sdk.NewChat("127.0.0.1:8080", "logic", "12312321", "2131") + chat = sdk.NewChat(net.ParseIP("0.0.0.0"), 8900, "logic", "12312321", "2131") // step2 创建 GUI 图层对象并进行参与与回调函数的配置 g, err := gocui.NewGui(gocui.OutputNormal) if err != nil { diff --git a/client/sdk/api.go b/client/sdk/api.go index a456157..8a58abe 100644 --- a/client/sdk/api.go +++ b/client/sdk/api.go @@ -1,5 +1,7 @@ package sdk +import "net" + const ( MsgTypeText = "text" ) @@ -20,24 +22,24 @@ type Message struct { Session string } -func NewChat(serverAddr, nick, userID, sessionID string) *Chat { +func NewChat(ip net.IP, port int, nick, userID, sessionID string) *Chat { return &Chat{ Nick: nick, UserID: userID, SessionID: sessionID, - conn: newConnet(serverAddr), + conn: newConnet(ip, port), } } func (chat *Chat) Send(msg *Message) { chat.conn.send(msg) } -//Close close chat +// Close chat func (chat *Chat) Close() { chat.conn.close() } -//Recv receive message +// Recv receive message func (chat *Chat) Recv() <-chan *Message { return chat.conn.recv() } diff --git a/client/sdk/net.go b/client/sdk/net.go index 05e97d8..356f374 100644 --- a/client/sdk/net.go +++ b/client/sdk/net.go @@ -1,27 +1,63 @@ package sdk +import ( + "encoding/json" + "github.com/hardcore-os/plato/common/tcp" + "net" +) + type connect struct { - serverAddr string sendChan, recvChan chan *Message + conn *net.TCPConn } -func newConnet(serverAddr string) *connect { - return &connect{ - serverAddr: serverAddr, - sendChan: make(chan *Message), - recvChan: make(chan *Message), +func newConnet(ip net.IP, port int) *connect { + clientConn := &connect{ + sendChan: make(chan *Message), + recvChan: make(chan *Message), + } + addr := &net.TCPAddr{ + IP: ip, + Port: port, } + conn, err := net.DialTCP("tcp", nil, addr) + if err != nil { + panic(err) + } + clientConn.conn = conn + go func() { + for { + data, err := tcp.ReadData(conn) + if err != nil { + panic(err) + } + msg := &Message{} + err = json.Unmarshal(data, msg) + if err != nil { + panic(err) + } + clientConn.recvChan <- msg + } + }() + return clientConn } func (c *connect) send(data *Message) { // 直接发送给接收方 - c.recvChan <- data + bytes, _ := json.Marshal(data) + dataPgk := tcp.DataPgk{ + Data: bytes, + Len: uint32(len(bytes)), + } + xx := dataPgk.Marshal() + c.conn.Write(xx) } -func (c *connect) recv() <- chan *Message { +func (c *connect) recv() <-chan *Message { return c.recvChan } func (c *connect) close() { // 目前没啥值得回收的 + c.conn.Close() } diff --git a/cmd/gateway.go b/cmd/gateway.go new file mode 100644 index 0000000..c5182b5 --- /dev/null +++ b/cmd/gateway.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "github.com/hardcore-os/plato/gateway" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(gatewayCmd) +} + +var gatewayCmd = &cobra.Command{ + Use: "gateway", + Run: GatewayHandle, +} + +func GatewayHandle(cmd *cobra.Command, args []string) { + gateway.RunMain(ConfigPath) +} diff --git a/common/config/gateway.go b/common/config/gateway.go new file mode 100644 index 0000000..0a7aa92 --- /dev/null +++ b/common/config/gateway.go @@ -0,0 +1,23 @@ +package config + +import "github.com/spf13/viper" + +func GetGatewayMaxTcpNum() int32 { + return viper.GetInt32("gateway.tcp_max_num") +} + +func GetGatewayEpollerChanNum() int { + return viper.GetInt("gateway.epoll_channel_size") +} +func GetGatewayEpollerNum() int { + return viper.GetInt("gateway.epoll_num") +} +func GetGatewayEpollWaitQueueSize() int { + return viper.GetInt("gateway.epoll_wait_queue_size") +} +func GetGatewayServerPort() int { + return viper.GetInt("gateway.server_port") +} +func GetGatewayWorkerPoolNum() int { + return viper.GetInt("gateway.worker_pool_num") +} diff --git a/common/tcp/coder.go b/common/tcp/coder.go new file mode 100644 index 0000000..aadc9af --- /dev/null +++ b/common/tcp/coder.go @@ -0,0 +1,17 @@ +package tcp + +import ( + "bytes" + "encoding/binary" +) + +type DataPgk struct { + Len uint32 + Data []byte +} + +func (d *DataPgk) Marshal() []byte { + bytesBuffer := bytes.NewBuffer([]byte{}) + binary.Write(bytesBuffer, binary.BigEndian, d.Len) + return append(bytesBuffer.Bytes(), d.Data...) +} diff --git a/common/tcp/read.go b/common/tcp/read.go new file mode 100644 index 0000000..6651579 --- /dev/null +++ b/common/tcp/read.go @@ -0,0 +1,47 @@ +package tcp + +import ( + "bytes" + "encoding/binary" + "fmt" + "net" + "time" +) + +func ReadData(conn *net.TCPConn) ([]byte, error) { + var dataLen uint32 + dataLenBuf := make([]byte, 4) + if err := readFixedData(conn, dataLenBuf); err != nil { + return nil, err + } + buffer := bytes.NewBuffer(dataLenBuf) + if err := binary.Read(buffer, binary.BigEndian, &dataLen); err != nil { + return nil, err + } + if dataLen <= 0 { + return nil, fmt.Errorf("wrong headlen: %d", dataLen) + } + dataBuf := make([]byte, dataLen) + if err := readFixedData(conn, dataBuf); err != nil { + return nil, fmt.Errorf("wrong headlen error: %s", err.Error()) + } + return dataBuf, nil +} + +// 读取固定buf长度的数据 +func readFixedData(conn *net.TCPConn, buf []byte) error { + _ = (*conn).SetReadDeadline(time.Now().Add(time.Duration(120) * time.Second)) + var pos int = 0 + var totalSize int = len(buf) + for { + c, err := (*conn).Read(buf[pos:]) + if err != nil { + return err + } + pos += c + if pos == totalSize { + break + } + } + return nil +} diff --git a/common/tcp/write.go b/common/tcp/write.go new file mode 100644 index 0000000..437e85d --- /dev/null +++ b/common/tcp/write.go @@ -0,0 +1,19 @@ +package tcp + +import "net" + +func SendData(conn *net.TCPConn, data []byte) error { + totalLen := len(data) + writeLen := 0 + for { + length, err := conn.Write(data[writeLen:]) + if err != nil { + return err + } + writeLen += length + if writeLen >= totalLen { + break + } + } + return nil +} diff --git a/gateway/epoll.go b/gateway/epoll.go new file mode 100644 index 0000000..6c61391 --- /dev/null +++ b/gateway/epoll.go @@ -0,0 +1,231 @@ +package gateway + +import ( + "context" + "fmt" + "github.com/hardcore-os/plato/common/config" + "golang.org/x/sys/unix" + "net" + "reflect" + "runtime" + "sync" + "sync/atomic" + "syscall" + + "github.com/bytedance/gopkg/util/logger" +) + +// 全局对象 +var ( + ep *ePool // epoll池 + tcpNum int32 // 当前服务允许接入的最大tcp连接数 +) + +type ePool struct { + eChan chan *net.TCPConn + eSize int + done chan struct{} + + ln *net.TCPListener + f func(conn *net.TCPConn, ep *epoller) // callback func +} + +func InitEpoll(ln *net.TCPListener, f func(conn *net.TCPConn, ep *epoller)) { + setLimit() + ep = NewEpoll(ln, f) + ep.createAcceptProcess() + ep.startEPoll() +} + +func NewEpoll(ln *net.TCPListener, callback func(conn *net.TCPConn, ep *epoller)) *ePool { + return &ePool{ + eChan: make(chan *net.TCPConn, config.GetGatewayEpollerChanNum()), + done: make(chan struct{}), + eSize: config.GetGatewayEpollerNum(), + ln: ln, + f: callback, + } +} + +// createAcceptProcess 创建一个专门处理 accept 事件的协程,与当前cpu的核数对应,能够发挥最大功效 +func (ep *ePool) createAcceptProcess() { + for i := 0; i < runtime.NumCPU(); i++ { + go func() { + ctx := context.Background() + for { + conn, err := ep.ln.AcceptTCP() + // 限流熔断 + if !checkTcp() { + _ = conn.Close() + continue + } + setTcpConfig(conn) + if err != nil { + if ne, ok := err.(net.Error); ok && ne.Temporary() { + logger.CtxErrorf(ctx, "accept temp err: %v", ne) + continue + } + fmt.Errorf("accept error: %v", err) + } + ep.addTask(conn) + } + }() + } +} + +func (ep *ePool) startEPoll() { + for i := 0; i < ep.eSize; i++ { + go ep.startEProc(i) + } +} + +// startEProc 轮询器池 处理器 +// epoll 的监听和处理逻辑 +func (ep *ePool) startEProc(id int) { + epl, err := NewEpoller(id) + if err != nil { + panic(err) + } + ctx := context.Background() + // listen events + go func() { + for { + select { + case <-ep.done: + return + case conn := <-ep.eChan: + // supply logs in below method + addTcpNum() + if addConnErr := epl.add(conn); addConnErr != nil { + logger.CtxErrorf(ctx, "epoll_%d failed to add connection %v\n", id, err) + _ = conn.Close() + continue + } + logger.CtxInfof(ctx, "EpollerPool new connection[%v], epoll_%d, tcpSize:%d", (conn).RemoteAddr().String(), id, tcpNum) + } + } + }() + + // wait for events + for { + select { + case <-ep.done: + return + default: + connections, waitErr := epl.Wait(200) // 200ms 一次轮询避免 忙轮询 + if waitErr != nil && waitErr != syscall.EINTR { + logger.CtxErrorf(ctx, "failed to epoll_%d wait %v\n", id, waitErr) + continue + } + + for _, conn := range connections { + if conn == nil { + break + } + ep.f(conn, epl) + } + } + } +} + +func (ep *ePool) addTask(conn *net.TCPConn) { + ep.eChan <- conn +} + +// epoller 对象 轮询器 +type epoller struct { + connections sync.Map + fd int + id int // id of epoll +} + +func NewEpoller(id int) (*epoller, error) { + fd, err := unix.EpollCreate1(0) + if err != nil { + return nil, err + } + return &epoller{ + connections: sync.Map{}, + fd: fd, + id: id, + }, nil +} + +func (epl *epoller) add(conn *net.TCPConn) error { + fd := socketFD(conn) + // the fd of epl is the epoll fd + // the fd of conn is the connection fd + err := unix.EpollCtl(epl.fd, syscall.EPOLL_CTL_ADD, fd, &unix.EpollEvent{Events: unix.EPOLLIN | unix.EPOLLHUP, Fd: int32(fd)}) + if err != nil { + return err + } + epl.connections.Store(fd, conn) + return nil +} + +func (epl *epoller) remove(conn *net.TCPConn) error { + subTcpNum() + fd := socketFD(conn) + err := unix.EpollCtl(epl.fd, syscall.EPOLL_CTL_DEL, fd, nil) + if err != nil { + return err + } + epl.connections.Delete(fd) + return nil +} + +func (epl *epoller) Wait(millSec int) ([]*net.TCPConn, error) { + events := make([]unix.EpollEvent, config.GetGatewayEpollWaitQueueSize()) + n, err := unix.EpollWait(epl.fd, events, millSec) + if err != nil { + return nil, err + } + var connections []*net.TCPConn + for i := 0; i < n; i++ { + if conn, ok := epl.connections.Load(int(events[i].Fd)); ok { + connections = append(connections, conn.(*net.TCPConn)) + } + } + return connections, nil +} + +func socketFD(conn *net.TCPConn) int { + tcpConn := reflect.Indirect(reflect.ValueOf(*conn).FieldByName("conn")) + fdVal := tcpConn.FieldByName("fd") + pfdVal := reflect.Indirect(fdVal).FieldByName("pfd") + return int(pfdVal.FieldByName("Sysfd").Int()) +} + +func setLimit() { + var rLimit syscall.Rlimit + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { + panic(err) + } + rLimit.Cur = rLimit.Max + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil { + panic(err) + } + logger.CtxInfof(context.Background(), "set cur limit: %d", rLimit.Cur) +} + +func addTcpNum() { + atomic.AddInt32(&tcpNum, 1) +} + +func getTcpNum() int32 { + return atomic.LoadInt32(&tcpNum) +} + +func subTcpNum() { + atomic.AddInt32(&tcpNum, -1) +} + +func checkTcp() bool { + num := getTcpNum() + maxTcpNum := config.GetGatewayMaxTcpNum() + return num <= maxTcpNum +} + +func setTcpConfig(c *net.TCPConn) { + _ = c.SetKeepAlive(true) +} diff --git a/gateway/server.go b/gateway/server.go new file mode 100644 index 0000000..45832e4 --- /dev/null +++ b/gateway/server.go @@ -0,0 +1,42 @@ +package gateway + +import ( + "context" + "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/tcp" + "net" +) + +func RunMain(path string) { + ctx := context.Background() + config.Init(path) + ln, err := net.ListenTCP("tcp", &net.TCPAddr{Port: config.GetGatewayServerPort()}) + if err != nil { + logger.CtxInfof(ctx, "StartTCPEPollServer err:%s", err.Error()) + } + initWorkPoll() + InitEpoll(ln, runProc) + logger.CtxInfof(context.Background(), "-------------IM Gateway stated------------") + select {} +} + +func runProc(conn *net.TCPConn, ep *epoller) { + // step1: 读取一个完整的消息包 + dataBuf, err := tcp.ReadData(conn) + if err != nil { + return + } + err = wPool.Submit(func() { + // step2:交给 state server rpc 处理 + bytes := tcp.DataPgk{ + Len: uint32(len(dataBuf)), + Data: dataBuf, + } + tcp.SendData(conn, bytes.Marshal()) + }) + + if err != nil { + logger.CtxInfof(context.Background(), "runProc.err: %+v", err.Error()) + } +} diff --git a/gateway/table.go b/gateway/table.go new file mode 100644 index 0000000..e78ada6 --- /dev/null +++ b/gateway/table.go @@ -0,0 +1,17 @@ +package gateway + +import ( + "sync" +) + +var tables table + +type table struct { + did2conn sync.Map +} + +func InitTable() { + tables = table{ + did2conn: sync.Map{}, + } +} diff --git a/gateway/workpool.go b/gateway/workpool.go new file mode 100644 index 0000000..c4ac246 --- /dev/null +++ b/gateway/workpool.go @@ -0,0 +1,17 @@ +package gateway + +import ( + "context" + "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/common/config" + "github.com/panjf2000/ants" +) + +var wPool *ants.Pool + +func initWorkPoll() { + var err error + if wPool, err = ants.NewPool(config.GetGatewayWorkerPoolNum()); err != nil { + logger.CtxErrorf(context.Background(), "InitWorkPool.err: %s num:%d\n", err.Error(), config.GetGatewayWorkerPoolNum()) + } +} diff --git a/go.mod b/go.mod index 516d44c..7b039fe 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b github.com/cloudwego/hertz v0.7.0 github.com/gookit/color v1.5.1 + github.com/panjf2000/ants v1.2.1 github.com/rocket049/gocui v0.3.2 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.16.0 @@ -75,7 +76,7 @@ require ( go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.11.0 // indirect + golang.org/x/sys v0.11.0 golang.org/x/text v0.11.0 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect diff --git a/go.sum b/go.sum index f635ffe..f856e66 100644 --- a/go.sum +++ b/go.sum @@ -215,6 +215,8 @@ github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpo github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/panjf2000/ants v1.2.1 h1:IlhLREssFi+YFOITnHdH3FHhulY6WDS0OB9e7+3fMHk= +github.com/panjf2000/ants v1.2.1/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/ipconf/domain/dispatcher.go b/ipconf/domain/dispatcher.go index 6836abf..454974a 100644 --- a/ipconf/domain/dispatcher.go +++ b/ipconf/domain/dispatcher.go @@ -75,10 +75,10 @@ func (d *Dispatcher) AddNode(event *source.Event) { ) if ed, ok = d.candidatePool[event.Key()]; !ok { // not exist, then create EndPort ed = NewEndport(event.IP, event.Port) + dp.candidatePool[event.Key()] = ed } ed.UpdateStat(&Stat{ ConnectNum: event.ConnectNum, MessageBytes: event.MessageBytes, }) - dp.candidatePool[event.Key()] = ed } diff --git a/plato.yaml b/plato.yaml index 52599ac..4813865 100644 --- a/plato.yaml +++ b/plato.yaml @@ -5,4 +5,21 @@ discovery: - localhost:2379 timeout: 5 ip_conf: - service_path: /plato/ip_dispatcher \ No newline at end of file + service_path: /plato/ip_dispatcher +prpc: + discov: + name: etcd + endpoints: + - localhost:2379 + trace: + enable: true + url: http://127.0.0.1:14268/api/traces + service_name: plato + sampler: 1.0 +gateway: + tcp_max_num: 10000 + epoll_channel_num: 100 + epoll_num: 8 + epoll_wait_queue_size: 100 + server_port: 8900 + worker_pool_num: 1024 \ No newline at end of file From c81d6d1ca62fde4d055808315b80de844141560b Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Fri, 6 Oct 2023 21:38:15 +0800 Subject: [PATCH 05/26] improve gateway epoll server --- chat.log | 3 ++ client/cui.go | 2 +- client/sdk/logic.go | 1 - cmd/perf.go | 20 ++++++++ {client => common}/sdk/api.go | 0 common/sdk/logic.go | 1 + {client => common}/sdk/net.go | 0 gateway/connection.go | 18 +++++++ gateway/epoll.go | 90 ++++++++++++++++++----------------- gateway/server.go | 12 +++-- perf/perf.go | 17 +++++++ 11 files changed, 116 insertions(+), 48 deletions(-) delete mode 100644 client/sdk/logic.go create mode 100644 cmd/perf.go rename {client => common}/sdk/api.go (100%) create mode 100644 common/sdk/logic.go rename {client => common}/sdk/net.go (100%) create mode 100644 gateway/connection.go create mode 100644 perf/perf.go diff --git a/chat.log b/chat.log index e69de29..407e992 100644 --- a/chat.log +++ b/chat.log @@ -0,0 +1,3 @@ +me: 1111 +logic: 1111 + diff --git a/client/cui.go b/client/cui.go index 627f67a..abe663c 100644 --- a/client/cui.go +++ b/client/cui.go @@ -2,6 +2,7 @@ package client import ( "fmt" + "github.com/hardcore-os/plato/common/sdk" "io/ioutil" "log" "math/rand" @@ -9,7 +10,6 @@ import ( "time" "github.com/gookit/color" - "github.com/hardcore-os/plato/client/sdk" "github.com/rocket049/gocui" ) diff --git a/client/sdk/logic.go b/client/sdk/logic.go deleted file mode 100644 index ab63730..0000000 --- a/client/sdk/logic.go +++ /dev/null @@ -1 +0,0 @@ -package sdk \ No newline at end of file diff --git a/cmd/perf.go b/cmd/perf.go new file mode 100644 index 0000000..0ea5f08 --- /dev/null +++ b/cmd/perf.go @@ -0,0 +1,20 @@ +package cmd + +import ( + "github.com/hardcore-os/plato/perf" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(perfCmd) + perfCmd.PersistentFlags().Int32Var(&perf.TcpConnNum, "tcp_conn_num", 10000, "tcp 连接的数量,默认10000") +} + +var perfCmd = &cobra.Command{ + Use: "perf", + Run: PerfHandle, +} + +func PerfHandle(cmd *cobra.Command, args []string) { + perf.RunMain() +} diff --git a/client/sdk/api.go b/common/sdk/api.go similarity index 100% rename from client/sdk/api.go rename to common/sdk/api.go diff --git a/common/sdk/logic.go b/common/sdk/logic.go new file mode 100644 index 0000000..0919fd1 --- /dev/null +++ b/common/sdk/logic.go @@ -0,0 +1 @@ +package sdk diff --git a/client/sdk/net.go b/common/sdk/net.go similarity index 100% rename from client/sdk/net.go rename to common/sdk/net.go diff --git a/gateway/connection.go b/gateway/connection.go new file mode 100644 index 0000000..2dee560 --- /dev/null +++ b/gateway/connection.go @@ -0,0 +1,18 @@ +package gateway + +import ( + "net" +) + +type connection struct { + fd int + conn *net.TCPConn +} + +func (c *connection) Close() error { + return c.conn.Close() +} + +func (c *connection) RemoteAddr() string { + return c.conn.RemoteAddr().String() +} diff --git a/gateway/epoll.go b/gateway/epoll.go index 6c61391..4303786 100644 --- a/gateway/epoll.go +++ b/gateway/epoll.go @@ -22,38 +22,40 @@ var ( ) type ePool struct { - eChan chan *net.TCPConn - eSize int - done chan struct{} + eChan chan *connection + tables sync.Map + eSize int + done chan struct{} ln *net.TCPListener - f func(conn *net.TCPConn, ep *epoller) // callback func + f func(conn *connection, ep *epoller) // callback func } -func InitEpoll(ln *net.TCPListener, f func(conn *net.TCPConn, ep *epoller)) { +func InitEpoll(ln *net.TCPListener, f func(conn *connection, ep *epoller)) { setLimit() ep = NewEpoll(ln, f) ep.createAcceptProcess() ep.startEPoll() } -func NewEpoll(ln *net.TCPListener, callback func(conn *net.TCPConn, ep *epoller)) *ePool { +func NewEpoll(ln *net.TCPListener, callback func(conn *connection, ep *epoller)) *ePool { return &ePool{ - eChan: make(chan *net.TCPConn, config.GetGatewayEpollerChanNum()), - done: make(chan struct{}), - eSize: config.GetGatewayEpollerNum(), - ln: ln, - f: callback, + eChan: make(chan *connection, config.GetGatewayEpollerChanNum()), + done: make(chan struct{}), + eSize: config.GetGatewayEpollerNum(), + tables: sync.Map{}, + ln: ln, + f: callback, } } // createAcceptProcess 创建一个专门处理 accept 事件的协程,与当前cpu的核数对应,能够发挥最大功效 -func (ep *ePool) createAcceptProcess() { +func (e *ePool) createAcceptProcess() { for i := 0; i < runtime.NumCPU(); i++ { go func() { ctx := context.Background() for { - conn, err := ep.ln.AcceptTCP() + conn, err := e.ln.AcceptTCP() // 限流熔断 if !checkTcp() { _ = conn.Close() @@ -67,21 +69,25 @@ func (ep *ePool) createAcceptProcess() { } fmt.Errorf("accept error: %v", err) } - ep.addTask(conn) + c := &connection{ + conn: conn, + fd: socketFD(conn), + } + ep.addTask(c) } }() } } -func (ep *ePool) startEPoll() { - for i := 0; i < ep.eSize; i++ { - go ep.startEProc(i) +func (e *ePool) startEPoll() { + for i := 0; i < e.eSize; i++ { + go e.startEProc(i) } } // startEProc 轮询器池 处理器 // epoll 的监听和处理逻辑 -func (ep *ePool) startEProc(id int) { +func (e *ePool) startEProc(id int) { epl, err := NewEpoller(id) if err != nil { panic(err) @@ -91,17 +97,17 @@ func (ep *ePool) startEProc(id int) { go func() { for { select { - case <-ep.done: + case <-e.done: return - case conn := <-ep.eChan: + case conn := <-e.eChan: // supply logs in below method addTcpNum() if addConnErr := epl.add(conn); addConnErr != nil { - logger.CtxErrorf(ctx, "epoll_%d failed to add connection %v\n", id, err) + logger.CtxErrorf(ctx, "epoll_%d failed to add connection %v\n", id, addConnErr) _ = conn.Close() continue } - logger.CtxInfof(ctx, "EpollerPool new connection[%v], epoll_%d, tcpSize:%d", (conn).RemoteAddr().String(), id, tcpNum) + logger.CtxInfof(ctx, "EpollerPool new connection[%v], epoll_%d, tcpSize:%d", conn.RemoteAddr(), id, tcpNum) } } }() @@ -109,10 +115,10 @@ func (ep *ePool) startEProc(id int) { // wait for events for { select { - case <-ep.done: + case <-e.done: return default: - connections, waitErr := epl.Wait(200) // 200ms 一次轮询避免 忙轮询 + connections, waitErr := epl.wait(200) // 200ms 一次轮询避免 忙轮询 if waitErr != nil && waitErr != syscall.EINTR { logger.CtxErrorf(ctx, "failed to epoll_%d wait %v\n", id, waitErr) continue @@ -122,21 +128,20 @@ func (ep *ePool) startEProc(id int) { if conn == nil { break } - ep.f(conn, epl) + e.f(conn, epl) } } } } -func (ep *ePool) addTask(conn *net.TCPConn) { - ep.eChan <- conn +func (e *ePool) addTask(conn *connection) { + e.eChan <- conn } // epoller 对象 轮询器 type epoller struct { - connections sync.Map - fd int - id int // id of epoll + fd int + id int // id of epoll } func NewEpoller(id int) (*epoller, error) { @@ -145,45 +150,44 @@ func NewEpoller(id int) (*epoller, error) { return nil, err } return &epoller{ - connections: sync.Map{}, - fd: fd, - id: id, + fd: fd, + id: id, }, nil } -func (epl *epoller) add(conn *net.TCPConn) error { - fd := socketFD(conn) +func (epl *epoller) add(conn *connection) error { + fd := conn.fd // the fd of epl is the epoll fd // the fd of conn is the connection fd err := unix.EpollCtl(epl.fd, syscall.EPOLL_CTL_ADD, fd, &unix.EpollEvent{Events: unix.EPOLLIN | unix.EPOLLHUP, Fd: int32(fd)}) if err != nil { return err } - epl.connections.Store(fd, conn) + ep.tables.Store(fd, conn) return nil } -func (epl *epoller) remove(conn *net.TCPConn) error { +func (epl *epoller) remove(conn *connection) error { subTcpNum() - fd := socketFD(conn) + fd := conn.fd err := unix.EpollCtl(epl.fd, syscall.EPOLL_CTL_DEL, fd, nil) if err != nil { return err } - epl.connections.Delete(fd) + ep.tables.Delete(fd) return nil } -func (epl *epoller) Wait(millSec int) ([]*net.TCPConn, error) { +func (epl *epoller) wait(millSec int) ([]*connection, error) { events := make([]unix.EpollEvent, config.GetGatewayEpollWaitQueueSize()) n, err := unix.EpollWait(epl.fd, events, millSec) if err != nil { return nil, err } - var connections []*net.TCPConn + var connections []*connection for i := 0; i < n; i++ { - if conn, ok := epl.connections.Load(int(events[i].Fd)); ok { - connections = append(connections, conn.(*net.TCPConn)) + if conn, ok := ep.tables.Load(int(events[i].Fd)); ok { + connections = append(connections, conn.(*connection)) } } return connections, nil diff --git a/gateway/server.go b/gateway/server.go index 45832e4..c8aef0e 100644 --- a/gateway/server.go +++ b/gateway/server.go @@ -2,9 +2,11 @@ package gateway import ( "context" + "errors" "github.com/bytedance/gopkg/util/logger" "github.com/hardcore-os/plato/common/config" "github.com/hardcore-os/plato/common/tcp" + "io" "net" ) @@ -21,10 +23,14 @@ func RunMain(path string) { select {} } -func runProc(conn *net.TCPConn, ep *epoller) { +func runProc(c *connection, ep *epoller) { // step1: 读取一个完整的消息包 - dataBuf, err := tcp.ReadData(conn) + dataBuf, err := tcp.ReadData(c.conn) if err != nil { + if errors.Is(err, io.EOF) { + logger.CtxInfof(context.Background(), "connection[%v] closed", c.RemoteAddr()) + ep.remove(c) + } return } err = wPool.Submit(func() { @@ -33,7 +39,7 @@ func runProc(conn *net.TCPConn, ep *epoller) { Len: uint32(len(dataBuf)), Data: dataBuf, } - tcp.SendData(conn, bytes.Marshal()) + tcp.SendData(c.conn, bytes.Marshal()) }) if err != nil { diff --git a/perf/perf.go b/perf/perf.go new file mode 100644 index 0000000..b1e9038 --- /dev/null +++ b/perf/perf.go @@ -0,0 +1,17 @@ +package perf + +import ( + "github.com/hardcore-os/plato/common/sdk" + "net" +) + +var ( + TcpConnNum int32 +) + +func RunMain() { + for i := 0; i < int(TcpConnNum); i++ { + sdk.NewChat(net.ParseIP("127.0.0.1"), 8900, "logic", "1223", "123") + } + select {} +} From 32cb76495289f78d2790bf9a97ce4e6902829d33 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sat, 21 Oct 2023 14:30:13 +0800 Subject: [PATCH 06/26] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Detcd=20watch?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E6=BC=8F=E6=95=B0=E6=8D=AE=E9=97=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/discovery/discovery.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/discovery/discovery.go b/common/discovery/discovery.go index 9dcc174..47d0092 100644 --- a/common/discovery/discovery.go +++ b/common/discovery/discovery.go @@ -43,12 +43,12 @@ func (s *ServiceDiscovery) WatchService(prefix string, set, del func(key, value set(string(kv.Key), string(kv.Value)) } // 监视前缀,修改变更的server - s.watcher(prefix, set, del) + s.watcher(prefix, resp.Header.Revision+1, set, del) return nil } -func (s *ServiceDiscovery) watcher(prefix string, set, del func(key, value string)) { - rch := s.cli.Watch(*s.ctx, prefix, clientv3.WithPrefix()) +func (s *ServiceDiscovery) watcher(prefix string, rev int64, set, del func(key, value string)) { + rch := s.cli.Watch(*s.ctx, prefix, clientv3.WithPrefix(), clientv3.WithRev(rev)) logger.CtxInfof(*s.ctx, "watching prefix:%s now...", prefix) for wresp := range rch { for _, ev := range wresp.Events { From 3a664b55e8a7af79b3bea9ba6966c412afe96e14 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sat, 21 Oct 2023 23:20:53 +0800 Subject: [PATCH 07/26] fix: add prpc client and prpc server --- common/prpc/client.go | 78 ++++ common/prpc/client_test.go | 19 + common/prpc/code/code.go | 10 + common/prpc/config/config.go | 33 ++ common/prpc/discov/discovery.go | 18 + common/prpc/discov/etcd/etcd_register.go | 358 ++++++++++++++++++ common/prpc/discov/etcd/etcd_register_test.go | 39 ++ common/prpc/discov/etcd/option.go | 57 +++ common/prpc/discov/plugin/plugin.go | 18 + common/prpc/discov/service.go | 14 + common/prpc/example/client/main.go | 46 +++ common/prpc/example/client/prpc_client.yaml | 19 + .../example/helloservice/helloworld.pb.go | 199 ++++++++++ .../example/helloservice/helloworld.proto | 22 ++ common/prpc/example/helloservice/service.go | 18 + common/prpc/example/server/main.go | 48 +++ common/prpc/example/server/prpc_server.yaml | 19 + .../interceptor/client/breaker_interceptor.go | 43 +++ .../interceptor/client/metric_interceptor.go | 50 +++ .../client/metric_interceptor_test.go | 26 ++ .../interceptor/client/timeout_interceptor.go | 38 ++ .../client/timeout_interceptor_test.go | 33 ++ .../interceptor/client/trace_interceptor.go | 47 +++ .../client/trace_interceptor_test.go | 30 ++ .../interceptor/server/metric_interceptor.go | 50 +++ .../server/ratelimit_interceptor.go | 41 ++ .../server/ratelimit_interceptor_test.go | 59 +++ .../server/recovery_interceptor.go | 25 ++ .../server/recovery_interceptor_test.go | 17 + .../interceptor/server/trace_interceptor.go | 46 +++ .../server/trace_interceptor_test.go | 30 ++ common/prpc/prome/agent.go | 26 ++ common/prpc/prome/prom.go | 21 + common/prpc/resolver/discov_builder.go | 62 +++ common/prpc/resolver/discov_builder_test.go | 1 + common/prpc/resolver/resolver.go | 5 + common/prpc/server.go | 177 +++++++++ common/prpc/server_test.go | 31 ++ common/prpc/trace/agent.go | 51 +++ common/prpc/trace/attr.go | 42 ++ common/prpc/trace/trace.go | 56 +++ common/prpc/trace/util.go | 70 ++++ common/prpc/util/ip.go | 56 +++ go.mod | 28 +- go.sum | 43 ++- 45 files changed, 2206 insertions(+), 13 deletions(-) create mode 100644 common/prpc/client.go create mode 100644 common/prpc/client_test.go create mode 100644 common/prpc/code/code.go create mode 100644 common/prpc/config/config.go create mode 100644 common/prpc/discov/discovery.go create mode 100644 common/prpc/discov/etcd/etcd_register.go create mode 100644 common/prpc/discov/etcd/etcd_register_test.go create mode 100644 common/prpc/discov/etcd/option.go create mode 100644 common/prpc/discov/plugin/plugin.go create mode 100644 common/prpc/discov/service.go create mode 100644 common/prpc/example/client/main.go create mode 100644 common/prpc/example/client/prpc_client.yaml create mode 100644 common/prpc/example/helloservice/helloworld.pb.go create mode 100644 common/prpc/example/helloservice/helloworld.proto create mode 100644 common/prpc/example/helloservice/service.go create mode 100644 common/prpc/example/server/main.go create mode 100644 common/prpc/example/server/prpc_server.yaml create mode 100644 common/prpc/interceptor/client/breaker_interceptor.go create mode 100644 common/prpc/interceptor/client/metric_interceptor.go create mode 100644 common/prpc/interceptor/client/metric_interceptor_test.go create mode 100644 common/prpc/interceptor/client/timeout_interceptor.go create mode 100644 common/prpc/interceptor/client/timeout_interceptor_test.go create mode 100644 common/prpc/interceptor/client/trace_interceptor.go create mode 100644 common/prpc/interceptor/client/trace_interceptor_test.go create mode 100644 common/prpc/interceptor/server/metric_interceptor.go create mode 100644 common/prpc/interceptor/server/ratelimit_interceptor.go create mode 100644 common/prpc/interceptor/server/ratelimit_interceptor_test.go create mode 100644 common/prpc/interceptor/server/recovery_interceptor.go create mode 100644 common/prpc/interceptor/server/recovery_interceptor_test.go create mode 100644 common/prpc/interceptor/server/trace_interceptor.go create mode 100644 common/prpc/interceptor/server/trace_interceptor_test.go create mode 100644 common/prpc/prome/agent.go create mode 100644 common/prpc/prome/prom.go create mode 100644 common/prpc/resolver/discov_builder.go create mode 100644 common/prpc/resolver/discov_builder_test.go create mode 100644 common/prpc/resolver/resolver.go create mode 100644 common/prpc/server.go create mode 100644 common/prpc/server_test.go create mode 100644 common/prpc/trace/agent.go create mode 100644 common/prpc/trace/attr.go create mode 100644 common/prpc/trace/trace.go create mode 100644 common/prpc/trace/util.go create mode 100644 common/prpc/util/ip.go diff --git a/common/prpc/client.go b/common/prpc/client.go new file mode 100644 index 0000000..a4185c0 --- /dev/null +++ b/common/prpc/client.go @@ -0,0 +1,78 @@ +package prpc + +import ( + "context" + "fmt" + "time" + + "github.com/hardcore-os/plato/common/prpc/discov/plugin" + + "google.golang.org/grpc/resolver" + + "github.com/hardcore-os/plato/common/prpc/discov" + clientinterceptor "github.com/hardcore-os/plato/common/prpc/interceptor/client" + presolver "github.com/hardcore-os/plato/common/prpc/resolver" + "google.golang.org/grpc" + "google.golang.org/grpc/balancer/roundrobin" +) + +const ( + dialTimeout = 5 * time.Second +) + +type PClient struct { + serviceName string + d discov.Discovery + interceptors []grpc.UnaryClientInterceptor + conn *grpc.ClientConn +} + +// NewPClient ... +func NewPClient(serviceName string, interceptors ...grpc.UnaryClientInterceptor) (*PClient, error) { + p := &PClient{ + serviceName: serviceName, + interceptors: interceptors, + } + + if p.d == nil { + dis, err := plugin.GetDiscovInstance() + if err != nil { + panic(err) + } + + p.d = dis + } + + resolver.Register(presolver.NewDiscovBuilder(p.d)) + + conn, err := p.dial() + p.conn = conn + + return p, err +} + +// Conn return *grpc.ClientConn +func (p *PClient) Conn() *grpc.ClientConn { + return p.conn +} + +func (p *PClient) dial() (*grpc.ClientConn, error) { + svcCfg := fmt.Sprintf(`{"loadBalancingPolicy":"%s"}`, roundrobin.Name) + balancerOpt := grpc.WithDefaultServiceConfig(svcCfg) + + interceptors := []grpc.UnaryClientInterceptor{ + clientinterceptor.TraceUnaryClientInterceptor(), + clientinterceptor.MetricUnaryClientInterceptor(), + } + interceptors = append(interceptors, p.interceptors...) + + options := []grpc.DialOption{ + balancerOpt, + grpc.WithChainUnaryInterceptor(interceptors...), + grpc.WithInsecure(), + } + + ctx, _ := context.WithTimeout(context.Background(), dialTimeout) + + return grpc.DialContext(ctx, fmt.Sprintf("discov:///%v", p.serviceName), options...) +} diff --git a/common/prpc/client_test.go b/common/prpc/client_test.go new file mode 100644 index 0000000..8300cd0 --- /dev/null +++ b/common/prpc/client_test.go @@ -0,0 +1,19 @@ +package prpc + +import ( + "testing" + + "github.com/hardcore-os/plato/common/config" + + ptrace "github.com/hardcore-os/plato/common/prpc/trace" + "github.com/stretchr/testify/assert" +) + +func TestNewPClient(t *testing.T) { + config.Init("../../plato.yaml") + ptrace.StartAgent() + defer ptrace.StopAgent() + + _, err := NewPClient("plato_server") + assert.NoError(t, err) +} diff --git a/common/prpc/code/code.go b/common/prpc/code/code.go new file mode 100644 index 0000000..4af05ee --- /dev/null +++ b/common/prpc/code/code.go @@ -0,0 +1,10 @@ +package code + +import "google.golang.org/grpc/codes" + +const ( + // CodeTooManyRequest ... + CodeTooManyRequest codes.Code = 100 + // CodeCircuitBreak ... + CodeCircuitBreak codes.Code = 101 +) diff --git a/common/prpc/config/config.go b/common/prpc/config/config.go new file mode 100644 index 0000000..086a0f3 --- /dev/null +++ b/common/prpc/config/config.go @@ -0,0 +1,33 @@ +package config + +import "github.com/spf13/viper" + +// GetDiscovName 获取discov用哪种方式实现 +func GetDiscovName() string { + return viper.GetString("prpc.discov.name") +} + +// GetDiscovEndpoints 获取discov的 endpoints +func GetDiscovEndpoints() []string { + return viper.GetStringSlice("discovery.endpoints") +} + +// GetTraceEnable 是否开启trace +func GetTraceEnable() bool { + return viper.GetBool("prpc.trace.enable") +} + +// GetTraceCollectionUrl 获取trace collection url +func GetTraceCollectionUrl() string { + return viper.GetString("prpc.trace.url") +} + +// GetTraceServiceName 获取服务名 +func GetTraceServiceName() string { + return viper.GetString("prpc.trace.service_name") +} + +// GetTraceSampler 获取trace采样率 +func GetTraceSampler() float64 { + return viper.GetFloat64("prpc.trace.sampler") +} diff --git a/common/prpc/discov/discovery.go b/common/prpc/discov/discovery.go new file mode 100644 index 0000000..6fde519 --- /dev/null +++ b/common/prpc/discov/discovery.go @@ -0,0 +1,18 @@ +package discov + +import "context" + +type Discovery interface { + // Name 服务发现名字 eg: etcd zk consul + Name() string + // Register 注册服务 + Register(ctx context.Context, service *Service) + // UnRegister 取消注册服务 + UnRegister(ctx context.Context, service *Service) + // GetService 获取服务节点信息 + GetService(ctx context.Context, name string) *Service + // AddListener 增加监听者 + AddListener(ctx context.Context, f func()) + // NotifyListeners 通知所有的监听者 + NotifyListeners() +} diff --git a/common/prpc/discov/etcd/etcd_register.go b/common/prpc/discov/etcd/etcd_register.go new file mode 100644 index 0000000..3acf70b --- /dev/null +++ b/common/prpc/discov/etcd/etcd_register.go @@ -0,0 +1,358 @@ +package etcd + +import ( + "context" + "encoding/json" + "fmt" + "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/common/prpc/discov" + "go.etcd.io/etcd/clientv3" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" +) + +const ( + KeyPrefix = "/plato/prpc" +) + +type Register struct { + Options + cli *clientv3.Client + serviceRegisterCh chan *discov.Service + serviceUnRegisterCh chan *discov.Service + lock sync.Mutex + downServices atomic.Value + registerServices map[string]*registerService + listeners []func() +} + +type registerService struct { + service *discov.Service + leaseID clientv3.LeaseID + isRegistered bool + keepAliveChan <-chan *clientv3.LeaseKeepAliveResponse +} + +func NewETCDRegister(opts ...Option) (discov.Discovery, error) { + opt := defaultOption + for _, o := range opts { + o(&opt) + } + + r := &Register{ + Options: opt, + serviceRegisterCh: make(chan *discov.Service), + serviceUnRegisterCh: make(chan *discov.Service), + lock: sync.Mutex{}, + downServices: atomic.Value{}, + registerServices: make(map[string]*registerService), + } + + if err := r.init(context.TODO()); err != nil { + return nil, err + } + + return r, nil +} + +func (r *Register) init(ctx context.Context) error { + var err error + r.cli, err = clientv3.New( + clientv3.Config{ + Endpoints: r.endpoints, + DialTimeout: r.dialTimeout, + }) + + if err != nil { + return err + } + + go r.run() + return nil +} + +func (r *Register) run() { + for { + select { + case service := <-r.serviceRegisterCh: + if _, ok := r.registerServices[service.Name]; ok { + r.registerServices[service.Name].service.Endpoints = append(r.registerServices[service.Name].service.Endpoints, service.Endpoints...) + r.registerServices[service.Name].isRegistered = false // 重新上报到etcd + } else { + r.registerServices[service.Name] = ®isterService{ + service: service, + isRegistered: false, + } + } + case service := <-r.serviceUnRegisterCh: + if _, ok := r.registerServices[service.Name]; !ok { + logger.CtxErrorf(context.TODO(), "UnRegisterService err, service %v was not registered", service.Name) + continue + } + r.unRegisterService(context.TODO(), service) + default: + r.registerServiceOrKeepAlive(context.TODO()) + time.Sleep(r.registerServiceOrKeepAliveInterval) + } + } +} + +func (r *Register) registerServiceOrKeepAlive(ctx context.Context) { + for _, service := range r.registerServices { + if !service.isRegistered { + r.registerService(ctx, service) + r.registerServices[service.service.Name].isRegistered = true + } else { + r.KeepAlive(ctx, service) + } + } +} + +func (r *Register) registerService(ctx context.Context, service *registerService) { + leaseGrantResp, err := r.cli.Grant(ctx, r.keepAliveInterval) + if err != nil { + logger.CtxErrorf(ctx, "register service grant, err:%v", err) + return + } + service.leaseID = leaseGrantResp.ID + + for _, endpoint := range service.service.Endpoints { + key := r.getEtcdRegisterKey(service.service.Name, endpoint.IP, endpoint.Port) + raw, err := json.Marshal(endpoint) + if err != nil { + logger.CtxErrorf(ctx, "register service err, err:%v, register data:%v", err, string(raw)) + continue + } + + _, err = r.cli.Put(ctx, key, string(raw), clientv3.WithLease(leaseGrantResp.ID)) + if err != nil { + logger.CtxErrorf(ctx, "register service err, err:%v, register data:%v", err, string(raw)) + continue + } + } + + keepAliveChan, err := r.cli.KeepAlive(ctx, leaseGrantResp.ID) + if err != nil { + logger.CtxErrorf(ctx, "register service keepalive err:%v", err) + return + } + + service.keepAliveChan = keepAliveChan + service.isRegistered = true +} + +func (r *Register) unRegisterService(ctx context.Context, service *discov.Service) { + endpoints := make([]*discov.Endpoint, 0) + for _, endpoint := range r.registerServices[service.Name].service.Endpoints { + var isRemove bool + for _, unRegisterEndpoint := range service.Endpoints { + if endpoint.IP == unRegisterEndpoint.IP && endpoint.Port == unRegisterEndpoint.Port { + _, err := r.cli.Delete(context.TODO(), r.getEtcdRegisterKey(service.Name, endpoint.IP, endpoint.Port)) + if err != nil { + logger.CtxErrorf(ctx, "UnRegisterService etcd del err, service %v was not registered", service.Name) + } + isRemove = true + break + } + } + + if !isRemove { + endpoints = append(endpoints, endpoint) + } + } + + if len(endpoints) == 0 { + delete(r.registerServices, service.Name) + } else { + // del service endpoints fail, put endpoints into map + r.registerServices[service.Name].service.Endpoints = endpoints + } +} + +func (r *Register) KeepAlive(ctx context.Context, service *registerService) { + for { + select { + case <-service.keepAliveChan: + default: + return + } + } +} + +func (r *Register) Name() string { + return "etcd" +} + +func (r *Register) AddListener(ctx context.Context, f func()) { + r.listeners = append(r.listeners, f) +} + +func (r *Register) NotifyListeners() { + for _, listener := range r.listeners { + listener() + } +} + +func (r *Register) Register(ctx context.Context, service *discov.Service) { + r.serviceRegisterCh <- service +} + +func (r *Register) UnRegister(ctx context.Context, service *discov.Service) { + r.serviceUnRegisterCh <- service +} + +func (r *Register) GetService(ctx context.Context, name string) *discov.Service { + allServices := r.getDownServices() + if val, ok := allServices[name]; ok { + return val + } + + // 防止并发获取service导致cache中的数据混乱 + r.lock.Lock() + defer r.lock.Unlock() + + key := r.getEtcdRegisterPrefixKey(name) + getResp, _ := r.cli.Get(ctx, key, clientv3.WithPrefix()) + service := &discov.Service{ + Name: name, + Endpoints: make([]*discov.Endpoint, 0), + } + + for _, item := range getResp.Kvs { + var endpoint discov.Endpoint + if err := json.Unmarshal(item.Value, &endpoint); err != nil { + continue + } + + service.Endpoints = append(service.Endpoints, &endpoint) + } + + allServices[name] = service + r.downServices.Store(allServices) + + go r.watch(ctx, key, getResp.Header.Revision+1) + return service +} + +func (r *Register) watch(ctx context.Context, key string, revision int64) { + rch := r.cli.Watch(ctx, key, clientv3.WithRev(revision), clientv3.WithPrefix()) + for n := range rch { + for _, ev := range n.Events { + switch ev.Type { + case clientv3.EventTypePut: + var endpoint discov.Endpoint + if err := json.Unmarshal(ev.Kv.Value, &endpoint); err != nil { + continue + } + serviceName, _, _ := r.getServiceNameByETCDKey(string(ev.Kv.Key)) + r.updateDownService(&discov.Service{ + Name: serviceName, + Endpoints: []*discov.Endpoint{&endpoint}, + }) + case clientv3.EventTypeDelete: + var endpoint discov.Endpoint + if err := json.Unmarshal(ev.Kv.Value, &endpoint); err != nil { + continue + } + serviceName, ip, port := r.getServiceNameByETCDKey(string(ev.Kv.Key)) + r.delDownService(&discov.Service{ + Name: serviceName, + Endpoints: []*discov.Endpoint{ + { + IP: ip, + Port: port, + }, + }, + }) + } + } + } +} + +func (r *Register) updateDownService(service *discov.Service) { + r.lock.Lock() + defer r.lock.Unlock() + + downService := r.downServices.Load().(map[string]*discov.Service) + if _, ok := downService[service.Name]; !ok { + downService[service.Name] = service + r.downServices.Store(downService) + return + } + + for _, newAddEndpoint := range service.Endpoints { + var isExist bool + for idx, endpoint := range downService[service.Name].Endpoints { + if newAddEndpoint.IP == endpoint.IP && newAddEndpoint.Port == endpoint.Port { + downService[service.Name].Endpoints[idx] = newAddEndpoint + isExist = true + break + } + } + + if !isExist { + downService[service.Name].Endpoints = append(downService[service.Name].Endpoints, newAddEndpoint) + } + } + + r.downServices.Store(downService) + r.NotifyListeners() +} + +func (r *Register) delDownService(service *discov.Service) { + r.lock.Lock() + defer r.lock.Unlock() + + downServices := r.downServices.Load().(map[string]*discov.Service) + if _, ok := downServices[service.Name]; !ok { + return + } + + endpoints := make([]*discov.Endpoint, 0) + for _, endpoint := range downServices[service.Name].Endpoints { + var isRemove bool + for _, delEndpoint := range service.Endpoints { + if delEndpoint.IP == endpoint.IP && delEndpoint.Port == endpoint.Port { + isRemove = true + break + } + } + + if !isRemove { + endpoints = append(endpoints, endpoint) + } + } + + downServices[service.Name].Endpoints = endpoints + r.downServices.Store(downServices) + + r.NotifyListeners() +} + +func (r *Register) getDownServices() map[string]*discov.Service { + allServices := r.downServices.Load() + if allServices == nil { + return make(map[string]*discov.Service, 0) + } + + return allServices.(map[string]*discov.Service) +} + +func (r *Register) getEtcdRegisterKey(name, ip string, port int) string { + return fmt.Sprintf(KeyPrefix+"%v/%v/%v", name, ip, port) +} + +func (r *Register) getEtcdRegisterPrefixKey(name string) string { + return fmt.Sprintf(KeyPrefix+"%v", name) +} + +func (r *Register) getServiceNameByETCDKey(key string) (string, string, int) { + trimStr := strings.TrimPrefix(key, KeyPrefix) + strs := strings.Split(trimStr, "/") + + ip, _ := strconv.Atoi(strs[2]) + return strs[0], strs[1], ip +} diff --git a/common/prpc/discov/etcd/etcd_register_test.go b/common/prpc/discov/etcd/etcd_register_test.go new file mode 100644 index 0000000..ddb4ca2 --- /dev/null +++ b/common/prpc/discov/etcd/etcd_register_test.go @@ -0,0 +1,39 @@ +package etcd + +import ( + "context" + "testing" + "time" + + "github.com/hardcore-os/plato/common/prpc/discov" + + "github.com/stretchr/testify/assert" +) + +func TestNewETCDRegister(t *testing.T) { + _, err := NewETCDRegister() + + assert.Nil(t, err) +} + +func TestRegister_Register(t *testing.T) { + register, _ := NewETCDRegister() + + service := &discov.Service{ + Name: "test", + Endpoints: []*discov.Endpoint{ + &discov.Endpoint{ + ServerName: "test", + IP: "127.0.0.1", + Port: 9557, + Weight: 100, + Enable: true, + }, + }, + } + register.Register(context.TODO(), service) + time.Sleep(2 * time.Second) + registerService := register.GetService(context.TODO(), "test") + + assert.Equal(t, *service.Endpoints[0], *registerService.Endpoints[0]) +} diff --git a/common/prpc/discov/etcd/option.go b/common/prpc/discov/etcd/option.go new file mode 100644 index 0000000..c030c40 --- /dev/null +++ b/common/prpc/discov/etcd/option.go @@ -0,0 +1,57 @@ +package etcd + +import "time" + +var ( + defaultOption = Options{ + endpoints: []string{"127.0.0.1:2379"}, + dialTimeout: 10 * time.Second, + syncFlushCacheInterval: 10 * time.Second, + keepAliveInterval: 10, + } +) + +type Options struct { + syncFlushCacheInterval time.Duration + endpoints []string + dialTimeout time.Duration + keepAliveInterval int64 + registerServiceOrKeepAliveInterval time.Duration +} + +type Option func(o *Options) + +// WithEndpoints ... +func WithEndpoints(endpoints []string) Option { + return func(o *Options) { + o.endpoints = endpoints + } +} + +// WithDialTimeout ... +func WithDialTimeout(dialTimeout time.Duration) Option { + return func(o *Options) { + o.dialTimeout = dialTimeout + } +} + +// WithSyncFlushCacheInterval ... +func WithSyncFlushCacheInterval(t time.Duration) Option { + return func(o *Options) { + o.syncFlushCacheInterval = t + } +} + +// WithKeepAliveInterval ... +func WithKeepAliveInterval(ttl int64) Option { + return func(o *Options) { + o.keepAliveInterval = ttl + } +} + +// WithRegisterServiceOrKeepAliveInterval ... +func WithRegisterServiceOrKeepAliveInterval(t time.Duration) Option { + return func(o *Options) { + o.registerServiceOrKeepAliveInterval = t + } +} diff --git a/common/prpc/discov/plugin/plugin.go b/common/prpc/discov/plugin/plugin.go new file mode 100644 index 0000000..a7bbd37 --- /dev/null +++ b/common/prpc/discov/plugin/plugin.go @@ -0,0 +1,18 @@ +package plugin + +import ( + "errors" + "fmt" + "github.com/hardcore-os/plato/common/prpc/config" + "github.com/hardcore-os/plato/common/prpc/discov" + "github.com/hardcore-os/plato/common/prpc/discov/etcd" +) + +func GetDiscovInstance() (discov.Discovery, error) { + name := config.GetDiscovName() + switch name { + case "etcd": + return etcd.NewETCDRegister(etcd.WithEndpoints(config.GetDiscovEndpoints())) + } + return nil, errors.New(fmt.Sprintf("not exist plugin:%v", name)) +} diff --git a/common/prpc/discov/service.go b/common/prpc/discov/service.go new file mode 100644 index 0000000..858c1df --- /dev/null +++ b/common/prpc/discov/service.go @@ -0,0 +1,14 @@ +package discov + +type Service struct { + Name string `json:"name"` + Endpoints []*Endpoint `json:"endpoints"` +} + +type Endpoint struct { + ServerName string `json:"server_name"` + IP string `json:"ip"` + Port int `json:"port"` + Weight int `json:"weight"` + Enable bool `json:"enable"` +} diff --git a/common/prpc/example/client/main.go b/common/prpc/example/client/main.go new file mode 100644 index 0000000..191a78f --- /dev/null +++ b/common/prpc/example/client/main.go @@ -0,0 +1,46 @@ +package main + +import ( + "context" + "fmt" + "runtime" + "strings" + "time" + + "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/prpc" + "github.com/hardcore-os/plato/common/prpc/example/helloservice" + ptrace "github.com/hardcore-os/plato/common/prpc/trace" +) + +func main() { + config.Init(currentFileDir() + "/prpc_client.yaml") + + ptrace.StartAgent() + defer ptrace.StopAgent() + + pCli, _ := prpc.NewPClient("prpc_server") + + ctx, _ := context.WithTimeout(context.TODO(), 100*time.Second) + cli := helloservice.NewGreeterClient(pCli.Conn()) + resp, err := cli.SayHello(ctx, &helloservice.HelloRequest{ + Name: "xxxxxx", + }) + fmt.Println(resp, err) +} + +func currentFileDir() string { + _, file, _, ok := runtime.Caller(1) + parts := strings.Split(file, "/") + + if !ok { + return "" + } + + dir := "" + for i := 0; i < len(parts)-1; i++ { + dir += "/" + parts[i] + } + + return dir[1:] +} diff --git a/common/prpc/example/client/prpc_client.yaml b/common/prpc/example/client/prpc_client.yaml new file mode 100644 index 0000000..8878ee5 --- /dev/null +++ b/common/prpc/example/client/prpc_client.yaml @@ -0,0 +1,19 @@ +global: + env: debug +discovery: + endpoints: + - localhost:2379 + timeout: 5 +ip_conf: + service_path: /plato/ip_dispatcher +prpc: + discov: + name: etcd + endpoints: + - localhost:2379 + trace: + enable: true + url: http://127.0.0.1:14268/api/traces + service_name: prpc_client + sampler: 1.0 + diff --git a/common/prpc/example/helloservice/helloworld.pb.go b/common/prpc/example/helloservice/helloworld.pb.go new file mode 100644 index 0000000..2a9cd5c --- /dev/null +++ b/common/prpc/example/helloservice/helloworld.pb.go @@ -0,0 +1,199 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: helloworld.proto + +package helloservice + +import ( + context "context" + fmt "fmt" + math "math" + + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// The request message containing the user's name. +type HelloRequest struct { + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HelloRequest) Reset() { *m = HelloRequest{} } +func (m *HelloRequest) String() string { return proto.CompactTextString(m) } +func (*HelloRequest) ProtoMessage() {} +func (*HelloRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_17b8c58d586b62f2, []int{0} +} + +func (m *HelloRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HelloRequest.Unmarshal(m, b) +} +func (m *HelloRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HelloRequest.Marshal(b, m, deterministic) +} +func (m *HelloRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_HelloRequest.Merge(m, src) +} +func (m *HelloRequest) XXX_Size() int { + return xxx_messageInfo_HelloRequest.Size(m) +} +func (m *HelloRequest) XXX_DiscardUnknown() { + xxx_messageInfo_HelloRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_HelloRequest proto.InternalMessageInfo + +func (m *HelloRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +// The response message containing the greetings +type HelloReply struct { + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *HelloReply) Reset() { *m = HelloReply{} } +func (m *HelloReply) String() string { return proto.CompactTextString(m) } +func (*HelloReply) ProtoMessage() {} +func (*HelloReply) Descriptor() ([]byte, []int) { + return fileDescriptor_17b8c58d586b62f2, []int{1} +} + +func (m *HelloReply) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_HelloReply.Unmarshal(m, b) +} +func (m *HelloReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_HelloReply.Marshal(b, m, deterministic) +} +func (m *HelloReply) XXX_Merge(src proto.Message) { + xxx_messageInfo_HelloReply.Merge(m, src) +} +func (m *HelloReply) XXX_Size() int { + return xxx_messageInfo_HelloReply.Size(m) +} +func (m *HelloReply) XXX_DiscardUnknown() { + xxx_messageInfo_HelloReply.DiscardUnknown(m) +} + +var xxx_messageInfo_HelloReply proto.InternalMessageInfo + +func (m *HelloReply) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func init() { + proto.RegisterType((*HelloRequest)(nil), "helloworld.HelloRequest") + proto.RegisterType((*HelloReply)(nil), "helloworld.HelloReply") +} + +func init() { proto.RegisterFile("helloworld.proto", fileDescriptor_17b8c58d586b62f2) } + +var fileDescriptor_17b8c58d586b62f2 = []byte{ + // 152 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xc8, 0x48, 0xcd, 0xc9, + 0xc9, 0x2f, 0xcf, 0x2f, 0xca, 0x49, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x88, + 0x28, 0x29, 0x71, 0xf1, 0x78, 0x80, 0x78, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42, + 0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x92, + 0x1a, 0x17, 0x17, 0x54, 0x4d, 0x41, 0x4e, 0xa5, 0x90, 0x04, 0x17, 0x7b, 0x6e, 0x6a, 0x71, 0x71, + 0x62, 0x3a, 0x4c, 0x11, 0x8c, 0x6b, 0xe4, 0xc9, 0xc5, 0xee, 0x5e, 0x94, 0x9a, 0x5a, 0x92, 0x5a, + 0x24, 0x64, 0xc7, 0xc5, 0x11, 0x9c, 0x58, 0x09, 0xd6, 0x25, 0x24, 0xa1, 0x87, 0xe4, 0x02, 0x64, + 0xcb, 0xa4, 0xc4, 0xb0, 0xc8, 0x14, 0xe4, 0x54, 0x2a, 0x31, 0x38, 0x71, 0x46, 0xb1, 0xeb, 0xe9, + 0x5b, 0x97, 0xa4, 0x16, 0x97, 0x24, 0xb1, 0x81, 0x1d, 0x6d, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, + 0x39, 0xe2, 0x94, 0x47, 0xc8, 0x00, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// GreeterClient is the client API for Greeter service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type GreeterClient interface { + // Sends a greeting + SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) +} + +type greeterClient struct { + cc *grpc.ClientConn +} + +func NewGreeterClient(cc *grpc.ClientConn) GreeterClient { + return &greeterClient{cc} +} + +func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := c.cc.Invoke(ctx, "/helloworld.Greeter/SayHello", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GreeterServer is the server API for Greeter service. +type GreeterServer interface { + // Sends a greeting + SayHello(context.Context, *HelloRequest) (*HelloReply, error) +} + +func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) { + s.RegisterService(&_Greeter_serviceDesc, srv) +} + +func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GreeterServer).SayHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/helloworld.Greeter/SayHello", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Greeter_serviceDesc = grpc.ServiceDesc{ + ServiceName: "helloworld.Greeter", + HandlerType: (*GreeterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayHello", + Handler: _Greeter_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "helloworld.proto", +} diff --git a/common/prpc/example/helloservice/helloworld.proto b/common/prpc/example/helloservice/helloworld.proto new file mode 100644 index 0000000..41b3b70 --- /dev/null +++ b/common/prpc/example/helloservice/helloworld.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +option go_package = "./;test"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) { + } +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/common/prpc/example/helloservice/service.go b/common/prpc/example/helloservice/service.go new file mode 100644 index 0000000..0e16a16 --- /dev/null +++ b/common/prpc/example/helloservice/service.go @@ -0,0 +1,18 @@ +package helloservice + +import ( + "context" +) + +type Service struct { +} + +type HelloServer struct { + service *Service +} + +func (s HelloServer) SayHello(ctx context.Context, re *HelloRequest) (*HelloReply, error) { + return &HelloReply{ + Message: "hello " + re.Name, + }, nil +} diff --git a/common/prpc/example/server/main.go b/common/prpc/example/server/main.go new file mode 100644 index 0000000..e682c25 --- /dev/null +++ b/common/prpc/example/server/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "context" + "runtime" + "strings" + + "github.com/hardcore-os/plato/common/config" + + "github.com/hardcore-os/plato/common/prpc" + "github.com/hardcore-os/plato/common/prpc/example/helloservice" + ptrace "github.com/hardcore-os/plato/common/prpc/trace" + "google.golang.org/grpc" +) + +const ( + testIp = "127.0.0.1" + testPort = 8867 +) + +func main() { + config.Init(currentFileDir() + "/prpc_server.yaml") + + ptrace.StartAgent() + defer ptrace.StopAgent() + + s := prpc.NewPServer(prpc.WithServiceName("prpc_server"), prpc.WithIP(testIp), prpc.WithPort(testPort), prpc.WithWeight(100)) + s.RegisterService(func(server *grpc.Server) { + helloservice.RegisterGreeterServer(server, helloservice.HelloServer{}) + }) + s.Start(context.TODO()) +} + +func currentFileDir() string { + _, file, _, ok := runtime.Caller(1) + parts := strings.Split(file, "/") + + if !ok { + return "" + } + + dir := "" + for i := 0; i < len(parts)-1; i++ { + dir += "/" + parts[i] + } + + return dir[1:] +} diff --git a/common/prpc/example/server/prpc_server.yaml b/common/prpc/example/server/prpc_server.yaml new file mode 100644 index 0000000..bdaef78 --- /dev/null +++ b/common/prpc/example/server/prpc_server.yaml @@ -0,0 +1,19 @@ +global: + env: debug +discovery: + endpoints: + - localhost:2379 + timeout: 5 +ip_conf: + service_path: /plato/ip_dispatcher +prpc: + discov: + name: etcd + endpoints: + - localhost:2379 + trace: + enable: true + url: http://127.0.0.1:14268/api/traces + service_name: prpc_server + sampler: 1.0 + diff --git a/common/prpc/interceptor/client/breaker_interceptor.go b/common/prpc/interceptor/client/breaker_interceptor.go new file mode 100644 index 0000000..2fa5124 --- /dev/null +++ b/common/prpc/interceptor/client/breaker_interceptor.go @@ -0,0 +1,43 @@ +package client + +import ( + "context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "time" + + "github.com/bytedance/gopkg/util/logger" + "github.com/sony/gobreaker" +) + +// BreakerUnaryClientInterceptor 熔断器,配置其实都可以考虑用option选项模式实现,等待有人缘人优化吧 +func BreakerUnaryClientInterceptor(name string, maxRequest uint32, interval, timeout time.Duration, readyToTrip func(counts gobreaker.Counts) bool) grpc.UnaryClientInterceptor { + var cb *gobreaker.CircuitBreaker + cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{ + Name: name, + MaxRequests: maxRequest, + Interval: interval, + ReadyToTrip: readyToTrip, + IsSuccessful: func(err error) bool { + switch status.Code(err) { + case codes.DeadlineExceeded, codes.Internal, codes.Unavailable, codes.DataLoss, codes.Unimplemented: + return false + default: + return true + } + }, + OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) { + logger.Errorf("name:%s,old state:%s,new state:%s", name, from, to) + }, + }) + + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + _, err := cb.Execute(func() (interface{}, error) { + err := invoker(ctx, method, req, reply, cc, opts...) + return nil, err + }) + + return err + } +} diff --git a/common/prpc/interceptor/client/metric_interceptor.go b/common/prpc/interceptor/client/metric_interceptor.go new file mode 100644 index 0000000..76df13a --- /dev/null +++ b/common/prpc/interceptor/client/metric_interceptor.go @@ -0,0 +1,50 @@ +package client + +import ( + "context" + + "github.com/prometheus/client_golang/prometheus" + + "time" + + "github.com/hardcore-os/plato/common/prpc/prome" + "github.com/hardcore-os/plato/common/prpc/util" + "google.golang.org/grpc" + "google.golang.org/grpc/status" +) + +const nameSpace = "prpc_client" + +var ( + clientHandleCounter = prome.NewCounterVec( + prometheus.CounterOpts{ + Namespace: nameSpace, + Subsystem: "req", + Name: "client_handle_total", + }, + []string{"method", "server", "code", "ip"}, + ) + + clientHandleHistogram = prome.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: nameSpace, + Subsystem: "req", + Name: "client_handle_seconds", + }, + []string{"method", "server", "ip"}, + ) +) + +// MetricUnaryClientInterceptor ... +func MetricUnaryClientInterceptor() grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + beg := time.Now() + err := invoker(ctx, method, req, reply, cc, opts...) + + code := status.Code(err) + clientHandleCounter.WithLabelValues(method, cc.Target(), code.String(), util.ExternalIP()).Inc() + clientHandleHistogram.WithLabelValues(method, cc.Target(), util.ExternalIP()).Observe(time.Since(beg).Seconds()) + + return err + } +} diff --git a/common/prpc/interceptor/client/metric_interceptor_test.go b/common/prpc/interceptor/client/metric_interceptor_test.go new file mode 100644 index 0000000..b3ddae7 --- /dev/null +++ b/common/prpc/interceptor/client/metric_interceptor_test.go @@ -0,0 +1,26 @@ +package client + +import ( + "context" + "testing" + "time" + + "google.golang.org/grpc" + + "github.com/hardcore-os/plato/common/prpc/prome" +) + +func TestMetricUnaryClientInterceptor(t *testing.T) { + prome.StartAgent("0.0.0.0", 8927) + + cc := new(grpc.ClientConn) + for { + MetricUnaryClientInterceptor()(context.TODO(), "/create", nil, nil, cc, + func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, + opts ...grpc.CallOption) error { + return nil + }) + time.Sleep(1 * time.Second) + } + +} diff --git a/common/prpc/interceptor/client/timeout_interceptor.go b/common/prpc/interceptor/client/timeout_interceptor.go new file mode 100644 index 0000000..b3bb793 --- /dev/null +++ b/common/prpc/interceptor/client/timeout_interceptor.go @@ -0,0 +1,38 @@ +package client + +import ( + "context" + "time" + + "github.com/bytedance/gopkg/util/logger" + "google.golang.org/grpc" + "google.golang.org/grpc/peer" +) + +// TimeoutUnaryClientInterceptor ... +func TimeoutUnaryClientInterceptor(timeout time.Duration, slowThreshold time.Duration) grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + now := time.Now() + // 若无自定义超时设置,默认设置超时 + _, ok := ctx.Deadline() + if !ok { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, timeout) + defer cancel() + } + var p peer.Peer + + err := invoker(ctx, method, req, reply, cc, append(opts, grpc.Peer(&p))...) + + du := time.Since(now) + remoteIP := "" + if p.Addr != nil { + remoteIP = p.Addr.String() + } + + if slowThreshold > time.Duration(0) && du > slowThreshold { + logger.CtxErrorf(ctx, "grpc slowlog:method%s,tagert:%s,cost:%v,remotIP:%s", method, cc.Target(), du, remoteIP) + } + return err + } +} diff --git a/common/prpc/interceptor/client/timeout_interceptor_test.go b/common/prpc/interceptor/client/timeout_interceptor_test.go new file mode 100644 index 0000000..6380eef --- /dev/null +++ b/common/prpc/interceptor/client/timeout_interceptor_test.go @@ -0,0 +1,33 @@ +package client + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "google.golang.org/grpc" +) + +func TestTimeoutUnaryClientInterceptor(t *testing.T) { + cc := new(grpc.ClientConn) + err := TimeoutUnaryClientInterceptor(3*time.Second, 3*time.Second)(context.TODO(), "/create", nil, nil, cc, + func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, + opts ...grpc.CallOption) error { + return nil + }, + ) + + assert.NoError(t, err) + + err = TimeoutUnaryClientInterceptor(3*time.Second, 3*time.Second)(context.TODO(), "/create", nil, nil, cc, + func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, + opts ...grpc.CallOption) error { + time.Sleep(4 * time.Second) + return nil + }, + ) + + assert.NoError(t, err) +} diff --git a/common/prpc/interceptor/client/trace_interceptor.go b/common/prpc/interceptor/client/trace_interceptor.go new file mode 100644 index 0000000..6e5d2a5 --- /dev/null +++ b/common/prpc/interceptor/client/trace_interceptor.go @@ -0,0 +1,47 @@ +package client + +import ( + "context" + + ptrace "github.com/hardcore-os/plato/common/prpc/trace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" + "google.golang.org/grpc" + gcodes "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// TraceUnaryClientInterceptor trace middleware +func TraceUnaryClientInterceptor() grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + md, ok := metadata.FromOutgoingContext(ctx) + if !ok { + md = metadata.MD{} + } + + tr := otel.GetTracerProvider().Tracer(ptrace.TraceName) + name, attrs := ptrace.BuildSpan(method, "") + ctx, span := tr.Start(ctx, name, trace.WithAttributes(attrs...), trace.WithSpanKind(trace.SpanKindClient)) + defer span.End() + + ptrace.Inject(ctx, otel.GetTextMapPropagator(), &md) + ctx = metadata.NewOutgoingContext(ctx, md) + + err := invoker(ctx, method, req, reply, cc, opts...) + if err != nil { + s, ok := status.FromError(err) + if ok { + span.SetStatus(codes.Error, s.Message()) + span.SetAttributes(ptrace.StatusCodeAttr(s.Code())) + } else { + span.SetStatus(codes.Error, err.Error()) + } + return err + } + + span.SetAttributes(ptrace.StatusCodeAttr(gcodes.OK)) + return nil + } +} diff --git a/common/prpc/interceptor/client/trace_interceptor_test.go b/common/prpc/interceptor/client/trace_interceptor_test.go new file mode 100644 index 0000000..08db601 --- /dev/null +++ b/common/prpc/interceptor/client/trace_interceptor_test.go @@ -0,0 +1,30 @@ +package client + +import ( + "context" + "testing" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + ptrace "github.com/hardcore-os/plato/common/prpc/trace" + "google.golang.org/grpc" +) + +func TestUnaryTraceInterceptor(t *testing.T) { + ptrace.StartAgent() + cc := new(grpc.ClientConn) + TraceUnaryClientInterceptor()(context.TODO(), "/create", nil, nil, cc, + func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, + opts ...grpc.CallOption) error { + return nil + }) + + TraceUnaryClientInterceptor()(context.TODO(), "/update", nil, nil, cc, + func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, + opts ...grpc.CallOption) error { + return status.Error(codes.DataLoss, "dummy") + }) + + defer ptrace.StopAgent() +} diff --git a/common/prpc/interceptor/server/metric_interceptor.go b/common/prpc/interceptor/server/metric_interceptor.go new file mode 100644 index 0000000..130a60c --- /dev/null +++ b/common/prpc/interceptor/server/metric_interceptor.go @@ -0,0 +1,50 @@ +package server + +import ( + "context" + "time" + + "github.com/prometheus/client_golang/prometheus" + + "github.com/hardcore-os/plato/common/prpc/prome" + + "github.com/hardcore-os/plato/common/prpc/util" + "google.golang.org/grpc" + "google.golang.org/grpc/status" +) + +const nameSpace = "prpc_server" + +var ( + serverHandleCounter = prome.NewCounterVec( + prometheus.CounterOpts{ + Namespace: nameSpace, + Subsystem: "req", + Name: "client_handle_total", + }, + []string{"method", "server", "code", "ip"}, + ) + + serverHandleHistogram = prome.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: nameSpace, + Subsystem: "req", + Name: "client_handle_seconds", + }, + []string{"method", "server", "ip"}, + ) +) + +// MetricUnaryServerInterceptor ... +func MetricUnaryServerInterceptor(serverName string) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + beg := time.Now() + resp, err = handler(ctx, req) + + code := status.Code(err) + serverHandleCounter.WithLabelValues(info.FullMethod, serverName, code.String(), util.ExternalIP()).Inc() + serverHandleHistogram.WithLabelValues(info.FullMethod, serverName, util.ExternalIP()).Observe(time.Since(beg).Seconds()) + + return + } +} diff --git a/common/prpc/interceptor/server/ratelimit_interceptor.go b/common/prpc/interceptor/server/ratelimit_interceptor.go new file mode 100644 index 0000000..58c0fb2 --- /dev/null +++ b/common/prpc/interceptor/server/ratelimit_interceptor.go @@ -0,0 +1,41 @@ +package server + +import ( + "context" + "time" + + "github.com/bytedance/gopkg/util/logger" + pcode "github.com/hardcore-os/plato/common/prpc/code" + "github.com/juju/ratelimit" + "google.golang.org/grpc" + "google.golang.org/grpc/status" +) + +type MethodName string + +type RateLimitConfig struct { + Cap int64 `json:"cap"` + Rate float64 `json:"rate"` + WaitMaxDuration time.Duration `json:"wait_max_duration"` +} + +// RateLimitUnaryServerInterceptor ... +func RateLimitUnaryServerInterceptor(configs map[MethodName]RateLimitConfig) grpc.UnaryServerInterceptor { + buckets := make(map[MethodName]*ratelimit.Bucket) + for name, config := range configs { + buckets[name] = ratelimit.NewBucketWithRate(config.Rate, config.Cap) + } + + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + if bucket, ok := buckets[MethodName(info.FullMethod)]; ok { + if _, ok := bucket.TakeMaxDuration(1, configs[MethodName(info.FullMethod)].WaitMaxDuration); !ok { + logger.CtxErrorf(ctx, "too many request") + return nil, status.Errorf(pcode.CodeTooManyRequest, "too many request") + } + + return handler(ctx, req) + } + + return handler(ctx, req) + } +} diff --git a/common/prpc/interceptor/server/ratelimit_interceptor_test.go b/common/prpc/interceptor/server/ratelimit_interceptor_test.go new file mode 100644 index 0000000..073d4c5 --- /dev/null +++ b/common/prpc/interceptor/server/ratelimit_interceptor_test.go @@ -0,0 +1,59 @@ +package server + +import ( + "context" + "testing" + + pcode "github.com/hardcore-os/plato/common/prpc/code" + "github.com/stretchr/testify/assert" + "google.golang.org/grpc" + "google.golang.org/grpc/status" +) + +func TestRateLimitUnaryServerInterceptor(t *testing.T) { + tests := []struct { + name string + config map[MethodName]RateLimitConfig + count int + res error + }{ + { + "suc", + map[MethodName]RateLimitConfig{ + "/helloworld.Greeter/SayHello": { + Cap: 3, + Rate: 1, + }, + }, + 1, + nil, + }, + { + "fail", + map[MethodName]RateLimitConfig{ + "/helloworld.Greeter/SayHello": { + Cap: 3, + Rate: 1, + }, + }, + 4, + status.Errorf(pcode.CodeTooManyRequest, "too many request"), + }, + } + + for _, item := range tests { + t.Run(item.name, func(t *testing.T) { + var err error + r := RateLimitUnaryServerInterceptor(item.config) + for i := 0; i < item.count; i++ { + _, err = r(context.Background(), nil, &grpc.UnaryServerInfo{ + FullMethod: "/helloworld.Greeter/SayHello", + }, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + } + + assert.Equal(t, item.res, err) + }) + } +} diff --git a/common/prpc/interceptor/server/recovery_interceptor.go b/common/prpc/interceptor/server/recovery_interceptor.go new file mode 100644 index 0000000..ce2f76c --- /dev/null +++ b/common/prpc/interceptor/server/recovery_interceptor.go @@ -0,0 +1,25 @@ +package server + +import ( + "context" + "runtime" + + "github.com/bytedance/gopkg/util/logger" + "google.golang.org/grpc" +) + +// RecoveryUnaryServerInterceptor recovery中间件最好放在第一个去执行 +func RecoveryUnaryServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + defer func() { + if err := recover(); err != nil { + stack := make([]byte, 4096) + stack = stack[:runtime.Stack(stack, false)] + logger.CtxErrorf(ctx, "err:%v\nstack:%s", err, stack) + } + + }() + + return handler(ctx, req) + } +} diff --git a/common/prpc/interceptor/server/recovery_interceptor_test.go b/common/prpc/interceptor/server/recovery_interceptor_test.go new file mode 100644 index 0000000..28d49c9 --- /dev/null +++ b/common/prpc/interceptor/server/recovery_interceptor_test.go @@ -0,0 +1,17 @@ +package server + +import ( + "context" + "testing" + + "google.golang.org/grpc" +) + +func TestRecoveryUnaryServerInterceptor(t *testing.T) { + RecoveryUnaryServerInterceptor()(context.Background(), nil, &grpc.UnaryServerInfo{ + FullMethod: "/helloworld.Greeter/SayHello", + }, func(ctx context.Context, req interface{}) (interface{}, error) { + panic("xxxxx") + return nil, nil + }) +} diff --git a/common/prpc/interceptor/server/trace_interceptor.go b/common/prpc/interceptor/server/trace_interceptor.go new file mode 100644 index 0000000..a3a0557 --- /dev/null +++ b/common/prpc/interceptor/server/trace_interceptor.go @@ -0,0 +1,46 @@ +package server + +import ( + "context" + + ptrace "github.com/hardcore-os/plato/common/prpc/trace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// TraceUnaryServerInterceptor ... +func TraceUnaryServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + md := metadata.MD{} + header, ok := metadata.FromIncomingContext(ctx) + + if ok { + md = header.Copy() + } + + spanCtx := ptrace.Extract(ctx, otel.GetTextMapPropagator(), &md) + tr := otel.Tracer(ptrace.TraceName) + name, attrs := ptrace.BuildSpan(info.FullMethod, ptrace.PeerFromCtx(ctx)) + + ctx, span := tr.Start(trace.ContextWithRemoteSpanContext(ctx, spanCtx), name, trace.WithSpanKind(trace.SpanKindServer), trace.WithAttributes(attrs...)) + defer span.End() + + resp, err = handler(ctx, req) + if err != nil { + s, ok := status.FromError(err) + if ok { + span.SetStatus(codes.Error, s.Message()) + span.SetAttributes(ptrace.StatusCodeAttr(s.Code())) + } else { + span.SetStatus(codes.Error, err.Error()) + } + return nil, err + } + + return resp, nil + } +} diff --git a/common/prpc/interceptor/server/trace_interceptor_test.go b/common/prpc/interceptor/server/trace_interceptor_test.go new file mode 100644 index 0000000..047ee55 --- /dev/null +++ b/common/prpc/interceptor/server/trace_interceptor_test.go @@ -0,0 +1,30 @@ +package server + +import ( + "context" + "testing" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + ptrace "github.com/hardcore-os/plato/common/prpc/trace" + "google.golang.org/grpc" +) + +func TestTraceUnaryServerInterceptor(t *testing.T) { + ptrace.StartAgent() + defer ptrace.StopAgent() + + //cc := new(grpc.ClientConn) + TraceUnaryServerInterceptor()(context.Background(), nil, &grpc.UnaryServerInfo{ + FullMethod: "/helloworld.Greeter/SayHello", + }, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + + TraceUnaryServerInterceptor()(context.Background(), nil, &grpc.UnaryServerInfo{ + FullMethod: "/helloworld.Greeter/SayBye", + }, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, status.Error(codes.DataLoss, "dummy") + }) +} diff --git a/common/prpc/prome/agent.go b/common/prpc/prome/agent.go new file mode 100644 index 0000000..6a0982b --- /dev/null +++ b/common/prpc/prome/agent.go @@ -0,0 +1,26 @@ +package prome + +import ( + "fmt" + "net/http" + "sync" + + "github.com/bytedance/gopkg/util/logger" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +var once sync.Once + +// StartAgent 开启prometheus +func StartAgent(host string, port int) { + go func() { + once.Do(func() { + http.Handle("/", promhttp.Handler()) + addr := fmt.Sprintf("%s:%d", host, port) + logger.Infof("Starting prometheus agent at %s", addr) + if err := http.ListenAndServe(addr, nil); err != nil { + logger.Error(err) + } + }) + }() +} diff --git a/common/prpc/prome/prom.go b/common/prpc/prome/prom.go new file mode 100644 index 0000000..e14dfa7 --- /dev/null +++ b/common/prpc/prome/prom.go @@ -0,0 +1,21 @@ +package prome + +import "github.com/prometheus/client_golang/prometheus" + +// NewCounterVec ... +func NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec { + counterVec := prometheus.NewCounterVec(opts, labelNames) + + prometheus.MustRegister(counterVec) + + return counterVec +} + +// NewHistogramVec ... +func NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec { + histogramVec := prometheus.NewHistogramVec(opts, labelNames) + + prometheus.MustRegister(histogramVec) + + return histogramVec +} diff --git a/common/prpc/resolver/discov_builder.go b/common/prpc/resolver/discov_builder.go new file mode 100644 index 0000000..10b9f87 --- /dev/null +++ b/common/prpc/resolver/discov_builder.go @@ -0,0 +1,62 @@ +package resolver + +import ( + "context" + "fmt" + + "github.com/hardcore-os/plato/common/prpc/discov" + "google.golang.org/grpc/attributes" + "google.golang.org/grpc/resolver" +) + +type DiscovBuilder struct { + discov discov.Discovery +} + +// NewDiscovBuilder ... +func NewDiscovBuilder(d discov.Discovery) resolver.Builder { + return &DiscovBuilder{ + discov: d, + } +} + +func (d *DiscovBuilder) Scheme() string { + return DiscovBuilderScheme +} + +func (d *DiscovBuilder) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) { + d.discov.GetService(context.TODO(), d.getServiceName(target)) + serviceName := d.getServiceName(target) + listener := func() { + service := d.discov.GetService(context.TODO(), serviceName) + var addrs []resolver.Address + for _, item := range service.Endpoints { + attr := attributes.New("weight", item.Weight) + addr := resolver.Address{ + Addr: fmt.Sprintf("%s:%d", item.IP, item.Port), + Attributes: attr, + } + + addrs = append(addrs, addr) + } + + cc.UpdateState(resolver.State{ + Addresses: addrs, + }) + } + + d.discov.AddListener(context.TODO(), listener) + listener() + + return d, nil +} + +func (d *DiscovBuilder) getServiceName(target resolver.Target) string { + return target.Endpoint +} + +func (d *DiscovBuilder) Close() { +} + +func (d *DiscovBuilder) ResolveNow(options resolver.ResolveNowOptions) { +} diff --git a/common/prpc/resolver/discov_builder_test.go b/common/prpc/resolver/discov_builder_test.go new file mode 100644 index 0000000..d356a7b --- /dev/null +++ b/common/prpc/resolver/discov_builder_test.go @@ -0,0 +1 @@ +package resolver diff --git a/common/prpc/resolver/resolver.go b/common/prpc/resolver/resolver.go new file mode 100644 index 0000000..26b344b --- /dev/null +++ b/common/prpc/resolver/resolver.go @@ -0,0 +1,5 @@ +package resolver + +const ( + DiscovBuilderScheme = "discov" +) diff --git a/common/prpc/server.go b/common/prpc/server.go new file mode 100644 index 0000000..ea86e28 --- /dev/null +++ b/common/prpc/server.go @@ -0,0 +1,177 @@ +package prpc + +import ( + "context" + "fmt" + "net" + "os" + "os/signal" + "syscall" + "time" + + "github.com/hardcore-os/plato/common/prpc/discov/plugin" + + "github.com/bytedance/gopkg/util/logger" + + "github.com/hardcore-os/plato/common/prpc/discov" + serverinterceptor "github.com/hardcore-os/plato/common/prpc/interceptor/server" + "google.golang.org/grpc" +) + +type RegisterFn func(*grpc.Server) + +type PServer struct { + serverOptions + registers []RegisterFn + interceptors []grpc.UnaryServerInterceptor +} + +type serverOptions struct { + serviceName string + ip string + port int + weight int + health bool + d discov.Discovery +} + +type ServerOption func(opts *serverOptions) + +// WithServiceName set serviceName +func WithServiceName(serviceName string) ServerOption { + return func(opts *serverOptions) { + opts.serviceName = serviceName + } +} + +// WithIP set ip +func WithIP(ip string) ServerOption { + return func(opts *serverOptions) { + opts.ip = ip + } +} + +// WithPort set port +func WithPort(port int) ServerOption { + return func(opts *serverOptions) { + opts.port = port + } +} + +// WithWeight set weight +func WithWeight(weight int) ServerOption { + return func(opts *serverOptions) { + opts.weight = weight + } +} + +// WithHealth set health +func WithHealth(health bool) ServerOption { + return func(opts *serverOptions) { + opts.health = health + } +} + +func NewPServer(opts ...ServerOption) *PServer { + opt := serverOptions{} + for _, o := range opts { + o(&opt) + } + + if opt.d == nil { + dis, err := plugin.GetDiscovInstance() + if err != nil { + panic(err) + } + + opt.d = dis + } + + return &PServer{ + opt, + make([]RegisterFn, 0), + make([]grpc.UnaryServerInterceptor, 0), + } +} + +// RegisterService ... +// eg : +// +// p.RegisterService(func(server *grpc.Server) { +// test.RegisterGreeterServer(server, &Server{}) +// }) +func (p *PServer) RegisterService(register ...RegisterFn) { + p.registers = append(p.registers, register...) +} + +// RegisterUnaryServerInterceptor 注册自定义拦截器,例如限流拦截器或者自己的一些业务自定义拦截器 +func (p *PServer) RegisterUnaryServerInterceptor(i grpc.UnaryServerInterceptor) { + p.interceptors = append(p.interceptors, i) +} + +// Start 开启server +func (p *PServer) Start(ctx context.Context) { + service := discov.Service{ + Name: p.serviceName, + Endpoints: []*discov.Endpoint{ + { + ServerName: p.serviceName, + IP: p.ip, + Port: p.port, + Weight: p.weight, + Enable: true, + }, + }, + } + + // 加载中间件 + interceptors := []grpc.UnaryServerInterceptor{ + serverinterceptor.RecoveryUnaryServerInterceptor(), + serverinterceptor.TraceUnaryServerInterceptor(), + serverinterceptor.MetricUnaryServerInterceptor(p.serviceName), + } + interceptors = append(interceptors, p.interceptors...) + s := grpc.NewServer( + grpc.UnaryInterceptor(serverinterceptor.RecoveryUnaryServerInterceptor()), + // TODO 多个拦截器怎么处理? + //grpc.UnaryInterceptor(serverinterceptor.TraceUnaryServerInterceptor()), + //grpc.UnaryInterceptor(serverinterceptor.MetricUnaryServerInterceptor(p.serviceName)), + ) + + // 注册服务 + for _, register := range p.registers { + register(s) + } + + lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", p.ip, p.port)) + if err != nil { + panic(err) + } + + go func() { + if err := s.Serve(lis); err != nil { + panic(err) + } + }() + // 服务注册 + p.d.Register(ctx, &service) + + logger.Info("start PRCP success") + + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) + for { + sig := <-c + switch sig { + case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT: + s.Stop() + p.d.UnRegister(ctx, &service) + time.Sleep(time.Second) + return + case syscall.SIGHUP: + default: + return + } + } + +} diff --git a/common/prpc/server_test.go b/common/prpc/server_test.go new file mode 100644 index 0000000..65a2742 --- /dev/null +++ b/common/prpc/server_test.go @@ -0,0 +1,31 @@ +package prpc + +import ( + "context" + "testing" + + "github.com/hardcore-os/plato/common/config" + + "github.com/hardcore-os/plato/common/prpc/example/helloservice" + + ptrace "github.com/hardcore-os/plato/common/prpc/trace" + "google.golang.org/grpc" +) + +const ( + testIp = "127.0.0.1" + testPort = 8867 +) + +func TestNewPServer(t *testing.T) { + config.Init("../../plato.yaml") + + ptrace.StartAgent() + defer ptrace.StopAgent() + + s := NewPServer(WithServiceName("plato_server"), WithIP(testIp), WithPort(testPort), WithWeight(100)) + s.RegisterService(func(server *grpc.Server) { + helloservice.RegisterGreeterServer(server, helloservice.HelloServer{}) + }) + s.Start(context.TODO()) +} diff --git a/common/prpc/trace/agent.go b/common/prpc/trace/agent.go new file mode 100644 index 0000000..19a84ea --- /dev/null +++ b/common/prpc/trace/agent.go @@ -0,0 +1,51 @@ +package trace + +import ( + "context" + "sync" + + "github.com/bytedance/gopkg/util/logger" + + "github.com/hardcore-os/plato/common/prpc/config" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/jaeger" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/resource" + tracesdk "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" +) + +var ( + tp *tracesdk.TracerProvider + once sync.Once +) + +// StartAgent 开启trace collector +func StartAgent() { + once.Do(func() { + exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(config.GetTraceCollectionUrl()))) + if err != nil { + logger.Errorf("trace start agent err:%s", err.Error()) + return + } + + tp = tracesdk.NewTracerProvider( + tracesdk.WithSampler(tracesdk.TraceIDRatioBased(config.GetTraceSampler())), + tracesdk.WithBatcher(exp), + tracesdk.WithResource(resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String(config.GetTraceServiceName()), + )), + ) + + otel.SetTracerProvider(tp) + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, propagation.Baggage{})) + }) +} + +// StopAgent 关闭trace collector,在服务停止时调用StopAgent,不然可能造成trace数据的丢失 +func StopAgent() { + _ = tp.Shutdown(context.TODO()) +} diff --git a/common/prpc/trace/attr.go b/common/prpc/trace/attr.go new file mode 100644 index 0000000..73c6c4f --- /dev/null +++ b/common/prpc/trace/attr.go @@ -0,0 +1,42 @@ +package trace + +import ( + "go.opentelemetry.io/otel/attribute" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" + gcodes "google.golang.org/grpc/codes" +) + +const ( + // GRPCStatusCodeKey is convention for numeric status code of a gRPC request. + GRPCStatusCodeKey = attribute.Key("rpc.grpc.status_code") + // RPCNameKey is the name of message transmitted or received. + RPCNameKey = attribute.Key("name") + // RPCMessageTypeKey is the type of message transmitted or received. + RPCMessageTypeKey = attribute.Key("message.type") + // RPCMessageIDKey is the identifier of message transmitted or received. + RPCMessageIDKey = attribute.Key("message.id") + // RPCMessageCompressedSizeKey is the compressed size of the message transmitted or received in bytes. + RPCMessageCompressedSizeKey = attribute.Key("message.compressed_size") + // RPCMessageUncompressedSizeKey is the uncompressed size of the message + // transmitted or received in bytes. + RPCMessageUncompressedSizeKey = attribute.Key("message.uncompressed_size") + // ServerEnvironment ... + ServerEnvironment = attribute.Key("environment") +) + +// Semantic conventions for common RPC attributes. +var ( + // RPCSystemGRPC is the semantic convention for gRPC as the remoting system. + RPCSystemGRPC = semconv.RPCSystemKey.String("grpc") + // RPCNameMessage is the semantic convention for a message named message. + RPCNameMessage = RPCNameKey.String("message") + // RPCMessageTypeSent is the semantic conventions for sent RPC message types. + RPCMessageTypeSent = RPCMessageTypeKey.String("SENT") + // RPCMessageTypeReceived is the semantic conventions for the received RPC message types. + RPCMessageTypeReceived = RPCMessageTypeKey.String("RECEIVED") +) + +// StatusCodeAttr returns an attribute.KeyValue that represents the give c. +func StatusCodeAttr(c gcodes.Code) attribute.KeyValue { + return GRPCStatusCodeKey.Int64(int64(c)) +} diff --git a/common/prpc/trace/trace.go b/common/prpc/trace/trace.go new file mode 100644 index 0000000..ac00b7f --- /dev/null +++ b/common/prpc/trace/trace.go @@ -0,0 +1,56 @@ +package trace + +import ( + "context" + + sdktrace "go.opentelemetry.io/otel/trace" + + "go.opentelemetry.io/otel/propagation" + "google.golang.org/grpc/metadata" +) + +const ( + TraceName = "plato-trace" +) + +type metadataSupplier struct { + metadata *metadata.MD +} + +func (s *metadataSupplier) Get(key string) string { + values := s.metadata.Get(key) + if len(values) == 0 { + return "" + } + + return values[0] +} + +func (s *metadataSupplier) Set(key, value string) { + s.metadata.Set(key, value) +} + +func (s *metadataSupplier) Keys() []string { + out := make([]string, 0, len(*s.metadata)) + for key := range *s.metadata { + out = append(out, key) + } + + return out +} + +// Inject set cross-cutting concerns from the Context into the metadata. +func Inject(ctx context.Context, p propagation.TextMapPropagator, m *metadata.MD) { + p.Inject(ctx, &metadataSupplier{ + metadata: m, + }) +} + +// Extract reads cross-cutting concerns from the metadata into a Context. +func Extract(ctx context.Context, p propagation.TextMapPropagator, metadata *metadata.MD) sdktrace.SpanContext { + ctx = p.Extract(ctx, &metadataSupplier{ + metadata: metadata, + }) + + return sdktrace.SpanContextFromContext(ctx) +} diff --git a/common/prpc/trace/util.go b/common/prpc/trace/util.go new file mode 100644 index 0000000..1dd24ab --- /dev/null +++ b/common/prpc/trace/util.go @@ -0,0 +1,70 @@ +package trace + +import ( + "context" + "net" + "strings" + + "go.opentelemetry.io/otel/attribute" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" + "google.golang.org/grpc/peer" +) + +const ( + localhost = "127.0.0.1" +) + +// BuildSpan returns the span info. +func BuildSpan(method, peerAddr string) (string, []attribute.KeyValue) { + attrs := make([]attribute.KeyValue, 0) + name, mAttrs := parseServiceAndMethod(method) + attrs = append(attrs, mAttrs...) + attrs = append(attrs, peerAttr(peerAddr)...) + return name, attrs +} + +// parseServiceAndMethod ... +func parseServiceAndMethod(fullMethod string) (string, []attribute.KeyValue) { + name := strings.TrimLeft(fullMethod, "/") + parts := strings.SplitN(name, "/", 2) + if len(parts) != 2 { + return name, []attribute.KeyValue(nil) + } + + var attrs []attribute.KeyValue + if service := parts[0]; service != "" { + attrs = append(attrs, semconv.RPCServiceKey.String(service)) + } + if method := parts[1]; method != "" { + attrs = append(attrs, semconv.RPCMethodKey.String(method)) + } + + return name, attrs +} + +// peerAttr returns the peer attributes. +func peerAttr(addr string) []attribute.KeyValue { + host, port, err := net.SplitHostPort(addr) + if err != nil { + return nil + } + + if len(host) == 0 { + host = localhost + } + + return []attribute.KeyValue{ + semconv.NetPeerIPKey.String(host), + semconv.NetPeerPortKey.String(port), + } +} + +// PeerFromCtx returns the peer from ctx. +func PeerFromCtx(ctx context.Context) string { + p, ok := peer.FromContext(ctx) + if !ok || p == nil { + return "" + } + + return p.Addr.String() +} diff --git a/common/prpc/util/ip.go b/common/prpc/util/ip.go new file mode 100644 index 0000000..57bd13e --- /dev/null +++ b/common/prpc/util/ip.go @@ -0,0 +1,56 @@ +package util + +import "net" + +const ( + localhost = "127.0.0.1" +) + +// ExternalIP 获取ip +func ExternalIP() string { + ifaces, err := net.Interfaces() + if err != nil { + return localhost + } + for _, iface := range ifaces { + if iface.Flags&net.FlagUp == 0 { + continue // interface down + } + if iface.Flags&net.FlagLoopback != 0 { + continue // loopback interface + } + addrs, err := iface.Addrs() + if err != nil { + return localhost + } + for _, addr := range addrs { + ip := getIpFromAddr(addr) + if ip == nil { + continue + } + return ip.String() + } + } + return localhost +} + +// 获取ip +func getIpFromAddr(addr net.Addr) net.IP { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + if ip == nil || ip.IsLoopback() { + return nil + } + ip = ip.To4() + if ip == nil { + return nil // not an ipv4 address + } + + return ip + +} diff --git a/go.mod b/go.mod index 7b039fe..1859586 100644 --- a/go.mod +++ b/go.mod @@ -4,27 +4,41 @@ go 1.18 replace github.com/coreos/bbolt v1.3.7 => go.etcd.io/bbolt v1.3.7 -replace google.golang.org/grpc => google.golang.org/grpc v1.25.1 +replace google.golang.org/grpc => google.golang.org/grpc v1.26.0 require ( github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b github.com/cloudwego/hertz v0.7.0 github.com/gookit/color v1.5.1 + github.com/juju/ratelimit v1.0.2 github.com/panjf2000/ants v1.2.1 + github.com/prometheus/client_golang v1.17.0 github.com/rocket049/gocui v0.3.2 + github.com/sony/gobreaker v0.5.0 github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.16.0 + github.com/stretchr/testify v1.8.4 + go.opentelemetry.io/otel v1.19.0 + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 + go.opentelemetry.io/otel/sdk v1.19.0 + go.opentelemetry.io/otel/trace v1.19.0 + google.golang.org/grpc v1.56.2 ) require ( + github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/go-tagexpr/v2 v2.9.2 // indirect github.com/bytedance/sonic v1.8.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cloudwego/netpoll v0.5.0 // indirect github.com/coreos/bbolt v1.3.7 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/google/btree v1.1.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect @@ -35,10 +49,14 @@ require ( github.com/jonboulle/clockwork v0.4.0 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/nyaruka/phonenumbers v1.0.55 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/prometheus/client_golang v1.17.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect + github.com/prometheus/common v0.44.0 // indirect + github.com/prometheus/procfs v0.11.1 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect @@ -50,9 +68,9 @@ require ( github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect + go.opentelemetry.io/otel/metric v1.19.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/time v0.3.0 // indirect - google.golang.org/grpc v1.56.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect @@ -64,7 +82,7 @@ require ( github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.3 github.com/google/uuid v1.3.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect @@ -76,7 +94,7 @@ require ( go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.11.0 + golang.org/x/sys v0.12.0 golang.org/x/text v0.11.0 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect diff --git a/go.sum b/go.sum index f856e66..d0d59d9 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,7 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= @@ -52,6 +53,7 @@ github.com/bytedance/sonic v1.8.1 h1:NqAHCaGaTzro0xMmnTCLUyRlbEP6r8MCA1cJUrH3Pu4 github.com/bytedance/sonic v1.8.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= @@ -78,7 +80,7 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= @@ -90,6 +92,11 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -189,6 +196,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI= +github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= @@ -206,6 +215,7 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -228,15 +238,18 @@ github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1 github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= +github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= +github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= +github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rocket049/gocui v0.3.2 h1:6QEaEX85VheVRLwA5FjAe2tswlIkIg0mgoeBHEguRzA= github.com/rocket049/gocui v0.3.2/go.mod h1:oKkm50/BFqMgu7hwBRMs7/uketHe9hRMoo29X1gxK9A= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= @@ -247,6 +260,8 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= +github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= @@ -262,6 +277,7 @@ github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1Fof 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -272,8 +288,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -305,6 +322,16 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= +go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= +go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= +go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= +go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= +go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= +go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= @@ -455,8 +482,8 @@ golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -596,8 +623,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1: google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -614,8 +641,8 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= From aae8cc796421ec89c84ec59ca6fd14c92801e52e Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sun, 29 Oct 2023 23:18:47 +0800 Subject: [PATCH 08/26] fix: etcd dependency --- common/discovery/discovery.go | 4 +- common/discovery/register.go | 2 +- common/prpc/config/config.go | 4 +- common/prpc/discov/etcd/etcd_register.go | 2 +- go.mod | 23 +---- go.sum | 119 ++++++++--------------- 6 files changed, 54 insertions(+), 100 deletions(-) diff --git a/common/discovery/discovery.go b/common/discovery/discovery.go index 47d0092..2e9a810 100644 --- a/common/discovery/discovery.go +++ b/common/discovery/discovery.go @@ -3,9 +3,9 @@ package discovery import ( "context" "github.com/bytedance/gopkg/util/logger" - "github.com/coreos/etcd/mvcc/mvccpb" "github.com/hardcore-os/plato/common/config" - "go.etcd.io/etcd/clientv3" + "go.etcd.io/etcd/api/v3/mvccpb" + clientv3 "go.etcd.io/etcd/client/v3" "sync" ) diff --git a/common/discovery/register.go b/common/discovery/register.go index 41ba593..8abf9c1 100644 --- a/common/discovery/register.go +++ b/common/discovery/register.go @@ -4,7 +4,7 @@ import ( "context" "github.com/bytedance/gopkg/util/logger" "github.com/hardcore-os/plato/common/config" - "go.etcd.io/etcd/clientv3" + clientv3 "go.etcd.io/etcd/client/v3" ) type ServiceRegister struct { diff --git a/common/prpc/config/config.go b/common/prpc/config/config.go index 086a0f3..90ac1a1 100644 --- a/common/prpc/config/config.go +++ b/common/prpc/config/config.go @@ -1,6 +1,8 @@ package config -import "github.com/spf13/viper" +import ( + "github.com/spf13/viper" +) // GetDiscovName 获取discov用哪种方式实现 func GetDiscovName() string { diff --git a/common/prpc/discov/etcd/etcd_register.go b/common/prpc/discov/etcd/etcd_register.go index 3acf70b..c8cb0e0 100644 --- a/common/prpc/discov/etcd/etcd_register.go +++ b/common/prpc/discov/etcd/etcd_register.go @@ -6,7 +6,7 @@ import ( "fmt" "github.com/bytedance/gopkg/util/logger" "github.com/hardcore-os/plato/common/prpc/discov" - "go.etcd.io/etcd/clientv3" + clientv3 "go.etcd.io/etcd/client/v3" "strconv" "strings" "sync" diff --git a/go.mod b/go.mod index 1859586..bc9cfb3 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.18 replace github.com/coreos/bbolt v1.3.7 => go.etcd.io/bbolt v1.3.7 -replace google.golang.org/grpc => google.golang.org/grpc v1.26.0 require ( github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b @@ -18,6 +17,8 @@ require ( github.com/spf13/cobra v1.5.0 github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 + go.etcd.io/etcd/api/v3 v3.5.9 + go.etcd.io/etcd/client/v3 v3.5.9 go.opentelemetry.io/otel v1.19.0 go.opentelemetry.io/otel/exporters/jaeger v1.17.0 go.opentelemetry.io/otel/sdk v1.19.0 @@ -32,21 +33,14 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/cloudwego/netpoll v0.5.0 // indirect - github.com/coreos/bbolt v1.3.7 // indirect + github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect - github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/google/btree v1.1.2 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/henrylee2cn/ameda v1.4.10 // indirect github.com/henrylee2cn/goutil v0.0.0-20210127050712-89660552f6f8 // indirect - github.com/jonboulle/clockwork v0.4.0 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect @@ -57,7 +51,6 @@ require ( github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect - github.com/soheilhy/cmux v0.1.5 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -65,32 +58,24 @@ require ( github.com/tidwall/gjson v1.14.4 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect - github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect go.opentelemetry.io/otel/metric v1.19.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/time v0.3.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect ) require ( - github.com/coreos/etcd v3.3.27+incompatible github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect - github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 - github.com/google/uuid v1.3.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/nsf/termbox-go v1.1.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - go.etcd.io/etcd v3.3.27+incompatible go.uber.org/multierr v1.10.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/net v0.12.0 // indirect diff --git a/go.sum b/go.sum index d0d59d9..18d79df 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= @@ -37,8 +38,6 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= @@ -60,52 +59,47 @@ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583j github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudwego/hertz v0.7.0 h1:9LFXPqHkGBNH/k/Y1h3udEloS5LVPNOUWekDfH0bQNM= github.com/cloudwego/hertz v0.7.0/go.mod h1:WliNtVbwihWHHgAaIQEbVXl0O3aWj0ks1eoPrcEAnjs= github.com/cloudwego/netpoll v0.5.0 h1:oRrOp58cPCvK2QbMozZNDESvrxQaEHW2dCimmwH1lcU= github.com/cloudwego/netpoll v0.5.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ= -github.com/coreos/etcd v3.3.27+incompatible h1:QIudLb9KeBsE5zyYxd1mjzRSkzLg9Wf9QlRwFgd6oTA= -github.com/coreos/etcd v3.3.27+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= -github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8 h1:NrLmX9HDyGvQhyZdrDx89zCvPdxQ/EHCo+xGNrjNmHc= -github.com/coreos/pkg v0.0.0-20230601102743-20bbbf26f4d8/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -132,8 +126,6 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -159,8 +151,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= @@ -168,14 +159,6 @@ github.com/gookit/color v1.5.1 h1:Vjg2VEcdHpwq+oY63s/ksHrgJYCTo0bwWvmmYWdE9fQ= github.com/gookit/color v1.5.1/go.mod h1:wZFzea4X8qN6vHOSP2apMb4/+w/orMznEzYsIHPaqKM= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= -github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -189,9 +172,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= -github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= @@ -202,7 +182,6 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -218,18 +197,14 @@ github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zk github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY= github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo= github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg= github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/panjf2000/ants v1.2.1 h1:IlhLREssFi+YFOITnHdH3FHhulY6WDS0OB9e7+3fMHk= github.com/panjf2000/ants v1.2.1/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -247,19 +222,13 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rocket049/gocui v0.3.2 h1:6QEaEX85VheVRLwA5FjAe2tswlIkIg0mgoeBHEguRzA= github.com/rocket049/gocui v0.3.2/go.mod h1:oKkm50/BFqMgu7hwBRMs7/uketHe9hRMoo29X1gxK9A= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/gobreaker v0.5.0 h1:dRCvqm0P490vZPmy7ppEk2qCnCieBooFJ+YoXGYB+yg= github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= @@ -275,7 +244,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= 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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -300,22 +268,20 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= -github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= -github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.etcd.io/etcd v3.3.27+incompatible h1:5hMrpf6REqTHV2LW2OclNpRtxI0k9ZplMemJsMSWju0= -go.etcd.io/etcd v3.3.27+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI= +go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= +go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= +go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= +go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= +go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -332,13 +298,9 @@ go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJ go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= @@ -351,7 +313,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -364,6 +325,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -385,6 +347,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -411,12 +374,10 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= @@ -429,6 +390,7 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -439,17 +401,16 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -475,9 +436,7 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -499,9 +458,8 @@ golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -516,7 +474,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -574,12 +531,14 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -600,10 +559,8 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -623,8 +580,24 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1: google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= -google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -647,12 +620,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -666,5 +635,3 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= From 4eaee12196fba61edc4fec564e811b05d1ab8689 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sun, 29 Oct 2023 23:25:00 +0800 Subject: [PATCH 09/26] feat: add gateway proto --- gateway/rpc/service/gateway.pb.go | 235 +++++++++++++++++++++++++ gateway/rpc/service/gateway.proto | 23 +++ gateway/rpc/service/gateway_grpc.pb.go | 146 +++++++++++++++ 3 files changed, 404 insertions(+) create mode 100644 gateway/rpc/service/gateway.pb.go create mode 100644 gateway/rpc/service/gateway.proto create mode 100644 gateway/rpc/service/gateway_grpc.pb.go diff --git a/gateway/rpc/service/gateway.pb.go b/gateway/rpc/service/gateway.pb.go new file mode 100644 index 0000000..ba3e22b --- /dev/null +++ b/gateway/rpc/service/gateway.pb.go @@ -0,0 +1,235 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.19.4 +// source: gateway.proto + +package service + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GatewayRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Fd int32 `protobuf:"varint,1,opt,name=fd,proto3" json:"fd,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *GatewayRequest) Reset() { + *x = GatewayRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GatewayRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GatewayRequest) ProtoMessage() {} + +func (x *GatewayRequest) ProtoReflect() protoreflect.Message { + mi := &file_gateway_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GatewayRequest.ProtoReflect.Descriptor instead. +func (*GatewayRequest) Descriptor() ([]byte, []int) { + return file_gateway_proto_rawDescGZIP(), []int{0} +} + +func (x *GatewayRequest) GetFd() int32 { + if x != nil { + return x.Fd + } + return 0 +} + +func (x *GatewayRequest) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type GatewayResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (x *GatewayResponse) Reset() { + *x = GatewayResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gateway_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GatewayResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GatewayResponse) ProtoMessage() {} + +func (x *GatewayResponse) ProtoReflect() protoreflect.Message { + mi := &file_gateway_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GatewayResponse.ProtoReflect.Descriptor instead. +func (*GatewayResponse) Descriptor() ([]byte, []int) { + return file_gateway_proto_rawDescGZIP(), []int{1} +} + +func (x *GatewayResponse) GetCode() int32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *GatewayResponse) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +var File_gateway_proto protoreflect.FileDescriptor + +var file_gateway_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x34, 0x0a, 0x0e, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x66, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x66, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x37, + 0x0a, 0x0f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0x82, 0x01, 0x0a, 0x07, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x12, 0x3c, 0x0a, 0x07, 0x44, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x12, 0x17, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x39, 0x0a, 0x04, 0x50, 0x75, 0x73, 0x68, 0x12, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, + 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0c, 0x5a, 0x0a, + 0x2e, 0x2f, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_gateway_proto_rawDescOnce sync.Once + file_gateway_proto_rawDescData = file_gateway_proto_rawDesc +) + +func file_gateway_proto_rawDescGZIP() []byte { + file_gateway_proto_rawDescOnce.Do(func() { + file_gateway_proto_rawDescData = protoimpl.X.CompressGZIP(file_gateway_proto_rawDescData) + }) + return file_gateway_proto_rawDescData +} + +var file_gateway_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_gateway_proto_goTypes = []interface{}{ + (*GatewayRequest)(nil), // 0: service.GatewayRequest + (*GatewayResponse)(nil), // 1: service.GatewayResponse +} +var file_gateway_proto_depIdxs = []int32{ + 0, // 0: service.Gateway.DelConn:input_type -> service.GatewayRequest + 0, // 1: service.Gateway.Push:input_type -> service.GatewayRequest + 1, // 2: service.Gateway.DelConn:output_type -> service.GatewayResponse + 1, // 3: service.Gateway.Push:output_type -> service.GatewayResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_gateway_proto_init() } +func file_gateway_proto_init() { + if File_gateway_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_gateway_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GatewayRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gateway_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GatewayResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_gateway_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_gateway_proto_goTypes, + DependencyIndexes: file_gateway_proto_depIdxs, + MessageInfos: file_gateway_proto_msgTypes, + }.Build() + File_gateway_proto = out.File + file_gateway_proto_rawDesc = nil + file_gateway_proto_goTypes = nil + file_gateway_proto_depIdxs = nil +} diff --git a/gateway/rpc/service/gateway.proto b/gateway/rpc/service/gateway.proto new file mode 100644 index 0000000..9b310d2 --- /dev/null +++ b/gateway/rpc/service/gateway.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +option go_package = "./;service"; + +package service; +// 网关机的 rpc server定义 +// cd gateway/rpc 下 执行 protoc -I service --go_out=plugins=grpc:service service/gateway.proto +// protoc -I service --go_out=service service/gateway.proto +// protoc -I service --go-grpc_out=service service/gateway.proto +service Gateway { + rpc DelConn (GatewayRequest) returns (GatewayResponse); + rpc Push (GatewayRequest) returns (GatewayResponse); +} + +message GatewayRequest{ + int32 fd = 1; + bytes data = 2; +} + +message GatewayResponse { + int32 code = 1; + string msg = 2; +} \ No newline at end of file diff --git a/gateway/rpc/service/gateway_grpc.pb.go b/gateway/rpc/service/gateway_grpc.pb.go new file mode 100644 index 0000000..b48a7f4 --- /dev/null +++ b/gateway/rpc/service/gateway_grpc.pb.go @@ -0,0 +1,146 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v3.19.4 +// source: gateway.proto + +package service + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + Gateway_DelConn_FullMethodName = "/service.Gateway/DelConn" + Gateway_Push_FullMethodName = "/service.Gateway/Push" +) + +// GatewayClient is the client API for Gateway service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type GatewayClient interface { + DelConn(ctx context.Context, in *GatewayRequest, opts ...grpc.CallOption) (*GatewayResponse, error) + Push(ctx context.Context, in *GatewayRequest, opts ...grpc.CallOption) (*GatewayResponse, error) +} + +type gatewayClient struct { + cc grpc.ClientConnInterface +} + +func NewGatewayClient(cc grpc.ClientConnInterface) GatewayClient { + return &gatewayClient{cc} +} + +func (c *gatewayClient) DelConn(ctx context.Context, in *GatewayRequest, opts ...grpc.CallOption) (*GatewayResponse, error) { + out := new(GatewayResponse) + err := c.cc.Invoke(ctx, Gateway_DelConn_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *gatewayClient) Push(ctx context.Context, in *GatewayRequest, opts ...grpc.CallOption) (*GatewayResponse, error) { + out := new(GatewayResponse) + err := c.cc.Invoke(ctx, Gateway_Push_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// GatewayServer is the server API for Gateway service. +// All implementations must embed UnimplementedGatewayServer +// for forward compatibility +type GatewayServer interface { + DelConn(context.Context, *GatewayRequest) (*GatewayResponse, error) + Push(context.Context, *GatewayRequest) (*GatewayResponse, error) + mustEmbedUnimplementedGatewayServer() +} + +// UnimplementedGatewayServer must be embedded to have forward compatible implementations. +type UnimplementedGatewayServer struct { +} + +func (UnimplementedGatewayServer) DelConn(context.Context, *GatewayRequest) (*GatewayResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DelConn not implemented") +} +func (UnimplementedGatewayServer) Push(context.Context, *GatewayRequest) (*GatewayResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Push not implemented") +} +func (UnimplementedGatewayServer) mustEmbedUnimplementedGatewayServer() {} + +// UnsafeGatewayServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GatewayServer will +// result in compilation errors. +type UnsafeGatewayServer interface { + mustEmbedUnimplementedGatewayServer() +} + +func RegisterGatewayServer(s grpc.ServiceRegistrar, srv GatewayServer) { + s.RegisterService(&Gateway_ServiceDesc, srv) +} + +func _Gateway_DelConn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GatewayRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GatewayServer).DelConn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gateway_DelConn_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GatewayServer).DelConn(ctx, req.(*GatewayRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Gateway_Push_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GatewayRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GatewayServer).Push(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Gateway_Push_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GatewayServer).Push(ctx, req.(*GatewayRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// Gateway_ServiceDesc is the grpc.ServiceDesc for Gateway service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var Gateway_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "service.Gateway", + HandlerType: (*GatewayServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "DelConn", + Handler: _Gateway_DelConn_Handler, + }, + { + MethodName: "Push", + Handler: _Gateway_Push_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "gateway.proto", +} From 65d6e848803a07ec81f32bb83385628b9d5245b4 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Mon, 30 Oct 2023 00:14:12 +0800 Subject: [PATCH 10/26] fix: rpc server interceptors --- common/prpc/discov/etcd/option.go | 1 + common/prpc/server.go | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/common/prpc/discov/etcd/option.go b/common/prpc/discov/etcd/option.go index c030c40..9272b07 100644 --- a/common/prpc/discov/etcd/option.go +++ b/common/prpc/discov/etcd/option.go @@ -4,6 +4,7 @@ import "time" var ( defaultOption = Options{ + // TODO replace default endpoints endpoints: []string{"127.0.0.1:2379"}, dialTimeout: 10 * time.Second, syncFlushCacheInterval: 10 * time.Second, diff --git a/common/prpc/server.go b/common/prpc/server.go index ea86e28..e2a0891 100644 --- a/common/prpc/server.go +++ b/common/prpc/server.go @@ -131,12 +131,7 @@ func (p *PServer) Start(ctx context.Context) { serverinterceptor.MetricUnaryServerInterceptor(p.serviceName), } interceptors = append(interceptors, p.interceptors...) - s := grpc.NewServer( - grpc.UnaryInterceptor(serverinterceptor.RecoveryUnaryServerInterceptor()), - // TODO 多个拦截器怎么处理? - //grpc.UnaryInterceptor(serverinterceptor.TraceUnaryServerInterceptor()), - //grpc.UnaryInterceptor(serverinterceptor.MetricUnaryServerInterceptor(p.serviceName)), - ) + s := grpc.NewServer(grpc.ChainUnaryInterceptor(interceptors...)) // 注册服务 for _, register := range p.registers { From 19d0801b0a2eab8f82995a11d269d187e89bf92e Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sun, 5 Nov 2023 17:56:24 +0800 Subject: [PATCH 11/26] fix: add state server --- cmd/state.go | 19 ++ common/config/gateway.go | 28 ++- common/config/state.go | 23 +++ common/prpc/resolver/discov_builder.go | 2 +- common/prpc/server.go | 2 +- gateway/rpc/Makefile | 9 + gateway/rpc/client/init.go | 27 +++ gateway/rpc/client/state.go | 33 ++++ gateway/rpc/service/service.go | 47 +++++ gateway/server.go | 104 +++++++++-- plato.yaml | 21 ++- state/rpc/Makefile | 9 + state/rpc/client/gateway.go | 31 ++++ state/rpc/client/init.go | 21 +++ state/rpc/service/service.go | 58 ++++++ state/rpc/service/state.pb.go | 244 +++++++++++++++++++++++++ state/rpc/service/state.proto | 22 +++ state/rpc/service/state_grpc.pb.go | 146 +++++++++++++++ state/server.go | 49 +++++ 19 files changed, 875 insertions(+), 20 deletions(-) create mode 100644 cmd/state.go create mode 100644 common/config/state.go create mode 100644 gateway/rpc/Makefile create mode 100644 gateway/rpc/client/init.go create mode 100644 gateway/rpc/client/state.go create mode 100644 gateway/rpc/service/service.go create mode 100644 state/rpc/Makefile create mode 100644 state/rpc/client/gateway.go create mode 100644 state/rpc/client/init.go create mode 100644 state/rpc/service/service.go create mode 100644 state/rpc/service/state.pb.go create mode 100644 state/rpc/service/state.proto create mode 100644 state/rpc/service/state_grpc.pb.go create mode 100644 state/server.go diff --git a/cmd/state.go b/cmd/state.go new file mode 100644 index 0000000..bf2c5aa --- /dev/null +++ b/cmd/state.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "github.com/hardcore-os/plato/state" + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(stateCmd) +} + +var stateCmd = &cobra.Command{ + Use: "state", + Run: StateHandle, +} + +func StateHandle(cmd *cobra.Command, args []string) { + state.RunMain(ConfigPath) +} diff --git a/common/config/gateway.go b/common/config/gateway.go index 0a7aa92..98da0a6 100644 --- a/common/config/gateway.go +++ b/common/config/gateway.go @@ -9,15 +9,39 @@ func GetGatewayMaxTcpNum() int32 { func GetGatewayEpollerChanNum() int { return viper.GetInt("gateway.epoll_channel_size") } + func GetGatewayEpollerNum() int { return viper.GetInt("gateway.epoll_num") } + func GetGatewayEpollWaitQueueSize() int { return viper.GetInt("gateway.epoll_wait_queue_size") } -func GetGatewayServerPort() int { - return viper.GetInt("gateway.server_port") + +func GetGatewayTCPServerPort() int { + return viper.GetInt("gateway.tcp_server_port") } + +func GetGatewayRPCServerPort() int { + return viper.GetInt("gateway.rpc_server_port") +} + func GetGatewayWorkerPoolNum() int { return viper.GetInt("gateway.worker_pool_num") } + +func GetGatewayCmdChannelNum() int { + return viper.GetInt("gateway.cmd_channel_num") +} + +func GetGatewayServiceAddr() string { + return viper.GetString("gateway.service_addr") +} + +func GetGatewayServiceName() string { + return viper.GetString("gateway.service_name") +} + +func GetGatewayRPCWeight() int { + return viper.GetInt("gateway.weight") +} diff --git a/common/config/state.go b/common/config/state.go new file mode 100644 index 0000000..18b2c0f --- /dev/null +++ b/common/config/state.go @@ -0,0 +1,23 @@ +package config + +import "github.com/spf13/viper" + +func GetStateCmdChannelNum() int { + return viper.GetInt("state.cmd_channel_num") +} + +func GetStateServiceAddr() string { + return viper.GetString("state.servide_addr") +} + +func GetStateServiceName() string { + return viper.GetString("state.service_name") +} + +func GetStateServerPort() int { + return viper.GetInt("state.server_port") +} + +func GetStateRPCWeight() int { + return viper.GetInt("state.weight") +} diff --git a/common/prpc/resolver/discov_builder.go b/common/prpc/resolver/discov_builder.go index 10b9f87..2fc2a90 100644 --- a/common/prpc/resolver/discov_builder.go +++ b/common/prpc/resolver/discov_builder.go @@ -52,7 +52,7 @@ func (d *DiscovBuilder) Build(target resolver.Target, cc resolver.ClientConn, _ } func (d *DiscovBuilder) getServiceName(target resolver.Target) string { - return target.Endpoint + return target.Endpoint() } func (d *DiscovBuilder) Close() { diff --git a/common/prpc/server.go b/common/prpc/server.go index e2a0891..21aeec1 100644 --- a/common/prpc/server.go +++ b/common/prpc/server.go @@ -151,7 +151,7 @@ func (p *PServer) Start(ctx context.Context) { // 服务注册 p.d.Register(ctx, &service) - logger.Info("start PRCP success") + logger.Info("start PRPC success") c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) diff --git a/gateway/rpc/Makefile b/gateway/rpc/Makefile new file mode 100644 index 0000000..4291017 --- /dev/null +++ b/gateway/rpc/Makefile @@ -0,0 +1,9 @@ +all: gateway + +gateway: + @echo "begin" + protoc -I service --go_out=service service/*.proto + @echo "*.pb.go success" + protoc -I service --go-grpc_out=service service/*.proto + @echo "*_grpc.pb.go success" + @echo "end" diff --git a/gateway/rpc/client/init.go b/gateway/rpc/client/init.go new file mode 100644 index 0000000..7baa52a --- /dev/null +++ b/gateway/rpc/client/init.go @@ -0,0 +1,27 @@ +package client + +import ( + "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/prpc" + "github.com/hardcore-os/plato/state/rpc/service" + "sync" +) + +var ( + stateClient service.StateClient + once sync.Once +) + +func Init() { + initStateClient() +} + +func initStateClient() { + once.Do(func() { + pCli, err := prpc.NewPClient(config.GetStateServiceName()) + if err != nil { + panic(err) + } + stateClient = service.NewStateClient(pCli.Conn()) + }) +} diff --git a/gateway/rpc/client/state.go b/gateway/rpc/client/state.go new file mode 100644 index 0000000..94198db --- /dev/null +++ b/gateway/rpc/client/state.go @@ -0,0 +1,33 @@ +package client + +import ( + "context" + "github.com/hardcore-os/plato/state/rpc/service" + "time" +) + +func CancelConn(ctx *context.Context, endpoint string, fd int32, playLoad []byte) error { + rpcCtx, _ := context.WithTimeout(*ctx, 100*time.Millisecond) + _, err := stateClient.CancelConn(rpcCtx, &service.StateRequest{ + Endpoint: endpoint, + Fd: fd, + Data: playLoad, + }) + if err != nil { + return err + } + return nil +} + +func SendMsg(ctx *context.Context, endpoint string, fd int32, playLoad []byte) error { + rpcCtx, _ := context.WithTimeout(*ctx, 100*time.Millisecond) + _, err := stateClient.SendMsg(rpcCtx, &service.StateRequest{ + Endpoint: endpoint, + Fd: fd, + Data: playLoad, + }) + if err != nil { + return err + } + return nil +} diff --git a/gateway/rpc/service/service.go b/gateway/rpc/service/service.go new file mode 100644 index 0000000..4ed8b34 --- /dev/null +++ b/gateway/rpc/service/service.go @@ -0,0 +1,47 @@ +package service + +import "context" + +const ( + DelConnCmd = 1 // DelConn + PushCmd = 2 //push +) + +type CmdContext struct { + Ctx *context.Context + Cmd int32 + FD int + PlayLoad []byte +} + +type Service struct { + UnimplementedGatewayServer + CmdChannel chan *CmdContext +} + +func (s *Service) DelConn(ctx context.Context, gr *GatewayRequest) (*GatewayResponse, error) { + c := context.TODO() + s.CmdChannel <- &CmdContext{ + Ctx: &c, + Cmd: DelConnCmd, + FD: int(gr.GetFd()), + } + return &GatewayResponse{ + Code: 0, + Msg: "success", + }, nil +} + +func (s *Service) Push(ctx context.Context, gr *GatewayRequest) (*GatewayResponse, error) { + c := context.TODO() + s.CmdChannel <- &CmdContext{ + Ctx: &c, + Cmd: PushCmd, + FD: int(gr.GetFd()), + PlayLoad: gr.GetData(), + } + return &GatewayResponse{ + Code: 0, + Msg: "success", + }, nil +} diff --git a/gateway/server.go b/gateway/server.go index c8aef0e..95221e0 100644 --- a/gateway/server.go +++ b/gateway/server.go @@ -3,46 +3,128 @@ package gateway import ( "context" "errors" + "fmt" + "google.golang.org/grpc" + "io" + "net" + "github.com/bytedance/gopkg/util/logger" "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/prpc" "github.com/hardcore-os/plato/common/tcp" - "io" - "net" + "github.com/hardcore-os/plato/gateway/rpc/client" + "github.com/hardcore-os/plato/gateway/rpc/service" +) + +var ( + cmdChannel chan *service.CmdContext ) func RunMain(path string) { - ctx := context.Background() config.Init(path) - ln, err := net.ListenTCP("tcp", &net.TCPAddr{Port: config.GetGatewayServerPort()}) + startTCPServer() + startRPCServer() +} + +func startTCPServer() { + ctx := context.Background() + ln, err := net.ListenTCP("tcp", &net.TCPAddr{Port: config.GetGatewayTCPServerPort()}) if err != nil { logger.CtxInfof(ctx, "StartTCPEPollServer err:%s", err.Error()) + panic(err) } initWorkPoll() InitEpoll(ln, runProc) - logger.CtxInfof(context.Background(), "-------------IM Gateway stated------------") - select {} + logger.CtxInfof(context.Background(), "-------------IM Gateway started------------") +} + +func startRPCServer() { + ctx := context.Background() + cmdChannel = make(chan *service.CmdContext, config.GetGatewayCmdChannelNum()) + s := prpc.NewPServer( + prpc.WithServiceName(config.GetGatewayServiceName()), + prpc.WithIP(config.GetGatewayServiceAddr()), + prpc.WithPort(config.GetGatewayRPCServerPort()), + prpc.WithWeight(config.GetGatewayRPCWeight()), + ) + logger.CtxInfof(ctx, "serviceName:%s Addr:%s:%d weight:%d", config.GetGatewayServiceName(), config.GetGatewayServiceAddr(), config.GetGatewayRPCServerPort(), config.GetGatewayRPCWeight()) + s.RegisterService(func(server *grpc.Server) { + service.RegisterGatewayServer(server, &service.Service{CmdChannel: cmdChannel}) + }) + // start client + client.Init() + // start cmdHandler + go cmdHandler() + // start rpc server + s.Start(context.TODO()) } func runProc(c *connection, ep *epoller) { + ctx := context.Background() // step1: 读取一个完整的消息包 dataBuf, err := tcp.ReadData(c.conn) if err != nil { if errors.Is(err, io.EOF) { logger.CtxInfof(context.Background(), "connection[%v] closed", c.RemoteAddr()) ep.remove(c) + client.CancelConn(&ctx, getEndpoint(), int32(c.fd), nil) } return } err = wPool.Submit(func() { // step2:交给 state server rpc 处理 - bytes := tcp.DataPgk{ - Len: uint32(len(dataBuf)), - Data: dataBuf, - } - tcp.SendData(c.conn, bytes.Marshal()) + client.SendMsg(&ctx, getEndpoint(), int32(c.fd), dataBuf) }) if err != nil { logger.CtxInfof(context.Background(), "runProc.err: %+v", err.Error()) + fmt.Errorf("runProc.err: %+v\n", err.Error()) } } + +func cmdHandler() { + for cmd := range cmdChannel { + // async submit task to goroutine pool + switch cmd.Cmd { + case service.DelConnCmd: + wPool.Submit(func() { + closeConn(cmd) + }) + case service.PushCmd: + wPool.Submit(func() { + sendMsgByCmd(cmd) + }) + default: + panic("command undefined") + } + } +} + +func closeConn(cmd *service.CmdContext) { + if cmdChannel == nil { + return + } + if connPtr, ok := ep.tables.Load(cmd.FD); ok { + conn, _ := connPtr.(*connection) + conn.Close() + ep.tables.Delete(cmd.FD) + } +} + +func sendMsgByCmd(cmd *service.CmdContext) { + if cmdChannel == nil { + return + } + if connPtr, ok := ep.tables.Load(cmd.FD); ok { + conn, _ := connPtr.(*connection) + dp := tcp.DataPgk{ + Len: uint32(len(cmd.PlayLoad)), + Data: cmd.PlayLoad, + } + tcp.SendData(conn.conn, dp.Marshal()) + } +} + +func getEndpoint() string { + return fmt.Sprintf("%s:%d", config.GetGatewayServiceAddr(), config.GetGatewayRPCServerPort()) +} diff --git a/plato.yaml b/plato.yaml index 4813865..9c8171d 100644 --- a/plato.yaml +++ b/plato.yaml @@ -2,7 +2,7 @@ global: env: debug discovery: endpoints: - - localhost:2379 + - localhost:2379 # 192.168.31.192:2379 timeout: 5 ip_conf: service_path: /plato/ip_dispatcher @@ -10,16 +10,27 @@ prpc: discov: name: etcd endpoints: - - localhost:2379 + - localhost:2379 # 192.168.31.192:2379 trace: enable: true url: http://127.0.0.1:14268/api/traces service_name: plato sampler: 1.0 gateway: - tcp_max_num: 10000 + service_name: "plato.access.gateway" + service_addr: "127.0.0.1" + tcp_max_num: 70000 epoll_channel_num: 100 epoll_num: 8 epoll_wait_queue_size: 100 - server_port: 8900 - worker_pool_num: 1024 \ No newline at end of file + tcp_server_port: 8900 + rpc_server_port: 8901 + worker_pool_num: 1024 + cmd_channel_num: 2048 + weight: 100 +state: + service_name: "plato.access.state" + servide_addr: "127.0.0.1" + cmd_channel_num: 2048 + server_port: 8902 + weight: 100 \ No newline at end of file diff --git a/state/rpc/Makefile b/state/rpc/Makefile new file mode 100644 index 0000000..40c86d3 --- /dev/null +++ b/state/rpc/Makefile @@ -0,0 +1,9 @@ +all: state + +state: + @echo "begin" + protoc -I service --go_out=service service/*.proto + @echo "*.pb.go success" + protoc -I service --go-grpc_out=service service/*.proto + @echo "*_grpc.pb.go success" + @echo "end" diff --git a/state/rpc/client/gateway.go b/state/rpc/client/gateway.go new file mode 100644 index 0000000..2e889d9 --- /dev/null +++ b/state/rpc/client/gateway.go @@ -0,0 +1,31 @@ +package client + +import ( + "context" + "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/gateway/rpc/service" + "time" +) + +func DelConn(ctx *context.Context, fd int32, playLoad []byte) error { + rpcCtx, _ := context.WithTimeout(*ctx, 100*time.Millisecond) + gatewayClient.DelConn(rpcCtx, &service.GatewayRequest{ + Fd: fd, + Data: playLoad, + }) + return nil +} + +func Push(ctx *context.Context, fd int32, playLoad []byte) error { + rpcCtx, _ := context.WithTimeout(*ctx, 100*time.Millisecond) + resp, err := gatewayClient.Push(rpcCtx, &service.GatewayRequest{ + Fd: fd, + Data: playLoad, + }) + if err != nil { + logger.CtxErrorf(rpcCtx, "state.gatewayClient push msg err, err=%v", err) + return err + } + logger.CtxInfof(rpcCtx, "state.gatewayClient push msg resp, resp=%+v", resp) + return nil +} diff --git a/state/rpc/client/init.go b/state/rpc/client/init.go new file mode 100644 index 0000000..cade9ac --- /dev/null +++ b/state/rpc/client/init.go @@ -0,0 +1,21 @@ +package client + +import ( + "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/prpc" + "github.com/hardcore-os/plato/gateway/rpc/service" +) + +var gatewayClient service.GatewayClient + +func Init() { + initGatewayClient() +} + +func initGatewayClient() { + pCli, err := prpc.NewPClient(config.GetGatewayServiceName()) + if err != nil { + panic(err) + } + gatewayClient = service.NewGatewayClient(pCli.Conn()) +} diff --git a/state/rpc/service/service.go b/state/rpc/service/service.go new file mode 100644 index 0000000..81517ae --- /dev/null +++ b/state/rpc/service/service.go @@ -0,0 +1,58 @@ +package service + +import ( + "context" + "github.com/bytedance/gopkg/util/logger" +) + +const ( + CancelConnCmd = 1 + SendMsgCmd = 2 +) + +type CmdContext struct { + Ctx *context.Context + Cmd int32 + Endpoint string + FD int + PlayLoad []byte +} + +type Service struct { + UnimplementedStateServer + CmdChannel chan *CmdContext +} + +func (s *Service) CancelConn(ctx context.Context, sr *StateRequest) (*StateResponse, error) { + c := context.TODO() + s.CmdChannel <- &CmdContext{ + Ctx: &c, + Cmd: CancelConnCmd, + Endpoint: sr.GetEndpoint(), + FD: int(sr.GetFd()), + } + + return &StateResponse{ + Code: 0, + Msg: "success", + }, nil +} + +func (s *Service) SendMsg(ctx context.Context, sr *StateRequest) (*StateResponse, error) { + logger.CtxInfof(ctx, "[state] receive SendMsg request ok") + c := context.TODO() + s.CmdChannel <- &CmdContext{ + Ctx: &c, + Cmd: SendMsgCmd, + FD: int(sr.GetFd()), + Endpoint: sr.GetEndpoint(), + PlayLoad: sr.GetData(), + } + + logger.CtxInfof(ctx, "[state] sendMsg to channel ok") + + return &StateResponse{ + Code: 0, + Msg: "success", + }, nil +} diff --git a/state/rpc/service/state.pb.go b/state/rpc/service/state.pb.go new file mode 100644 index 0000000..2223b93 --- /dev/null +++ b/state/rpc/service/state.pb.go @@ -0,0 +1,244 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.19.4 +// source: state.proto + +package service + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type StateRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Endpoint string `protobuf:"bytes,1,opt,name=endpoint,proto3" json:"endpoint,omitempty"` + Fd int32 `protobuf:"varint,2,opt,name=fd,proto3" json:"fd,omitempty"` + Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *StateRequest) Reset() { + *x = StateRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateRequest) ProtoMessage() {} + +func (x *StateRequest) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateRequest.ProtoReflect.Descriptor instead. +func (*StateRequest) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{0} +} + +func (x *StateRequest) GetEndpoint() string { + if x != nil { + return x.Endpoint + } + return "" +} + +func (x *StateRequest) GetFd() int32 { + if x != nil { + return x.Fd + } + return 0 +} + +func (x *StateRequest) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type StateResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code int32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (x *StateResponse) Reset() { + *x = StateResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateResponse) ProtoMessage() {} + +func (x *StateResponse) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateResponse.ProtoReflect.Descriptor instead. +func (*StateResponse) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{1} +} + +func (x *StateResponse) GetCode() int32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *StateResponse) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +var File_state_proto protoreflect.FileDescriptor + +var file_state_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x4e, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x66, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, + 0x66, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x35, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, + 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0x7e, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x43, 0x6f, 0x6e, 0x6e, 0x12, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x12, 0x15, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0c, 0x5a, + 0x0a, 0x2e, 0x2f, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_state_proto_rawDescOnce sync.Once + file_state_proto_rawDescData = file_state_proto_rawDesc +) + +func file_state_proto_rawDescGZIP() []byte { + file_state_proto_rawDescOnce.Do(func() { + file_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_state_proto_rawDescData) + }) + return file_state_proto_rawDescData +} + +var file_state_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_state_proto_goTypes = []interface{}{ + (*StateRequest)(nil), // 0: service.StateRequest + (*StateResponse)(nil), // 1: service.StateResponse +} +var file_state_proto_depIdxs = []int32{ + 0, // 0: service.state.CancelConn:input_type -> service.StateRequest + 0, // 1: service.state.SendMsg:input_type -> service.StateRequest + 1, // 2: service.state.CancelConn:output_type -> service.StateResponse + 1, // 3: service.state.SendMsg:output_type -> service.StateResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_state_proto_init() } +func file_state_proto_init() { + if File_state_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_state_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_state_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StateResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_state_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_state_proto_goTypes, + DependencyIndexes: file_state_proto_depIdxs, + MessageInfos: file_state_proto_msgTypes, + }.Build() + File_state_proto = out.File + file_state_proto_rawDesc = nil + file_state_proto_goTypes = nil + file_state_proto_depIdxs = nil +} diff --git a/state/rpc/service/state.proto b/state/rpc/service/state.proto new file mode 100644 index 0000000..5dafc77 --- /dev/null +++ b/state/rpc/service/state.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +option go_package = "./;service"; + +package service; +// 网关机的 rpc server定义 +// cd state/rpc 下 执行 protoc -I service --go_out=plugins=grpc:service service/state.proto +service state { + rpc CancelConn (StateRequest) returns (StateResponse); + rpc SendMsg (StateRequest) returns (StateResponse); +} + +message StateRequest{ + string endpoint = 1; + int32 fd = 2; + bytes data = 3; +} + +message StateResponse { + int32 code = 1; + string msg = 2; +} \ No newline at end of file diff --git a/state/rpc/service/state_grpc.pb.go b/state/rpc/service/state_grpc.pb.go new file mode 100644 index 0000000..540bbec --- /dev/null +++ b/state/rpc/service/state_grpc.pb.go @@ -0,0 +1,146 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v3.19.4 +// source: state.proto + +package service + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + State_CancelConn_FullMethodName = "/service.state/CancelConn" + State_SendMsg_FullMethodName = "/service.state/SendMsg" +) + +// StateClient is the client API for State service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type StateClient interface { + CancelConn(ctx context.Context, in *StateRequest, opts ...grpc.CallOption) (*StateResponse, error) + SendMsg(ctx context.Context, in *StateRequest, opts ...grpc.CallOption) (*StateResponse, error) +} + +type stateClient struct { + cc grpc.ClientConnInterface +} + +func NewStateClient(cc grpc.ClientConnInterface) StateClient { + return &stateClient{cc} +} + +func (c *stateClient) CancelConn(ctx context.Context, in *StateRequest, opts ...grpc.CallOption) (*StateResponse, error) { + out := new(StateResponse) + err := c.cc.Invoke(ctx, State_CancelConn_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *stateClient) SendMsg(ctx context.Context, in *StateRequest, opts ...grpc.CallOption) (*StateResponse, error) { + out := new(StateResponse) + err := c.cc.Invoke(ctx, State_SendMsg_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// StateServer is the server API for State service. +// All implementations must embed UnimplementedStateServer +// for forward compatibility +type StateServer interface { + CancelConn(context.Context, *StateRequest) (*StateResponse, error) + SendMsg(context.Context, *StateRequest) (*StateResponse, error) + mustEmbedUnimplementedStateServer() +} + +// UnimplementedStateServer must be embedded to have forward compatible implementations. +type UnimplementedStateServer struct { +} + +func (UnimplementedStateServer) CancelConn(context.Context, *StateRequest) (*StateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CancelConn not implemented") +} +func (UnimplementedStateServer) SendMsg(context.Context, *StateRequest) (*StateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendMsg not implemented") +} +func (UnimplementedStateServer) mustEmbedUnimplementedStateServer() {} + +// UnsafeStateServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StateServer will +// result in compilation errors. +type UnsafeStateServer interface { + mustEmbedUnimplementedStateServer() +} + +func RegisterStateServer(s grpc.ServiceRegistrar, srv StateServer) { + s.RegisterService(&State_ServiceDesc, srv) +} + +func _State_CancelConn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateServer).CancelConn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: State_CancelConn_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateServer).CancelConn(ctx, req.(*StateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _State_SendMsg_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StateServer).SendMsg(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: State_SendMsg_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StateServer).SendMsg(ctx, req.(*StateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// State_ServiceDesc is the grpc.ServiceDesc for State service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var State_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "service.state", + HandlerType: (*StateServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CancelConn", + Handler: _State_CancelConn_Handler, + }, + { + MethodName: "SendMsg", + Handler: _State_SendMsg_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "state.proto", +} diff --git a/state/server.go b/state/server.go new file mode 100644 index 0000000..8fe1b06 --- /dev/null +++ b/state/server.go @@ -0,0 +1,49 @@ +package state + +import ( + "context" + "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/prpc" + "github.com/hardcore-os/plato/state/rpc/client" + "github.com/hardcore-os/plato/state/rpc/service" + "google.golang.org/grpc" +) + +var cmdChannel chan *service.CmdContext + +func RunMain(path string) { + config.Init(path) + cmdChannel = make(chan *service.CmdContext, config.GetStateCmdChannelNum()) + + s := prpc.NewPServer( + prpc.WithServiceName(config.GetStateServiceName()), + prpc.WithIP(config.GetStateServiceAddr()), + prpc.WithPort(config.GetStateServerPort()), + prpc.WithWeight(config.GetStateRPCWeight()), + ) + s.RegisterService(func(server *grpc.Server) { + service.RegisterStateServer(server, &service.Service{CmdChannel: cmdChannel}) + }) + // init rpc client + client.Init() + // start cmd handler + go cmdHandler() + // start rpc server + s.Start(context.TODO()) +} + +func cmdHandler() { + for cmd := range cmdChannel { + switch cmd.Cmd { + case service.CancelConnCmd: + logger.CtxInfof(*cmd.Ctx, "cancelConn endpoint:%s, fd:%d, data:%+v", cmd.Endpoint, cmd.FD, cmd.PlayLoad) + case service.SendMsgCmd: + logger.CtxInfof(*cmd.Ctx, "cmdHandler: %v", string(cmd.PlayLoad)) + client.Push(cmd.Ctx, int32(cmd.FD), cmd.PlayLoad) + default: + logger.CtxInfof(*cmd.Ctx, "invalid cmd type, type=%v", cmd.Cmd) + } + + } +} From 42f279e2339b5097f932f18e7ab547559aa8ab30 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sun, 12 Nov 2023 20:07:53 +0800 Subject: [PATCH 12/26] add zap logger --- common/logger/log.go | 1 + common/logger/log_test.go | 1 + common/logger/option.go | 1 + common/logger/trace.go | 1 + 4 files changed, 4 insertions(+) create mode 100644 common/logger/log.go create mode 100644 common/logger/log_test.go create mode 100644 common/logger/option.go create mode 100644 common/logger/trace.go diff --git a/common/logger/log.go b/common/logger/log.go new file mode 100644 index 0000000..90c66f6 --- /dev/null +++ b/common/logger/log.go @@ -0,0 +1 @@ +package logger diff --git a/common/logger/log_test.go b/common/logger/log_test.go new file mode 100644 index 0000000..90c66f6 --- /dev/null +++ b/common/logger/log_test.go @@ -0,0 +1 @@ +package logger diff --git a/common/logger/option.go b/common/logger/option.go new file mode 100644 index 0000000..90c66f6 --- /dev/null +++ b/common/logger/option.go @@ -0,0 +1 @@ +package logger diff --git a/common/logger/trace.go b/common/logger/trace.go new file mode 100644 index 0000000..90c66f6 --- /dev/null +++ b/common/logger/trace.go @@ -0,0 +1 @@ +package logger From f8378378f349eb154e936e9f56cd61966ebaaae6 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sun, 12 Nov 2023 20:10:03 +0800 Subject: [PATCH 13/26] add zap logger --- common/logger/log.go | 91 +++++++++++++++++++++++++++++++++++++++ common/logger/log_test.go | 33 ++++++++++++++ common/logger/option.go | 80 ++++++++++++++++++++++++++++++++++ common/logger/trace.go | 19 ++++++++ go.mod | 6 +-- go.sum | 4 ++ plato.yaml | 4 +- 7 files changed, 232 insertions(+), 5 deletions(-) diff --git a/common/logger/log.go b/common/logger/log.go index 90c66f6..2643e85 100644 --- a/common/logger/log.go +++ b/common/logger/log.go @@ -1 +1,92 @@ package logger + +import ( + "context" + "fmt" + "github.com/hardcore-os/plato/common/config" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "os" + + "gopkg.in/natefinch/lumberjack.v2" +) + +var ( + logger = &Logger{} +) + +type Logger struct { + Options + + logger *zap.Logger +} + +func NewLogger(opts ...Option) { + logger.Options = defaultOptions + for _, o := range opts { + o.apply(&logger.Options) + } + + fileWriteSyncer := logger.getFileLogWriter() + var core zapcore.Core + encoderConfig := zap.NewProductionEncoderConfig() + encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + encoder := zapcore.NewJSONEncoder(encoderConfig) + if config.IsDebug() { + core = zapcore.NewTee( + zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.DebugLevel), + zapcore.NewCore(encoder, fileWriteSyncer, zap.DebugLevel), + ) + } else { + core = zapcore.NewTee( + zapcore.NewCore(encoder, fileWriteSyncer, zapcore.InfoLevel), + ) + } + logger.logger = zap.New(core, zap.WithCaller(true), zap.AddCallerSkip(logger.callerSkip)) +} + +func (l *Logger) getFileLogWriter() (writeSyncer zapcore.WriteSyncer) { + lumberJackLogger := &lumberjack.Logger{ + Filename: fmt.Sprintf("%s/%s", l.logDir, l.filename), + MaxSize: l.maxSize, + MaxAge: l.maxAge, + MaxBackups: l.maxBackups, + } + + return zapcore.AddSync(lumberJackLogger) +} + +// DebugCtx ... +func DebugCtx(ctx context.Context, message string, fields ...zap.Field) { + logger.logger.With(zap.String(traceID, GetTraceID(ctx))).Debug(message, fields...) +} + +// InfoCtx ... +func InfoCtx(ctx context.Context, message string, fields ...zap.Field) { + logger.logger.With(zap.String(traceID, GetTraceID(ctx))).Info(message, fields...) +} + +// WarnCtx ... +func WarnCtx(ctx context.Context, message string, fields ...zap.Field) { + logger.logger.With(zap.String(traceID, GetTraceID(ctx))).Warn(message, fields...) +} + +// ErrorCtx ... +func ErrorCtx(ctx context.Context, message string, fields ...zap.Field) { + logger.logger.With(zap.String(traceID, GetTraceID(ctx))).Error(message, fields...) +} + +// DPanicCtx ... +func DPanicCtx(ctx context.Context, message string, fields ...zap.Field) { + logger.logger.With(zap.String(traceID, GetTraceID(ctx))).DPanic(message, fields...) +} + +// PanicCtx ... +func PanicCtx(ctx context.Context, message string, fields ...zap.Field) { + logger.logger.With(zap.String(traceID, GetTraceID(ctx))).Panic(message, fields...) +} + +// FatalCtx ... +func FatalCtx(ctx context.Context, message string, fields ...zap.Field) { + logger.logger.With(zap.String(traceID, GetTraceID(ctx))).Fatal(message, fields...) +} diff --git a/common/logger/log_test.go b/common/logger/log_test.go index 90c66f6..290dfd6 100644 --- a/common/logger/log_test.go +++ b/common/logger/log_test.go @@ -1 +1,34 @@ package logger + +import ( + "context" + "github.com/hardcore-os/plato/common/config" + ptrace "github.com/hardcore-os/plato/common/prpc/trace" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + "testing" + "time" +) + +func TestLogger(t *testing.T) { + config.Init("../../plato.yaml") + NewLogger() + InfoCtx(context.Background(), "info test") + DebugCtx(context.Background(), "debug test") + WarnCtx(context.Background(), "warn test") + ErrorCtx(context.Background(), "error test") + time.Sleep(1 * time.Second) +} + +func TestTraceLog(t *testing.T) { + config.Init("../../plato.yaml") + NewLogger() + ptrace.StartAgent() + defer ptrace.StopAgent() + + tr := otel.GetTracerProvider().Tracer(ptrace.TraceName) + ctx, span := tr.Start(context.Background(), "logger-trace", trace.WithAttributes(), trace.WithSpanKind(trace.SpanKindClient)) + defer span.End() + + InfoCtx(ctx, "test") +} diff --git a/common/logger/option.go b/common/logger/option.go index 90c66f6..5febbdb 100644 --- a/common/logger/option.go +++ b/common/logger/option.go @@ -1 +1,81 @@ package logger + +var ( + defaultOptions = Options{ + logDir: "/home/dev/go_project/logs/app_logs", + filename: "default.log", + maxSize: 500, + maxAge: 1, + maxBackups: 10, + callerSkip: 1, + } +) + +type Options struct { + logDir string + filename string + maxSize int + maxBackups int + maxAge int + compress bool + callerSkip int +} + +type Option interface { + apply(*Options) +} + +type OptionFunc func(*Options) + +func (o OptionFunc) apply(opts *Options) { + o(opts) +} + +// WithLogDir ... +func WithLogDir(dir string) Option { + return OptionFunc(func(options *Options) { + options.logDir = dir + }) +} + +// WithHistoryLogFileName ... +func WithHistoryLogFileName(fileName string) Option { + return OptionFunc(func(options *Options) { + options.filename = fileName + }) +} + +// WithMaxSize ... +func WithMaxSize(size int) Option { + return OptionFunc(func(options *Options) { + options.maxSize = size + }) +} + +// WithMaxBackups ... +func WithMaxBackups(backup int) Option { + return OptionFunc(func(options *Options) { + options.maxBackups = backup + }) +} + +// WithMaxAge ... +func WithMaxAge(maxAge int) Option { + return OptionFunc(func(options *Options) { + options.maxAge = maxAge + }) +} + +// WithCompress ... +func WithCompress(b bool) Option { + return OptionFunc(func(options *Options) { + options.compress = b + }) +} + +// WithCallerSkip ... +func WithCallerSkip(skip int) Option { + return OptionFunc(func(options *Options) { + options.callerSkip = skip + }) +} diff --git a/common/logger/trace.go b/common/logger/trace.go index 90c66f6..73583e0 100644 --- a/common/logger/trace.go +++ b/common/logger/trace.go @@ -1 +1,20 @@ package logger + +import ( + "context" + "go.opentelemetry.io/otel/trace" +) + +const ( + traceID = "trace_id" +) + +func GetTraceID(ctx context.Context) string { + var traceID string + span := trace.SpanFromContext(ctx) + if span.SpanContext().TraceID().IsValid() { + traceID = span.SpanContext().TraceID().String() + } + + return traceID +} diff --git a/go.mod b/go.mod index bc9cfb3..2d86c81 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.18 replace github.com/coreos/bbolt v1.3.7 => go.etcd.io/bbolt v1.3.7 - require ( github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b github.com/cloudwego/hertz v0.7.0 @@ -77,12 +76,13 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect go.uber.org/multierr v1.10.0 // indirect - go.uber.org/zap v1.26.0 // indirect + go.uber.org/zap v1.26.0 golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.12.0 golang.org/x/text v0.11.0 // indirect google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.31.0 + gopkg.in/natefinch/lumberjack.v2 v2.0.0 ) diff --git a/go.sum b/go.sum index 18d79df..475d33c 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,7 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -619,7 +620,10 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/plato.yaml b/plato.yaml index 9c8171d..e60b79b 100644 --- a/plato.yaml +++ b/plato.yaml @@ -2,7 +2,7 @@ global: env: debug discovery: endpoints: - - localhost:2379 # 192.168.31.192:2379 + - 192.168.31.192:2379 # 192.168.31.192:2379 timeout: 5 ip_conf: service_path: /plato/ip_dispatcher @@ -10,7 +10,7 @@ prpc: discov: name: etcd endpoints: - - localhost:2379 # 192.168.31.192:2379 + - 192.168.31.192:2379 # 192.168.31.192:2379 trace: enable: true url: http://127.0.0.1:14268/api/traces From 0ebb2c37a7842761e86f67a3d52e29e282611ada Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Sun, 31 Dec 2023 16:17:21 +0800 Subject: [PATCH 14/26] add timingWheel --- common/idl/Makefile | 7 + common/idl/state/state.pb.go | 689 ++++++++++++++++++ common/idl/state/state.proto | 55 ++ common/timingwheel/README.md | 0 common/timingwheel/bucket.go | 127 ++++ common/timingwheel/delayqueue.go | 183 +++++ common/timingwheel/timeingwheel.go | 210 ++++++ .../timingwheel/timingwheel_example_test.go | 39 + common/timingwheel/timingwheel_test.go | 89 +++ common/timingwheel/utils.go | 45 ++ 10 files changed, 1444 insertions(+) create mode 100644 common/idl/Makefile create mode 100644 common/idl/state/state.pb.go create mode 100644 common/idl/state/state.proto create mode 100644 common/timingwheel/README.md create mode 100644 common/timingwheel/bucket.go create mode 100644 common/timingwheel/delayqueue.go create mode 100644 common/timingwheel/timeingwheel.go create mode 100644 common/timingwheel/timingwheel_example_test.go create mode 100644 common/timingwheel/timingwheel_test.go create mode 100644 common/timingwheel/utils.go diff --git a/common/idl/Makefile b/common/idl/Makefile new file mode 100644 index 0000000..0eeb3c2 --- /dev/null +++ b/common/idl/Makefile @@ -0,0 +1,7 @@ +all: idl + +idl: + @echo "begin" + protoc -I state --go_out=state state/*.proto + @echo "*.pb.go success" + @echo "end" \ No newline at end of file diff --git a/common/idl/state/state.pb.go b/common/idl/state/state.pb.go new file mode 100644 index 0000000..d6e2662 --- /dev/null +++ b/common/idl/state/state.pb.go @@ -0,0 +1,689 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v3.19.4 +// source: state.proto + +package pb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// cd common/idl; protoc -I state --go_out=plugins=grpc:state state/state.proto +type CmdType int32 + +const ( + CmdType_Login CmdType = 0 + CmdType_Heartbeat CmdType = 1 + CmdType_ReConn CmdType = 2 + CmdType_ACK CmdType = 3 +) + +// Enum value maps for CmdType. +var ( + CmdType_name = map[int32]string{ + 0: "Login", + 1: "Heartbeat", + 2: "ReConn", + 3: "ACK", + } + CmdType_value = map[string]int32{ + "Login": 0, + "Heartbeat": 1, + "ReConn": 2, + "ACK": 3, + } +) + +func (x CmdType) Enum() *CmdType { + p := new(CmdType) + *p = x + return p +} + +func (x CmdType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CmdType) Descriptor() protoreflect.EnumDescriptor { + return file_state_proto_enumTypes[0].Descriptor() +} + +func (CmdType) Type() protoreflect.EnumType { + return &file_state_proto_enumTypes[0] +} + +func (x CmdType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CmdType.Descriptor instead. +func (CmdType) EnumDescriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{0} +} + +// 顶层cmd pb结构 +type MsgCmd struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type CmdType `protobuf:"varint,1,opt,name=Type,proto3,enum=pb.CmdType" json:"Type,omitempty"` + Payload []byte `protobuf:"bytes,2,opt,name=Payload,proto3" json:"Payload,omitempty"` +} + +func (x *MsgCmd) Reset() { + *x = MsgCmd{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MsgCmd) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MsgCmd) ProtoMessage() {} + +func (x *MsgCmd) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MsgCmd.ProtoReflect.Descriptor instead. +func (*MsgCmd) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{0} +} + +func (x *MsgCmd) GetType() CmdType { + if x != nil { + return x.Type + } + return CmdType_Login +} + +func (x *MsgCmd) GetPayload() []byte { + if x != nil { + return x.Payload + } + return nil +} + +// 登陆消息 +type LoginMsgHead struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DeviceID uint64 `protobuf:"varint,1,opt,name=DeviceID,proto3" json:"DeviceID,omitempty"` +} + +func (x *LoginMsgHead) Reset() { + *x = LoginMsgHead{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoginMsgHead) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginMsgHead) ProtoMessage() {} + +func (x *LoginMsgHead) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginMsgHead.ProtoReflect.Descriptor instead. +func (*LoginMsgHead) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{1} +} + +func (x *LoginMsgHead) GetDeviceID() uint64 { + if x != nil { + return x.DeviceID + } + return 0 +} + +type LoginMsg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Head *LoginMsgHead `protobuf:"bytes,1,opt,name=Head,proto3" json:"Head,omitempty"` + LoginMsgBody []byte `protobuf:"bytes,2,opt,name=LoginMsgBody,proto3" json:"LoginMsgBody,omitempty"` +} + +func (x *LoginMsg) Reset() { + *x = LoginMsg{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LoginMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LoginMsg) ProtoMessage() {} + +func (x *LoginMsg) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LoginMsg.ProtoReflect.Descriptor instead. +func (*LoginMsg) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{2} +} + +func (x *LoginMsg) GetHead() *LoginMsgHead { + if x != nil { + return x.Head + } + return nil +} + +func (x *LoginMsg) GetLoginMsgBody() []byte { + if x != nil { + return x.LoginMsgBody + } + return nil +} + +// ACK 消息 +type ACKMsg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (x *ACKMsg) Reset() { + *x = ACKMsg{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ACKMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ACKMsg) ProtoMessage() {} + +func (x *ACKMsg) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ACKMsg.ProtoReflect.Descriptor instead. +func (*ACKMsg) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{3} +} + +func (x *ACKMsg) GetCode() uint32 { + if x != nil { + return x.Code + } + return 0 +} + +func (x *ACKMsg) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +// 心跳消息 +type HeartbeatMsgHead struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *HeartbeatMsgHead) Reset() { + *x = HeartbeatMsgHead{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HeartbeatMsgHead) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeartbeatMsgHead) ProtoMessage() {} + +func (x *HeartbeatMsgHead) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeartbeatMsgHead.ProtoReflect.Descriptor instead. +func (*HeartbeatMsgHead) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{4} +} + +type HeartbeatMsg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Head *HeartbeatMsgHead `protobuf:"bytes,1,opt,name=Head,proto3" json:"Head,omitempty"` + HeartbeatMsgBody []byte `protobuf:"bytes,2,opt,name=HeartbeatMsgBody,proto3" json:"HeartbeatMsgBody,omitempty"` +} + +func (x *HeartbeatMsg) Reset() { + *x = HeartbeatMsg{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HeartbeatMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeartbeatMsg) ProtoMessage() {} + +func (x *HeartbeatMsg) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeartbeatMsg.ProtoReflect.Descriptor instead. +func (*HeartbeatMsg) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{5} +} + +func (x *HeartbeatMsg) GetHead() *HeartbeatMsgHead { + if x != nil { + return x.Head + } + return nil +} + +func (x *HeartbeatMsg) GetHeartbeatMsgBody() []byte { + if x != nil { + return x.HeartbeatMsgBody + } + return nil +} + +// 重连消息 +type ReConnMsgHead struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ConnID uint64 `protobuf:"varint,1,opt,name=ConnID,proto3" json:"ConnID,omitempty"` +} + +func (x *ReConnMsgHead) Reset() { + *x = ReConnMsgHead{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReConnMsgHead) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReConnMsgHead) ProtoMessage() {} + +func (x *ReConnMsgHead) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReConnMsgHead.ProtoReflect.Descriptor instead. +func (*ReConnMsgHead) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{6} +} + +func (x *ReConnMsgHead) GetConnID() uint64 { + if x != nil { + return x.ConnID + } + return 0 +} + +type ReConnMsg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Head *ReConnMsgHead `protobuf:"bytes,1,opt,name=Head,proto3" json:"Head,omitempty"` + ReConnMsgBody []byte `protobuf:"bytes,2,opt,name=ReConnMsgBody,proto3" json:"ReConnMsgBody,omitempty"` +} + +func (x *ReConnMsg) Reset() { + *x = ReConnMsg{} + if protoimpl.UnsafeEnabled { + mi := &file_state_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReConnMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReConnMsg) ProtoMessage() {} + +func (x *ReConnMsg) ProtoReflect() protoreflect.Message { + mi := &file_state_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ReConnMsg.ProtoReflect.Descriptor instead. +func (*ReConnMsg) Descriptor() ([]byte, []int) { + return file_state_proto_rawDescGZIP(), []int{7} +} + +func (x *ReConnMsg) GetHead() *ReConnMsgHead { + if x != nil { + return x.Head + } + return nil +} + +func (x *ReConnMsg) GetReConnMsgBody() []byte { + if x != nil { + return x.ReConnMsgBody + } + return nil +} + +var File_state_proto protoreflect.FileDescriptor + +var file_state_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, + 0x62, 0x22, 0x43, 0x0a, 0x06, 0x4d, 0x73, 0x67, 0x43, 0x6d, 0x64, 0x12, 0x1f, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x43, + 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x2a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, + 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x49, 0x44, 0x22, 0x54, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x24, + 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, + 0x62, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, + 0x48, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, + 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x2e, 0x0a, 0x06, 0x41, 0x43, 0x4b, 0x4d, + 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x12, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, + 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x22, 0x64, 0x0a, 0x0c, + 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x28, 0x0a, 0x04, + 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, + 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, + 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, + 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, + 0x64, 0x79, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, + 0x65, 0x61, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x22, 0x58, 0x0a, 0x09, 0x52, + 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x25, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x43, 0x6f, + 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, + 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, + 0x67, 0x42, 0x6f, 0x64, 0x79, 0x2a, 0x38, 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x48, + 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x65, + 0x43, 0x6f, 0x6e, 0x6e, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x42, + 0x07, 0x5a, 0x05, 0x2e, 0x2f, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_state_proto_rawDescOnce sync.Once + file_state_proto_rawDescData = file_state_proto_rawDesc +) + +func file_state_proto_rawDescGZIP() []byte { + file_state_proto_rawDescOnce.Do(func() { + file_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_state_proto_rawDescData) + }) + return file_state_proto_rawDescData +} + +var file_state_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_state_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_state_proto_goTypes = []interface{}{ + (CmdType)(0), // 0: pb.CmdType + (*MsgCmd)(nil), // 1: pb.MsgCmd + (*LoginMsgHead)(nil), // 2: pb.LoginMsgHead + (*LoginMsg)(nil), // 3: pb.LoginMsg + (*ACKMsg)(nil), // 4: pb.ACKMsg + (*HeartbeatMsgHead)(nil), // 5: pb.HeartbeatMsgHead + (*HeartbeatMsg)(nil), // 6: pb.HeartbeatMsg + (*ReConnMsgHead)(nil), // 7: pb.ReConnMsgHead + (*ReConnMsg)(nil), // 8: pb.ReConnMsg +} +var file_state_proto_depIdxs = []int32{ + 0, // 0: pb.MsgCmd.Type:type_name -> pb.CmdType + 2, // 1: pb.LoginMsg.Head:type_name -> pb.LoginMsgHead + 5, // 2: pb.HeartbeatMsg.Head:type_name -> pb.HeartbeatMsgHead + 7, // 3: pb.ReConnMsg.Head:type_name -> pb.ReConnMsgHead + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_state_proto_init() } +func file_state_proto_init() { + if File_state_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_state_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MsgCmd); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_state_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginMsgHead); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_state_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginMsg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_state_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ACKMsg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_state_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HeartbeatMsgHead); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_state_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HeartbeatMsg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_state_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReConnMsgHead); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_state_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReConnMsg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_state_proto_rawDesc, + NumEnums: 1, + NumMessages: 8, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_state_proto_goTypes, + DependencyIndexes: file_state_proto_depIdxs, + EnumInfos: file_state_proto_enumTypes, + MessageInfos: file_state_proto_msgTypes, + }.Build() + File_state_proto = out.File + file_state_proto_rawDesc = nil + file_state_proto_goTypes = nil + file_state_proto_depIdxs = nil +} diff --git a/common/idl/state/state.proto b/common/idl/state/state.proto new file mode 100644 index 0000000..30cfaa7 --- /dev/null +++ b/common/idl/state/state.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; + +option go_package = "./;pb"; + +package pb; +// cd common/idl; protoc -I state --go_out=plugins=grpc:state state/state.proto +enum CmdType { //枚举消息类型 + Login = 0; + Heartbeat = 1; + ReConn = 2; + ACK = 3; +} + +// 顶层cmd pb结构 +message MsgCmd{ + CmdType Type = 1; + bytes Payload = 2; +} + + +// 登陆消息 +message LoginMsgHead { + uint64 DeviceID = 1; +} + +message LoginMsg { + LoginMsgHead Head = 1; + bytes LoginMsgBody = 2; +} + +// ACK 消息 +message ACKMsg { + uint32 code = 1; + string msg = 2; +} + + +// 心跳消息 +message HeartbeatMsgHead { +} + +message HeartbeatMsg { + HeartbeatMsgHead Head = 1; + bytes HeartbeatMsgBody = 2; +} + +// 重连消息 +message ReConnMsgHead { + uint64 ConnID = 1; +} + +message ReConnMsg { + ReConnMsgHead Head = 1; + bytes ReConnMsgBody = 2; +} diff --git a/common/timingwheel/README.md b/common/timingwheel/README.md new file mode 100644 index 0000000..e69de29 diff --git a/common/timingwheel/bucket.go b/common/timingwheel/bucket.go new file mode 100644 index 0000000..9d79cb7 --- /dev/null +++ b/common/timingwheel/bucket.go @@ -0,0 +1,127 @@ +package timingwheel + +import ( + "container/list" + "sync" + "sync/atomic" + "unsafe" +) + +type Timer struct { + expiration int64 // in milliseconds + task func() + + // The bucket that holds the list to which this timer's element belongs. + // + // NOTE: This field may be updated and read concurrently, + // through Timer.Stop() and Bucket.Flush(). + b unsafe.Pointer // type: *bucket + + // The timer's element. + element *list.Element +} + +func (t *Timer) getBucket() *bucket { + return (*bucket)(atomic.LoadPointer(&t.b)) +} + +func (t *Timer) setBucket(b *bucket) { + atomic.StorePointer(&t.b, unsafe.Pointer(b)) +} + +// Stop prevents the Timer from firing. It returns true if the call +// stops the timer, false if the timer has already expired or been stopped. +// +// If the timer t has already expired and the t.task has been started in its own +// goroutine; Stop does not wait for t.task to complete before returning. If the caller +// needs to know whether t.task is completed, it must coordinate with t.task explicitly. +func (t *Timer) Stop() bool { + stopped := false + for b := t.getBucket(); b != nil; b = t.getBucket() { + // If b.Remove is called just after the timing wheel's goroutine has: + // 1. removed t from b (through b.Flush -> b.remove) + // 2. moved t from b to another bucket ab (through b.Flush -> b.remove and ab.Add) + // this may fail to remove t due to the change of t's bucket. + stopped = b.Remove(t) + + // Thus, here we re-get t's possibly new bucket (nil for case 1, or ab (non-nil) for case 2), + // and retry until the bucket becomes nil, which indicates that t has finally been removed. + } + return stopped +} + +type bucket struct { + // 64-bit atomic operations require 64-bit alignment, but 32-bit + // compilers do not ensure it. So we must keep the 64-bit field + // as the first field of the struct. + // + // For more explanations, see https://golang.org/pkg/sync/atomic/#pkg-note-BUG + // and https://go101.org/article/memory-layout.html. + expiration int64 + + mu sync.Mutex + timers *list.List +} + +func newBucket() *bucket { + return &bucket{ + expiration: -1, + timers: list.New(), + } +} + +func (b *bucket) Expiration() int64 { + return atomic.LoadInt64(&b.expiration) +} + +func (b *bucket) SetExpiration(expiration int64) bool { + return atomic.SwapInt64(&b.expiration, expiration) != expiration +} + +func (b *bucket) Add(t *Timer) { + b.mu.Lock() + e := b.timers.PushBack(t) + t.setBucket(b) + t.element = e + + b.mu.Unlock() +} + +func (b *bucket) remove(t *Timer) bool { + if t.getBucket() != b { + return false + } + b.timers.Remove(t.element) + t.setBucket(nil) + t.element = nil + return true +} + +func (b *bucket) Remove(t *Timer) bool { + b.mu.Lock() + defer b.mu.Unlock() + + return b.remove(t) +} + +func (b *bucket) Flush(reinsert func(*Timer)) { + b.mu.Lock() + defer b.mu.Unlock() + + for e := b.timers.Front(); e != nil; { + next := e.Next() + + t := e.Value.(*Timer) + b.remove(t) + + // Note that this operation will either execute the timer's task, or + // insert the timer into another bucket belonging to a lower-level wheel. + // + // In either case, no further lock operation will happen to b.mu. + reinsert(t) + + e = next + } + + b.SetExpiration(-1) +} diff --git a/common/timingwheel/delayqueue.go b/common/timingwheel/delayqueue.go new file mode 100644 index 0000000..0ab4296 --- /dev/null +++ b/common/timingwheel/delayqueue.go @@ -0,0 +1,183 @@ +package timingwheel + +import ( + "container/heap" + "sync" + "sync/atomic" + "time" +) + +// The start of PriorityQueue implementation. +// Borrowed from https://github.com/nsqio/nsq/blob/master/internal/pqueue/pqueue.go + +type item struct { + Value interface{} + Priority int64 + Index int +} + +// this is a priority queue as implemented by a min heap +// ie. the 0th element is the *lowest* value +type priorityQueue []*item + +func newPriorityQueue(capacity int) priorityQueue { + return make(priorityQueue, 0, capacity) +} + +func (pq priorityQueue) Len() int { + return len(pq) +} + +func (pq priorityQueue) Less(i, j int) bool { + return pq[i].Priority < pq[j].Priority +} + +func (pq priorityQueue) Swap(i, j int) { + pq[i], pq[j] = pq[j], pq[i] + pq[i].Index = i + pq[j].Index = j +} + +func (pq *priorityQueue) Push(x interface{}) { + n := len(*pq) + c := cap(*pq) + + if n+1 > c { + npq := make(priorityQueue, n, c*2) + copy(npq, *pq) + *pq = npq + } + *pq = (*pq)[0 : n+1] + item := x.(*item) + item.Index = n + (*pq)[n] = item +} + +func (pq *priorityQueue) Pop() interface{} { + n := len(*pq) + c := cap(*pq) + if n < (c/2) && c > 25 { + npq := make(priorityQueue, 0, c/2) + copy(npq, *pq) + *pq = npq + } + item := (*pq)[n-1] + item.Index = -1 + *pq = (*pq)[0 : n-1] + return item +} + +func (pq *priorityQueue) PeekAndShift(max int64) (*item, int64) { + if pq.Len() == 0 { + return nil, 0 + } + + item := (*pq)[0] + if item.Priority > max { + return nil, item.Priority - max + } + heap.Remove(pq, 0) + return item, 0 +} + +// The end of PriorityQueue implementation. + +// DelayQueue is an unbounded blocking queue of *Delayed* elements, in which +// an element can only be taken when its delay has expired. The head of the +// queue is the *Delayed* element whose delay expired furthest in the past. +type DelayQueue struct { + C chan interface{} + + mu sync.Mutex + pq priorityQueue + + // Similar to the sleeping state of runtime.timers + sleeping int32 + wakeupC chan struct{} +} + +// NewDelayQueue New creates an instance of delayQueue with the specified size. +func NewDelayQueue(size int) *DelayQueue { + return &DelayQueue{ + C: make(chan interface{}), + pq: newPriorityQueue(size), + wakeupC: make(chan struct{}), + } +} + +func (dq *DelayQueue) Offer(elem interface{}, expiration int64) { + item := &item{ + Value: elem, + Priority: expiration, + } + + dq.mu.Lock() + heap.Push(&dq.pq, item) + index := item.Index + dq.mu.Unlock() + + if index == 0 { + // A new item with the earliest expiration is added + if atomic.CompareAndSwapInt32(&dq.sleeping, 1, 0) { + dq.wakeupC <- struct{}{} + } + } +} + +func (dq *DelayQueue) Poll(exitC chan struct{}, nowF func() int64) { + for { + now := nowF() + dq.mu.Lock() + item, delta := dq.pq.PeekAndShift(now) + if item == nil { + // No items left or at least one item is pending. + + // We must ensure the atomicity of the whole operation, which is + // composed of the above PeekAndShift and the following StoreInt32, + // to avoid possible race conditions between Offer and Poll. + atomic.StoreInt32(&dq.sleeping, 1) + } + dq.mu.Unlock() + + if item == nil { + if delta == 0 { + // No items left + select { + case <-dq.wakeupC: + // wait until a new item added + continue + case <-exitC: + goto exit + } + } else if delta > 0 { + select { + case <-dq.wakeupC: + // A new item with an "earlier" expiration than the current "earliest" one is added. + continue + case <-time.After(time.Duration(delta) * time.Millisecond): + // The current "earliest" item expires. + + // Reset the sleeping state since there's no need to receive from wakeupC. + if atomic.SwapInt32(&dq.sleeping, 0) == 0 { + // A caller of Offer() is being blocked on sending to wakeupC, + // drain wakeupC to unblock the caller. + <-dq.wakeupC + } + continue + case <-exitC: + goto exit + } + } + } + select { + case dq.C <- item.Value: + // The expired element has been sent out successfully. + case <-exitC: + goto exit + } + } + +exit: + // Reset the states + atomic.StoreInt32(&dq.sleeping, 0) +} diff --git a/common/timingwheel/timeingwheel.go b/common/timingwheel/timeingwheel.go new file mode 100644 index 0000000..d01f2af --- /dev/null +++ b/common/timingwheel/timeingwheel.go @@ -0,0 +1,210 @@ +package timingwheel + +import ( + "errors" + "sync/atomic" + "time" + "unsafe" +) + +// TimingWheel is an implementation of Hierarchical Timing Wheels. +type TimingWheel struct { + tick int64 // in milliseconds + wheelSize int64 + + interval int64 // in milliseconds + currentTime int64 // in milliseconds + buckets []*bucket + queue *DelayQueue + + // The higher-level overflow wheel. + // + // NOTE: This field may be updated and read concurrently, through Add(). + overflowWheel unsafe.Pointer // type: *TimingWheel + + exitC chan struct{} + waitGroup waitGroupWrapper +} + +func NewTimingWheel(tick time.Duration, wheelSize int64) *TimingWheel { + tickMs := int64(tick / time.Millisecond) + if tickMs <= 0 { + panic(errors.New("tick must be greater than or equal to 1ms")) + } + + startMs := timeToMs(time.Now().UTC()) + + return newTimingWheel( + tickMs, + wheelSize, + startMs, + NewDelayQueue(int(wheelSize)), + ) +} + +func newTimingWheel(tickMs int64, wheelSize int64, startMs int64, queue *DelayQueue) *TimingWheel { + buckets := make([]*bucket, wheelSize) + for i := range buckets { + buckets[i] = newBucket() + } + + return &TimingWheel{ + tick: tickMs, + wheelSize: wheelSize, + interval: tickMs * wheelSize, + currentTime: truncate(startMs, tickMs), + buckets: buckets, + queue: queue, + exitC: make(chan struct{}), + } +} + +// add inserts the timer t into the current timing wheel. +func (tw *TimingWheel) add(t *Timer) bool { + currentTime := atomic.LoadInt64(&tw.currentTime) + if t.expiration < currentTime+tw.tick { + return false + } else if t.expiration < currentTime+tw.interval { + // Put it into its own bucket + virtualID := t.expiration / tw.tick + b := tw.buckets[virtualID%tw.wheelSize] + b.Add(t) + + // Set the bucket expiration time + if b.SetExpiration(virtualID * tw.tick) { + // The bucket needs to be enqueued since it was an expired bucket. + // We only need to enqueue the bucket when its expiration time has changed, + // i.e. the wheel has advanced and this bucket get reused with a new expiration. + // Any further calls to set the expiration within the same wheel cycle will + // pass in the same value and hence return false, thus the bucket with the + // same expiration will not be enqueued multiple times. + tw.queue.Offer(b, b.expiration) + } + + return true + } else { + // Out of the interval. Put it into the overflow wheel + overflowWheel := atomic.LoadPointer(&tw.overflowWheel) + if overflowWheel == nil { + atomic.CompareAndSwapPointer(&tw.overflowWheel, nil, unsafe.Pointer(newTimingWheel(tw.interval, tw.wheelSize, currentTime, tw.queue))) + overflowWheel = atomic.LoadPointer(&tw.overflowWheel) + } + return (*TimingWheel)(overflowWheel).add(t) + } +} + +// addOrRun inserts the timer t into the current timing wheel, or run the +// timer's task if it has already expired. +func (tw *TimingWheel) addOrRun(t *Timer) { + if !tw.add(t) { + // Already expired + + // Like the standard time. AfterFunc (https://golang.org/pkg/time/#AfterFunc), + // always execute the timer's task in its goroutine + go t.task() + } +} + +func (tw *TimingWheel) advanceClock(expiration int64) { + currentTime := atomic.LoadInt64(&tw.currentTime) + if expiration >= currentTime+tw.tick { + currentTime = truncate(expiration, tw.tick) + atomic.StoreInt64(&tw.currentTime, currentTime) + + // Try to advance the clock of the overflow wheel if present + overflowWheel := atomic.LoadPointer(&tw.overflowWheel) + if overflowWheel != nil { + (*TimingWheel)(overflowWheel).advanceClock(currentTime) + } + } +} + +func (tw *TimingWheel) Start() { + tw.waitGroup.Wrap(func() { + tw.queue.Poll(tw.exitC, func() int64 { + return timeToMs(time.Now().UTC()) + }) + }) + + tw.waitGroup.Wrap(func() { + for { + select { + case elem := <-tw.queue.C: + b := elem.(*bucket) + tw.advanceClock(b.Expiration()) + b.Flush(tw.addOrRun) + case <-tw.exitC: + return + } + } + }) +} + +// Stop stops the current timing wheel. +// +// If there is any timer's task being running in its own goroutine, Stop does +// not wait for the task to complete before returning. If the caller needs to +// know whether the task is completed, it must coordinate with the task explicitly. +func (tw *TimingWheel) Stop() { + close(tw.exitC) + tw.waitGroup.Wait() +} + +// AfterFunc waits for the duration to elapse and then calls f in its own goroutine. +// It returns a Timer that can be used to cancel the call using its Stop method. +func (tw *TimingWheel) AfterFunc(d time.Duration, f func()) *Timer { + t := &Timer{ + expiration: timeToMs(time.Now().UTC().Add(d)), + task: f, + } + tw.addOrRun(t) + return t +} + +type Scheduler interface { + // Next returns the next execution time after the given(previous) time. + // It will return a zero time if no next it scheduled. + // + // All times must be UTC + Next(time.Time) time.Time +} + +// ScheduleFunc calls f (in its own goroutine) according to the execution +// plan scheduled by s. It returns a Timer that can be used to cancel the +// call using its Stop method. +// +// If the caller want to terminate the execution plan halfway, it must +// stop the timer and ensure that the timer is stopped actually, since in +// the current implementation, there is a gap between the expiring and the +// restarting of the timer. The wait time for ensuring is short since the +// gap is very small. +// +// Internally, ScheduleFunc will ask the first execution time (by calling +// s.Next()) initially, and create a timer if the execution time is non-zero. +// Afterward, it will ask the next execution time each time f is about to +// be executed, and f will be called at the next execution time if the time +// is non-zero. +func (tw *TimingWheel) ScheduleFunc(s Scheduler, fn func()) (t *Timer) { + expiration := s.Next(time.Now().UTC()) + if expiration.IsZero() { + // No time is scheduled, return nil + return nil + } + + t = &Timer{ + expiration: timeToMs(expiration), + task: func() { + // Schedule the task to execute at the next time if possible + expiration := s.Next(msToTime(t.expiration)) + if !expiration.IsZero() { + t.expiration = timeToMs(expiration) + tw.addOrRun(t) + } + + // Actually execute the task + fn() + }, + } + tw.addOrRun(t) + return +} diff --git a/common/timingwheel/timingwheel_example_test.go b/common/timingwheel/timingwheel_example_test.go new file mode 100644 index 0000000..a97b370 --- /dev/null +++ b/common/timingwheel/timingwheel_example_test.go @@ -0,0 +1,39 @@ +package timingwheel + +import ( + "fmt" + "time" +) + +func Example_startTimer() { + tw := NewTimingWheel(time.Millisecond, 20) + tw.Start() + defer tw.Stop() + exitC := make(chan time.Time, 1) + tw.AfterFunc(time.Second, func() { + fmt.Println("The timer fires") + exitC <- time.Now().UTC() + }) + + <-exitC + + // Output: + // The timer fires +} + +func Example_stopTimer() { + tw := NewTimingWheel(time.Millisecond, 20) + tw.Start() + defer tw.Stop() + + t := tw.AfterFunc(time.Second, func() { + fmt.Println("The timer fires") + }) + + <-time.After(900 * time.Millisecond) + // Stop the timer before it fires + t.Stop() + + // Output: + // +} diff --git a/common/timingwheel/timingwheel_test.go b/common/timingwheel/timingwheel_test.go new file mode 100644 index 0000000..c0b1a31 --- /dev/null +++ b/common/timingwheel/timingwheel_test.go @@ -0,0 +1,89 @@ +package timingwheel + +import ( + "testing" + "time" +) + +func TestTimingWheel_AfterFunc(t *testing.T) { + tw := NewTimingWheel(time.Millisecond, 20) + tw.Start() + defer tw.Stop() + + durations := []time.Duration{ + 1 * time.Millisecond, + 5 * time.Millisecond, + 10 * time.Millisecond, + 50 * time.Millisecond, + 100 * time.Millisecond, + 500 * time.Millisecond, + 1 * time.Second, + } + for _, d := range durations { + t.Run("", func(t *testing.T) { + exitC := make(chan time.Time) + + start := time.Now().UTC() + tw.AfterFunc(d, func() { + exitC <- time.Now().UTC() + }) + + got := (<-exitC).Truncate(time.Millisecond) + min := start.Add(d).Truncate(time.Millisecond) + + err := 5 * time.Millisecond + if got.Before(min) || got.After(min.Add(err)) { + t.Errorf("Timer(%s) expiration: want [%s, %s], got %s", d, min, min.Add(err), got) + } + }) + } +} + +type scheduler struct { + intervals []time.Duration + current int +} + +func (s *scheduler) Next(prev time.Time) time.Time { + if s.current >= len(s.intervals) { + return time.Time{} + } + next := prev.Add(s.intervals[s.current]) + s.current += 1 + return next +} + +func TestTimingWheel_ScheduleFunc(t *testing.T) { + tw := NewTimingWheel(time.Millisecond, 20) + tw.Start() + defer tw.Stop() + + s := &scheduler{intervals: []time.Duration{ + 1 * time.Millisecond, // start + 1ms + 4 * time.Millisecond, // start + 5ms + 5 * time.Millisecond, // start + 10ms + 40 * time.Millisecond, // start + 50ms + 50 * time.Millisecond, // start + 100ms + 400 * time.Millisecond, // start + 500ms + 500 * time.Millisecond, // start + 1s + }} + + exitC := make(chan time.Time, len(s.intervals)) + + start := time.Now().UTC() + tw.ScheduleFunc(s, func() { + exitC <- time.Now().UTC() + }) + + accum := time.Duration(0) + for _, d := range s.intervals { + got := (<-exitC).Truncate(time.Millisecond) + accum += d + min := start.Add(accum).Truncate(time.Millisecond) + + err := 5 * time.Millisecond + if got.Before(min) || got.After(min.Add(err)) { + t.Errorf("Timer(%s) expiration: want [%s, %s], got %s", accum, min, min.Add(err), got) + } + } +} diff --git a/common/timingwheel/utils.go b/common/timingwheel/utils.go new file mode 100644 index 0000000..ea2f2b2 --- /dev/null +++ b/common/timingwheel/utils.go @@ -0,0 +1,45 @@ +package timingwheel + +import ( + "fmt" + "sync" + "time" +) + +// truncate returns the result of rounding x toward zero to a multiple of m. +// If m <= 0, Truncate returns x unchanged. +func truncate(x, m int64) int64 { + if m <= 0 { + return x + } + return x - x%m +} + +// timeToMs returns an integer number, which represents t in milliseconds. +func timeToMs(t time.Time) int64 { + return t.UnixNano() / int64(time.Millisecond) +} + +// msToTime returns the UTC time corresponding to the given Unix time, +// t milliseconds since January 1, 1970 UTC. +func msToTime(t int64) time.Time { + return time.Unix(0, t*int64(time.Millisecond)).UTC() +} + +type waitGroupWrapper struct { + sync.WaitGroup +} + +func (w *waitGroupWrapper) Wrap(cb func()) { + w.Add(1) + go func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf("execute func panic: %+v", r) + } + }() + + cb() + w.Done() + }() +} From fab2d2ddc3be5ca359baf141b882c28332926dc1 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Mon, 1 Jan 2024 16:08:21 +0800 Subject: [PATCH 15/26] add connection available --- chat.log | 26 +- client/cui.go | 22 +- common/config/state.go | 10 +- common/idl/Makefile | 2 +- .../state.pb.go => message/message.pb.go} | 375 ++++++++++-------- .../state.proto => message/message.proto} | 20 +- .../interceptor/client/breaker_interceptor.go | 2 +- common/sdk/api.go | 123 +++++- common/sdk/logic.go | 1 - common/sdk/net.go | 77 ++-- common/timingwheel/delayqueue.go | 4 +- gateway/connection.go | 25 +- gateway/epoll.go | 17 +- gateway/rpc/client/state.go | 14 +- gateway/rpc/service/gateway.pb.go | 44 +- gateway/rpc/service/gateway.proto | 2 +- gateway/rpc/service/service.go | 22 +- gateway/server.go | 15 +- perf/perf.go | 2 +- plato.yaml | 2 +- state/rpc/client/gateway.go | 16 +- state/rpc/service/service.go | 14 +- state/rpc/service/state.pb.go | 50 +-- state/rpc/service/state.proto | 2 +- state/rpc/service/state_grpc.pb.go | 10 +- state/server.go | 128 +++++- state/state.go | 45 +++ state/timer.go | 23 ++ 28 files changed, 747 insertions(+), 346 deletions(-) rename common/idl/{state/state.pb.go => message/message.pb.go} (57%) rename common/idl/{state/state.proto => message/message.proto} (74%) delete mode 100644 common/sdk/logic.go create mode 100644 state/state.go create mode 100644 state/timer.go diff --git a/chat.log b/chat.log index 407e992..e405450 100644 --- a/chat.log +++ b/chat.log @@ -1,3 +1,25 @@ -me: 1111 -logic: 1111 +me: 111 +logic: 111 +logic: 222 +me: 222 +me: 33333 +logic: 33333 +me: 22222 +logic: 22222 +me: 2212 +logic: 2212 +logic: 333 +me: 333 +logic: 122321 +me: 122321 +me: 312312 +logic: 312312 +logic: 312312 +me: 312312 +me: 3123123 +logic: 3123123 +logic: 3123213 +me: 3123213 +me: 312321 +logic: 312321 diff --git a/client/cui.go b/client/cui.go index abe663c..0479542 100644 --- a/client/cui.go +++ b/client/cui.go @@ -64,12 +64,8 @@ func viewPrint(g *gocui.Gui, name, msg string, newline bool) { func doRecv(g *gocui.Gui) { recvChannel := chat.Recv() for msg := range recvChannel { - switch msg.Type { - case sdk.MsgTypeText: - viewPrint(g, msg.Name, msg.Content, false) - } + viewPrint(g, msg.Name, msg.Content, false) } - g.Close() } func quit(g *gocui.Gui, v *gocui.View) error { @@ -169,7 +165,7 @@ func viewHead(g *gocui.Gui, x0, y0, x1, y1 int) error { } v.Wrap = false v.Overwrite = true - msg := "开始聊天了!" + msg := "Plato: IM系统聊天对话框" setHeadText(g, msg) } return nil @@ -224,7 +220,7 @@ func pasteDown(g *gocui.Gui, cv *gocui.View) error { func RunMain() { // step1 创建caht的核心对象 - chat = sdk.NewChat(net.ParseIP("0.0.0.0"), 8900, "logic", "12312321", "2131") + chat = sdk.NewChat(net.ParseIP("0.0.0.0"), 8900, "logic", "12312321", "2131", 0, false) // step2 创建 GUI 图层对象并进行参与与回调函数的配置 g, err := gocui.NewGui(gocui.OutputNormal) if err != nil { @@ -257,6 +253,18 @@ func RunMain() { if err := g.SetKeybinding("main", gocui.KeyArrowUp, gocui.ModNone, pasteUP); err != nil { log.Panicln(err) } + + // emit disconnection + go func() { + time.Sleep(10 * time.Second) + chat.Close() + time.Sleep(3 * time.Second) + connID := chat.GetConnID() + // reconnection + chat = sdk.NewChat(net.ParseIP("0.0.0.0"), 8900, "logic", "12312321", "2131", connID, true) + go doRecv(g) + }() + // 启动消费函数 go doRecv(g) if err := g.MainLoop(); err != nil { diff --git a/common/config/state.go b/common/config/state.go index 18b2c0f..54286c0 100644 --- a/common/config/state.go +++ b/common/config/state.go @@ -3,21 +3,21 @@ package config import "github.com/spf13/viper" func GetStateCmdChannelNum() int { - return viper.GetInt("state.cmd_channel_num") + return viper.GetInt("message.cmd_channel_num") } func GetStateServiceAddr() string { - return viper.GetString("state.servide_addr") + return viper.GetString("message.servide_addr") } func GetStateServiceName() string { - return viper.GetString("state.service_name") + return viper.GetString("message.service_name") } func GetStateServerPort() int { - return viper.GetInt("state.server_port") + return viper.GetInt("message.server_port") } func GetStateRPCWeight() int { - return viper.GetInt("state.weight") + return viper.GetInt("message.weight") } diff --git a/common/idl/Makefile b/common/idl/Makefile index 0eeb3c2..6cf3c4a 100644 --- a/common/idl/Makefile +++ b/common/idl/Makefile @@ -2,6 +2,6 @@ all: idl idl: @echo "begin" - protoc -I state --go_out=state state/*.proto + protoc -I message --go_out=message message/*.proto @echo "*.pb.go success" @echo "end" \ No newline at end of file diff --git a/common/idl/state/state.pb.go b/common/idl/message/message.pb.go similarity index 57% rename from common/idl/state/state.pb.go rename to common/idl/message/message.pb.go index d6e2662..33bced2 100644 --- a/common/idl/state/state.pb.go +++ b/common/idl/message/message.pb.go @@ -2,9 +2,9 @@ // versions: // protoc-gen-go v1.31.0 // protoc v3.19.4 -// source: state.proto +// source: message.proto -package pb +package message import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -20,7 +20,7 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// cd common/idl; protoc -I state --go_out=plugins=grpc:state state/state.proto +// cd common/idl; protoc -I message --go_out=plugins=grpc:message message/message.proto type CmdType int32 const ( @@ -57,11 +57,11 @@ func (x CmdType) String() string { } func (CmdType) Descriptor() protoreflect.EnumDescriptor { - return file_state_proto_enumTypes[0].Descriptor() + return file_message_proto_enumTypes[0].Descriptor() } func (CmdType) Type() protoreflect.EnumType { - return &file_state_proto_enumTypes[0] + return &file_message_proto_enumTypes[0] } func (x CmdType) Number() protoreflect.EnumNumber { @@ -70,7 +70,7 @@ func (x CmdType) Number() protoreflect.EnumNumber { // Deprecated: Use CmdType.Descriptor instead. func (CmdType) EnumDescriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{0} + return file_message_proto_rawDescGZIP(), []int{0} } // 顶层cmd pb结构 @@ -79,14 +79,14 @@ type MsgCmd struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Type CmdType `protobuf:"varint,1,opt,name=Type,proto3,enum=pb.CmdType" json:"Type,omitempty"` + Type CmdType `protobuf:"varint,1,opt,name=Type,proto3,enum=message.CmdType" json:"Type,omitempty"` Payload []byte `protobuf:"bytes,2,opt,name=Payload,proto3" json:"Payload,omitempty"` } func (x *MsgCmd) Reset() { *x = MsgCmd{} if protoimpl.UnsafeEnabled { - mi := &file_state_proto_msgTypes[0] + mi := &file_message_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -99,7 +99,7 @@ func (x *MsgCmd) String() string { func (*MsgCmd) ProtoMessage() {} func (x *MsgCmd) ProtoReflect() protoreflect.Message { - mi := &file_state_proto_msgTypes[0] + mi := &file_message_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -112,7 +112,7 @@ func (x *MsgCmd) ProtoReflect() protoreflect.Message { // Deprecated: Use MsgCmd.ProtoReflect.Descriptor instead. func (*MsgCmd) Descriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{0} + return file_message_proto_rawDescGZIP(), []int{0} } func (x *MsgCmd) GetType() CmdType { @@ -129,32 +129,35 @@ func (x *MsgCmd) GetPayload() []byte { return nil } -// 登陆消息 -type LoginMsgHead struct { +// ACK 消息 +type ACKMsg struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - DeviceID uint64 `protobuf:"varint,1,opt,name=DeviceID,proto3" json:"DeviceID,omitempty"` + Code uint32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"` + Type CmdType `protobuf:"varint,3,opt,name=Type,proto3,enum=message.CmdType" json:"Type,omitempty"` + ConnID uint64 `protobuf:"varint,4,opt,name=ConnID,proto3" json:"ConnID,omitempty"` } -func (x *LoginMsgHead) Reset() { - *x = LoginMsgHead{} +func (x *ACKMsg) Reset() { + *x = ACKMsg{} if protoimpl.UnsafeEnabled { - mi := &file_state_proto_msgTypes[1] + mi := &file_message_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *LoginMsgHead) String() string { +func (x *ACKMsg) String() string { return protoimpl.X.MessageStringOf(x) } -func (*LoginMsgHead) ProtoMessage() {} +func (*ACKMsg) ProtoMessage() {} -func (x *LoginMsgHead) ProtoReflect() protoreflect.Message { - mi := &file_state_proto_msgTypes[1] +func (x *ACKMsg) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -165,44 +168,65 @@ func (x *LoginMsgHead) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use LoginMsgHead.ProtoReflect.Descriptor instead. -func (*LoginMsgHead) Descriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{1} +// Deprecated: Use ACKMsg.ProtoReflect.Descriptor instead. +func (*ACKMsg) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{1} } -func (x *LoginMsgHead) GetDeviceID() uint64 { +func (x *ACKMsg) GetCode() uint32 { if x != nil { - return x.DeviceID + return x.Code } return 0 } -type LoginMsg struct { +func (x *ACKMsg) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +func (x *ACKMsg) GetType() CmdType { + if x != nil { + return x.Type + } + return CmdType_Login +} + +func (x *ACKMsg) GetConnID() uint64 { + if x != nil { + return x.ConnID + } + return 0 +} + +// 登陆消息 +type LoginMsgHead struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Head *LoginMsgHead `protobuf:"bytes,1,opt,name=Head,proto3" json:"Head,omitempty"` - LoginMsgBody []byte `protobuf:"bytes,2,opt,name=LoginMsgBody,proto3" json:"LoginMsgBody,omitempty"` + DeviceID uint64 `protobuf:"varint,1,opt,name=DeviceID,proto3" json:"DeviceID,omitempty"` } -func (x *LoginMsg) Reset() { - *x = LoginMsg{} +func (x *LoginMsgHead) Reset() { + *x = LoginMsgHead{} if protoimpl.UnsafeEnabled { - mi := &file_state_proto_msgTypes[2] + mi := &file_message_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *LoginMsg) String() string { +func (x *LoginMsgHead) String() string { return protoimpl.X.MessageStringOf(x) } -func (*LoginMsg) ProtoMessage() {} +func (*LoginMsgHead) ProtoMessage() {} -func (x *LoginMsg) ProtoReflect() protoreflect.Message { - mi := &file_state_proto_msgTypes[2] +func (x *LoginMsgHead) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -213,52 +237,44 @@ func (x *LoginMsg) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use LoginMsg.ProtoReflect.Descriptor instead. -func (*LoginMsg) Descriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{2} -} - -func (x *LoginMsg) GetHead() *LoginMsgHead { - if x != nil { - return x.Head - } - return nil +// Deprecated: Use LoginMsgHead.ProtoReflect.Descriptor instead. +func (*LoginMsgHead) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{2} } -func (x *LoginMsg) GetLoginMsgBody() []byte { +func (x *LoginMsgHead) GetDeviceID() uint64 { if x != nil { - return x.LoginMsgBody + return x.DeviceID } - return nil + return 0 } -// ACK 消息 -type ACKMsg struct { +type LoginMsg struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` - Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` + Head *LoginMsgHead `protobuf:"bytes,1,opt,name=Head,proto3" json:"Head,omitempty"` + LoginMsgBody []byte `protobuf:"bytes,2,opt,name=LoginMsgBody,proto3" json:"LoginMsgBody,omitempty"` } -func (x *ACKMsg) Reset() { - *x = ACKMsg{} +func (x *LoginMsg) Reset() { + *x = LoginMsg{} if protoimpl.UnsafeEnabled { - mi := &file_state_proto_msgTypes[3] + mi := &file_message_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *ACKMsg) String() string { +func (x *LoginMsg) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ACKMsg) ProtoMessage() {} +func (*LoginMsg) ProtoMessage() {} -func (x *ACKMsg) ProtoReflect() protoreflect.Message { - mi := &file_state_proto_msgTypes[3] +func (x *LoginMsg) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -269,23 +285,23 @@ func (x *ACKMsg) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ACKMsg.ProtoReflect.Descriptor instead. -func (*ACKMsg) Descriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{3} +// Deprecated: Use LoginMsg.ProtoReflect.Descriptor instead. +func (*LoginMsg) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{3} } -func (x *ACKMsg) GetCode() uint32 { +func (x *LoginMsg) GetHead() *LoginMsgHead { if x != nil { - return x.Code + return x.Head } - return 0 + return nil } -func (x *ACKMsg) GetMsg() string { +func (x *LoginMsg) GetLoginMsgBody() []byte { if x != nil { - return x.Msg + return x.LoginMsgBody } - return "" + return nil } // 心跳消息 @@ -298,7 +314,7 @@ type HeartbeatMsgHead struct { func (x *HeartbeatMsgHead) Reset() { *x = HeartbeatMsgHead{} if protoimpl.UnsafeEnabled { - mi := &file_state_proto_msgTypes[4] + mi := &file_message_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -311,7 +327,7 @@ func (x *HeartbeatMsgHead) String() string { func (*HeartbeatMsgHead) ProtoMessage() {} func (x *HeartbeatMsgHead) ProtoReflect() protoreflect.Message { - mi := &file_state_proto_msgTypes[4] + mi := &file_message_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -324,7 +340,7 @@ func (x *HeartbeatMsgHead) ProtoReflect() protoreflect.Message { // Deprecated: Use HeartbeatMsgHead.ProtoReflect.Descriptor instead. func (*HeartbeatMsgHead) Descriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{4} + return file_message_proto_rawDescGZIP(), []int{4} } type HeartbeatMsg struct { @@ -339,7 +355,7 @@ type HeartbeatMsg struct { func (x *HeartbeatMsg) Reset() { *x = HeartbeatMsg{} if protoimpl.UnsafeEnabled { - mi := &file_state_proto_msgTypes[5] + mi := &file_message_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -352,7 +368,7 @@ func (x *HeartbeatMsg) String() string { func (*HeartbeatMsg) ProtoMessage() {} func (x *HeartbeatMsg) ProtoReflect() protoreflect.Message { - mi := &file_state_proto_msgTypes[5] + mi := &file_message_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -365,7 +381,7 @@ func (x *HeartbeatMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use HeartbeatMsg.ProtoReflect.Descriptor instead. func (*HeartbeatMsg) Descriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{5} + return file_message_proto_rawDescGZIP(), []int{5} } func (x *HeartbeatMsg) GetHead() *HeartbeatMsgHead { @@ -394,7 +410,7 @@ type ReConnMsgHead struct { func (x *ReConnMsgHead) Reset() { *x = ReConnMsgHead{} if protoimpl.UnsafeEnabled { - mi := &file_state_proto_msgTypes[6] + mi := &file_message_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -407,7 +423,7 @@ func (x *ReConnMsgHead) String() string { func (*ReConnMsgHead) ProtoMessage() {} func (x *ReConnMsgHead) ProtoReflect() protoreflect.Message { - mi := &file_state_proto_msgTypes[6] + mi := &file_message_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -420,7 +436,7 @@ func (x *ReConnMsgHead) ProtoReflect() protoreflect.Message { // Deprecated: Use ReConnMsgHead.ProtoReflect.Descriptor instead. func (*ReConnMsgHead) Descriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{6} + return file_message_proto_rawDescGZIP(), []int{6} } func (x *ReConnMsgHead) GetConnID() uint64 { @@ -442,7 +458,7 @@ type ReConnMsg struct { func (x *ReConnMsg) Reset() { *x = ReConnMsg{} if protoimpl.UnsafeEnabled { - mi := &file_state_proto_msgTypes[7] + mi := &file_message_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -455,7 +471,7 @@ func (x *ReConnMsg) String() string { func (*ReConnMsg) ProtoMessage() {} func (x *ReConnMsg) ProtoReflect() protoreflect.Message { - mi := &file_state_proto_msgTypes[7] + mi := &file_message_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -468,7 +484,7 @@ func (x *ReConnMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use ReConnMsg.ProtoReflect.Descriptor instead. func (*ReConnMsg) Descriptor() ([]byte, []int) { - return file_state_proto_rawDescGZIP(), []int{7} + return file_message_proto_rawDescGZIP(), []int{7} } func (x *ReConnMsg) GetHead() *ReConnMsgHead { @@ -485,92 +501,99 @@ func (x *ReConnMsg) GetReConnMsgBody() []byte { return nil } -var File_state_proto protoreflect.FileDescriptor - -var file_state_proto_rawDesc = []byte{ - 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02, 0x70, - 0x62, 0x22, 0x43, 0x0a, 0x06, 0x4d, 0x73, 0x67, 0x43, 0x6d, 0x64, 0x12, 0x1f, 0x0a, 0x04, 0x54, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x43, - 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, - 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x2a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, - 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x49, 0x44, 0x22, 0x54, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x24, - 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, - 0x62, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, - 0x48, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, - 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x2e, 0x0a, 0x06, 0x41, 0x43, 0x4b, 0x4d, - 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, - 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x22, 0x12, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, - 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x22, 0x64, 0x0a, 0x0c, - 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x28, 0x0a, 0x04, - 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x62, 0x2e, - 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, - 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, - 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, - 0x64, 0x79, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, - 0x65, 0x61, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x22, 0x58, 0x0a, 0x09, 0x52, - 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x25, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, 0x43, 0x6f, - 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, - 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, - 0x67, 0x42, 0x6f, 0x64, 0x79, 0x2a, 0x38, 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x48, - 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x65, - 0x43, 0x6f, 0x6e, 0x6e, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x42, - 0x07, 0x5a, 0x05, 0x2e, 0x2f, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +var File_message_proto protoreflect.FileDescriptor + +var file_message_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x48, 0x0a, 0x06, 0x4d, 0x73, 0x67, 0x43, + 0x6d, 0x64, 0x12, 0x24, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x10, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6d, 0x64, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x22, 0x6c, 0x0a, 0x06, 0x41, 0x43, 0x4b, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, + 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, + 0x73, 0x67, 0x12, 0x24, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x10, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6d, 0x64, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, + 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, + 0x22, 0x2a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x22, 0x59, 0x0a, 0x08, + 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x29, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, + 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x42, + 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x12, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, + 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x22, 0x69, 0x0a, 0x0c, 0x48, + 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x2d, 0x0a, 0x04, 0x48, + 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, + 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x48, 0x65, + 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, + 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, + 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, + 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x22, + 0x5d, 0x0a, 0x09, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x2a, 0x0a, 0x04, + 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, + 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, + 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x2a, 0x38, + 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, + 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x10, 0x02, 0x12, + 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x3b, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( - file_state_proto_rawDescOnce sync.Once - file_state_proto_rawDescData = file_state_proto_rawDesc + file_message_proto_rawDescOnce sync.Once + file_message_proto_rawDescData = file_message_proto_rawDesc ) -func file_state_proto_rawDescGZIP() []byte { - file_state_proto_rawDescOnce.Do(func() { - file_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_state_proto_rawDescData) +func file_message_proto_rawDescGZIP() []byte { + file_message_proto_rawDescOnce.Do(func() { + file_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_message_proto_rawDescData) }) - return file_state_proto_rawDescData -} - -var file_state_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_state_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_state_proto_goTypes = []interface{}{ - (CmdType)(0), // 0: pb.CmdType - (*MsgCmd)(nil), // 1: pb.MsgCmd - (*LoginMsgHead)(nil), // 2: pb.LoginMsgHead - (*LoginMsg)(nil), // 3: pb.LoginMsg - (*ACKMsg)(nil), // 4: pb.ACKMsg - (*HeartbeatMsgHead)(nil), // 5: pb.HeartbeatMsgHead - (*HeartbeatMsg)(nil), // 6: pb.HeartbeatMsg - (*ReConnMsgHead)(nil), // 7: pb.ReConnMsgHead - (*ReConnMsg)(nil), // 8: pb.ReConnMsg -} -var file_state_proto_depIdxs = []int32{ - 0, // 0: pb.MsgCmd.Type:type_name -> pb.CmdType - 2, // 1: pb.LoginMsg.Head:type_name -> pb.LoginMsgHead - 5, // 2: pb.HeartbeatMsg.Head:type_name -> pb.HeartbeatMsgHead - 7, // 3: pb.ReConnMsg.Head:type_name -> pb.ReConnMsgHead - 4, // [4:4] is the sub-list for method output_type - 4, // [4:4] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name -} - -func init() { file_state_proto_init() } -func file_state_proto_init() { - if File_state_proto != nil { + return file_message_proto_rawDescData +} + +var file_message_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_message_proto_goTypes = []interface{}{ + (CmdType)(0), // 0: message.CmdType + (*MsgCmd)(nil), // 1: message.MsgCmd + (*ACKMsg)(nil), // 2: message.ACKMsg + (*LoginMsgHead)(nil), // 3: message.LoginMsgHead + (*LoginMsg)(nil), // 4: message.LoginMsg + (*HeartbeatMsgHead)(nil), // 5: message.HeartbeatMsgHead + (*HeartbeatMsg)(nil), // 6: message.HeartbeatMsg + (*ReConnMsgHead)(nil), // 7: message.ReConnMsgHead + (*ReConnMsg)(nil), // 8: message.ReConnMsg +} +var file_message_proto_depIdxs = []int32{ + 0, // 0: message.MsgCmd.Type:type_name -> message.CmdType + 0, // 1: message.ACKMsg.Type:type_name -> message.CmdType + 3, // 2: message.LoginMsg.Head:type_name -> message.LoginMsgHead + 5, // 3: message.HeartbeatMsg.Head:type_name -> message.HeartbeatMsgHead + 7, // 4: message.ReConnMsg.Head:type_name -> message.ReConnMsgHead + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_message_proto_init() } +func file_message_proto_init() { + if File_message_proto != nil { return } if !protoimpl.UnsafeEnabled { - file_state_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*MsgCmd); i { case 0: return &v.state @@ -582,8 +605,8 @@ func file_state_proto_init() { return nil } } - file_state_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginMsgHead); i { + file_message_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ACKMsg); i { case 0: return &v.state case 1: @@ -594,8 +617,8 @@ func file_state_proto_init() { return nil } } - file_state_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginMsg); i { + file_message_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginMsgHead); i { case 0: return &v.state case 1: @@ -606,8 +629,8 @@ func file_state_proto_init() { return nil } } - file_state_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ACKMsg); i { + file_message_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LoginMsg); i { case 0: return &v.state case 1: @@ -618,7 +641,7 @@ func file_state_proto_init() { return nil } } - file_state_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_message_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HeartbeatMsgHead); i { case 0: return &v.state @@ -630,7 +653,7 @@ func file_state_proto_init() { return nil } } - file_state_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_message_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*HeartbeatMsg); i { case 0: return &v.state @@ -642,7 +665,7 @@ func file_state_proto_init() { return nil } } - file_state_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_message_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReConnMsgHead); i { case 0: return &v.state @@ -654,7 +677,7 @@ func file_state_proto_init() { return nil } } - file_state_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_message_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReConnMsg); i { case 0: return &v.state @@ -671,19 +694,19 @@ func file_state_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_state_proto_rawDesc, + RawDescriptor: file_message_proto_rawDesc, NumEnums: 1, NumMessages: 8, NumExtensions: 0, NumServices: 0, }, - GoTypes: file_state_proto_goTypes, - DependencyIndexes: file_state_proto_depIdxs, - EnumInfos: file_state_proto_enumTypes, - MessageInfos: file_state_proto_msgTypes, + GoTypes: file_message_proto_goTypes, + DependencyIndexes: file_message_proto_depIdxs, + EnumInfos: file_message_proto_enumTypes, + MessageInfos: file_message_proto_msgTypes, }.Build() - File_state_proto = out.File - file_state_proto_rawDesc = nil - file_state_proto_goTypes = nil - file_state_proto_depIdxs = nil + File_message_proto = out.File + file_message_proto_rawDesc = nil + file_message_proto_goTypes = nil + file_message_proto_depIdxs = nil } diff --git a/common/idl/state/state.proto b/common/idl/message/message.proto similarity index 74% rename from common/idl/state/state.proto rename to common/idl/message/message.proto index 30cfaa7..3c2b684 100644 --- a/common/idl/state/state.proto +++ b/common/idl/message/message.proto @@ -1,9 +1,9 @@ syntax = "proto3"; -option go_package = "./;pb"; +option go_package = "./;message"; -package pb; -// cd common/idl; protoc -I state --go_out=plugins=grpc:state state/state.proto +package message; +// cd common/idl; protoc -I message --go_out=plugins=grpc:message message/message.proto enum CmdType { //枚举消息类型 Login = 0; Heartbeat = 1; @@ -17,6 +17,13 @@ message MsgCmd{ bytes Payload = 2; } +// ACK 消息 +message ACKMsg { + uint32 Code = 1; + string Msg = 2; + CmdType Type = 3; + uint64 ConnID = 4; +} // 登陆消息 message LoginMsgHead { @@ -28,13 +35,6 @@ message LoginMsg { bytes LoginMsgBody = 2; } -// ACK 消息 -message ACKMsg { - uint32 code = 1; - string msg = 2; -} - - // 心跳消息 message HeartbeatMsgHead { } diff --git a/common/prpc/interceptor/client/breaker_interceptor.go b/common/prpc/interceptor/client/breaker_interceptor.go index 2fa5124..88e9b24 100644 --- a/common/prpc/interceptor/client/breaker_interceptor.go +++ b/common/prpc/interceptor/client/breaker_interceptor.go @@ -28,7 +28,7 @@ func BreakerUnaryClientInterceptor(name string, maxRequest uint32, interval, tim } }, OnStateChange: func(name string, from gobreaker.State, to gobreaker.State) { - logger.Errorf("name:%s,old state:%s,new state:%s", name, from, to) + logger.Errorf("name:%s,old message:%s,new message:%s", name, from, to) }, }) diff --git a/common/sdk/api.go b/common/sdk/api.go index 8a58abe..4203f39 100644 --- a/common/sdk/api.go +++ b/common/sdk/api.go @@ -1,9 +1,20 @@ package sdk -import "net" +import ( + "fmt" + "github.com/golang/protobuf/proto" + "github.com/hardcore-os/plato/common/idl/message" + "github.com/hardcore-os/plato/common/tcp" + "net" + "time" +) const ( - MsgTypeText = "text" + MsgTypeText = "text" + MsgTypeAck = "ack" + MsgTypeReConn = "reConn" + MsgTypeHeartbeat = "heartbeat" + MsgLogin = "loginMsg" ) type Chat struct { @@ -11,6 +22,7 @@ type Chat struct { UserID string SessionID string conn *connect + closeChan chan struct{} } type Message struct { @@ -22,24 +34,123 @@ type Message struct { Session string } -func NewChat(ip net.IP, port int, nick, userID, sessionID string) *Chat { - return &Chat{ +func NewChat(ip net.IP, port int, nick, userID, sessionID string, connID uint64, isReConn bool) *Chat { + chat := &Chat{ Nick: nick, UserID: userID, SessionID: sessionID, - conn: newConnet(ip, port), + conn: newConnet(ip, port, connID), + closeChan: make(chan struct{}, 0), + } + go chat.loop() + if isReConn { + chat.reConn(connID) + } else { + chat.login() } + go chat.heartbeat() + return chat } + func (chat *Chat) Send(msg *Message) { - chat.conn.send(msg) + //chat.conn.send(msg) + chat.conn.recvChan <- msg } // Close chat func (chat *Chat) Close() { chat.conn.close() + close(chat.closeChan) + close(chat.conn.sendChan) + close(chat.conn.recvChan) +} + +func (chat *Chat) GetConnID() uint64 { + return chat.conn.connID } // Recv receive message func (chat *Chat) Recv() <-chan *Message { return chat.conn.recv() } + +func (chat *Chat) loop() { + defer func() { + if r := recover(); r != nil { + fmt.Printf("[chat] loop panic, err=%v\n", r) + } + }() + for { + select { + case <-chat.closeChan: + return + default: + mc := &message.MsgCmd{} + data, err := tcp.ReadData(chat.conn.conn) + if err != nil { + fmt.Printf("[chat] loop: read data from conn err=%v, data=%v\n", err, string(data)) + continue + } + err = proto.Unmarshal(data, mc) + if err != nil { + fmt.Printf("[chat] loop: Unmarshal data failed, err=%v, data=%v\n", string(data)) + continue + } + var msg *Message + switch mc.Type { + case message.CmdType_ACK: + msg = handAckMsg(chat.conn, mc.Payload) + } + chat.conn.recvChan <- msg + } + } +} + +func (chat *Chat) login() { + loginMsg := message.LoginMsg{ + Head: &message.LoginMsgHead{ + DeviceID: 123, + }, + } + payload, err := proto.Marshal(&loginMsg) + if err != nil { + fmt.Printf("[chat] login, marshal msg failed, err=%v, loginMsg.Head=%+v, loginMsg.Body=%+v\n", err, loginMsg.Head, loginMsg.LoginMsgBody) + return + } + chat.conn.send(message.CmdType_Login, payload) +} + +func (chat *Chat) reConn(connID uint64) { + reConn := message.ReConnMsg{ + Head: &message.ReConnMsgHead{ + ConnID: connID, + }, + } + payload, err := proto.Marshal(&reConn) + if err != nil { + fmt.Printf("[chat] login, marshal msg failed, err=%v, ReConnMsg.Head=%+v, ReConnMsg.Body=%+v\n", err, reConn.Head, reConn.ReConnMsgBody) + return + } + chat.conn.send(message.CmdType_ReConn, payload) + +} + +func (chat *Chat) heartbeat() { + tc := time.NewTicker(1 * time.Second) + for { + select { + case <-chat.closeChan: + return + case <-tc.C: + heartbeat := message.HeartbeatMsg{ + Head: &message.HeartbeatMsgHead{}, + } + payload, err := proto.Marshal(&heartbeat) + if err != nil { + fmt.Printf("[chat] heartbeat, marshal msg failed, err=%v\n", err) + return + } + chat.conn.send(message.CmdType_Heartbeat, payload) + } + } +} diff --git a/common/sdk/logic.go b/common/sdk/logic.go deleted file mode 100644 index 0919fd1..0000000 --- a/common/sdk/logic.go +++ /dev/null @@ -1 +0,0 @@ -package sdk diff --git a/common/sdk/net.go b/common/sdk/net.go index 356f374..2180bb9 100644 --- a/common/sdk/net.go +++ b/common/sdk/net.go @@ -1,7 +1,9 @@ package sdk import ( - "encoding/json" + "fmt" + "github.com/golang/protobuf/proto" + "github.com/hardcore-os/plato/common/idl/message" "github.com/hardcore-os/plato/common/tcp" "net" ) @@ -9,9 +11,10 @@ import ( type connect struct { sendChan, recvChan chan *Message conn *net.TCPConn + connID uint64 } -func newConnet(ip net.IP, port int) *connect { +func newConnet(ip net.IP, port int, connID uint64) *connect { clientConn := &connect{ sendChan: make(chan *Message), recvChan: make(chan *Message), @@ -22,35 +25,63 @@ func newConnet(ip net.IP, port int) *connect { } conn, err := net.DialTCP("tcp", nil, addr) if err != nil { - panic(err) + fmt.Printf("DialTcp.err=%+v", err) + return nil } clientConn.conn = conn - go func() { - for { - data, err := tcp.ReadData(conn) - if err != nil { - panic(err) - } - msg := &Message{} - err = json.Unmarshal(data, msg) - if err != nil { - panic(err) - } - clientConn.recvChan <- msg - } - }() + if connID != 0 { + clientConn.connID = connID + } return clientConn + //go func() { + // for { + // data, err := tcp.ReadData(conn) + // if err != nil { + // panic(err) + // } + // msg := &Message{} + // err = json.Unmarshal(data, msg) + // if err != nil { + // panic(err) + // } + // clientConn.recvChan <- msg + // } + //}() + //return clientConn +} + +func handAckMsg(c *connect, data []byte) *Message { + ackMsg := &message.ACKMsg{} + _ = proto.Unmarshal(data, ackMsg) + switch ackMsg.Type { + case message.CmdType_Login: + c.connID = ackMsg.ConnID + } + return &Message{ + Type: MsgTypeAck, + Name: "plato", + FormUserID: "1212121", + ToUserID: "222212122", + Content: ackMsg.Msg, + } } -func (c *connect) send(data *Message) { +func (c *connect) send(ty message.CmdType, payload []byte) { // 直接发送给接收方 - bytes, _ := json.Marshal(data) + msgCmd := message.MsgCmd{ + Type: ty, + Payload: payload, + } + msg, err := proto.Marshal(&msgCmd) + if err != nil { + fmt.Printf("[connect] send marshal msg failed, err=%v, type=%v, payload=%v\n", err, ty, string(payload)) + return + } dataPgk := tcp.DataPgk{ - Data: bytes, - Len: uint32(len(bytes)), + Len: uint32(len(msg)), + Data: msg, } - xx := dataPgk.Marshal() - c.conn.Write(xx) + c.conn.Write(dataPgk.Marshal()) } func (c *connect) recv() <-chan *Message { diff --git a/common/timingwheel/delayqueue.go b/common/timingwheel/delayqueue.go index 0ab4296..e290d71 100644 --- a/common/timingwheel/delayqueue.go +++ b/common/timingwheel/delayqueue.go @@ -91,7 +91,7 @@ type DelayQueue struct { mu sync.Mutex pq priorityQueue - // Similar to the sleeping state of runtime.timers + // Similar to the sleeping message of runtime.timers sleeping int32 wakeupC chan struct{} } @@ -157,7 +157,7 @@ func (dq *DelayQueue) Poll(exitC chan struct{}, nowF func() int64) { case <-time.After(time.Duration(delta) * time.Millisecond): // The current "earliest" item expires. - // Reset the sleeping state since there's no need to receive from wakeupC. + // Reset the sleeping message since there's no need to receive from wakeupC. if atomic.SwapInt32(&dq.sleeping, 0) == 0 { // A caller of Offer() is being blocked on sending to wakeupC, // drain wakeupC to unblock the caller. diff --git a/gateway/connection.go b/gateway/connection.go index 2dee560..9e8dac2 100644 --- a/gateway/connection.go +++ b/gateway/connection.go @@ -2,17 +2,40 @@ package gateway import ( "net" + "sync/atomic" ) +var nextConnID uint64 // 全局ConnID + type connection struct { + id uint64 // 进程级别的生命周期 fd int + e *epoller conn *net.TCPConn } +func NewConnection(conn *net.TCPConn) *connection { + connID := atomic.AddUint64(&nextConnID, 1) + return &connection{ + id: connID, + fd: socketFD(conn), + conn: conn, + } +} + func (c *connection) Close() error { - return c.conn.Close() + ep.tables.Delete(c.id) + if c.e != nil { + c.e.fdToConnTable.Delete(c.fd) + } + err := c.conn.Close() + panic(err) } func (c *connection) RemoteAddr() string { return c.conn.RemoteAddr().String() } + +func (c *connection) BindEpoller(e *epoller) { + c.e = e +} diff --git a/gateway/epoll.go b/gateway/epoll.go index 4303786..1ce6c0a 100644 --- a/gateway/epoll.go +++ b/gateway/epoll.go @@ -69,10 +69,7 @@ func (e *ePool) createAcceptProcess() { } fmt.Errorf("accept error: %v", err) } - c := &connection{ - conn: conn, - fd: socketFD(conn), - } + c := NewConnection(conn) ep.addTask(c) } }() @@ -140,8 +137,9 @@ func (e *ePool) addTask(conn *connection) { // epoller 对象 轮询器 type epoller struct { - fd int - id int // id of epoll + fd int + fdToConnTable sync.Map + id int // id of epoll } func NewEpoller(id int) (*epoller, error) { @@ -155,7 +153,9 @@ func NewEpoller(id int) (*epoller, error) { }, nil } +// TODO: 默认水平触发模式,可采用非阻塞FD,优化边沿触发模式 func (epl *epoller) add(conn *connection) error { + // Extract file descriptor associated with the connection fd := conn.fd // the fd of epl is the epoll fd // the fd of conn is the connection fd @@ -163,7 +163,9 @@ func (epl *epoller) add(conn *connection) error { if err != nil { return err } + epl.fdToConnTable.Store(conn.fd, conn) ep.tables.Store(fd, conn) + conn.BindEpoller(epl) return nil } @@ -175,6 +177,7 @@ func (epl *epoller) remove(conn *connection) error { return err } ep.tables.Delete(fd) + epl.fdToConnTable.Delete(conn.fd) return nil } @@ -186,7 +189,7 @@ func (epl *epoller) wait(millSec int) ([]*connection, error) { } var connections []*connection for i := 0; i < n; i++ { - if conn, ok := ep.tables.Load(int(events[i].Fd)); ok { + if conn, ok := epl.fdToConnTable.Load(int(events[i].Fd)); ok { connections = append(connections, conn.(*connection)) } } diff --git a/gateway/rpc/client/state.go b/gateway/rpc/client/state.go index 94198db..eac97c1 100644 --- a/gateway/rpc/client/state.go +++ b/gateway/rpc/client/state.go @@ -2,16 +2,17 @@ package client import ( "context" + "github.com/bytedance/gopkg/util/logger" "github.com/hardcore-os/plato/state/rpc/service" "time" ) -func CancelConn(ctx *context.Context, endpoint string, fd int32, playLoad []byte) error { +func CancelConn(ctx *context.Context, endpoint string, connID uint64, payLoad []byte) error { rpcCtx, _ := context.WithTimeout(*ctx, 100*time.Millisecond) _, err := stateClient.CancelConn(rpcCtx, &service.StateRequest{ Endpoint: endpoint, - Fd: fd, - Data: playLoad, + ConnID: connID, + Data: payLoad, }) if err != nil { return err @@ -19,12 +20,13 @@ func CancelConn(ctx *context.Context, endpoint string, fd int32, playLoad []byte return nil } -func SendMsg(ctx *context.Context, endpoint string, fd int32, playLoad []byte) error { +func SendMsg(ctx *context.Context, endpoint string, connID uint64, payLoad []byte) error { rpcCtx, _ := context.WithTimeout(*ctx, 100*time.Millisecond) + logger.CtxInfof(*ctx, "[gateway.stateClient] SendMsg, connID=%v, payload=%v", connID, string(payLoad)) _, err := stateClient.SendMsg(rpcCtx, &service.StateRequest{ Endpoint: endpoint, - Fd: fd, - Data: playLoad, + ConnID: connID, + Data: payLoad, }) if err != nil { return err diff --git a/gateway/rpc/service/gateway.pb.go b/gateway/rpc/service/gateway.pb.go index ba3e22b..ecbc902 100644 --- a/gateway/rpc/service/gateway.pb.go +++ b/gateway/rpc/service/gateway.pb.go @@ -25,8 +25,8 @@ type GatewayRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Fd int32 `protobuf:"varint,1,opt,name=fd,proto3" json:"fd,omitempty"` - Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + ConnID uint64 `protobuf:"varint,1,opt,name=connID,proto3" json:"connID,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` } func (x *GatewayRequest) Reset() { @@ -61,9 +61,9 @@ func (*GatewayRequest) Descriptor() ([]byte, []int) { return file_gateway_proto_rawDescGZIP(), []int{0} } -func (x *GatewayRequest) GetFd() int32 { +func (x *GatewayRequest) GetConnID() uint64 { if x != nil { - return x.Fd + return x.ConnID } return 0 } @@ -134,24 +134,24 @@ var File_gateway_proto protoreflect.FileDescriptor var file_gateway_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x34, 0x0a, 0x0e, 0x47, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x66, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x66, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x37, - 0x0a, 0x0f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0x82, 0x01, 0x0a, 0x07, 0x47, 0x61, 0x74, 0x65, - 0x77, 0x61, 0x79, 0x12, 0x3c, 0x0a, 0x07, 0x44, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x12, 0x17, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x39, 0x0a, 0x04, 0x50, 0x75, 0x73, 0x68, 0x12, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, - 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0c, 0x5a, 0x0a, - 0x2e, 0x2f, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x3c, 0x0a, 0x0e, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, + 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x6e, + 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x37, 0x0a, 0x0f, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, + 0x82, 0x01, 0x0a, 0x07, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x12, 0x3c, 0x0a, 0x07, 0x44, + 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x12, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, + 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x50, 0x75, 0x73, + 0x68, 0x12, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, + 0x77, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/gateway/rpc/service/gateway.proto b/gateway/rpc/service/gateway.proto index 9b310d2..163ca6e 100644 --- a/gateway/rpc/service/gateway.proto +++ b/gateway/rpc/service/gateway.proto @@ -13,7 +13,7 @@ service Gateway { } message GatewayRequest{ - int32 fd = 1; + uint64 connID = 1; bytes data = 2; } diff --git a/gateway/rpc/service/service.go b/gateway/rpc/service/service.go index 4ed8b34..6481a7f 100644 --- a/gateway/rpc/service/service.go +++ b/gateway/rpc/service/service.go @@ -8,10 +8,10 @@ const ( ) type CmdContext struct { - Ctx *context.Context - Cmd int32 - FD int - PlayLoad []byte + Ctx *context.Context + Cmd int32 + ConnID uint64 + PayLoad []byte } type Service struct { @@ -22,9 +22,9 @@ type Service struct { func (s *Service) DelConn(ctx context.Context, gr *GatewayRequest) (*GatewayResponse, error) { c := context.TODO() s.CmdChannel <- &CmdContext{ - Ctx: &c, - Cmd: DelConnCmd, - FD: int(gr.GetFd()), + Ctx: &c, + Cmd: DelConnCmd, + ConnID: gr.GetConnID(), } return &GatewayResponse{ Code: 0, @@ -35,10 +35,10 @@ func (s *Service) DelConn(ctx context.Context, gr *GatewayRequest) (*GatewayResp func (s *Service) Push(ctx context.Context, gr *GatewayRequest) (*GatewayResponse, error) { c := context.TODO() s.CmdChannel <- &CmdContext{ - Ctx: &c, - Cmd: PushCmd, - FD: int(gr.GetFd()), - PlayLoad: gr.GetData(), + Ctx: &c, + Cmd: PushCmd, + ConnID: gr.GetConnID(), + PayLoad: gr.GetData(), } return &GatewayResponse{ Code: 0, diff --git a/gateway/server.go b/gateway/server.go index 95221e0..7beb6a6 100644 --- a/gateway/server.go +++ b/gateway/server.go @@ -67,13 +67,13 @@ func runProc(c *connection, ep *epoller) { if errors.Is(err, io.EOF) { logger.CtxInfof(context.Background(), "connection[%v] closed", c.RemoteAddr()) ep.remove(c) - client.CancelConn(&ctx, getEndpoint(), int32(c.fd), nil) + client.CancelConn(&ctx, getEndpoint(), c.id, nil) } return } err = wPool.Submit(func() { - // step2:交给 state server rpc 处理 - client.SendMsg(&ctx, getEndpoint(), int32(c.fd), dataBuf) + // step2:交给 message server rpc 处理 + client.SendMsg(&ctx, getEndpoint(), c.id, dataBuf) }) if err != nil { @@ -104,10 +104,9 @@ func closeConn(cmd *service.CmdContext) { if cmdChannel == nil { return } - if connPtr, ok := ep.tables.Load(cmd.FD); ok { + if connPtr, ok := ep.tables.Load(cmd.ConnID); ok { conn, _ := connPtr.(*connection) conn.Close() - ep.tables.Delete(cmd.FD) } } @@ -115,11 +114,11 @@ func sendMsgByCmd(cmd *service.CmdContext) { if cmdChannel == nil { return } - if connPtr, ok := ep.tables.Load(cmd.FD); ok { + if connPtr, ok := ep.tables.Load(cmd.ConnID); ok { conn, _ := connPtr.(*connection) dp := tcp.DataPgk{ - Len: uint32(len(cmd.PlayLoad)), - Data: cmd.PlayLoad, + Len: uint32(len(cmd.PayLoad)), + Data: cmd.PayLoad, } tcp.SendData(conn.conn, dp.Marshal()) } diff --git a/perf/perf.go b/perf/perf.go index b1e9038..1298a89 100644 --- a/perf/perf.go +++ b/perf/perf.go @@ -11,7 +11,7 @@ var ( func RunMain() { for i := 0; i < int(TcpConnNum); i++ { - sdk.NewChat(net.ParseIP("127.0.0.1"), 8900, "logic", "1223", "123") + sdk.NewChat(net.ParseIP("127.0.0.1"), 8900, "logic", "1223", "123", 0, false) } select {} } diff --git a/plato.yaml b/plato.yaml index e60b79b..33c228f 100644 --- a/plato.yaml +++ b/plato.yaml @@ -29,7 +29,7 @@ gateway: cmd_channel_num: 2048 weight: 100 state: - service_name: "plato.access.state" + service_name: "plato.access.message" servide_addr: "127.0.0.1" cmd_channel_num: 2048 server_port: 8902 diff --git a/state/rpc/client/gateway.go b/state/rpc/client/gateway.go index 2e889d9..a99e6b0 100644 --- a/state/rpc/client/gateway.go +++ b/state/rpc/client/gateway.go @@ -7,25 +7,25 @@ import ( "time" ) -func DelConn(ctx *context.Context, fd int32, playLoad []byte) error { +func DelConn(ctx *context.Context, connID uint64, payLoad []byte) error { rpcCtx, _ := context.WithTimeout(*ctx, 100*time.Millisecond) gatewayClient.DelConn(rpcCtx, &service.GatewayRequest{ - Fd: fd, - Data: playLoad, + ConnID: connID, + Data: payLoad, }) return nil } -func Push(ctx *context.Context, fd int32, playLoad []byte) error { +func Push(ctx *context.Context, connID uint64, payLoad []byte) error { rpcCtx, _ := context.WithTimeout(*ctx, 100*time.Millisecond) resp, err := gatewayClient.Push(rpcCtx, &service.GatewayRequest{ - Fd: fd, - Data: playLoad, + ConnID: connID, + Data: payLoad, }) if err != nil { - logger.CtxErrorf(rpcCtx, "state.gatewayClient push msg err, err=%v", err) + logger.CtxErrorf(rpcCtx, "message.gatewayClient push msg err, err=%v", err) return err } - logger.CtxInfof(rpcCtx, "state.gatewayClient push msg resp, resp=%+v", resp) + logger.CtxInfof(rpcCtx, "message.gatewayClient push msg resp, resp=%+v", resp) return nil } diff --git a/state/rpc/service/service.go b/state/rpc/service/service.go index 81517ae..3a67b92 100644 --- a/state/rpc/service/service.go +++ b/state/rpc/service/service.go @@ -14,8 +14,8 @@ type CmdContext struct { Ctx *context.Context Cmd int32 Endpoint string - FD int - PlayLoad []byte + ConnID uint64 + PayLoad []byte } type Service struct { @@ -29,7 +29,7 @@ func (s *Service) CancelConn(ctx context.Context, sr *StateRequest) (*StateRespo Ctx: &c, Cmd: CancelConnCmd, Endpoint: sr.GetEndpoint(), - FD: int(sr.GetFd()), + ConnID: sr.GetConnID(), } return &StateResponse{ @@ -39,17 +39,17 @@ func (s *Service) CancelConn(ctx context.Context, sr *StateRequest) (*StateRespo } func (s *Service) SendMsg(ctx context.Context, sr *StateRequest) (*StateResponse, error) { - logger.CtxInfof(ctx, "[state] receive SendMsg request ok") + logger.CtxInfof(ctx, "[message] receive SendMsg request ok") c := context.TODO() s.CmdChannel <- &CmdContext{ Ctx: &c, Cmd: SendMsgCmd, - FD: int(sr.GetFd()), + ConnID: sr.GetConnID(), Endpoint: sr.GetEndpoint(), - PlayLoad: sr.GetData(), + PayLoad: sr.GetData(), } - logger.CtxInfof(ctx, "[state] sendMsg to channel ok") + logger.CtxInfof(ctx, "[message] sendMsg to channel ok") return &StateResponse{ Code: 0, diff --git a/state/rpc/service/state.pb.go b/state/rpc/service/state.pb.go index 2223b93..44968b1 100644 --- a/state/rpc/service/state.pb.go +++ b/state/rpc/service/state.pb.go @@ -2,7 +2,7 @@ // versions: // protoc-gen-go v1.31.0 // protoc v3.19.4 -// source: state.proto +// source: message.proto package service @@ -26,7 +26,7 @@ type StateRequest struct { unknownFields protoimpl.UnknownFields Endpoint string `protobuf:"bytes,1,opt,name=endpoint,proto3" json:"endpoint,omitempty"` - Fd int32 `protobuf:"varint,2,opt,name=fd,proto3" json:"fd,omitempty"` + ConnID uint64 `protobuf:"varint,2,opt,name=connID,proto3" json:"connID,omitempty"` Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` } @@ -69,9 +69,9 @@ func (x *StateRequest) GetEndpoint() string { return "" } -func (x *StateRequest) GetFd() int32 { +func (x *StateRequest) GetConnID() uint64 { if x != nil { - return x.Fd + return x.ConnID } return 0 } @@ -142,25 +142,25 @@ var File_state_proto protoreflect.FileDescriptor var file_state_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x4e, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x56, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x66, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, - 0x66, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x35, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, - 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0x7e, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x43, 0x6f, 0x6e, 0x6e, 0x12, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x12, 0x15, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0c, 0x5a, - 0x0a, 0x2e, 0x2f, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x35, + 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, + 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6d, 0x73, 0x67, 0x32, 0x7e, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3b, + 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x43, 0x6f, 0x6e, 0x6e, 0x12, 0x15, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, 0x07, 0x53, + 0x65, 0x6e, 0x64, 0x4d, 0x73, 0x67, 0x12, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x3b, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -181,10 +181,10 @@ var file_state_proto_goTypes = []interface{}{ (*StateResponse)(nil), // 1: service.StateResponse } var file_state_proto_depIdxs = []int32{ - 0, // 0: service.state.CancelConn:input_type -> service.StateRequest - 0, // 1: service.state.SendMsg:input_type -> service.StateRequest - 1, // 2: service.state.CancelConn:output_type -> service.StateResponse - 1, // 3: service.state.SendMsg:output_type -> service.StateResponse + 0, // 0: service.message.CancelConn:input_type -> service.StateRequest + 0, // 1: service.message.SendMsg:input_type -> service.StateRequest + 1, // 2: service.message.CancelConn:output_type -> service.StateResponse + 1, // 3: service.message.SendMsg:output_type -> service.StateResponse 2, // [2:4] is the sub-list for method output_type 0, // [0:2] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name diff --git a/state/rpc/service/state.proto b/state/rpc/service/state.proto index 5dafc77..43d8dc4 100644 --- a/state/rpc/service/state.proto +++ b/state/rpc/service/state.proto @@ -12,7 +12,7 @@ service state { message StateRequest{ string endpoint = 1; - int32 fd = 2; + uint64 connID = 2; bytes data = 3; } diff --git a/state/rpc/service/state_grpc.pb.go b/state/rpc/service/state_grpc.pb.go index 540bbec..0d9d814 100644 --- a/state/rpc/service/state_grpc.pb.go +++ b/state/rpc/service/state_grpc.pb.go @@ -2,7 +2,7 @@ // versions: // - protoc-gen-go-grpc v1.3.0 // - protoc v3.19.4 -// source: state.proto +// source: message.proto package service @@ -19,8 +19,8 @@ import ( const _ = grpc.SupportPackageIsVersion7 const ( - State_CancelConn_FullMethodName = "/service.state/CancelConn" - State_SendMsg_FullMethodName = "/service.state/SendMsg" + State_CancelConn_FullMethodName = "/service.message/CancelConn" + State_SendMsg_FullMethodName = "/service.message/SendMsg" ) // StateClient is the client API for State service. @@ -129,7 +129,7 @@ func _State_SendMsg_Handler(srv interface{}, ctx context.Context, dec func(inter // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) var State_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "service.state", + ServiceName: "service.message", HandlerType: (*StateServer)(nil), Methods: []grpc.MethodDesc{ { @@ -142,5 +142,5 @@ var State_ServiceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "state.proto", + Metadata: "message.proto", } diff --git a/state/server.go b/state/server.go index 8fe1b06..8cac541 100644 --- a/state/server.go +++ b/state/server.go @@ -3,18 +3,22 @@ package state import ( "context" "github.com/bytedance/gopkg/util/logger" + "github.com/golang/protobuf/proto" "github.com/hardcore-os/plato/common/config" "github.com/hardcore-os/plato/common/prpc" "github.com/hardcore-os/plato/state/rpc/client" "github.com/hardcore-os/plato/state/rpc/service" "google.golang.org/grpc" -) + "sync" + "time" -var cmdChannel chan *service.CmdContext + "github.com/hardcore-os/plato/common/idl/message" +) func RunMain(path string) { config.Init(path) cmdChannel = make(chan *service.CmdContext, config.GetStateCmdChannelNum()) + connToStateTable = sync.Map{} s := prpc.NewPServer( prpc.WithServiceName(config.GetStateServiceName()), @@ -27,6 +31,8 @@ func RunMain(path string) { }) // init rpc client client.Init() + // init timingWheel + InitTimer() // start cmd handler go cmdHandler() // start rpc server @@ -34,16 +40,122 @@ func RunMain(path string) { } func cmdHandler() { - for cmd := range cmdChannel { - switch cmd.Cmd { + for cmdCtx := range cmdChannel { + switch cmdCtx.Cmd { case service.CancelConnCmd: - logger.CtxInfof(*cmd.Ctx, "cancelConn endpoint:%s, fd:%d, data:%+v", cmd.Endpoint, cmd.FD, cmd.PlayLoad) + logger.CtxInfof(*cmdCtx.Ctx, "cancelConn endpoint:%s, fd:%d, data:%+v", cmdCtx.Endpoint, cmdCtx.ConnID, cmdCtx.PayLoad) case service.SendMsgCmd: - logger.CtxInfof(*cmd.Ctx, "cmdHandler: %v", string(cmd.PlayLoad)) - client.Push(cmd.Ctx, int32(cmd.FD), cmd.PlayLoad) + logger.CtxInfof(*cmdCtx.Ctx, "cmdHandler: %v", string(cmdCtx.PayLoad)) + msgCmd := &message.MsgCmd{} + err := proto.Unmarshal(cmdCtx.PayLoad, msgCmd) + if err != nil { + logger.CtxErrorf(*cmdCtx.Ctx, "SendMsgCmd: err=%s", err.Error()) + continue + } + msgCmdHandler(cmdCtx, msgCmd) default: - logger.CtxInfof(*cmd.Ctx, "invalid cmd type, type=%v", cmd.Cmd) + logger.CtxInfof(*cmdCtx.Ctx, "invalid cmd type, type=%v", cmdCtx.Cmd) + } + } +} + +func msgCmdHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { + if msgCmd == nil { + return + } + switch msgCmd.Type { + case message.CmdType_Login: + loginMsgHandler(cmdCtx, msgCmd) + case message.CmdType_Heartbeat: + heartbeatMsgHandler(cmdCtx, msgCmd) + case message.CmdType_ReConn: + reConnMsgHandler(cmdCtx, msgCmd) + } +} + +func loginMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { + loginMsg := &message.LoginMsg{} + err := proto.Unmarshal(msgCmd.Payload, loginMsg) + if err != nil { + logger.CtxErrorf(*cmdCtx.Ctx, "[loginMsgHandler] Unmarshal failed, err=%v", err) + return + } + if loginMsg.Head != nil { + // 这里会把 login msg 传送给业务层做处理 + logger.CtxInfof(*cmdCtx.Ctx, "loginMsgHandler", loginMsg.Head.DeviceID) + } + + // create timer + t := AfterFunc(300*time.Second, func() { + clearState(cmdCtx.ConnID) + }) + + // init conn message + connToStateTable.Store(cmdCtx.ConnID, &connState{heartTimer: t, connID: cmdCtx.ConnID}) + sendAckMsg(cmdCtx.ConnID, 0, "login") +} + +func heartbeatMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { + heartMsg := &message.HeartbeatMsg{} + err := proto.Unmarshal(msgCmd.Payload, heartMsg) + if err != nil { + logger.CtxErrorf(*cmdCtx.Ctx, "[heartbeatMsgHandler] Unmarshal failed, err=%v", err) + return + } + if data, ok := connToStateTable.Load(cmdCtx.ConnID); ok { + state, _ := data.(*connState) + state.resetHeartTimer() + } + // 减少通信量,可以暂时不回复心跳的ack +} + +func reConnMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { + reConnMsg := &message.ReConnMsg{} + err := proto.Unmarshal(msgCmd.Payload, reConnMsg) + if err != nil { + logger.CtxErrorf(*cmdCtx.Ctx, "[reConnMsgHandler] Unmarshal failed, err=%v", err) + return + } + // 重连的消息头中的connID才是上一次断开连接的connID + if data, ok := connToStateTable.Load(reConnMsg.Head.ConnID); ok { + state, _ := data.(*connState) + state.Lock() + defer state.Unlock() + // 重连的消息头中的connID才是上一次断开连接的connID + if state.reConnTimer != nil { + state.reConnTimer.Stop() + state.reConnTimer = nil } + // 从索引中删除 旧的connID + connToStateTable.Delete(reConnMsg.Head.ConnID) + // 变更connID, cmdCtx中的connID才是 gateway重连的新连接 + state.connID = cmdCtx.ConnID + connToStateTable.Store(state.connID, state) + sendAckMsg(cmdCtx.ConnID, 0, "reconn ok") + } else { + sendAckMsg(cmdCtx.ConnID, 1, "reconn failed") + } +} + +func sendAckMsg(connID uint64, code uint32, msg string) { + ackMsg := &message.ACKMsg{} + ackMsg.Code = code + ackMsg.Msg = msg + ackMsg.ConnID = connID + ctx := context.TODO() + downLoad, err := proto.Marshal(ackMsg) + if err != nil { + logger.CtxErrorf(ctx, "sendMsg err=%s, connID=%v, code=%v, msg=%v", err, connID, code, msg) + return + } + mc := &message.MsgCmd{} + mc.Type = message.CmdType_ACK + mc.Payload = downLoad + data, err := proto.Marshal(mc) + if err != nil { + logger.CtxErrorf(ctx, "sendMsg err=%s, connID=%v, code=%v, msg=%v", err, connID, code, msg) + return } + client.Push(&ctx, connID, data) } diff --git a/state/state.go b/state/state.go new file mode 100644 index 0000000..501a09e --- /dev/null +++ b/state/state.go @@ -0,0 +1,45 @@ +package state + +import ( + "context" + "github.com/hardcore-os/plato/common/timingwheel" + "github.com/hardcore-os/plato/state/rpc/client" + "sync" + "time" + + "github.com/hardcore-os/plato/state/rpc/service" +) + +var cmdChannel chan *service.CmdContext +var connToStateTable sync.Map + +type connState struct { + sync.RWMutex + heartTimer *timingwheel.Timer + reConnTimer *timingwheel.Timer + connID uint64 +} + +func (c *connState) resetHeartTimer() { + c.Lock() + defer c.Unlock() + c.heartTimer.Stop() + c.heartTimer = AfterFunc(5*time.Second, func() { + clearState(c.connID) + }) +} + +func clearState(connID uint64) { + if data, ok := connToStateTable.Load(connID); ok { + state, _ := data.(*connState) + state.Lock() + defer state.Unlock() + // prevent fake disconnection, wait for 10s + state.reConnTimer = AfterFunc(10*time.Second, func() { + ctx := context.TODO() + client.DelConn(&ctx, connID, nil) + // del conn message + connToStateTable.Delete(connID) + }) + } +} diff --git a/state/timer.go b/state/timer.go new file mode 100644 index 0000000..d0ce576 --- /dev/null +++ b/state/timer.go @@ -0,0 +1,23 @@ +package state + +import ( + "time" + + "github.com/hardcore-os/plato/common/timingwheel" +) + +var wheel *timingwheel.TimingWheel + +func InitTimer() { + wheel = timingwheel.NewTimingWheel(time.Millisecond, 20) + wheel.Start() +} + +func CloseTimer() { + wheel.Stop() +} + +func AfterFunc(d time.Duration, f func()) *timingwheel.Timer { + t := wheel.AfterFunc(d, f) + return t +} From ad72717c8b03d167e38cdf33b363291fe0825bff Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Mon, 1 Jan 2024 21:56:31 +0800 Subject: [PATCH 16/26] fix config --- chat.log | 38 ++++++++++++++------------------------ common/config/state.go | 10 +++++----- gateway/server.go | 2 +- plato.yaml | 2 +- state/server.go | 4 +++- 5 files changed, 24 insertions(+), 32 deletions(-) diff --git a/chat.log b/chat.log index e405450..f844317 100644 --- a/chat.log +++ b/chat.log @@ -1,25 +1,15 @@ -me: 111 -logic: 111 -logic: 222 -me: 222 -me: 33333 -logic: 33333 -me: 22222 -logic: 22222 -me: 2212 -logic: 2212 -logic: 333 -me: 333 -logic: 122321 -me: 122321 -me: 312312 -logic: 312312 -logic: 312312 -me: 312312 -me: 3123123 -logic: 3123123 -logic: 3123213 -me: 3123213 -me: 312321 -logic: 312321 +me: 1112 +logic: 1112 +me: 213 +logic: 213 +me: wd +logic: wd +me: askdjklasjdklasjdlksajldkjaslkdjaskljdlksajdlsadkl +logic: askdjklasjdklasjdlksajldkjaslkdjaskljdlksajdlsadkl +me: djlkasjdklsajdlksajdklsa +logic: djlkasjdklsajdlksajdklsa +me: dklsadjklsjlkdask +logic: dklsadjklsjlkdask +me: dklasjldjaklsj +logic: dklasjldjaklsj diff --git a/common/config/state.go b/common/config/state.go index 54286c0..18b2c0f 100644 --- a/common/config/state.go +++ b/common/config/state.go @@ -3,21 +3,21 @@ package config import "github.com/spf13/viper" func GetStateCmdChannelNum() int { - return viper.GetInt("message.cmd_channel_num") + return viper.GetInt("state.cmd_channel_num") } func GetStateServiceAddr() string { - return viper.GetString("message.servide_addr") + return viper.GetString("state.servide_addr") } func GetStateServiceName() string { - return viper.GetString("message.service_name") + return viper.GetString("state.service_name") } func GetStateServerPort() int { - return viper.GetInt("message.server_port") + return viper.GetInt("state.server_port") } func GetStateRPCWeight() int { - return viper.GetInt("message.weight") + return viper.GetInt("state.weight") } diff --git a/gateway/server.go b/gateway/server.go index 7beb6a6..dcabf55 100644 --- a/gateway/server.go +++ b/gateway/server.go @@ -47,7 +47,7 @@ func startRPCServer() { prpc.WithPort(config.GetGatewayRPCServerPort()), prpc.WithWeight(config.GetGatewayRPCWeight()), ) - logger.CtxInfof(ctx, "serviceName:%s Addr:%s:%d weight:%d", config.GetGatewayServiceName(), config.GetGatewayServiceAddr(), config.GetGatewayRPCServerPort(), config.GetGatewayRPCWeight()) + logger.CtxInfof(ctx, "[gateway] serviceName:%s Addr:%s:%d weight:%d", config.GetGatewayServiceName(), config.GetGatewayServiceAddr(), config.GetGatewayRPCServerPort(), config.GetGatewayRPCWeight()) s.RegisterService(func(server *grpc.Server) { service.RegisterGatewayServer(server, &service.Service{CmdChannel: cmdChannel}) }) diff --git a/plato.yaml b/plato.yaml index 33c228f..e60b79b 100644 --- a/plato.yaml +++ b/plato.yaml @@ -29,7 +29,7 @@ gateway: cmd_channel_num: 2048 weight: 100 state: - service_name: "plato.access.message" + service_name: "plato.access.state" servide_addr: "127.0.0.1" cmd_channel_num: 2048 server_port: 8902 diff --git a/state/server.go b/state/server.go index 8cac541..44b3fbd 100644 --- a/state/server.go +++ b/state/server.go @@ -36,7 +36,9 @@ func RunMain(path string) { // start cmd handler go cmdHandler() // start rpc server - s.Start(context.TODO()) + ctx := context.TODO() + logger.CtxInfof(ctx, "[state] serviceName:%s Addr:%s:%d weight:%d", config.GetStateServiceName(), config.GetStateServiceAddr(), config.GetStateServerPort(), config.GetStateRPCWeight()) + s.Start(ctx) } func cmdHandler() { From 1d967bff8b5dc83b219926ac7272d435d5f9e182 Mon Sep 17 00:00:00 2001 From: vagrantZero <750437163@qq.com> Date: Tue, 9 Jan 2024 22:54:41 +0800 Subject: [PATCH 17/26] feat: update readme and net --- common/sdk/net.go | 15 --------------- common/timingwheel/README.md | 1 + 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/common/sdk/net.go b/common/sdk/net.go index 2180bb9..9407112 100644 --- a/common/sdk/net.go +++ b/common/sdk/net.go @@ -33,21 +33,6 @@ func newConnet(ip net.IP, port int, connID uint64) *connect { clientConn.connID = connID } return clientConn - //go func() { - // for { - // data, err := tcp.ReadData(conn) - // if err != nil { - // panic(err) - // } - // msg := &Message{} - // err = json.Unmarshal(data, msg) - // if err != nil { - // panic(err) - // } - // clientConn.recvChan <- msg - // } - //}() - //return clientConn } func handAckMsg(c *connect, data []byte) *Message { diff --git a/common/timingwheel/README.md b/common/timingwheel/README.md index e69de29..96150c6 100644 --- a/common/timingwheel/README.md +++ b/common/timingwheel/README.md @@ -0,0 +1 @@ +fork in : https://github.com/RussellLuo/timingwheel \ No newline at end of file From 39ef3d23f2b1e1d3d97a3f28186dfb7beb9b58dc Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Fri, 9 Feb 2024 11:07:36 +0800 Subject: [PATCH 18/26] feat: add server msg fsm --- common/idl/message/message.pb.go | 412 ++++++++++++++++++++++++------- common/idl/message/message.proto | 21 ++ state/server.go | 88 ++++++- state/state.go | 33 +++ 4 files changed, 459 insertions(+), 95 deletions(-) diff --git a/common/idl/message/message.pb.go b/common/idl/message/message.pb.go index 33bced2..0f03ec1 100644 --- a/common/idl/message/message.pb.go +++ b/common/idl/message/message.pb.go @@ -28,6 +28,8 @@ const ( CmdType_Heartbeat CmdType = 1 CmdType_ReConn CmdType = 2 CmdType_ACK CmdType = 3 + CmdType_UP CmdType = 4 // 上行消息 + CmdType_Push CmdType = 5 // 下行 推送消息 ) // Enum value maps for CmdType. @@ -37,12 +39,16 @@ var ( 1: "Heartbeat", 2: "ReConn", 3: "ACK", + 4: "UP", + 5: "Push", } CmdType_value = map[string]int32{ "Login": 0, "Heartbeat": 1, "ReConn": 2, "ACK": 3, + "UP": 4, + "Push": 5, } ) @@ -129,22 +135,191 @@ func (x *MsgCmd) GetPayload() []byte { return nil } +// 上行消息 pb结构 +type UPMsg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Head *UPMsgHead `protobuf:"bytes,1,opt,name=Head,proto3" json:"Head,omitempty"` + UPMsgBody []byte `protobuf:"bytes,2,opt,name=UPMsgBody,proto3" json:"UPMsgBody,omitempty"` +} + +func (x *UPMsg) Reset() { + *x = UPMsg{} + if protoimpl.UnsafeEnabled { + mi := &file_message_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UPMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UPMsg) ProtoMessage() {} + +func (x *UPMsg) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UPMsg.ProtoReflect.Descriptor instead. +func (*UPMsg) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{1} +} + +func (x *UPMsg) GetHead() *UPMsgHead { + if x != nil { + return x.Head + } + return nil +} + +func (x *UPMsg) GetUPMsgBody() []byte { + if x != nil { + return x.UPMsgBody + } + return nil +} + +// 上行消息头 pb结构 +type UPMsgHead struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientID uint64 `protobuf:"varint,1,opt,name=ClientID,proto3" json:"ClientID,omitempty"` + ConnID uint64 `protobuf:"varint,2,opt,name=ConnID,proto3" json:"ConnID,omitempty"` +} + +func (x *UPMsgHead) Reset() { + *x = UPMsgHead{} + if protoimpl.UnsafeEnabled { + mi := &file_message_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UPMsgHead) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UPMsgHead) ProtoMessage() {} + +func (x *UPMsgHead) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UPMsgHead.ProtoReflect.Descriptor instead. +func (*UPMsgHead) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{2} +} + +func (x *UPMsgHead) GetClientID() uint64 { + if x != nil { + return x.ClientID + } + return 0 +} + +func (x *UPMsgHead) GetConnID() uint64 { + if x != nil { + return x.ConnID + } + return 0 +} + +// 下行消息 pb结构 +type PushMsg struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MsgID uint64 `protobuf:"varint,1,opt,name=MsgID,proto3" json:"MsgID,omitempty"` + Content []byte `protobuf:"bytes,2,opt,name=Content,proto3" json:"Content,omitempty"` +} + +func (x *PushMsg) Reset() { + *x = PushMsg{} + if protoimpl.UnsafeEnabled { + mi := &file_message_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PushMsg) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PushMsg) ProtoMessage() {} + +func (x *PushMsg) ProtoReflect() protoreflect.Message { + mi := &file_message_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PushMsg.ProtoReflect.Descriptor instead. +func (*PushMsg) Descriptor() ([]byte, []int) { + return file_message_proto_rawDescGZIP(), []int{3} +} + +func (x *PushMsg) GetMsgID() uint64 { + if x != nil { + return x.MsgID + } + return 0 +} + +func (x *PushMsg) GetContent() []byte { + if x != nil { + return x.Content + } + return nil +} + // ACK 消息 type ACKMsg struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Code uint32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"` - Msg string `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"` - Type CmdType `protobuf:"varint,3,opt,name=Type,proto3,enum=message.CmdType" json:"Type,omitempty"` - ConnID uint64 `protobuf:"varint,4,opt,name=ConnID,proto3" json:"ConnID,omitempty"` + Code uint32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"` + Type CmdType `protobuf:"varint,3,opt,name=Type,proto3,enum=message.CmdType" json:"Type,omitempty"` + ConnID uint64 `protobuf:"varint,4,opt,name=ConnID,proto3" json:"ConnID,omitempty"` + ClientID uint64 `protobuf:"varint,5,opt,name=ClientID,proto3" json:"ClientID,omitempty"` // client msg id -> cid } func (x *ACKMsg) Reset() { *x = ACKMsg{} if protoimpl.UnsafeEnabled { - mi := &file_message_proto_msgTypes[1] + mi := &file_message_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -157,7 +332,7 @@ func (x *ACKMsg) String() string { func (*ACKMsg) ProtoMessage() {} func (x *ACKMsg) ProtoReflect() protoreflect.Message { - mi := &file_message_proto_msgTypes[1] + mi := &file_message_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -170,7 +345,7 @@ func (x *ACKMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use ACKMsg.ProtoReflect.Descriptor instead. func (*ACKMsg) Descriptor() ([]byte, []int) { - return file_message_proto_rawDescGZIP(), []int{1} + return file_message_proto_rawDescGZIP(), []int{4} } func (x *ACKMsg) GetCode() uint32 { @@ -201,6 +376,13 @@ func (x *ACKMsg) GetConnID() uint64 { return 0 } +func (x *ACKMsg) GetClientID() uint64 { + if x != nil { + return x.ClientID + } + return 0 +} + // 登陆消息 type LoginMsgHead struct { state protoimpl.MessageState @@ -213,7 +395,7 @@ type LoginMsgHead struct { func (x *LoginMsgHead) Reset() { *x = LoginMsgHead{} if protoimpl.UnsafeEnabled { - mi := &file_message_proto_msgTypes[2] + mi := &file_message_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -226,7 +408,7 @@ func (x *LoginMsgHead) String() string { func (*LoginMsgHead) ProtoMessage() {} func (x *LoginMsgHead) ProtoReflect() protoreflect.Message { - mi := &file_message_proto_msgTypes[2] + mi := &file_message_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -239,7 +421,7 @@ func (x *LoginMsgHead) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginMsgHead.ProtoReflect.Descriptor instead. func (*LoginMsgHead) Descriptor() ([]byte, []int) { - return file_message_proto_rawDescGZIP(), []int{2} + return file_message_proto_rawDescGZIP(), []int{5} } func (x *LoginMsgHead) GetDeviceID() uint64 { @@ -261,7 +443,7 @@ type LoginMsg struct { func (x *LoginMsg) Reset() { *x = LoginMsg{} if protoimpl.UnsafeEnabled { - mi := &file_message_proto_msgTypes[3] + mi := &file_message_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -274,7 +456,7 @@ func (x *LoginMsg) String() string { func (*LoginMsg) ProtoMessage() {} func (x *LoginMsg) ProtoReflect() protoreflect.Message { - mi := &file_message_proto_msgTypes[3] + mi := &file_message_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -287,7 +469,7 @@ func (x *LoginMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginMsg.ProtoReflect.Descriptor instead. func (*LoginMsg) Descriptor() ([]byte, []int) { - return file_message_proto_rawDescGZIP(), []int{3} + return file_message_proto_rawDescGZIP(), []int{6} } func (x *LoginMsg) GetHead() *LoginMsgHead { @@ -314,7 +496,7 @@ type HeartbeatMsgHead struct { func (x *HeartbeatMsgHead) Reset() { *x = HeartbeatMsgHead{} if protoimpl.UnsafeEnabled { - mi := &file_message_proto_msgTypes[4] + mi := &file_message_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -327,7 +509,7 @@ func (x *HeartbeatMsgHead) String() string { func (*HeartbeatMsgHead) ProtoMessage() {} func (x *HeartbeatMsgHead) ProtoReflect() protoreflect.Message { - mi := &file_message_proto_msgTypes[4] + mi := &file_message_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -340,7 +522,7 @@ func (x *HeartbeatMsgHead) ProtoReflect() protoreflect.Message { // Deprecated: Use HeartbeatMsgHead.ProtoReflect.Descriptor instead. func (*HeartbeatMsgHead) Descriptor() ([]byte, []int) { - return file_message_proto_rawDescGZIP(), []int{4} + return file_message_proto_rawDescGZIP(), []int{7} } type HeartbeatMsg struct { @@ -355,7 +537,7 @@ type HeartbeatMsg struct { func (x *HeartbeatMsg) Reset() { *x = HeartbeatMsg{} if protoimpl.UnsafeEnabled { - mi := &file_message_proto_msgTypes[5] + mi := &file_message_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -368,7 +550,7 @@ func (x *HeartbeatMsg) String() string { func (*HeartbeatMsg) ProtoMessage() {} func (x *HeartbeatMsg) ProtoReflect() protoreflect.Message { - mi := &file_message_proto_msgTypes[5] + mi := &file_message_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -381,7 +563,7 @@ func (x *HeartbeatMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use HeartbeatMsg.ProtoReflect.Descriptor instead. func (*HeartbeatMsg) Descriptor() ([]byte, []int) { - return file_message_proto_rawDescGZIP(), []int{5} + return file_message_proto_rawDescGZIP(), []int{8} } func (x *HeartbeatMsg) GetHead() *HeartbeatMsgHead { @@ -410,7 +592,7 @@ type ReConnMsgHead struct { func (x *ReConnMsgHead) Reset() { *x = ReConnMsgHead{} if protoimpl.UnsafeEnabled { - mi := &file_message_proto_msgTypes[6] + mi := &file_message_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +605,7 @@ func (x *ReConnMsgHead) String() string { func (*ReConnMsgHead) ProtoMessage() {} func (x *ReConnMsgHead) ProtoReflect() protoreflect.Message { - mi := &file_message_proto_msgTypes[6] + mi := &file_message_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +618,7 @@ func (x *ReConnMsgHead) ProtoReflect() protoreflect.Message { // Deprecated: Use ReConnMsgHead.ProtoReflect.Descriptor instead. func (*ReConnMsgHead) Descriptor() ([]byte, []int) { - return file_message_proto_rawDescGZIP(), []int{6} + return file_message_proto_rawDescGZIP(), []int{9} } func (x *ReConnMsgHead) GetConnID() uint64 { @@ -458,7 +640,7 @@ type ReConnMsg struct { func (x *ReConnMsg) Reset() { *x = ReConnMsg{} if protoimpl.UnsafeEnabled { - mi := &file_message_proto_msgTypes[7] + mi := &file_message_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -471,7 +653,7 @@ func (x *ReConnMsg) String() string { func (*ReConnMsg) ProtoMessage() {} func (x *ReConnMsg) ProtoReflect() protoreflect.Message { - mi := &file_message_proto_msgTypes[7] + mi := &file_message_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -484,7 +666,7 @@ func (x *ReConnMsg) ProtoReflect() protoreflect.Message { // Deprecated: Use ReConnMsg.ProtoReflect.Descriptor instead. func (*ReConnMsg) Descriptor() ([]byte, []int) { - return file_message_proto_rawDescGZIP(), []int{7} + return file_message_proto_rawDescGZIP(), []int{10} } func (x *ReConnMsg) GetHead() *ReConnMsgHead { @@ -510,43 +692,59 @@ var file_message_proto_rawDesc = []byte{ 0x32, 0x10, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, - 0x61, 0x64, 0x22, 0x6c, 0x0a, 0x06, 0x41, 0x43, 0x4b, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, - 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, - 0x73, 0x67, 0x12, 0x24, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x10, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6d, 0x64, 0x54, 0x79, - 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, - 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, - 0x22, 0x2a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, - 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x08, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x22, 0x59, 0x0a, 0x08, - 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x29, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, - 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x42, - 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x12, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, - 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x22, 0x69, 0x0a, 0x0c, 0x48, - 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x2d, 0x0a, 0x04, 0x48, - 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, - 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x48, 0x65, - 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, - 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, - 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, - 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x22, - 0x5d, 0x0a, 0x09, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x2a, 0x0a, 0x04, - 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, - 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, - 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x2a, 0x38, - 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, - 0x69, 0x6e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, - 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x10, 0x02, 0x12, - 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4b, 0x10, 0x03, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x3b, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x64, 0x22, 0x4d, 0x0a, 0x05, 0x55, 0x50, 0x4d, 0x73, 0x67, 0x12, 0x26, 0x0a, 0x04, 0x48, + 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x55, 0x50, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, + 0x65, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x55, 0x50, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x55, 0x50, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, + 0x79, 0x22, 0x3f, 0x0a, 0x09, 0x55, 0x50, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, + 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, + 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, + 0x49, 0x44, 0x22, 0x39, 0x0a, 0x07, 0x50, 0x75, 0x73, 0x68, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, + 0x05, 0x4d, 0x73, 0x67, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x4d, 0x73, + 0x67, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x88, 0x01, + 0x0a, 0x06, 0x41, 0x43, 0x4b, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x24, + 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x22, 0x2a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x44, 0x22, 0x59, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, + 0x12, 0x29, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, + 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, + 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, + 0x12, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, + 0x65, 0x61, 0x64, 0x22, 0x69, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, + 0x4d, 0x73, 0x67, 0x12, 0x2d, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x72, + 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, + 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, + 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x48, 0x65, + 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x27, + 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x22, 0x5d, 0x0a, 0x09, 0x52, 0x65, 0x43, 0x6f, 0x6e, + 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x2a, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x43, + 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, + 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, + 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x2a, 0x4a, 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, + 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, + 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4b, 0x10, 0x03, + 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x75, 0x73, 0x68, + 0x10, 0x05, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x3b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -562,29 +760,33 @@ func file_message_proto_rawDescGZIP() []byte { } var file_message_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_message_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_message_proto_goTypes = []interface{}{ (CmdType)(0), // 0: message.CmdType (*MsgCmd)(nil), // 1: message.MsgCmd - (*ACKMsg)(nil), // 2: message.ACKMsg - (*LoginMsgHead)(nil), // 3: message.LoginMsgHead - (*LoginMsg)(nil), // 4: message.LoginMsg - (*HeartbeatMsgHead)(nil), // 5: message.HeartbeatMsgHead - (*HeartbeatMsg)(nil), // 6: message.HeartbeatMsg - (*ReConnMsgHead)(nil), // 7: message.ReConnMsgHead - (*ReConnMsg)(nil), // 8: message.ReConnMsg + (*UPMsg)(nil), // 2: message.UPMsg + (*UPMsgHead)(nil), // 3: message.UPMsgHead + (*PushMsg)(nil), // 4: message.PushMsg + (*ACKMsg)(nil), // 5: message.ACKMsg + (*LoginMsgHead)(nil), // 6: message.LoginMsgHead + (*LoginMsg)(nil), // 7: message.LoginMsg + (*HeartbeatMsgHead)(nil), // 8: message.HeartbeatMsgHead + (*HeartbeatMsg)(nil), // 9: message.HeartbeatMsg + (*ReConnMsgHead)(nil), // 10: message.ReConnMsgHead + (*ReConnMsg)(nil), // 11: message.ReConnMsg } var file_message_proto_depIdxs = []int32{ - 0, // 0: message.MsgCmd.Type:type_name -> message.CmdType - 0, // 1: message.ACKMsg.Type:type_name -> message.CmdType - 3, // 2: message.LoginMsg.Head:type_name -> message.LoginMsgHead - 5, // 3: message.HeartbeatMsg.Head:type_name -> message.HeartbeatMsgHead - 7, // 4: message.ReConnMsg.Head:type_name -> message.ReConnMsgHead - 5, // [5:5] is the sub-list for method output_type - 5, // [5:5] is the sub-list for method input_type - 5, // [5:5] is the sub-list for extension type_name - 5, // [5:5] is the sub-list for extension extendee - 0, // [0:5] is the sub-list for field type_name + 0, // 0: message.MsgCmd.Type:type_name -> message.CmdType + 3, // 1: message.UPMsg.Head:type_name -> message.UPMsgHead + 0, // 2: message.ACKMsg.Type:type_name -> message.CmdType + 6, // 3: message.LoginMsg.Head:type_name -> message.LoginMsgHead + 8, // 4: message.HeartbeatMsg.Head:type_name -> message.HeartbeatMsgHead + 10, // 5: message.ReConnMsg.Head:type_name -> message.ReConnMsgHead + 6, // [6:6] is the sub-list for method output_type + 6, // [6:6] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name } func init() { file_message_proto_init() } @@ -606,7 +808,7 @@ func file_message_proto_init() { } } file_message_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ACKMsg); i { + switch v := v.(*UPMsg); i { case 0: return &v.state case 1: @@ -618,7 +820,7 @@ func file_message_proto_init() { } } file_message_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginMsgHead); i { + switch v := v.(*UPMsgHead); i { case 0: return &v.state case 1: @@ -630,7 +832,7 @@ func file_message_proto_init() { } } file_message_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginMsg); i { + switch v := v.(*PushMsg); i { case 0: return &v.state case 1: @@ -642,7 +844,7 @@ func file_message_proto_init() { } } file_message_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HeartbeatMsgHead); i { + switch v := v.(*ACKMsg); i { case 0: return &v.state case 1: @@ -654,7 +856,7 @@ func file_message_proto_init() { } } file_message_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HeartbeatMsg); i { + switch v := v.(*LoginMsgHead); i { case 0: return &v.state case 1: @@ -666,7 +868,7 @@ func file_message_proto_init() { } } file_message_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReConnMsgHead); i { + switch v := v.(*LoginMsg); i { case 0: return &v.state case 1: @@ -678,6 +880,42 @@ func file_message_proto_init() { } } file_message_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HeartbeatMsgHead); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HeartbeatMsg); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReConnMsgHead); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_message_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ReConnMsg); i { case 0: return &v.state @@ -696,7 +934,7 @@ func file_message_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_message_proto_rawDesc, NumEnums: 1, - NumMessages: 8, + NumMessages: 11, NumExtensions: 0, NumServices: 0, }, diff --git a/common/idl/message/message.proto b/common/idl/message/message.proto index 3c2b684..650189b 100644 --- a/common/idl/message/message.proto +++ b/common/idl/message/message.proto @@ -9,6 +9,8 @@ enum CmdType { //枚举消息类型 Heartbeat = 1; ReConn = 2; ACK = 3; + UP = 4; // 上行消息 + Push = 5; // 下行 推送消息 } // 顶层cmd pb结构 @@ -17,12 +19,31 @@ message MsgCmd{ bytes Payload = 2; } +// 上行消息 pb结构 +message UPMsg { + UPMsgHead Head = 1; + bytes UPMsgBody = 2; +} + +// 上行消息头 pb结构 +message UPMsgHead { + uint64 ClientID = 1; + uint64 ConnID = 2; +} + +// 下行消息 pb结构 +message PushMsg { + uint64 MsgID = 1; + bytes Content = 2; +} + // ACK 消息 message ACKMsg { uint32 Code = 1; string Msg = 2; CmdType Type = 3; uint64 ConnID = 4; + uint64 ClientID = 5; // client msg id -> cid } // 登陆消息 diff --git a/state/server.go b/state/server.go index 44b3fbd..63d0090 100644 --- a/state/server.go +++ b/state/server.go @@ -72,6 +72,10 @@ func msgCmdHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { heartbeatMsgHandler(cmdCtx, msgCmd) case message.CmdType_ReConn: reConnMsgHandler(cmdCtx, msgCmd) + case message.CmdType_UP: + upMsgHandler(cmdCtx, msgCmd) + case message.CmdType_ACK: + ackMsgHandler(cmdCtx, msgCmd) } } @@ -94,7 +98,7 @@ func loginMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { // init conn message connToStateTable.Store(cmdCtx.ConnID, &connState{heartTimer: t, connID: cmdCtx.ConnID}) - sendAckMsg(cmdCtx.ConnID, 0, "login") + sendAckMsg(message.CmdType_Login, cmdCtx.ConnID, 0, 0, "login") } func heartbeatMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { @@ -134,30 +138,98 @@ func reConnMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { // 变更connID, cmdCtx中的connID才是 gateway重连的新连接 state.connID = cmdCtx.ConnID connToStateTable.Store(state.connID, state) - sendAckMsg(cmdCtx.ConnID, 0, "reconn ok") + sendAckMsg(message.CmdType_ReConn, cmdCtx.ConnID, 0, 0, "reconn ok") } else { - sendAckMsg(cmdCtx.ConnID, 1, "reconn failed") + sendAckMsg(message.CmdType_ReConn, cmdCtx.ConnID, 0, 1, "reconn failed") } } -func sendAckMsg(connID uint64, code uint32, msg string) { +func sendAckMsg(ackType message.CmdType, connID, clientID uint64, code uint32, msg string) { ackMsg := &message.ACKMsg{} ackMsg.Code = code ackMsg.Msg = msg ackMsg.ConnID = connID + ackMsg.Type = ackType + ackMsg.ClientID = clientID ctx := context.TODO() downLoad, err := proto.Marshal(ackMsg) if err != nil { - logger.CtxErrorf(ctx, "sendMsg err=%s, connID=%v, code=%v, msg=%v", err, connID, code, msg) + logger.CtxErrorf(ctx, "sendAckMsg err=%s, connID=%v, code=%v, msg=%v", err, connID, code, msg) return } + sendMsg(connID, message.CmdType_ACK, downLoad) +} + +func sendMsg(connID uint64, ty message.CmdType, download []byte) { mc := &message.MsgCmd{} - mc.Type = message.CmdType_ACK - mc.Payload = downLoad + mc.Type = ty + mc.Payload = download data, err := proto.Marshal(mc) + ctx := context.TODO() if err != nil { - logger.CtxErrorf(ctx, "sendMsg err=%s, connID=%v, code=%v, msg=%v", err, connID, code, msg) + logger.CtxErrorf(ctx, "sendMsg err=%s, connID=%v, ty=%v, msg=%v", err, connID, ty, string(download)) return } client.Push(&ctx, connID, data) } + +// 处理下行消息 +func ackMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { + ackMsg := &message.ACKMsg{} + err := proto.Unmarshal(msgCmd.Payload, ackMsg) + if err != nil { + logger.CtxErrorf(*cmdCtx.Ctx, "ackMsgHandler err=%v", err.Error()) + return + } + if data, ok := connToStateTable.Load(ackMsg.ConnID); ok { + state, _ := data.(*connState) + state.Lock() + defer state.Unlock() + if state.msgTimer != nil { + state.msgTimer.Stop() + state.msgTimer = nil + } + } +} + +// 处理上行消息,并进行消息可靠性检查 +func upMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { + upMsg := &message.UPMsg{} + err := proto.Unmarshal(msgCmd.Payload, upMsg) + if err != nil { + logger.CtxErrorf(*cmdCtx.Ctx, "upMsgHandler err=%v", err.Error()) + return + } + if data, ok := connToStateTable.Load(upMsg.Head.ConnID); ok { + state, _ := data.(*connState) + if !state.checkUPMsg(upMsg.Head.ClientID) { + // todo 如果没有通过检查,当作先直接忽略即可 + return + } + // 调用下游业务层rpc,只有当rpc回复成功后才能更新max_clientID + // 这里先假设成功 + state.addMaxClientID() + state.msgID++ + sendAckMsg(message.CmdType_UP, upMsg.Head.ConnID, upMsg.Head.ClientID, 0, "ok") + + // todo 先在这里push消息 + pushMsg := &message.PushMsg{ + MsgID: state.msgID, + Content: upMsg.UPMsgBody, + } + pData, err := proto.Marshal(pushMsg) + if err != nil { + logger.CtxErrorf(*cmdCtx.Ctx, "upMsgHandler Marshal pushMsg err=%v, pData=%v", err.Error(), string(pData)) + return + } + sendMsg(state.connID, message.CmdType_Push, pData) + if state.msgTimer != nil { + state.msgTimer = nil + } + // create pushMsg timer + t := AfterFunc(100*time.Millisecond, func() { + rePush(cmdCtx.ConnID, pData) + }) + state.msgTimer = t + } +} diff --git a/state/state.go b/state/state.go index 501a09e..d20ceab 100644 --- a/state/state.go +++ b/state/state.go @@ -2,6 +2,7 @@ package state import ( "context" + "github.com/hardcore-os/plato/common/idl/message" "github.com/hardcore-os/plato/common/timingwheel" "github.com/hardcore-os/plato/state/rpc/client" "sync" @@ -17,7 +18,23 @@ type connState struct { sync.RWMutex heartTimer *timingwheel.Timer reConnTimer *timingwheel.Timer + msgTimer *timingwheel.Timer connID uint64 + maxClientID uint64 + msgID uint64 // use for test +} + +func (c *connState) checkUPMsg(clientID uint64) bool { + c.Lock() + defer c.Unlock() + return clientID == c.maxClientID+1 +} + +// todo 这里可以考虑设计成无锁的并发模式 +func (c *connState) addMaxClientID() { + c.Lock() // 不要迷恋原子操作,如果锁的临界区很小,性能与原子操作相差无己并发性能瓶颈,保持简单可靠即可。 + defer c.Unlock() // go的读写锁本身就有自旋等无锁优化 + c.maxClientID++ } func (c *connState) resetHeartTimer() { @@ -43,3 +60,19 @@ func clearState(connID uint64) { }) } } + +func rePush(connID uint64, msgData []byte) { + sendMsg(connID, message.CmdType_Push, msgData) + if data, ok := connToStateTable.Load(connID); ok { + state, _ := data.(*connState) + state.Lock() + defer state.Unlock() + if state.msgTimer != nil { + state.msgTimer.Stop() + } + state.msgTimer = AfterFunc(100*time.Millisecond, func() { + rePush(connID, msgData) + }) + + } +} From a013b2c6849ee48ad0baec28968b0a107ba0d7a3 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Wed, 28 Feb 2024 20:49:10 +0800 Subject: [PATCH 19/26] feat: improve msg reliability --- chat.log | 28 +++++++++--------- client/cui.go | 26 +++++++++------- common/sdk/api.go | 75 ++++++++++++++++++++++++++++++++--------------- common/sdk/net.go | 44 +++++++++++++++++++++++---- gateway/epoll.go | 4 +-- gateway/server.go | 2 +- perf/perf.go | 2 +- state/server.go | 11 +++---- 8 files changed, 128 insertions(+), 64 deletions(-) diff --git a/chat.log b/chat.log index f844317..20bd952 100644 --- a/chat.log +++ b/chat.log @@ -1,15 +1,15 @@ -me: 1112 -logic: 1112 -me: 213 -logic: 213 -me: wd -logic: wd -me: askdjklasjdklasjdlksajldkjaslkdjaskljdlksajdlsadkl -logic: askdjklasjdklasjdlksajldkjaslkdjaskljdlksajdlsadkl -me: djlkasjdklsajdlksajdklsa -logic: djlkasjdklsajdlksajdklsa -me: dklsadjklsjlkdask -logic: dklsadjklsjlkdask -me: dklasjldjaklsj -logic: dklasjldjaklsj +me: 11111 +logic: 11111 +me: 2222 +logic: 2222 +me: dsadsa +logic: dsadsa +me: jdklasjdl +logic: jdklasjdl +me: dklsajdlkjsalkdlksd +logic: dklsajdlkjsalkdlksd +me: kalsjdkljsalkd +logic: kalsjdkljsalkd +me: abcdfdsfksjfklas +logic: abcdfdsfksjfklas diff --git a/client/cui.go b/client/cui.go index 0479542..db9dd29 100644 --- a/client/cui.go +++ b/client/cui.go @@ -64,7 +64,14 @@ func viewPrint(g *gocui.Gui, name, msg string, newline bool) { func doRecv(g *gocui.Gui) { recvChannel := chat.Recv() for msg := range recvChannel { - viewPrint(g, msg.Name, msg.Content, false) + if msg != nil { + switch msg.Type { + case sdk.MsgTypeText: + viewPrint(g, msg.Name, msg.Content, false) + case sdk.MsgTypeAck: + //TODO 默认不处理 + } + } } } @@ -220,7 +227,7 @@ func pasteDown(g *gocui.Gui, cv *gocui.View) error { func RunMain() { // step1 创建caht的核心对象 - chat = sdk.NewChat(net.ParseIP("0.0.0.0"), 8900, "logic", "12312321", "2131", 0, false) + chat = sdk.NewChat(net.ParseIP("0.0.0.0"), 8900, "logic", "12312321", "2131") // step2 创建 GUI 图层对象并进行参与与回调函数的配置 g, err := gocui.NewGui(gocui.OutputNormal) if err != nil { @@ -255,15 +262,12 @@ func RunMain() { } // emit disconnection - go func() { - time.Sleep(10 * time.Second) - chat.Close() - time.Sleep(3 * time.Second) - connID := chat.GetConnID() - // reconnection - chat = sdk.NewChat(net.ParseIP("0.0.0.0"), 8900, "logic", "12312321", "2131", connID, true) - go doRecv(g) - }() + //go func() { + // time.Sleep(10 * time.Second) + // // reconnection + // chat.ReConn() + // go doRecv(g) + //}() // 启动消费函数 go doRecv(g) diff --git a/common/sdk/api.go b/common/sdk/api.go index 4203f39..bd3adbc 100644 --- a/common/sdk/api.go +++ b/common/sdk/api.go @@ -1,11 +1,13 @@ package sdk import ( + "encoding/json" "fmt" "github.com/golang/protobuf/proto" "github.com/hardcore-os/plato/common/idl/message" "github.com/hardcore-os/plato/common/tcp" "net" + "sync" "time" ) @@ -18,11 +20,13 @@ const ( ) type Chat struct { - Nick string - UserID string - SessionID string - conn *connect - closeChan chan struct{} + Nick string + UserID string + SessionID string + conn *connect + closeChan chan struct{} + MsgClientIDTable map[string]uint64 + sync.RWMutex } type Message struct { @@ -34,27 +38,32 @@ type Message struct { Session string } -func NewChat(ip net.IP, port int, nick, userID, sessionID string, connID uint64, isReConn bool) *Chat { +func NewChat(ip net.IP, port int, nick, userID, sessionID string) *Chat { chat := &Chat{ - Nick: nick, - UserID: userID, - SessionID: sessionID, - conn: newConnet(ip, port, connID), - closeChan: make(chan struct{}, 0), + Nick: nick, + UserID: userID, + SessionID: sessionID, + conn: newConnet(ip, port), + closeChan: make(chan struct{}), + MsgClientIDTable: make(map[string]uint64), } go chat.loop() - if isReConn { - chat.reConn(connID) - } else { - chat.login() - } + chat.login() go chat.heartbeat() return chat } func (chat *Chat) Send(msg *Message) { - //chat.conn.send(msg) - chat.conn.recvChan <- msg + data, _ := json.Marshal(msg) + upMsg := &message.UPMsg{ + Head: &message.UPMsgHead{ + ClientID: chat.getClientID(msg.Session), + ConnID: chat.conn.connID, + }, + UPMsgBody: data, + } + payload, _ := proto.Marshal(upMsg) + chat.conn.send(message.CmdType_UP, payload) } // Close chat @@ -65,8 +74,11 @@ func (chat *Chat) Close() { close(chat.conn.recvChan) } -func (chat *Chat) GetConnID() uint64 { - return chat.conn.connID +func (chat *Chat) ReConn() { + chat.Lock() + defer chat.Unlock() + chat.conn.reConn() + chat.reConn() } // Recv receive message @@ -75,6 +87,7 @@ func (chat *Chat) Recv() <-chan *Message { } func (chat *Chat) loop() { +Loop: defer func() { if r := recover(); r != nil { fmt.Printf("[chat] loop panic, err=%v\n", r) @@ -89,17 +102,19 @@ func (chat *Chat) loop() { data, err := tcp.ReadData(chat.conn.conn) if err != nil { fmt.Printf("[chat] loop: read data from conn err=%v, data=%v\n", err, string(data)) - continue + goto Loop } err = proto.Unmarshal(data, mc) if err != nil { - fmt.Printf("[chat] loop: Unmarshal data failed, err=%v, data=%v\n", string(data)) + fmt.Printf("[chat] loop: Unmarshal data failed, err=%v, data=%v\n", err, string(data)) continue } var msg *Message switch mc.Type { case message.CmdType_ACK: msg = handAckMsg(chat.conn, mc.Payload) + case message.CmdType_Push: + msg = handlePushMsg(chat.conn, mc.Payload) } chat.conn.recvChan <- msg } @@ -120,10 +135,10 @@ func (chat *Chat) login() { chat.conn.send(message.CmdType_Login, payload) } -func (chat *Chat) reConn(connID uint64) { +func (chat *Chat) reConn() { reConn := message.ReConnMsg{ Head: &message.ReConnMsgHead{ - ConnID: connID, + ConnID: chat.conn.connID, }, } payload, err := proto.Marshal(&reConn) @@ -154,3 +169,15 @@ func (chat *Chat) heartbeat() { } } } + +func (chat *Chat) getClientID(sessionID string) uint64 { + chat.Lock() + defer chat.Unlock() + var res uint64 + if id, ok := chat.MsgClientIDTable[sessionID]; ok { + res = id + } + res++ + chat.MsgClientIDTable[sessionID] = res + return res +} diff --git a/common/sdk/net.go b/common/sdk/net.go index 9407112..54b5a4d 100644 --- a/common/sdk/net.go +++ b/common/sdk/net.go @@ -1,23 +1,31 @@ package sdk import ( + "context" + "encoding/json" "fmt" + "github.com/bytedance/gopkg/util/logger" "github.com/golang/protobuf/proto" "github.com/hardcore-os/plato/common/idl/message" "github.com/hardcore-os/plato/common/tcp" "net" + "sync/atomic" ) type connect struct { sendChan, recvChan chan *Message conn *net.TCPConn connID uint64 + ip net.IP + port int } -func newConnet(ip net.IP, port int, connID uint64) *connect { +func newConnet(ip net.IP, port int) *connect { clientConn := &connect{ sendChan: make(chan *Message), recvChan: make(chan *Message), + ip: ip, + port: port, } addr := &net.TCPAddr{ IP: ip, @@ -29,9 +37,6 @@ func newConnet(ip net.IP, port int, connID uint64) *connect { return nil } clientConn.conn = conn - if connID != 0 { - clientConn.connID = connID - } return clientConn } @@ -39,8 +44,8 @@ func handAckMsg(c *connect, data []byte) *Message { ackMsg := &message.ACKMsg{} _ = proto.Unmarshal(data, ackMsg) switch ackMsg.Type { - case message.CmdType_Login: - c.connID = ackMsg.ConnID + case message.CmdType_Login, message.CmdType_ReConn: + atomic.StoreUint64(&c.connID, ackMsg.ConnID) } return &Message{ Type: MsgTypeAck, @@ -51,6 +56,33 @@ func handAckMsg(c *connect, data []byte) *Message { } } +func handlePushMsg(c *connect, data []byte) *Message { + pushMsg := &message.PushMsg{} + _ = proto.Unmarshal(data, pushMsg) + msg := &Message{} + _ = json.Unmarshal(pushMsg.Content, msg) + ackMsg := &message.ACKMsg{ + Type: message.CmdType_UP, + ConnID: c.connID, + } + ackData, _ := proto.Marshal(ackMsg) + c.send(message.CmdType_ACK, ackData) + return msg +} + +func (c *connect) reConn() { + c.conn.Close() + addr := &net.TCPAddr{ + IP: c.ip, + Port: c.port, + } + conn, err := net.DialTCP("tcp", nil, addr) + if err != nil { + logger.CtxErrorf(context.TODO(), "reConn DialTcp.err=%+v", err) + } + c.conn = conn +} + func (c *connect) send(ty message.CmdType, payload []byte) { // 直接发送给接收方 msgCmd := message.MsgCmd{ diff --git a/gateway/epoll.go b/gateway/epoll.go index 1ce6c0a..4369036 100644 --- a/gateway/epoll.go +++ b/gateway/epoll.go @@ -164,7 +164,7 @@ func (epl *epoller) add(conn *connection) error { return err } epl.fdToConnTable.Store(conn.fd, conn) - ep.tables.Store(fd, conn) + ep.tables.Store(conn.id, conn) conn.BindEpoller(epl) return nil } @@ -176,7 +176,7 @@ func (epl *epoller) remove(conn *connection) error { if err != nil { return err } - ep.tables.Delete(fd) + ep.tables.Delete(conn.id) epl.fdToConnTable.Delete(conn.fd) return nil } diff --git a/gateway/server.go b/gateway/server.go index dcabf55..79d82f8 100644 --- a/gateway/server.go +++ b/gateway/server.go @@ -47,7 +47,6 @@ func startRPCServer() { prpc.WithPort(config.GetGatewayRPCServerPort()), prpc.WithWeight(config.GetGatewayRPCWeight()), ) - logger.CtxInfof(ctx, "[gateway] serviceName:%s Addr:%s:%d weight:%d", config.GetGatewayServiceName(), config.GetGatewayServiceAddr(), config.GetGatewayRPCServerPort(), config.GetGatewayRPCWeight()) s.RegisterService(func(server *grpc.Server) { service.RegisterGatewayServer(server, &service.Service{CmdChannel: cmdChannel}) }) @@ -57,6 +56,7 @@ func startRPCServer() { go cmdHandler() // start rpc server s.Start(context.TODO()) + logger.CtxInfof(ctx, "[gateway] serviceName:%s Addr:%s:%d weight:%d", config.GetGatewayServiceName(), config.GetGatewayServiceAddr(), config.GetGatewayRPCServerPort(), config.GetGatewayRPCWeight()) } func runProc(c *connection, ep *epoller) { diff --git a/perf/perf.go b/perf/perf.go index 1298a89..b1e9038 100644 --- a/perf/perf.go +++ b/perf/perf.go @@ -11,7 +11,7 @@ var ( func RunMain() { for i := 0; i < int(TcpConnNum); i++ { - sdk.NewChat(net.ParseIP("127.0.0.1"), 8900, "logic", "1223", "123", 0, false) + sdk.NewChat(net.ParseIP("127.0.0.1"), 8900, "logic", "1223", "123") } select {} } diff --git a/state/server.go b/state/server.go index 63d0090..ab349fc 100644 --- a/state/server.go +++ b/state/server.go @@ -47,7 +47,7 @@ func cmdHandler() { case service.CancelConnCmd: logger.CtxInfof(*cmdCtx.Ctx, "cancelConn endpoint:%s, fd:%d, data:%+v", cmdCtx.Endpoint, cmdCtx.ConnID, cmdCtx.PayLoad) case service.SendMsgCmd: - logger.CtxInfof(*cmdCtx.Ctx, "cmdHandler: %v", string(cmdCtx.PayLoad)) + logger.CtxInfof(*cmdCtx.Ctx, "cmdHandler: %v\n", string(cmdCtx.PayLoad)) msgCmd := &message.MsgCmd{} err := proto.Unmarshal(cmdCtx.PayLoad, msgCmd) if err != nil { @@ -88,7 +88,7 @@ func loginMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { } if loginMsg.Head != nil { // 这里会把 login msg 传送给业务层做处理 - logger.CtxInfof(*cmdCtx.Ctx, "loginMsgHandler", loginMsg.Head.DeviceID) + logger.CtxInfof(*cmdCtx.Ctx, "loginMsgHandler:%v", loginMsg.Head.DeviceID) } // create timer @@ -98,7 +98,7 @@ func loginMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { // init conn message connToStateTable.Store(cmdCtx.ConnID, &connState{heartTimer: t, connID: cmdCtx.ConnID}) - sendAckMsg(message.CmdType_Login, cmdCtx.ConnID, 0, 0, "login") + sendAckMsg(message.CmdType_Login, cmdCtx.ConnID, 0, 0, "login ok") } func heartbeatMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { @@ -111,6 +111,7 @@ func heartbeatMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { if data, ok := connToStateTable.Load(cmdCtx.ConnID); ok { state, _ := data.(*connState) state.resetHeartTimer() + logger.CtxInfof(*cmdCtx.Ctx, "[heartbeatMsgHandler] reset heartbeat success, connID=%v", cmdCtx.ConnID) } // 减少通信量,可以暂时不回复心跳的ack } @@ -222,9 +223,9 @@ func upMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { logger.CtxErrorf(*cmdCtx.Ctx, "upMsgHandler Marshal pushMsg err=%v, pData=%v", err.Error(), string(pData)) return } - sendMsg(state.connID, message.CmdType_Push, pData) + sendMsg(upMsg.Head.ConnID, message.CmdType_Push, pData) if state.msgTimer != nil { - state.msgTimer = nil + state.msgTimer.Stop() } // create pushMsg timer t := AfterFunc(100*time.Millisecond, func() { From cf1592e4b8d0b18ff502a8ba833dfacd4168b610 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Thu, 2 May 2024 14:45:06 +0800 Subject: [PATCH 20/26] feat: state decentralized --- client/cui.go | 3 +- common/cache/const.go | 10 ++ common/cache/lua.go | 34 +++++ common/cache/redis.go | 123 +++++++++++++++ common/config/config.go | 4 + common/config/gateway.go | 8 +- common/config/state.go | 34 ++++- common/idl/message/message.pb.go | 129 +++++++++------- common/idl/message/message.proto | 5 +- common/prpc/client.go | 15 ++ common/router/table.go | 55 +++++++ common/sdk/api.go | 43 ++++-- common/sdk/net.go | 12 +- common/utils/hash.go | 13 ++ gateway/connection.go | 74 ++++++++- gateway/rpc/client/init.go | 7 +- gateway/rpc/service/service.go | 6 +- go.mod | 2 + go.sum | 6 + plato.yaml | 9 +- state/cache.go | 247 +++++++++++++++++++++++++++++++ state/rpc/client/init.go | 7 +- state/rpc/service/service.go | 2 +- state/server.go | 230 +++++++++++++++++----------- state/state.go | 174 +++++++++++++++++----- 25 files changed, 1045 insertions(+), 207 deletions(-) create mode 100644 common/cache/const.go create mode 100644 common/cache/lua.go create mode 100644 common/cache/redis.go create mode 100644 common/router/table.go create mode 100644 common/utils/hash.go create mode 100644 state/cache.go diff --git a/client/cui.go b/client/cui.go index db9dd29..e7e09bc 100644 --- a/client/cui.go +++ b/client/cui.go @@ -95,7 +95,8 @@ func doSay(g *gocui.Gui, cv *gocui.View) { ToUserID: "222222", Content: string(p)} // 先把自己说的话显示到消息流中 - viewPrint(g, "me", msg.Content, false) + idKey := fmt.Sprintf("%d", chat.GetCurClientID()) + viewPrint(g, "me-clientID:"+idKey, msg.Content, false) chat.Send(msg) } v.Autoscroll = true diff --git a/common/cache/const.go b/common/cache/const.go new file mode 100644 index 0000000..3a14f69 --- /dev/null +++ b/common/cache/const.go @@ -0,0 +1,10 @@ +package cache + +import "time" + +const ( + MaxClientIDKey = "max_client_id_{%d}_%d" // slot_connID + LastMsgKey = "last_msg_{%d}_%d" // slot_connID + LoginSlotSetKey = "login_slot_set_{%d}" // 通过 hash tag保证在cluster模式上 key都在一个shard上 // slot + TTL7D = 7 * 24 * time.Hour +) diff --git a/common/cache/lua.go b/common/cache/lua.go new file mode 100644 index 0000000..b67bd7c --- /dev/null +++ b/common/cache/lua.go @@ -0,0 +1,34 @@ +package cache + +import ( + "context" + "fmt" +) + +const ( + LuaCompareAndIncrClientID = "LuaCompareAndIncrClientID" +) + +type luaPart struct { + LuaScript string + Sha string +} + +var luaScriptTable map[string]*luaPart = map[string]*luaPart{ + LuaCompareAndIncrClientID: &luaPart{ + LuaScript: "if reds.call('exists', KEYS[1]) == 0 then redis.call('set', KEYS[1], 0) end; if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('incr', KEYS[1]);redis.call('expire', KEYS[1], ARGV[2]);return 1 else return -1 end", + }, +} + +func initLuaScript(ctx context.Context) { + for name, part := range luaScriptTable { + cmd := rdb.ScriptLoad(ctx, part.LuaScript) + if cmd == nil { + panic(fmt.Sprintf("lua init failed, lua=%v", name)) + } + if cmd.Err() != nil { + panic(cmd.Err()) + } + part.Sha = cmd.Val() + } +} diff --git a/common/cache/redis.go b/common/cache/redis.go new file mode 100644 index 0000000..3ff34f1 --- /dev/null +++ b/common/cache/redis.go @@ -0,0 +1,123 @@ +package cache + +import ( + "context" + "errors" + "time" + + "github.com/hardcore-os/plato/common/config" + redis "github.com/redis/go-redis/v9" +) + +// 声明一个全局的rdb变量,这是一个单机client +var rdb *redis.Client + +func InitRedis(ctx context.Context) { + if rdb != nil { + return + } + endpoints := config.GetCacheRedisEndpointList() + opt := &redis.Options{Addr: endpoints[0], PoolSize: 10000} + rdb = redis.NewClient(opt) + if _, err := rdb.Ping(ctx).Result(); err != nil { + panic(err) + } + initLuaScript(ctx) +} +func GetBytes(ctx context.Context, key string) ([]byte, error) { + cmd := rdb.Conn().Get(ctx, key) + if cmd == nil { + return nil, errors.New("redis GetBytes cmd is nil") + } + data, err := cmd.Bytes() + if redis.Nil == err { + return nil, nil + } + return data, err +} + +func GetUInt64(ctx context.Context, key string) (uint64, error) { + cmd := rdb.Conn().Get(ctx, key) + if cmd == nil { + return 0, errors.New("redis GetUInt64 cmd is nil") + } + return cmd.Uint64() +} + +func SetBytes(ctx context.Context, key string, value []byte, ttl time.Duration) error { + cmd := rdb.Set(ctx, key, value, ttl) + if cmd == nil { + return errors.New("redis SetBytes cmd is nil") + } + return cmd.Err() +} + +func Del(ctx context.Context, key string) error { + cmd := rdb.Conn().Del(ctx, key) + if cmd == nil { + return errors.New("redis Del cmd is nil") + } + return cmd.Err() +} + +func SADD(ctx context.Context, key string, member interface{}) error { + cmd := rdb.SAdd(ctx, key, member) + if cmd == nil { + return errors.New("redis SADD cmd is nil") + } + return cmd.Err() +} + +func SREM(ctx context.Context, key string, members ...interface{}) error { + cmd := rdb.Conn().SRem(ctx, key, members...) + if cmd == nil { + return errors.New("redis SREM cmd is nil") + } + return cmd.Err() +} + +func SmembersStrSlice(ctx context.Context, key string) ([]string, error) { + cmd := rdb.Conn().SMembers(ctx, key) + if cmd == nil { + return nil, errors.New("redis SmembersUint64StructMap cmd is nil") + } + return cmd.Result() +} + +func Incr(ctx context.Context, key string, ttl time.Duration) error { + _, err := rdb.Conn().Pipelined(ctx, func(p redis.Pipeliner) error { + p.Incr(ctx, key) + p.Expire(ctx, key, ttl) + return nil + }) + return err +} + +func SetString(ctx context.Context, key string, value string, ttl time.Duration) error { + cmd := rdb.Set(ctx, key, value, ttl) + if cmd == nil { + return errors.New("redis SetString cmd is nil") + } + return cmd.Err() +} + +func GetString(ctx context.Context, key string) (string, error) { + cmd := rdb.Get(ctx, key) + if cmd == nil { + return "", errors.New("redis GetString cmd is nil") + } + return cmd.String(), cmd.Err() +} + +func RunLuaInt(ctx context.Context, name string, keys []string, args ...interface{}) (int, error) { + if part, ok := luaScriptTable[name]; !ok { + return -1, errors.New("lua not registered") + } else { + cmd := rdb.EvalSha(ctx, part.Sha, keys, args...) + if cmd == nil { + return -1, errors.New("redis RunLua cmd is nil") + } + + return cmd.Int() + } +} diff --git a/common/config/config.go b/common/config/config.go index b0352c8..2363285 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -27,6 +27,10 @@ func GetServicePathForIPConf() string { return viper.GetString("ip_conf.service_path") } +func GetCacheRedisEndpointList() []string { + return viper.GetStringSlice("cache.redis.endpoints") +} + // IsDebug 判断是不是debug环境 func IsDebug() bool { env := viper.GetString("global.env") diff --git a/common/config/gateway.go b/common/config/gateway.go index 98da0a6..0f5f623 100644 --- a/common/config/gateway.go +++ b/common/config/gateway.go @@ -1,6 +1,8 @@ package config -import "github.com/spf13/viper" +import ( + "github.com/spf13/viper" +) func GetGatewayMaxTcpNum() int32 { return viper.GetInt32("gateway.tcp_max_num") @@ -45,3 +47,7 @@ func GetGatewayServiceName() string { func GetGatewayRPCWeight() int { return viper.GetInt("gateway.weight") } + +func GetGatewayStateServerEndPoint() string { + return viper.GetString("gateway.state_server_endpoint") +} diff --git a/common/config/state.go b/common/config/state.go index 18b2c0f..0cacfb7 100644 --- a/common/config/state.go +++ b/common/config/state.go @@ -1,6 +1,10 @@ package config -import "github.com/spf13/viper" +import ( + "github.com/spf13/viper" + "strconv" + "strings" +) func GetStateCmdChannelNum() int { return viper.GetInt("state.cmd_channel_num") @@ -21,3 +25,31 @@ func GetStateServerPort() int { func GetStateRPCWeight() int { return viper.GetInt("state.weight") } + +var connStateSlotList []int + +func GetStateServerLoginSlotRange() []int { + if len(connStateSlotList) != 0 { + return connStateSlotList + } + slotRnageStr := viper.GetString("state.conn_state_slot_range") + slotRnage := strings.Split(slotRnageStr, ",") + left, err := strconv.Atoi(slotRnage[0]) + if err != nil { + panic(err) + } + right, err := strconv.Atoi(slotRnage[1]) + if err != nil { + panic(err) + } + res := make([]int, right-left+1) + for i := left; i <= right; i++ { + res[i] = i + } + connStateSlotList = res + return connStateSlotList +} + +func GetStateServerGatewayServerEndpoint() string { + return viper.GetString("state.gateway_server_endpoint") +} diff --git a/common/idl/message/message.pb.go b/common/idl/message/message.pb.go index 0f03ec1..86a1ae6 100644 --- a/common/idl/message/message.pb.go +++ b/common/idl/message/message.pb.go @@ -253,8 +253,9 @@ type PushMsg struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - MsgID uint64 `protobuf:"varint,1,opt,name=MsgID,proto3" json:"MsgID,omitempty"` - Content []byte `protobuf:"bytes,2,opt,name=Content,proto3" json:"Content,omitempty"` + MsgID uint64 `protobuf:"varint,1,opt,name=MsgID,proto3" json:"MsgID,omitempty"` + SessionID uint64 `protobuf:"varint,2,opt,name=SessionID,proto3" json:"SessionID,omitempty"` + Content []byte `protobuf:"bytes,3,opt,name=Content,proto3" json:"Content,omitempty"` } func (x *PushMsg) Reset() { @@ -296,6 +297,13 @@ func (x *PushMsg) GetMsgID() uint64 { return 0 } +func (x *PushMsg) GetSessionID() uint64 { + if x != nil { + return x.SessionID + } + return 0 +} + func (x *PushMsg) GetContent() []byte { if x != nil { return x.Content @@ -309,11 +317,13 @@ type ACKMsg struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Code uint32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"` - Msg string `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"` - Type CmdType `protobuf:"varint,3,opt,name=Type,proto3,enum=message.CmdType" json:"Type,omitempty"` - ConnID uint64 `protobuf:"varint,4,opt,name=ConnID,proto3" json:"ConnID,omitempty"` - ClientID uint64 `protobuf:"varint,5,opt,name=ClientID,proto3" json:"ClientID,omitempty"` // client msg id -> cid + Code uint32 `protobuf:"varint,1,opt,name=Code,proto3" json:"Code,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=Msg,proto3" json:"Msg,omitempty"` + Type CmdType `protobuf:"varint,3,opt,name=Type,proto3,enum=message.CmdType" json:"Type,omitempty"` + ConnID uint64 `protobuf:"varint,4,opt,name=ConnID,proto3" json:"ConnID,omitempty"` + ClientID uint64 `protobuf:"varint,5,opt,name=ClientID,proto3" json:"ClientID,omitempty"` // client msg id -> cid + SessionID uint64 `protobuf:"varint,6,opt,name=SessionID,proto3" json:"SessionID,omitempty"` + MsgID uint64 `protobuf:"varint,7,opt,name=MsgID,proto3" json:"MsgID,omitempty"` } func (x *ACKMsg) Reset() { @@ -383,6 +393,20 @@ func (x *ACKMsg) GetClientID() uint64 { return 0 } +func (x *ACKMsg) GetSessionID() uint64 { + if x != nil { + return x.SessionID + } + return 0 +} + +func (x *ACKMsg) GetMsgID() uint64 { + if x != nil { + return x.MsgID + } + return 0 +} + // 登陆消息 type LoginMsgHead struct { state protoimpl.MessageState @@ -701,50 +725,55 @@ var file_message_proto_rawDesc = []byte{ 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, - 0x49, 0x44, 0x22, 0x39, 0x0a, 0x07, 0x50, 0x75, 0x73, 0x68, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, + 0x49, 0x44, 0x22, 0x57, 0x0a, 0x07, 0x50, 0x75, 0x73, 0x68, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x4d, 0x73, 0x67, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x4d, 0x73, - 0x67, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x88, 0x01, - 0x0a, 0x06, 0x41, 0x43, 0x4b, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, - 0x4d, 0x73, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x24, - 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x22, 0x2a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x49, 0x44, 0x22, 0x59, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, - 0x12, 0x29, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, - 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, - 0x12, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, - 0x65, 0x61, 0x64, 0x22, 0x69, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, - 0x4d, 0x73, 0x67, 0x12, 0x2d, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x72, - 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, - 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, - 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x48, 0x65, - 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x27, - 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, - 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, - 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x22, 0x5d, 0x0a, 0x09, 0x52, 0x65, 0x43, 0x6f, 0x6e, - 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x2a, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x43, - 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, - 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, - 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x2a, 0x4a, 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, - 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, - 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4b, 0x10, 0x03, - 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x75, 0x73, 0x68, - 0x10, 0x05, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x3b, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x67, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x44, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x07, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0xbc, 0x01, 0x0a, 0x06, + 0x41, 0x43, 0x4b, 0x4d, 0x73, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x73, + 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x73, 0x67, 0x12, 0x24, 0x0a, 0x04, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x43, 0x6d, 0x64, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x4d, 0x73, 0x67, 0x49, 0x44, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x05, 0x4d, 0x73, 0x67, 0x49, 0x44, 0x22, 0x2a, 0x0a, 0x0c, 0x4c, 0x6f, + 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x44, 0x22, 0x59, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, + 0x73, 0x67, 0x12, 0x29, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x22, 0x0a, + 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, + 0x79, 0x22, 0x12, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, + 0x67, 0x48, 0x65, 0x61, 0x64, 0x22, 0x69, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, + 0x61, 0x74, 0x4d, 0x73, 0x67, 0x12, 0x2d, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x48, 0x65, + 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, + 0x48, 0x65, 0x61, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, + 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, + 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, + 0x22, 0x27, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, + 0x64, 0x12, 0x16, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x43, 0x6f, 0x6e, 0x6e, 0x49, 0x44, 0x22, 0x5d, 0x0a, 0x09, 0x52, 0x65, 0x43, + 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x2a, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x52, + 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x48, 0x65, 0x61, 0x64, 0x52, 0x04, 0x48, 0x65, + 0x61, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x4d, 0x73, 0x67, 0x42, + 0x6f, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x52, 0x65, 0x43, 0x6f, 0x6e, + 0x6e, 0x4d, 0x73, 0x67, 0x42, 0x6f, 0x64, 0x79, 0x2a, 0x4a, 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x10, 0x00, 0x12, 0x0d, + 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x10, 0x01, 0x12, 0x0a, 0x0a, + 0x06, 0x52, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x43, 0x4b, + 0x10, 0x03, 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50, 0x10, 0x04, 0x12, 0x08, 0x0a, 0x04, 0x50, 0x75, + 0x73, 0x68, 0x10, 0x05, 0x42, 0x0c, 0x5a, 0x0a, 0x2e, 0x2f, 0x3b, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/common/idl/message/message.proto b/common/idl/message/message.proto index 650189b..fcd1133 100644 --- a/common/idl/message/message.proto +++ b/common/idl/message/message.proto @@ -34,7 +34,8 @@ message UPMsgHead { // 下行消息 pb结构 message PushMsg { uint64 MsgID = 1; - bytes Content = 2; + uint64 SessionID = 2; + bytes Content = 3; } // ACK 消息 @@ -44,6 +45,8 @@ message ACKMsg { CmdType Type = 3; uint64 ConnID = 4; uint64 ClientID = 5; // client msg id -> cid + uint64 SessionID = 6; + uint64 MsgID = 7; } // 登陆消息 diff --git a/common/prpc/client.go b/common/prpc/client.go index a4185c0..d2b73a5 100644 --- a/common/prpc/client.go +++ b/common/prpc/client.go @@ -76,3 +76,18 @@ func (p *PClient) dial() (*grpc.ClientConn, error) { return grpc.DialContext(ctx, fmt.Sprintf("discov:///%v", p.serviceName), options...) } + +func (p *PClient) DialByEndPoint(address string) (*grpc.ClientConn, error) { + interceptors := []grpc.UnaryClientInterceptor{ + clientinterceptor.TraceUnaryClientInterceptor(), + clientinterceptor.MetricUnaryClientInterceptor(), + } + interceptors = append(interceptors, p.interceptors...) + options := []grpc.DialOption{ + grpc.WithChainUnaryInterceptor(interceptors...), + grpc.WithInsecure(), + } + + ctx, _ := context.WithTimeout(context.TODO(), dialTimeout) + return grpc.DialContext(ctx, address, options...) +} diff --git a/common/router/table.go b/common/router/table.go new file mode 100644 index 0000000..f6fddf2 --- /dev/null +++ b/common/router/table.go @@ -0,0 +1,55 @@ +package router + +import ( + "context" + "fmt" + "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/common/cache" + "strconv" + "strings" + "time" +) + +const ( + gatewayRouterKey = "gateway_router_%d" // router key + ttl7D = 7 * 24 * 60 * 60 * time.Second +) + +type Record struct { + Endpoint string + ConnID uint64 +} + +func Init(ctx context.Context) { + cache.InitRedis(ctx) +} + +func AddRouter(ctx context.Context, did uint64, endpoint string, connID uint64) error { + key := fmt.Sprintf(gatewayRouterKey, did) + value := fmt.Sprintf("%s-%d", endpoint, connID) + return cache.SetString(ctx, key, value, ttl7D) +} + +func DelRouter(ctx context.Context, did uint64) error { + key := fmt.Sprintf(gatewayRouterKey, did) + return cache.Del(ctx, key) +} + +func QueryRecord(ctx context.Context, did uint64) (*Record, error) { + key := fmt.Sprintf(gatewayRouterKey, did) + data, err := cache.GetString(ctx, key) + if err != nil { + // data can not be nil when err is not nil + return nil, err + } + ec := strings.Split(data, "-") + connID, err := strconv.ParseUint(ec[1], 10, 64) + if err != nil { + logger.CtxErrorf(ctx, "QueryRecord when transfer connID failed, data=%v, err=%v", data, err) + return nil, err + } + return &Record{ + Endpoint: ec[0], + ConnID: connID, + }, nil +} diff --git a/common/sdk/api.go b/common/sdk/api.go index bd3adbc..a784907 100644 --- a/common/sdk/api.go +++ b/common/sdk/api.go @@ -55,15 +55,27 @@ func NewChat(ip net.IP, port int, nick, userID, sessionID string) *Chat { func (chat *Chat) Send(msg *Message) { data, _ := json.Marshal(msg) + key := fmt.Sprintf("%d", chat.conn.connID) upMsg := &message.UPMsg{ Head: &message.UPMsgHead{ - ClientID: chat.getClientID(msg.Session), + ClientID: chat.getClientID(key), ConnID: chat.conn.connID, }, UPMsgBody: data, } payload, _ := proto.Marshal(upMsg) - chat.conn.send(message.CmdType_UP, payload) + err := chat.conn.send(message.CmdType_UP, payload) + if err != nil { + fmt.Printf("[chat] send up msg failed, err=%v\n", err) + } +} + +func (chat *Chat) GetCurClientID() uint64 { + key := fmt.Sprintf("%d", chat.conn.connID) + if id, ok := chat.MsgClientIDTable[key]; ok { + return id + } + return 0 } // Close chat @@ -132,7 +144,10 @@ func (chat *Chat) login() { fmt.Printf("[chat] login, marshal msg failed, err=%v, loginMsg.Head=%+v, loginMsg.Body=%+v\n", err, loginMsg.Head, loginMsg.LoginMsgBody) return } - chat.conn.send(message.CmdType_Login, payload) + err = chat.conn.send(message.CmdType_Login, payload) + if err != nil { + fmt.Printf("[chat] send login msg failed, err=%v\n", err) + } } func (chat *Chat) reConn() { @@ -146,12 +161,19 @@ func (chat *Chat) reConn() { fmt.Printf("[chat] login, marshal msg failed, err=%v, ReConnMsg.Head=%+v, ReConnMsg.Body=%+v\n", err, reConn.Head, reConn.ReConnMsgBody) return } - chat.conn.send(message.CmdType_ReConn, payload) - + err = chat.conn.send(message.CmdType_ReConn, payload) + if err != nil { + fmt.Printf("[chat] send reconn msg failed, err=%v\n", err) + } } func (chat *Chat) heartbeat() { tc := time.NewTicker(1 * time.Second) + defer func() { + chat.heartbeat() + }() + +loop: for { select { case <-chat.closeChan: @@ -163,9 +185,13 @@ func (chat *Chat) heartbeat() { payload, err := proto.Marshal(&heartbeat) if err != nil { fmt.Printf("[chat] heartbeat, marshal msg failed, err=%v\n", err) - return + goto loop + } + err = chat.conn.send(message.CmdType_Heartbeat, payload) + if err != nil { + fmt.Printf("[chat] heartbeat, send heartbeat msg failed, err=%v\n", err) + goto loop } - chat.conn.send(message.CmdType_Heartbeat, payload) } } } @@ -177,7 +203,6 @@ func (chat *Chat) getClientID(sessionID string) uint64 { if id, ok := chat.MsgClientIDTable[sessionID]; ok { res = id } - res++ - chat.MsgClientIDTable[sessionID] = res + chat.MsgClientIDTable[sessionID] = res + 1 return res } diff --git a/common/sdk/net.go b/common/sdk/net.go index 54b5a4d..a35969f 100644 --- a/common/sdk/net.go +++ b/common/sdk/net.go @@ -66,7 +66,10 @@ func handlePushMsg(c *connect, data []byte) *Message { ConnID: c.connID, } ackData, _ := proto.Marshal(ackMsg) - c.send(message.CmdType_ACK, ackData) + err := c.send(message.CmdType_ACK, ackData) + if err != nil { + fmt.Printf("[chat] send push msg failed, pushMsg = %+v, err=%v\n", msg, err) + } return msg } @@ -83,7 +86,7 @@ func (c *connect) reConn() { c.conn = conn } -func (c *connect) send(ty message.CmdType, payload []byte) { +func (c *connect) send(ty message.CmdType, payload []byte) error { // 直接发送给接收方 msgCmd := message.MsgCmd{ Type: ty, @@ -92,13 +95,14 @@ func (c *connect) send(ty message.CmdType, payload []byte) { msg, err := proto.Marshal(&msgCmd) if err != nil { fmt.Printf("[connect] send marshal msg failed, err=%v, type=%v, payload=%v\n", err, ty, string(payload)) - return + return err } dataPgk := tcp.DataPgk{ Len: uint32(len(msg)), Data: msg, } - c.conn.Write(dataPgk.Marshal()) + _, err = c.conn.Write(dataPgk.Marshal()) + return err } func (c *connect) recv() <-chan *Message { diff --git a/common/utils/hash.go b/common/utils/hash.go new file mode 100644 index 0000000..7528c94 --- /dev/null +++ b/common/utils/hash.go @@ -0,0 +1,13 @@ +package utils + +import "hash/crc32" + +// HashStr hash func +func HashStr(key string) uint32 { + if len(key) < 64 { + var scratch [64]byte + copy(scratch[:], key) + return crc32.ChecksumIEEE(scratch[:len(key)]) + } + return crc32.ChecksumIEEE([]byte(key)) +} diff --git a/gateway/connection.go b/gateway/connection.go index 9e8dac2..beb0491 100644 --- a/gateway/connection.go +++ b/gateway/connection.go @@ -1,11 +1,33 @@ package gateway import ( + "errors" "net" - "sync/atomic" + "sync" + "time" ) -var nextConnID uint64 // 全局ConnID +//var nextConnID uint64 // 全局ConnID + +var node *ConnIDGenerator + +const ( + version = uint64(0) // 版本控制 + sequenceBits = uint64(16) + + maxSequence = int64(-1) ^ (int64(-1) << sequenceBits) // 低sequenceBits个bit位都为1,其他高位都为0 + + timeLeft = uint8(16) // timeLeft = sequence // 时间戳向左偏移量 + versionLeft = uint8(63) // 左移动到最高位 + // 2020-05-20 08:00:00 +0800 CST + twepoch = int64(1589923200000) // 常量时间戳(毫秒) +) + +type ConnIDGenerator struct { + mu sync.Mutex + LastStamp int64 // 记录上一次ID的时间戳 + Sequence int64 // 当前毫秒已经生成的ID序列号(从0 开始累加) 1毫秒内最多生成2^16个ID +} type connection struct { id uint64 // 进程级别的生命周期 @@ -14,10 +36,54 @@ type connection struct { conn *net.TCPConn } +func init() { + node = &ConnIDGenerator{} +} + +func (c *ConnIDGenerator) getMilliSeconds() int64 { + return time.Now().UnixMilli() +} + +// NextID 这里的锁会自旋,不会多么影响性能,主要是临界区小 +func (c *ConnIDGenerator) NextID() (uint64, error) { + c.mu.Lock() + defer c.mu.Unlock() + return c.nextID() +} + +func (c *ConnIDGenerator) nextID() (uint64, error) { + timestamp := c.getMilliSeconds() + if timestamp < c.LastStamp { + return 0, errors.New("time is moving backwards, waiting until") + } + + if c.LastStamp == timestamp { + c.Sequence = (c.Sequence + 1) & maxSequence + if c.Sequence == 0 { // 如果这里发生溢出,就等到下一个毫秒时再分配,这样就一定不出现重复 + for timestamp <= c.LastStamp { + timestamp = c.getMilliSeconds() + } + } + } else { // 如果与上次分配的时间戳不等,则为了防止可能的时钟飘移现象,就必须重新计数 + c.Sequence = 0 + } + c.LastStamp = timestamp + // 减法可以压缩一下时间戳 + id := ((timestamp - twepoch) << timeLeft) | c.Sequence + connID := uint64(id) | (version << versionLeft) + return connID, nil +} + func NewConnection(conn *net.TCPConn) *connection { - connID := atomic.AddUint64(&nextConnID, 1) + var ( + id uint64 + err error + ) + if id, err = node.NextID(); err != nil { + panic(err) //在线服务需要解决这个问题 ,报错而不能panic + } return &connection{ - id: connID, + id: id, fd: socketFD(conn), conn: conn, } diff --git a/gateway/rpc/client/init.go b/gateway/rpc/client/init.go index 7baa52a..9276e7f 100644 --- a/gateway/rpc/client/init.go +++ b/gateway/rpc/client/init.go @@ -1,6 +1,7 @@ package client import ( + "fmt" "github.com/hardcore-os/plato/common/config" "github.com/hardcore-os/plato/common/prpc" "github.com/hardcore-os/plato/state/rpc/service" @@ -22,6 +23,10 @@ func initStateClient() { if err != nil { panic(err) } - stateClient = service.NewStateClient(pCli.Conn()) + cli, err := pCli.DialByEndPoint(config.GetGatewayStateServerEndPoint()) + if err != nil { + panic(fmt.Sprintf("gateway.state client DialByEndPoint fialed, err=%v", err)) + } + stateClient = service.NewStateClient(cli) }) } diff --git a/gateway/rpc/service/service.go b/gateway/rpc/service/service.go index 6481a7f..923d638 100644 --- a/gateway/rpc/service/service.go +++ b/gateway/rpc/service/service.go @@ -5,6 +5,8 @@ import "context" const ( DelConnCmd = 1 // DelConn PushCmd = 2 //push + + successRespMsg = "success" ) type CmdContext struct { @@ -28,7 +30,7 @@ func (s *Service) DelConn(ctx context.Context, gr *GatewayRequest) (*GatewayResp } return &GatewayResponse{ Code: 0, - Msg: "success", + Msg: successRespMsg, }, nil } @@ -42,6 +44,6 @@ func (s *Service) Push(ctx context.Context, gr *GatewayRequest) (*GatewayRespons } return &GatewayResponse{ Code: 0, - Msg: "success", + Msg: successRespMsg, }, nil } diff --git a/go.mod b/go.mod index 2d86c81..5c0f92d 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/juju/ratelimit v1.0.2 github.com/panjf2000/ants v1.2.1 github.com/prometheus/client_golang v1.17.0 + github.com/redis/go-redis/v9 v9.5.1 github.com/rocket049/gocui v0.3.2 github.com/sony/gobreaker v0.5.0 github.com/spf13/cobra v1.5.0 @@ -34,6 +35,7 @@ require ( github.com/cloudwego/netpoll v0.5.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff --git a/go.sum b/go.sum index 475d33c..824fa6e 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bytedance/go-tagexpr/v2 v2.9.2 h1:QySJaAIQgOEDQBLS3x9BxOWrnhqu5sQ+f6HaZIxD39I= github.com/bytedance/go-tagexpr/v2 v2.9.2/go.mod h1:5qsx05dYOiUXOUgnQ7w3Oz8BYs2qtM/bJokdLb79wRM= github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q= @@ -76,6 +78,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -219,6 +223,8 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= +github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rocket049/gocui v0.3.2 h1:6QEaEX85VheVRLwA5FjAe2tswlIkIg0mgoeBHEguRzA= diff --git a/plato.yaml b/plato.yaml index e60b79b..4ca83e9 100644 --- a/plato.yaml +++ b/plato.yaml @@ -4,6 +4,10 @@ discovery: endpoints: - 192.168.31.192:2379 # 192.168.31.192:2379 timeout: 5 +cache: + redis: + endpoints: + - 192.168.31.192:6379 # 192.168.31.192:2379 ip_conf: service_path: /plato/ip_dispatcher prpc: @@ -28,9 +32,12 @@ gateway: worker_pool_num: 1024 cmd_channel_num: 2048 weight: 100 + state_server_endpoint: "127.0.0.1:8902" state: service_name: "plato.access.state" servide_addr: "127.0.0.1" cmd_channel_num: 2048 server_port: 8902 - weight: 100 \ No newline at end of file + weight: 100 + conn_state_slot_range: "0,1024" + gateway_server_endpoint: "127.0.0.1:8901" \ No newline at end of file diff --git a/state/cache.go b/state/cache.go new file mode 100644 index 0000000..6096b15 --- /dev/null +++ b/state/cache.go @@ -0,0 +1,247 @@ +package state + +import ( + "context" + "errors" + "fmt" + "github.com/bytedance/gopkg/util/logger" + "github.com/golang/protobuf/proto" + "github.com/hardcore-os/plato/common/cache" + "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/idl/message" + "github.com/hardcore-os/plato/common/router" + "github.com/hardcore-os/plato/state/rpc/service" + "strconv" + "strings" + "sync" +) + +var cs *cacheState + +// 远程cache状态 +type cacheState struct { + msgID uint64 // for test + connToStateTable sync.Map + server *service.Service +} + +// InitCacheState 初始化全局cache +func InitCacheState(ctx context.Context) { + cs = &cacheState{} + cache.InitRedis(ctx) + router.Init(ctx) + cs.connToStateTable = sync.Map{} + cs.initLoginSlot(ctx) + cs.server = &service.Service{ + CmdChannel: make(chan *service.CmdContext, config.GetStateCmdChannelNum()), + } +} + +// 初始化连接登陆槽 +func (cs *cacheState) initLoginSlot(ctx context.Context) error { + loginSlotRange := config.GetStateServerLoginSlotRange() + for _, slot := range loginSlotRange { + loginSlotKey := fmt.Sprintf(cache.LoginSlotSetKey, slot) + // async + go func() { + // 这里可以使用lua脚本进行批处理 + loginSlot, err := cache.SmembersStrSlice(ctx, loginSlotKey) + if err != nil { + panic(err) + } + for _, mate := range loginSlot { + did, connID := cs.loginSlotUnmarshal(mate) + cs.connReLogin(ctx, did, connID) + } + }() + } + return nil +} + +func (cs *cacheState) newConnState(did uint64, connID uint64) *connState { + // create connState object + st := &connState{ + connID: connID, + did: did, + } + // start heartbeat timer + st.resetHeartTimer() + return st +} + +func (cs *cacheState) connLogin(ctx context.Context, did uint64, connID uint64) error { + st := cs.newConnState(did, connID) + // store login slot + slotKey := cs.getLoginSlotKey(connID) + meta := cs.loginSlotMarshal(did, connID) + err := cache.SADD(ctx, slotKey, meta) + if err != nil { + logger.CtxErrorf(ctx, "[connLogin] sadd login meta into redis failed, did=%v, connID=%v, err=%v", did, connID, err) + return err + } + + // add router in router table + endpoint := fmt.Sprintf("%s:%d", config.GetGatewayServiceAddr(), config.GetStateServerPort()) + err = router.AddRouter(ctx, did, endpoint, connID) + if err != nil { + logger.CtxErrorf(ctx, "[connLogin] add record in router table failed , did=%v, connID=%v, err=%v", did, connID, err) + return err + } + //TODO 上行消息 max_client_id 初始化, 现在相当于生命周期在conn维度,后面重构sdk时会调整到会话维度 + + // store local state + cs.storeConnIDState(connID, st) + return nil +} + +func (cs *cacheState) connReLogin(ctx context.Context, did uint64, connID uint64) { + st := cs.newConnState(did, connID) + cs.storeConnIDState(connID, st) + st.loadMsgTimer(ctx) +} + +func (cs *cacheState) connLogout(ctx context.Context, connID uint64) (uint64, error) { + if st, ok := cs.loadConnIDState(connID); ok { + did := st.did + return did, st.close(ctx) + } + return 0, nil +} + +func (cs *cacheState) reConn(ctx context.Context, oldConnID, newConnID uint64) error { + var ( + did uint64 + err error + ) + if did, err = cs.connLogout(ctx, oldConnID); err != nil { + return err + } + return cs.connLogin(ctx, did, newConnID) // todo 重连路由是不用更新的? +} + +func (cs *cacheState) resetHeartTimer(connID uint64) { + if st, ok := cs.loadConnIDState(connID); ok { + st.resetHeartTimer() + } +} + +func (cs *cacheState) loadConnIDState(connID uint64) (*connState, bool) { + if data, ok := cs.connToStateTable.Load(connID); ok { + st, _ := data.(*connState) + return st, true + } + return nil, false +} + +func (cs *cacheState) deleteConnIDState(ctx context.Context, connID uint64) { + cs.connToStateTable.Delete(connID) +} + +func (cs *cacheState) storeConnIDState(connID uint64, state *connState) { + cs.connToStateTable.Store(connID, state) +} + +// 获取登陆槽位的key +func (cs *cacheState) getLoginSlotKey(connID uint64) string { + connStateSlotList := config.GetStateServerLoginSlotRange() + slotSize := uint64(len(connStateSlotList)) + slot := connID % slotSize + slotKey := fmt.Sprintf(cache.LoginSlotSetKey, connStateSlotList[slot]) + return slotKey +} + +func (cs *cacheState) getConnStateSLot(connID uint64) uint64 { + connStateSlotList := config.GetStateServerLoginSlotRange() + slotSize := uint64(len(connStateSlotList)) + slot := connID % slotSize + return slot +} + +// 使用lua实现比较并自增 +func (cs *cacheState) compareAndIncrClientID(ctx context.Context, connID, oldMaxClientID uint64) bool { + slot := cs.getConnStateSLot(connID) + key := fmt.Sprintf(cache.MaxClientIDKey, slot, connID) + logger.CtxInfof(ctx, "[compareAndIncrClientID] run luaInt key=%v, oldClientID=%v, connID=%v", key, oldMaxClientID, connID) + + var ( + res int + err error + ) + if res, err = cache.RunLuaInt(ctx, cache.LuaCompareAndIncrClientID, []string{key}, oldMaxClientID, cache.TTL7D); err != nil { + logger.CtxErrorf(ctx, "[compareAndIncrClientID] run luaInt failed, key=%v, oldClientID=%v, connID=%v, err=%v", key, oldMaxClientID, connID, err) + panic(err) + } + return res > 0 +} + +func (cs *cacheState) appendLastMsg(ctx context.Context, connID uint64, pushMsg *message.PushMsg) error { + if pushMsg == nil { + logger.CtxWarnf(ctx, "[appendLastMsg] pushMsg is nil, return") + return nil + } + var ( + st *connState + ok bool + ) + if st, ok = cs.loadConnIDState(connID); !ok { + logger.CtxErrorf(ctx, "[appendLastMsg] load connState from map failed, connID=%v", connID) + return errors.New("connState is nil ") + } + slot := cs.getConnStateSLot(connID) + key := fmt.Sprintf(cache.LastMsgKey, slot, connID) + // TODO 现在假设一个链接只有一个会话,后面再讲IMserver,会进行重构 + msgTimerLock := fmt.Sprintf("%d_%d", pushMsg.SessionID, pushMsg.MsgID) + msgData, _ := proto.Marshal(pushMsg) + st.appendMsg(ctx, key, msgTimerLock, msgData) + return nil +} + +func (cs *cacheState) ackLastMsg(ctx context.Context, connID, sessionID, msgID uint64) { + var ( + st *connState + ok bool + ) + if st, ok = cs.loadConnIDState(connID); ok { + st.ackLastMsg(ctx, sessionID, msgID) + } +} + +func (cs *cacheState) getLastMsg(ctx context.Context, connID uint64) (*message.PushMsg, error) { + slot := cs.getConnStateSLot(connID) + key := fmt.Sprintf(cache.LastMsgKey, slot, connID) + data, err := cache.GetBytes(ctx, key) + if err != nil { + logger.CtxErrorf(ctx, "[getLastMsg] get lastNsg from cache failed, connID = %v, err=%v", connID, err) + return nil, err + } + if len(data) == 0 { + return nil, nil + } + pMsg := &message.PushMsg{} + err = proto.Unmarshal(data, pMsg) + if err != nil { + logger.CtxErrorf(ctx, "[getLastMsg] unmarshal data to pushMsg failed, connID = %v, data=%v, err=%v", connID, string(data), err) + return nil, err + } + return pMsg, nil +} + +func (cs *cacheState) loginSlotUnmarshal(mate string) (uint64, uint64) { + strSlice := strings.Split(mate, "|") + if len(strSlice) < 2 { + return 0, 0 + } + did, err := strconv.ParseUint(strSlice[0], 10, 64) + if err != nil { + return 0, 0 + } + connID, err := strconv.ParseUint(strSlice[1], 10, 64) + if err != nil { + return 0, 0 + } + return did, connID +} + +func (cs *cacheState) loginSlotMarshal(did, connID uint64) string { + return fmt.Sprintf("%d|%d", did, connID) +} diff --git a/state/rpc/client/init.go b/state/rpc/client/init.go index cade9ac..2e1cf42 100644 --- a/state/rpc/client/init.go +++ b/state/rpc/client/init.go @@ -1,6 +1,7 @@ package client import ( + "fmt" "github.com/hardcore-os/plato/common/config" "github.com/hardcore-os/plato/common/prpc" "github.com/hardcore-os/plato/gateway/rpc/service" @@ -17,5 +18,9 @@ func initGatewayClient() { if err != nil { panic(err) } - gatewayClient = service.NewGatewayClient(pCli.Conn()) + conn, err := pCli.DialByEndPoint(config.GetStateServerGatewayServerEndpoint()) + if err != nil { + panic(fmt.Sprintf("state.gateway client DialByEndPoint fialed, err=%v", err)) + } + gatewayClient = service.NewGatewayClient(conn) } diff --git a/state/rpc/service/service.go b/state/rpc/service/service.go index 3a67b92..f24ee53 100644 --- a/state/rpc/service/service.go +++ b/state/rpc/service/service.go @@ -49,7 +49,7 @@ func (s *Service) SendMsg(ctx context.Context, sr *StateRequest) (*StateResponse PayLoad: sr.GetData(), } - logger.CtxInfof(ctx, "[message] sendMsg to channel ok") + logger.CtxInfof(ctx, "[message] sendMsg, connID=%v, channel = %d", sr.GetConnID(), len(s.CmdChannel)) return &StateResponse{ Code: 0, diff --git a/state/server.go b/state/server.go index ab349fc..a379c48 100644 --- a/state/server.go +++ b/state/server.go @@ -5,47 +5,72 @@ import ( "github.com/bytedance/gopkg/util/logger" "github.com/golang/protobuf/proto" "github.com/hardcore-os/plato/common/config" + "github.com/hardcore-os/plato/common/idl/message" "github.com/hardcore-os/plato/common/prpc" "github.com/hardcore-os/plato/state/rpc/client" "github.com/hardcore-os/plato/state/rpc/service" "google.golang.org/grpc" - "sync" - "time" - - "github.com/hardcore-os/plato/common/idl/message" ) func RunMain(path string) { + // init ctx + ctx := context.TODO() + // init config config.Init(path) - cmdChannel = make(chan *service.CmdContext, config.GetStateCmdChannelNum()) - connToStateTable = sync.Map{} + // init rpc client + client.Init() + // start timeWheel + InitTimer() + // start remote cache + InitCacheState(ctx) + // start cmdHandler + go func() { + defer func() { + if r := recover(); r != nil { + logger.CtxErrorf(ctx, "cmdHandler panic, r=%v", r) + } + }() + cmdHandler() + }() + // register rpc server s := prpc.NewPServer( prpc.WithServiceName(config.GetStateServiceName()), prpc.WithIP(config.GetStateServiceAddr()), prpc.WithPort(config.GetStateServerPort()), - prpc.WithWeight(config.GetStateRPCWeight()), - ) + prpc.WithWeight(config.GetStateRPCWeight())) s.RegisterService(func(server *grpc.Server) { - service.RegisterStateServer(server, &service.Service{CmdChannel: cmdChannel}) + service.RegisterStateServer(server, cs.server) }) - // init rpc client - client.Init() - // init timingWheel - InitTimer() - // start cmd handler - go cmdHandler() - // start rpc server - ctx := context.TODO() + //cmdChannel = make(chan *service.CmdContext, config.GetStateCmdChannelNum()) + //connToStateTable = sync.Map{} + // + //s := prpc.NewPServer( + // prpc.WithServiceName(config.GetStateServiceName()), + // prpc.WithIP(config.GetStateServiceAddr()), + // prpc.WithPort(config.GetStateServerPort()), + // prpc.WithWeight(config.GetStateRPCWeight()), + //) + //s.RegisterService(func(server *grpc.Server) { + // service.RegisterStateServer(server, &service.Service{CmdChannel: cmdChannel}) + //}) + //// init rpc client + //client.Init() + //// init timingWheel + //InitTimer() + //// start cmd handler + //go cmdHandler() logger.CtxInfof(ctx, "[state] serviceName:%s Addr:%s:%d weight:%d", config.GetStateServiceName(), config.GetStateServiceAddr(), config.GetStateServerPort(), config.GetStateRPCWeight()) s.Start(ctx) } +// 消费信令通道,识别gateway与state server之间的协议路由 func cmdHandler() { for cmdCtx := range cmdChannel { switch cmdCtx.Cmd { case service.CancelConnCmd: logger.CtxInfof(*cmdCtx.Ctx, "cancelConn endpoint:%s, fd:%d, data:%+v", cmdCtx.Endpoint, cmdCtx.ConnID, cmdCtx.PayLoad) + cs.connLogout(*cmdCtx.Ctx, cmdCtx.ConnID) case service.SendMsgCmd: logger.CtxInfof(*cmdCtx.Ctx, "cmdHandler: %v\n", string(cmdCtx.PayLoad)) msgCmd := &message.MsgCmd{} @@ -61,6 +86,7 @@ func cmdHandler() { } } +// 识别消息类型,识别客户端与state server之间的协议路由 func msgCmdHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { if msgCmd == nil { return @@ -83,21 +109,18 @@ func loginMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { loginMsg := &message.LoginMsg{} err := proto.Unmarshal(msgCmd.Payload, loginMsg) if err != nil { - logger.CtxErrorf(*cmdCtx.Ctx, "[loginMsgHandler] Unmarshal failed, err=%v", err) + logger.CtxErrorf(*cmdCtx.Ctx, "[loginMsgHandler] Unmarshal failed, payload=%v, err=%v", string(msgCmd.Payload), err) return } if loginMsg.Head != nil { // 这里会把 login msg 传送给业务层做处理 - logger.CtxInfof(*cmdCtx.Ctx, "loginMsgHandler:%v", loginMsg.Head.DeviceID) + logger.CtxInfof(*cmdCtx.Ctx, "[loginMsgHandler]:%v", loginMsg.Head.DeviceID) + } + err = cs.connLogin(*cmdCtx.Ctx, loginMsg.Head.DeviceID, cmdCtx.ConnID) + if err != nil { + logger.CtxErrorf(*cmdCtx.Ctx, "[loginMsgHandler] connStateLogin failed, did=%v, connID=%v, err=%v", loginMsg.Head.DeviceID, cmdCtx.ConnID, err) + return } - - // create timer - t := AfterFunc(300*time.Second, func() { - clearState(cmdCtx.ConnID) - }) - - // init conn message - connToStateTable.Store(cmdCtx.ConnID, &connState{heartTimer: t, connID: cmdCtx.ConnID}) sendAckMsg(message.CmdType_Login, cmdCtx.ConnID, 0, 0, "login ok") } @@ -108,12 +131,9 @@ func heartbeatMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { logger.CtxErrorf(*cmdCtx.Ctx, "[heartbeatMsgHandler] Unmarshal failed, err=%v", err) return } - if data, ok := connToStateTable.Load(cmdCtx.ConnID); ok { - state, _ := data.(*connState) - state.resetHeartTimer() - logger.CtxInfof(*cmdCtx.Ctx, "[heartbeatMsgHandler] reset heartbeat success, connID=%v", cmdCtx.ConnID) - } - // 减少通信量,可以暂时不回复心跳的ack + cs.resetHeartTimer(cmdCtx.ConnID) + logger.CtxInfof(*cmdCtx.Ctx, "[heartbeatMsgHandler] reset heartbeat success, connID=%v", cmdCtx.ConnID) + // TODO 未减少通信量,可以暂时不回复心跳的ack } func reConnMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { @@ -123,26 +143,15 @@ func reConnMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { logger.CtxErrorf(*cmdCtx.Ctx, "[reConnMsgHandler] Unmarshal failed, err=%v", err) return } + var code uint32 + msg := "reconnection OK" // 重连的消息头中的connID才是上一次断开连接的connID - if data, ok := connToStateTable.Load(reConnMsg.Head.ConnID); ok { - state, _ := data.(*connState) - state.Lock() - defer state.Unlock() - // 重连的消息头中的connID才是上一次断开连接的connID - if state.reConnTimer != nil { - state.reConnTimer.Stop() - state.reConnTimer = nil - } - - // 从索引中删除 旧的connID - connToStateTable.Delete(reConnMsg.Head.ConnID) - // 变更connID, cmdCtx中的connID才是 gateway重连的新连接 - state.connID = cmdCtx.ConnID - connToStateTable.Store(state.connID, state) - sendAckMsg(message.CmdType_ReConn, cmdCtx.ConnID, 0, 0, "reconn ok") - } else { - sendAckMsg(message.CmdType_ReConn, cmdCtx.ConnID, 0, 1, "reconn failed") + if err = cs.reConn(*cmdCtx.Ctx, reConnMsg.Head.ConnID, cmdCtx.ConnID); err != nil { + code, msg = 1, "reconnection failed" + logger.CtxErrorf(*cmdCtx.Ctx, "[reConnMsgHandler] reconnection failed, old connID=%v, newConnID=%v, err=%v", reConnMsg.Head.ConnID, cmdCtx.ConnID, err) + return } + sendAckMsg(message.CmdType_ReConn, cmdCtx.ConnID, 0, code, msg) } func sendAckMsg(ackType message.CmdType, connID, clientID uint64, code uint32, msg string) { @@ -182,15 +191,16 @@ func ackMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { logger.CtxErrorf(*cmdCtx.Ctx, "ackMsgHandler err=%v", err.Error()) return } - if data, ok := connToStateTable.Load(ackMsg.ConnID); ok { - state, _ := data.(*connState) - state.Lock() - defer state.Unlock() - if state.msgTimer != nil { - state.msgTimer.Stop() - state.msgTimer = nil - } - } + cs.ackLastMsg(*cmdCtx.Ctx, ackMsg.ConnID, ackMsg.SessionID, ackMsg.MsgID) + //if data, ok := connToStateTable.Load(ackMsg.ConnID); ok { + // state, _ := data.(*connState) + // state.Lock() + // defer state.Unlock() + // if state.msgTimer != nil { + // state.msgTimer.Stop() + // state.msgTimer = nil + // } + //} } // 处理上行消息,并进行消息可靠性检查 @@ -201,36 +211,78 @@ func upMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { logger.CtxErrorf(*cmdCtx.Ctx, "upMsgHandler err=%v", err.Error()) return } - if data, ok := connToStateTable.Load(upMsg.Head.ConnID); ok { - state, _ := data.(*connState) - if !state.checkUPMsg(upMsg.Head.ClientID) { - // todo 如果没有通过检查,当作先直接忽略即可 - return - } + if cs.compareAndIncrClientID(*cmdCtx.Ctx, cmdCtx.ConnID, upMsg.Head.ClientID) { // 调用下游业务层rpc,只有当rpc回复成功后才能更新max_clientID - // 这里先假设成功 - state.addMaxClientID() - state.msgID++ - sendAckMsg(message.CmdType_UP, upMsg.Head.ConnID, upMsg.Head.ClientID, 0, "ok") + sendAckMsg(message.CmdType_UP, cmdCtx.ConnID, upMsg.Head.ClientID, 0, "OK") + // TODO 这里应该调用业务层的代码 + pushMsg(*cmdCtx.Ctx, cmdCtx.ConnID, cs.msgID, 0, upMsg.UPMsgBody) + } - // todo 先在这里push消息 - pushMsg := &message.PushMsg{ - MsgID: state.msgID, - Content: upMsg.UPMsgBody, - } - pData, err := proto.Marshal(pushMsg) - if err != nil { - logger.CtxErrorf(*cmdCtx.Ctx, "upMsgHandler Marshal pushMsg err=%v, pData=%v", err.Error(), string(pData)) - return - } - sendMsg(upMsg.Head.ConnID, message.CmdType_Push, pData) - if state.msgTimer != nil { - state.msgTimer.Stop() - } - // create pushMsg timer - t := AfterFunc(100*time.Millisecond, func() { - rePush(cmdCtx.ConnID, pData) - }) - state.msgTimer = t + //if data, ok := connToStateTable.Load(upMsg.Head.ConnID); ok { + // state, _ := data.(*connState) + // if !state.checkUPMsg(upMsg.Head.ClientID) { + // // todo 如果没有通过检查,当作先直接忽略即可 + // return + // } + // // 调用下游业务层rpc,只有当rpc回复成功后才能更新max_clientID + // // 这里先假设成功 + // state.addMaxClientID() + // state.msgID++ + // sendAckMsg(message.CmdType_UP, upMsg.Head.ConnID, upMsg.Head.ClientID, 0, "ok") + // + // // todo 先在这里push消息 + // pushMsg := &message.PushMsg{ + // MsgID: state.msgID, + // Content: upMsg.UPMsgBody, + // } + // pData, err := proto.Marshal(pushMsg) + // if err != nil { + // logger.CtxErrorf(*cmdCtx.Ctx, "upMsgHandler Marshal pushMsg err=%v, pData=%v", err.Error(), string(pData)) + // return + // } + // sendMsg(upMsg.Head.ConnID, message.CmdType_Push, pData) + // if state.msgTimer != nil { + // state.msgTimer.Stop() + // } + // // create pushMsg timer + // t := AfterFunc(100*time.Millisecond, func() { + // rePush(cmdCtx.ConnID, pData) + // }) + // state.msgTimer = t + //} +} + +func pushMsg(ctx context.Context, connID, sessionID, msgID uint64, data []byte) { + // TODO 先在这里push消息 + pMsg := &message.PushMsg{ + MsgID: cs.msgID, + Content: data, + } + pData, err := proto.Marshal(pMsg) + if err != nil { + logger.CtxErrorf(ctx, "[pushMsg] pushMsg failed, connID=%v, sessionID=%v, msgID=%v, data=%v, err=%v", connID, sessionID, msgID, string(data), err) + return + } + sendMsg(connID, message.CmdType_Push, pData) + if err = cs.appendLastMsg(ctx, connID, pMsg); err != nil { + logger.CtxErrorf(ctx, "[pushMsg] append last msg failed, connID=%v, sessionID=%v, msgID=%v, data=%v, err=%v", connID, sessionID, msgID, string(data), err) + } +} + +func rePush(connID uint64) { + ctx := context.TODO() + pMsg, err := cs.getLastMsg(ctx, connID) + if err != nil { + logger.CtxErrorf(ctx, "rePushMsg failed, connID=%v", connID) + return + } + msgData, err := proto.Marshal(pMsg) + if err != nil { + logger.CtxErrorf(ctx, "rePushMsg marshal msg failed, connID=%v, msg=%+v", connID, pMsg) + return + } + sendMsg(connID, message.CmdType_Push, msgData) + if st, ok := cs.loadConnIDState(connID); ok { + st.resetMsgTimer(connID, pMsg.SessionID, pMsg.MsgID) } } diff --git a/state/state.go b/state/state.go index d20ceab..6aa258c 100644 --- a/state/state.go +++ b/state/state.go @@ -2,7 +2,10 @@ package state import ( "context" - "github.com/hardcore-os/plato/common/idl/message" + "fmt" + "github.com/bytedance/gopkg/util/logger" + "github.com/hardcore-os/plato/common/cache" + "github.com/hardcore-os/plato/common/router" "github.com/hardcore-os/plato/common/timingwheel" "github.com/hardcore-os/plato/state/rpc/client" "sync" @@ -16,63 +19,152 @@ var connToStateTable sync.Map type connState struct { sync.RWMutex - heartTimer *timingwheel.Timer - reConnTimer *timingwheel.Timer - msgTimer *timingwheel.Timer - connID uint64 - maxClientID uint64 - msgID uint64 // use for test + heartTimer *timingwheel.Timer + reConnTimer *timingwheel.Timer + msgTimer *timingwheel.Timer + msgTimerLock string + connID uint64 + did uint64 } -func (c *connState) checkUPMsg(clientID uint64) bool { +func (c *connState) close(ctx context.Context) error { c.Lock() defer c.Unlock() - return clientID == c.maxClientID+1 + if c.heartTimer != nil { + c.heartTimer.Stop() + } + if c.reConnTimer != nil { + c.reConnTimer.Stop() + } + if c.msgTimer != nil { + c.msgTimer.Stop() + } + // TODO 这里如何保证事务性,值得思考一下,或者说有没有必要保证 + // TODO 这里也可以使用lua或者pipeline 来尽可能合并两次redis的操作 通常在大规模的应用中这是有效的 + // TODO 这里是要好好思考一下,网络调用次数的时间&空间复杂度的 + + // TODO 可以加一个simple retry,redis的del操作是幂等的,但是也没有解决事务的问题 + slotKey := cs.getLoginSlotKey(c.connID) + meta := cs.loginSlotMarshal(c.did, c.connID) + err := cache.SREM(ctx, slotKey, meta) + if err != nil { + logger.CtxErrorf(ctx, "[close] cache set remove login meta failed, did=%v, connID=%v, err=%v", c.did, c.connID, err) + return err + } + slot := cs.getConnStateSLot(c.connID) + key := fmt.Sprintf(cache.MaxClientIDKey, slot, c.connID) + err = cache.Del(ctx, key) + if err != nil { + logger.CtxErrorf(ctx, "[close] cache remove login data failed, slot=%v, connID=%v, err=%v", slot, c.connID, err) + return err + } + err = router.DelRouter(ctx, c.did) + if err != nil { + logger.CtxErrorf(ctx, "[close] cache del record failed, did=%v, err=%v", c.did, err) + return err + } + lastMsgKey := fmt.Sprintf(cache.LastMsgKey, slot, c.connID) + err = cache.Del(ctx, lastMsgKey) + if err != nil { + logger.CtxErrorf(ctx, "[close] cache del lastMsg failed, slot=%v, connID=%v, err=%v", slot, c.connID, err) + return err + } + err = client.DelConn(&ctx, c.connID, nil) + if err != nil { + logger.CtxErrorf(ctx, "[close] gateway client del conn failed, connID=%v, err=%v", c.connID, err) + return err + } + cs.deleteConnIDState(ctx, c.connID) + return nil +} + +func (c *connState) appendMsg(ctx context.Context, key, msgTimerLock string, msgData []byte) { + c.Lock() + defer c.Unlock() + c.msgTimerLock = msgTimerLock + if c.msgTimer != nil { + c.msgTimer.Stop() + c.msgTimer = nil + } + // create timer + t := AfterFunc(100*time.Millisecond, func() { + rePush(c.connID) + }) + c.msgTimer = t + err := cache.SetBytes(ctx, key, msgData, cache.TTL7D) + if err != nil { + logger.CtxErrorf(ctx, "[appendMsg] set rePush cache failed, key=%v, msgData=%v, err=%v", key, msgData, err) + return + } +} + +func (c *connState) resetMsgTimer(connID, sessionID, msgID uint64) { + c.Lock() + defer c.Unlock() + if c.msgTimer != nil { + c.msgTimer.Stop() + c.msgTimer = nil + } + c.msgTimerLock = fmt.Sprintf("%d_%d", sessionID, msgID) + c.msgTimer = AfterFunc(100*time.Millisecond, func() { + rePush(c.connID) + }) } -// todo 这里可以考虑设计成无锁的并发模式 -func (c *connState) addMaxClientID() { - c.Lock() // 不要迷恋原子操作,如果锁的临界区很小,性能与原子操作相差无己并发性能瓶颈,保持简单可靠即可。 - defer c.Unlock() // go的读写锁本身就有自旋等无锁优化 - c.maxClientID++ +func (c *connState) loadMsgTimer(ctx context.Context) { + // create timer + data, err := cs.getLastMsg(ctx, c.connID) + if err != nil { + return + } + if data == nil { + return + } + c.resetMsgTimer(c.connID, data.SessionID, data.MsgID) } func (c *connState) resetHeartTimer() { c.Lock() defer c.Unlock() - c.heartTimer.Stop() + if c.heartTimer != nil { + c.heartTimer.Stop() + c.heartTimer = nil + } c.heartTimer = AfterFunc(5*time.Second, func() { - clearState(c.connID) + c.resetConnTimer() }) } -func clearState(connID uint64) { - if data, ok := connToStateTable.Load(connID); ok { - state, _ := data.(*connState) - state.Lock() - defer state.Unlock() - // prevent fake disconnection, wait for 10s - state.reConnTimer = AfterFunc(10*time.Second, func() { - ctx := context.TODO() - client.DelConn(&ctx, connID, nil) - // del conn message - connToStateTable.Delete(connID) - }) +func (c *connState) resetConnTimer() { + c.Lock() + defer c.Unlock() + if c.reConnTimer != nil { + c.reConnTimer.Stop() + c.reConnTimer = nil } -} -func rePush(connID uint64, msgData []byte) { - sendMsg(connID, message.CmdType_Push, msgData) - if data, ok := connToStateTable.Load(connID); ok { - state, _ := data.(*connState) - state.Lock() - defer state.Unlock() - if state.msgTimer != nil { - state.msgTimer.Stop() - } - state.msgTimer = AfterFunc(100*time.Millisecond, func() { - rePush(connID, msgData) - }) + c.reConnTimer = AfterFunc(10*time.Second, func() { + ctx := context.TODO() + // 整体connID状态登出 + // 不马上清理,而是等待重连,10s之后才会清理连接的数据 + cs.connLogout(ctx, c.connID) + }) +} +func (c *connState) ackLastMsg(ctx context.Context, sessionID, msgID uint64) bool { + c.Lock() + defer c.Unlock() + msgTimerLock := fmt.Sprintf("%d_%d", sessionID, msgID) + if c.msgTimerLock != msgTimerLock { + return false + } + slot := cs.getConnStateSLot(c.connID) + key := fmt.Sprintf(cache.LastMsgKey, slot, c.connID) + if err := cache.Del(ctx, key); err != nil { + return false + } + if c.msgTimer != nil { + c.msgTimer.Stop() } + return true } From a765d457c5835baf61bd8ccdf85e5d26d0a5c9c9 Mon Sep 17 00:00:00 2001 From: vagrant <750437163@qq.com> Date: Thu, 2 May 2024 15:38:24 +0800 Subject: [PATCH 21/26] feat: [state decentralize]fix redis lua bug and decrease slot number todo: send msg would lose message sometimes. --- chat.log | 55 ++++++++++++++++++++++++++++---------- common/cache/lua.go | 2 +- common/cache/redis.go | 2 ++ plato.yaml | 8 +++--- state/cache.go | 1 + state/server.go | 62 +------------------------------------------ state/state.go | 5 ---- 7 files changed, 50 insertions(+), 85 deletions(-) diff --git a/chat.log b/chat.log index 20bd952..87ec344 100644 --- a/chat.log +++ b/chat.log @@ -1,15 +1,42 @@ -me: 11111 -logic: 11111 -me: 2222 -logic: 2222 -me: dsadsa -logic: dsadsa -me: jdklasjdl -logic: jdklasjdl -me: dklsajdlkjsalkdlksd -logic: dklsajdlkjsalkdlksd -me: kalsjdkljsalkd -logic: kalsjdkljsalkd -me: abcdfdsfksjfklas -logic: abcdfdsfksjfklas +me-clientID:0: 123 +logic: 123 +me-clientID:0: 345566 +me-clientID:1: sadklasjdl +logic: sadklasjdl +me-clientID:2: sdksajdlsa +logic: sdksajdlsa +me-clientID:3: djsalkjdlsa +logic: djsalkjdlsa +me-clientID:4: dhaskljdlks +logic: dhaskljdlks +me-clientID:5: dhjakshdks +logic: dhjakshdks +me-clientID:6: dhjksahdks +logic: dhjksahdks +me-clientID:7: 123daksjdklas +logic: 123daksjdklas +me-clientID:8: dmaklsdklsa +logic: dmaklsdklsa +me-clientID:9: dmksamdlsa +logic: dmksamdlsa +me-clientID:10: dals;dk;asd +logic: dals;dk;asd +me-clientID:11: dhaskjhdkasdk +logic: dhaskjhdkasdk +me-clientID:12: sdklajdklsad +logic: sdklajdklsad +me-clientID:13: djaslkdlsa +logic: djaslkdlsa +me-clientID:14: asdkljsaljdslajd +logic: asdkljsaljdslajd +me-clientID:15: djskahdkhsakd +logic: djskahdkhsakd +me-clientID:16: dklasjdklsajkld +logic: dklasjdklsajkld +me-clientID:17: djklsajdlsajdl +logic: djklsajdlsajdl +me-clientID:18: djaksljdlasdjl +logic: djaksljdlasdjl +me-clientID:19: djaslkjdlas +logic: djaslkjdlas diff --git a/common/cache/lua.go b/common/cache/lua.go index b67bd7c..2abe38a 100644 --- a/common/cache/lua.go +++ b/common/cache/lua.go @@ -16,7 +16,7 @@ type luaPart struct { var luaScriptTable map[string]*luaPart = map[string]*luaPart{ LuaCompareAndIncrClientID: &luaPart{ - LuaScript: "if reds.call('exists', KEYS[1]) == 0 then redis.call('set', KEYS[1], 0) end; if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('incr', KEYS[1]);redis.call('expire', KEYS[1], ARGV[2]);return 1 else return -1 end", + LuaScript: "if redis.call('exists', KEYS[1]) == 0 then redis.call('set', KEYS[1], 0) end; if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('incr', KEYS[1]);redis.call('expire', KEYS[1], ARGV[2]);return 1 else return -1 end", }, } diff --git a/common/cache/redis.go b/common/cache/redis.go index 3ff34f1..2e441e8 100644 --- a/common/cache/redis.go +++ b/common/cache/redis.go @@ -3,6 +3,7 @@ package cache import ( "context" "errors" + "github.com/bytedance/gopkg/util/logger" "time" "github.com/hardcore-os/plato/common/config" @@ -22,6 +23,7 @@ func InitRedis(ctx context.Context) { if _, err := rdb.Ping(ctx).Result(); err != nil { panic(err) } + logger.CtxInfof(ctx, "init redis success") initLuaScript(ctx) } func GetBytes(ctx context.Context, key string) ([]byte, error) { diff --git a/plato.yaml b/plato.yaml index 4ca83e9..0e6cebc 100644 --- a/plato.yaml +++ b/plato.yaml @@ -2,19 +2,19 @@ global: env: debug discovery: endpoints: - - 192.168.31.192:2379 # 192.168.31.192:2379 + - 192.168.10.102:2379 # 192.168.31.192:2379 timeout: 5 cache: redis: endpoints: - - 192.168.31.192:6379 # 192.168.31.192:2379 + - 192.168.10.102:6379 # 192.168.31.192:2379 ip_conf: service_path: /plato/ip_dispatcher prpc: discov: name: etcd endpoints: - - 192.168.31.192:2379 # 192.168.31.192:2379 + - 192.168.10.102:2379 # 192.168.31.192:2379 trace: enable: true url: http://127.0.0.1:14268/api/traces @@ -39,5 +39,5 @@ state: cmd_channel_num: 2048 server_port: 8902 weight: 100 - conn_state_slot_range: "0,1024" + conn_state_slot_range: "0,512" gateway_server_endpoint: "127.0.0.1:8901" \ No newline at end of file diff --git a/state/cache.go b/state/cache.go index 6096b15..1ae6212 100644 --- a/state/cache.go +++ b/state/cache.go @@ -47,6 +47,7 @@ func (cs *cacheState) initLoginSlot(ctx context.Context) error { // 这里可以使用lua脚本进行批处理 loginSlot, err := cache.SmembersStrSlice(ctx, loginSlotKey) if err != nil { + logger.CtxErrorf(ctx, "loginSlotKey=%v, err=%v", loginSlotKey, err) panic(err) } for _, mate := range loginSlot { diff --git a/state/server.go b/state/server.go index a379c48..27fda69 100644 --- a/state/server.go +++ b/state/server.go @@ -42,31 +42,13 @@ func RunMain(path string) { s.RegisterService(func(server *grpc.Server) { service.RegisterStateServer(server, cs.server) }) - //cmdChannel = make(chan *service.CmdContext, config.GetStateCmdChannelNum()) - //connToStateTable = sync.Map{} - // - //s := prpc.NewPServer( - // prpc.WithServiceName(config.GetStateServiceName()), - // prpc.WithIP(config.GetStateServiceAddr()), - // prpc.WithPort(config.GetStateServerPort()), - // prpc.WithWeight(config.GetStateRPCWeight()), - //) - //s.RegisterService(func(server *grpc.Server) { - // service.RegisterStateServer(server, &service.Service{CmdChannel: cmdChannel}) - //}) - //// init rpc client - //client.Init() - //// init timingWheel - //InitTimer() - //// start cmd handler - //go cmdHandler() logger.CtxInfof(ctx, "[state] serviceName:%s Addr:%s:%d weight:%d", config.GetStateServiceName(), config.GetStateServiceAddr(), config.GetStateServerPort(), config.GetStateRPCWeight()) s.Start(ctx) } // 消费信令通道,识别gateway与state server之间的协议路由 func cmdHandler() { - for cmdCtx := range cmdChannel { + for cmdCtx := range cs.server.CmdChannel { switch cmdCtx.Cmd { case service.CancelConnCmd: logger.CtxInfof(*cmdCtx.Ctx, "cancelConn endpoint:%s, fd:%d, data:%+v", cmdCtx.Endpoint, cmdCtx.ConnID, cmdCtx.PayLoad) @@ -192,15 +174,6 @@ func ackMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { return } cs.ackLastMsg(*cmdCtx.Ctx, ackMsg.ConnID, ackMsg.SessionID, ackMsg.MsgID) - //if data, ok := connToStateTable.Load(ackMsg.ConnID); ok { - // state, _ := data.(*connState) - // state.Lock() - // defer state.Unlock() - // if state.msgTimer != nil { - // state.msgTimer.Stop() - // state.msgTimer = nil - // } - //} } // 处理上行消息,并进行消息可靠性检查 @@ -217,39 +190,6 @@ func upMsgHandler(cmdCtx *service.CmdContext, msgCmd *message.MsgCmd) { // TODO 这里应该调用业务层的代码 pushMsg(*cmdCtx.Ctx, cmdCtx.ConnID, cs.msgID, 0, upMsg.UPMsgBody) } - - //if data, ok := connToStateTable.Load(upMsg.Head.ConnID); ok { - // state, _ := data.(*connState) - // if !state.checkUPMsg(upMsg.Head.ClientID) { - // // todo 如果没有通过检查,当作先直接忽略即可 - // return - // } - // // 调用下游业务层rpc,只有当rpc回复成功后才能更新max_clientID - // // 这里先假设成功 - // state.addMaxClientID() - // state.msgID++ - // sendAckMsg(message.CmdType_UP, upMsg.Head.ConnID, upMsg.Head.ClientID, 0, "ok") - // - // // todo 先在这里push消息 - // pushMsg := &message.PushMsg{ - // MsgID: state.msgID, - // Content: upMsg.UPMsgBody, - // } - // pData, err := proto.Marshal(pushMsg) - // if err != nil { - // logger.CtxErrorf(*cmdCtx.Ctx, "upMsgHandler Marshal pushMsg err=%v, pData=%v", err.Error(), string(pData)) - // return - // } - // sendMsg(upMsg.Head.ConnID, message.CmdType_Push, pData) - // if state.msgTimer != nil { - // state.msgTimer.Stop() - // } - // // create pushMsg timer - // t := AfterFunc(100*time.Millisecond, func() { - // rePush(cmdCtx.ConnID, pData) - // }) - // state.msgTimer = t - //} } func pushMsg(ctx context.Context, connID, sessionID, msgID uint64, data []byte) { diff --git a/state/state.go b/state/state.go index 6aa258c..c35ed9c 100644 --- a/state/state.go +++ b/state/state.go @@ -10,13 +10,8 @@ import ( "github.com/hardcore-os/plato/state/rpc/client" "sync" "time" - - "github.com/hardcore-os/plato/state/rpc/service" ) -var cmdChannel chan *service.CmdContext -var connToStateTable sync.Map - type connState struct { sync.RWMutex heartTimer *timingwheel.Timer From c6b10ec9a4f4929d6e4ab7ec23516a9a0c4d0c79 Mon Sep 17 00:00:00 2001 From: vagrantZero <750437163@qq.com> Date: Sun, 2 Jun 2024 18:00:05 +0800 Subject: [PATCH 22/26] feat: add dockerfile & docker-compose & start.sh --- Dockerfile | 40 ++++++++++++++++++++++++++++++++++++++++ docker-compose.yaml | 39 +++++++++++++++++++++++++++++++++++++++ plato.yaml | 14 +++++++------- start.sh | 10 ++++++++++ 4 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yaml create mode 100755 start.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e54ae66 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +# 使用官方的 Go 镜像作为基础镜像 +FROM golang:1.20 AS builder + +# 设置工作目录 +WORKDIR /app + +# 拷贝 Go 项目代码到容器中 +COPY . . + +# 为 Linux 构建 plato 可执行文件 +# 为了在mac上能够执行,指定了 GOOS=linux GOARCH=amd64 +# 其他linux环境编译时不需要添加该命令,直接 go build -o plato . 即可 +RUN GOOS=linux GOARCH=amd64 go build -o plato . + + +# 创建最终的生产环境镜像 +FROM alpine:latest + +# 设置工作目录 +WORKDIR /app + +# 拷贝构建好的可执行文件到生产镜像中 +COPY --from=builder /app/plato . + +# 赋予 plato-gateway 和 plato-state 可执行权限 +RUN #chmod +x ./plato-gateway && chmod +x ./plato-state +RUN chmod +x ./plato + +# 拷贝项目的配置文件到容器中 +COPY ./plato.yaml . + +# 声明 gateway 服务运行时监听的端口 +EXPOSE 8900 +EXPOSE 8901 + +# 声明 state 服务运行时监听的端口 +EXPOSE 8902 + +# 启动应用程序 +#CMD ["./plato gateway"] diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..d62fcc1 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,39 @@ +version: '3.8' + +services: + plato-etcd: + image: bitnami/etcd:latest + environment: + - ETCD_ROOT_PASSWORD=yyy1526510 + ports: + - '2379:2379' + networks: + - plato-network + + plato-redis: + image: redis:latest + ports: + - '6379:6379' + networks: + - plato-network + + gateway: + image: plato + ports: + - '8900:8900' + - '8901:8901' + networks: + - plato-network + command: sh -c "/app/plato gateway" + + state: + image: plato + ports: + - '8902:8902' + networks: + - plato-network + command: sh -c "/app/plato state" + +networks: + plato-network: + driver: bridge diff --git a/plato.yaml b/plato.yaml index 0e6cebc..b238a26 100644 --- a/plato.yaml +++ b/plato.yaml @@ -2,19 +2,19 @@ global: env: debug discovery: endpoints: - - 192.168.10.102:2379 # 192.168.31.192:2379 + - plato-etcd:2379 # 192.168.31.192:2379 timeout: 5 cache: redis: endpoints: - - 192.168.10.102:6379 # 192.168.31.192:2379 + - plato-redis:6379 # 192.168.31.192:2379 ip_conf: service_path: /plato/ip_dispatcher prpc: discov: name: etcd endpoints: - - 192.168.10.102:2379 # 192.168.31.192:2379 + - plato-etcd:2379 # 192.168.31.192:2379 trace: enable: true url: http://127.0.0.1:14268/api/traces @@ -22,7 +22,7 @@ prpc: sampler: 1.0 gateway: service_name: "plato.access.gateway" - service_addr: "127.0.0.1" + service_addr: "gateway" #127.0.0.1 tcp_max_num: 70000 epoll_channel_num: 100 epoll_num: 8 @@ -32,12 +32,12 @@ gateway: worker_pool_num: 1024 cmd_channel_num: 2048 weight: 100 - state_server_endpoint: "127.0.0.1:8902" + state_server_endpoint: "state:8902" #127.0.0.1 state: service_name: "plato.access.state" - servide_addr: "127.0.0.1" + servide_addr: "state" #127.0.0.1 cmd_channel_num: 2048 server_port: 8902 weight: 100 conn_state_slot_range: "0,512" - gateway_server_endpoint: "127.0.0.1:8901" \ No newline at end of file + gateway_server_endpoint: "gateway:8901" #127.0.0.1 \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..39ab21a --- /dev/null +++ b/start.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# 停止并删除现有的容器 +docker-compose down + +# 清理网络状态 +docker network prune -f + +# 重新启动服务 +docker-compose up \ No newline at end of file From 8291b4b48a91b3f8f853246d25acbac0f86df93b Mon Sep 17 00:00:00 2001 From: vagrantZero <750437163@qq.com> Date: Sun, 2 Jun 2024 21:33:42 +0800 Subject: [PATCH 23/26] feat: add build Makefile --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d16fd9f --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +all:build + +build: + @echo "go build plato begin" + go build -o . + @echo "go build plato success" From 9594ad10ec065bf08c010e7453d0c7c39578accd Mon Sep 17 00:00:00 2001 From: vagrantZero <750437163@qq.com> Date: Sun, 2 Jun 2024 21:35:56 +0800 Subject: [PATCH 24/26] feat: add build Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d16fd9f..9033293 100644 --- a/Makefile +++ b/Makefile @@ -2,5 +2,5 @@ all:build build: @echo "go build plato begin" - go build -o . + go build -o plato . @echo "go build plato success" From 258fb540b136aa9be2b5085abc9175cb0d64b03f Mon Sep 17 00:00:00 2001 From: vagrantZero <750437163@qq.com> Date: Sun, 2 Jun 2024 21:48:41 +0800 Subject: [PATCH 25/26] feat: add docker-compose.yaml --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index d62fcc1..a1b2611 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -4,7 +4,7 @@ services: plato-etcd: image: bitnami/etcd:latest environment: - - ETCD_ROOT_PASSWORD=yyy1526510 + - ETCD_ROOT_PASSWORD=123456 ports: - '2379:2379' networks: From 0dcf1fed435aa5ac94c27ad57e8e7804ae3a623c Mon Sep 17 00:00:00 2001 From: vagrantZero <750437163@qq.com> Date: Sat, 29 Jun 2024 14:50:07 +0800 Subject: [PATCH 26/26] feat: add log --- gateway/epoll.go | 5 +++++ gateway/server.go | 3 +++ 2 files changed, 8 insertions(+) diff --git a/gateway/epoll.go b/gateway/epoll.go index 4369036..447a576 100644 --- a/gateway/epoll.go +++ b/gateway/epoll.go @@ -163,8 +163,11 @@ func (epl *epoller) add(conn *connection) error { if err != nil { return err } + // epoll实例存储 fd -> conn 的映射 epl.fdToConnTable.Store(conn.fd, conn) + // 全局epoll池存储 connID -> conn的映射 ep.tables.Store(conn.id, conn) + // 每个连接绑定所属的epoll实例 conn.BindEpoller(epl) return nil } @@ -189,6 +192,8 @@ func (epl *epoller) wait(millSec int) ([]*connection, error) { } var connections []*connection for i := 0; i < n; i++ { + // 单个epoll实例是根据fd来反查conn的 + // 全局的conn是根据epoll池中的connID来查询的 if conn, ok := epl.fdToConnTable.Load(int(events[i].Fd)); ok { connections = append(connections, conn.(*connection)) } diff --git a/gateway/server.go b/gateway/server.go index 79d82f8..99354d3 100644 --- a/gateway/server.go +++ b/gateway/server.go @@ -47,7 +47,9 @@ func startRPCServer() { prpc.WithPort(config.GetGatewayRPCServerPort()), prpc.WithWeight(config.GetGatewayRPCWeight()), ) + s.RegisterService(func(server *grpc.Server) { + // 指定gateway server的实现类(之前都是接口,这里明确告诉grpc,该接口由哪个实现类实现,后续接收到grpc时,由该实现类接收请求) service.RegisterGatewayServer(server, &service.Service{CmdChannel: cmdChannel}) }) // start client @@ -114,6 +116,7 @@ func sendMsgByCmd(cmd *service.CmdContext) { if cmdChannel == nil { return } + // 从全局epoll池中根据 connID 获取 conn if connPtr, ok := ep.tables.Load(cmd.ConnID); ok { conn, _ := connPtr.(*connection) dp := tcp.DataPgk{