├── .gitignore
├── README.md
├── application.go
├── application_test.go
├── code_enum.go
├── conf
├── cluster.yaml
├── log.xml
└── moa.toml
├── go.mod
├── go.sum
├── moa_codec.go
├── moa_codec_test.go
├── option.go
├── proxy.go
├── proxy_test.go
├── registry.go
├── registry_file.go
├── registry_file_test.go
├── registry_zk.go
├── registry_zk_test.go
├── stat.go
└── zk.go
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Go template
3 | # Binaries for programs and plugins
4 | *.exe
5 | *.exe~
6 | *.dll
7 | *.so
8 | *.dylib
9 |
10 | # Test binary, built with `go test -c`
11 | *.test
12 |
13 | # Output of the go coverage tool, specifically when used with LiteIDE
14 | *.out
15 |
16 | *.iml
17 | *.xml
18 |
19 | # Dependency directories (remove the comment below to include it)
20 | # vendor/
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #### MOA Server
2 |
3 | #### 简介
4 | * 支持zk做集群管理
5 | * 支持本地配置配置集群
6 | * 基于[turbo](https://github.com/blackbeans/turbo)
7 | * 使用json序列化协议作为传用户协议传输
8 | * 基于GroupId划分同服务下的服务,做到环境隔离
9 |
10 | #### 使用样例
11 | [样例参考](https://github.com/blackbeans/go-moa-demo)
12 |
13 | #### MOA协议简介
14 |
15 | * 基于turbo的二进制协议(https://github.com/blackbeans/turbo/packet)
16 |
17 | * {"action":"/service/bibi/go-moa","params":{"m":"setName","args":["a"]}}
18 |
19 | action:理解为服务名称(service-uri)
20 |
21 | m:需要调用该服务的方法名称(已经做了go和java关于方法名首字母大写兼容)
22 |
23 | args:m方法的调用参数序列。
24 |
25 |
26 | #### 安装:
27 |
28 | * 安装ZooKeeper (不需要集群可以不安装)
29 | $Zookeeper/bin/zkServer.sh start
30 |
31 | ```
32 | go get github.com/blackbeans/go-moa/core
33 |
34 | ```
35 |
36 | * 定义服务的接口对应
37 |
38 | - 例如接口为:
39 |
40 | ```goalng
41 | //接口
42 | type DemoResult struct {
43 | Hosts []string `json:"hosts"`
44 | Uri string `json:"uri"`
45 | }
46 |
47 | type IGoMoaDemo interface {
48 | GetDemoName(serviceUri, proto string) (DemoResult, error)
49 | }
50 | //服务实现
51 | type GoMoaDemo struct {
52 | }
53 |
54 | func (self GoMoaDemo) GetDemoName(serviceUri, proto string) ( DemoResult, error) {
55 | return DemoResult{[]string{"fuck gfw"}, serviceUri}, nil
56 | }
57 | ```
58 | - 约定:
59 | 为了给客户端友好的返回错误信息,go-moa的服务接口最后一个返回必须为error类型。并且为了满足Java单一返回结果所以返回参数最多2个。
60 |
61 | * 服务端启动启动:
62 |
63 | ```goalng
64 |
65 | func main(){
66 | app := core.NewApplcation("./conf/cluster_test.toml",
67 | func() []proxy.Service {
68 | return []proxy.Service{
69 | proxy.Service{
70 | ServiceUri: "/service/bibi/go-moa",
71 | Instance: GoMoaDemo{},
72 | Interface: (*IGoMoaDemo)(nil)}}
73 | })
74 |
75 | //设置启动项
76 | ch := make(chan os.Signal, 1)
77 | signal.Notify(ch, os.Kill)
78 | //kill掉的server
79 | <-ch
80 | app.DestroyApplication()
81 | }
82 |
83 | ```
84 |
85 | * 说明
86 | - Service为一个服务单元,对应了本服务对外的服务名称、以及对应的接口
87 |
88 | - Applcation需要对应的Moa的配置文件,toml类型,具体配置参见./conf/cluster_test. toml
89 | * 发布服务成功可以使用客户端进行测试,具体[客户端的使用请参考](http://github.com/blackbeans/go-moa-client/blob/master/README.md)
90 |
91 | #### Moa状态接口
92 |
93 | * MOAHOME
94 |
95 | URL :
96 | ```http
97 | http://host:${moaport+1000}/debug/moa
98 | ```
99 | 返回 :
100 |
101 | ```text
102 | /debug/moa/
103 |
104 | Types of moaprofiles available:
105 | moa
106 | index
107 | MOA首页
108 |
109 | stat
110 | MOA系统状态指标
111 |
112 | list.clients
113 | MOA当前所有连接
114 |
115 | list.services
116 | MOA发布的服务列表
117 |
118 | list.methods
119 | MOA来源调用统计信息
120 | ```
121 |
122 | * 查询MOA状态信息
123 |
124 | URL :
125 | ```http
126 | http://host:${moaport+1000}/debug/moa/stat
127 | ```
128 | 返回 :
129 |
130 | ```json
131 | {
132 | recv: 0, //接收请求数
133 | proc: 0, //处理请求数
134 | error: 0, //处理失败数量
135 | timeout: 0, //超时数量
136 | invoke_gos: 0, //方法执行的gopool
137 | conns: 0, //客户端连接数
138 | total_gos: 12 //总goroutine数量
139 | }
140 | ```
141 | * 查询MOA发布的服务列表
142 |
143 | URL :
144 |
145 | ```http
146 | http://host:${moaport+1000}/debug/moa/list/services
147 | ```
148 | 返回 :
149 |
150 | ```json
151 | [
152 | "/service/go-moa"
153 | ]
154 |
155 | ```
156 |
157 | * 查询服务方法调用统计情况
158 |
159 | URL :
160 |
161 | ```http
162 | http://host:${moaport+1000}/debug/moa/list/methods?service=/service/go-moa
163 | ```
164 | 返回 :
165 |
166 | ```json
167 | [
168 | {
169 | client: "192.168.50.88:63072",
170 | service_name: "/service/go-moa",
171 | methods: [
172 | {
173 | name: "SetName",
174 | count: 58939 //总调用次数
175 | }
176 | ]
177 | }
178 | ]
179 | ```
180 |
--------------------------------------------------------------------------------
/application.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 | "github.com/blackbeans/logx"
8 | "github.com/google/gops/agent"
9 | "github.com/opentracing/opentracing-go"
10 | "github.com/prometheus/client_golang/prometheus/promhttp"
11 | "github.com/uber/jaeger-client-go"
12 | jaegercfg "github.com/uber/jaeger-client-go/config"
13 | "html/template"
14 | "net"
15 | "net/http"
16 | "net/http/pprof"
17 | "sort"
18 | "strings"
19 |
20 | "time"
21 |
22 | "github.com/blackbeans/turbo"
23 | )
24 |
25 | type MoaProfile struct {
26 | Href string
27 | Name string
28 | Desc string
29 | }
30 |
31 | var profiles []MoaProfile
32 |
33 | func init() {
34 | profiles = []MoaProfile{
35 | MoaProfile{Name: "index", Href: "/debug/moa", Desc: "MOA首页"},
36 | MoaProfile{Name: "stat", Href: "/debug/moa/stat", Desc: "MOA系统状态指标"},
37 | MoaProfile{Name: "list.clients", Href: "/debug/moa/list/clients", Desc: "MOA当前所有连接"},
38 | MoaProfile{Name: "list.services", Href: "/debug/moa/list/services", Desc: "MOA发布的服务列表"},
39 | MoaProfile{Name: "list.methods", Href: "/debug/moa/list/methods", Desc: "MOA来源调用统计信息"},
40 | MoaProfile{Name: "metrics", Href: "/metrics", Desc: "prometheus metrics"},
41 | }
42 | }
43 |
44 | type ServiceBundle func() []Service
45 |
46 | var log = logx.GetLogger("moa-server")
47 |
48 | type Application struct {
49 | ctx context.Context
50 | stop context.CancelFunc
51 | http.Handler
52 | remoting *turbo.TServer
53 | invokeHandler *InvocationHandler
54 | options Option
55 | //任务处理
56 | invokePool *turbo.GPool
57 | configCenter *ConfigCenter
58 | moaStat *MoaStat
59 | }
60 |
61 | func NewApplicationWithContext(ctx context.Context, configPath string, bundle ServiceBundle, monitor func(serviceUri, host string, moainfo MoaInfo)) *Application {
62 | return initApplication(ctx, configPath, bundle, monitor)
63 | }
64 |
65 | func initApplication(ctx context.Context, configPath string, bundle ServiceBundle, monitor func(serviceUri, host string, moainfo MoaInfo)) *Application {
66 | log = logx.GetLogger("moa-server")
67 | services := bundle()
68 | options, err := LoadConfiguration(configPath)
69 | if nil != err {
70 | panic(err)
71 | }
72 |
73 | serverOp := InitServerOption(options)
74 |
75 | cloneServs := make([]Service, 0, len(services))
76 |
77 | for i, s := range services {
78 | //服务分默认不配置是使用*分组
79 | if len(s.GroupId) <= 0 {
80 | s.GroupId = "*"
81 | }
82 | //是否是预发环境
83 | s.IsPre = serverOp.Server.IsPre
84 | services[i] = s
85 | cloneServs = append(cloneServs, s)
86 | }
87 |
88 | name := serverOp.Server.BindAddress
89 | cluster := serverOp.Clusters[serverOp.Server.RunMode]
90 | config := turbo.NewTConfig(name,
91 | cluster.MaxDispatcherSize,
92 | cluster.ReadBufferSize,
93 | cluster.ReadBufferSize,
94 | cluster.WriteChannelSize,
95 | cluster.ReadChannelSize,
96 | cluster.IdleTimeout,
97 | 50*10000)
98 |
99 | // tracing
100 | if !opentracing.IsGlobalTracerRegistered() {
101 | // 如果 global tracer 还没有注册,我们就生成一个
102 | // 默认发送 span 到有可能不存在的 localhost上的 agent
103 | cfg := jaegercfg.Configuration{
104 | ServiceName: "moa-server",
105 | Sampler: &jaegercfg.SamplerConfig{
106 | Type: jaeger.SamplerTypeConst,
107 | Param: 1,
108 | },
109 | Reporter: &jaegercfg.ReporterConfig{
110 | //LogSpans: true,
111 | },
112 | }
113 | //jLogger := jaegerlog.StdLogger
114 | tracer, _, _ := cfg.NewTracer(
115 | //jaegercfg.Logger(jLogger),
116 | )
117 | opentracing.SetGlobalTracer(tracer)
118 | }
119 |
120 | ctx, cancel := context.WithCancel(ctx)
121 | invokePool := turbo.NewLimitPool(
122 | ctx,
123 | cluster.MaxDispatcherSize)
124 |
125 | //是否启用snappy
126 | snappy := false
127 | if strings.ToLower(serverOp.Server.Compress) == "snappy" {
128 | snappy = true
129 | }
130 |
131 | //需要开发对应的codec
132 | codec := func() turbo.ICodec {
133 | return BinaryCodec{MaxFrameLength: turbo.MAX_PACKET_BYTES, SnappyCompress: snappy}
134 | }
135 |
136 | //创建注册服务
137 | configCenter := NewConfigCenter(cluster.Registry,
138 | serverOp.Server.BindAddress,
139 | services)
140 |
141 | app := &Application{}
142 | app.options = options
143 | app.configCenter = configCenter
144 | app.invokePool = invokePool
145 | app.ctx = ctx
146 | app.stop = cancel
147 | //启动remoting
148 | remoting := turbo.NewTServerWithCodec(
149 | serverOp.Server.BindAddress,
150 | config,
151 | codec,
152 | func(ctx *turbo.TContext) error {
153 | dis(app, ctx)
154 | return nil
155 | })
156 | app.remoting = remoting
157 | err = remoting.ListenAndServer()
158 | if nil != err {
159 | panic(err)
160 | }
161 |
162 | //moastat
163 | moaStat := NewMoaStat(serverOp.Server.BindAddress,
164 | services[0].ServiceUri, invokePool,
165 | monitor,
166 | func() turbo.NetworkStat {
167 | return app.remoting.NetworkStat()
168 |
169 | })
170 | app.moaStat = moaStat
171 |
172 | app.invokeHandler = NewInvocationHandler(services, moaStat)
173 | moaStat.StartLog()
174 |
175 | //------------启动pprof
176 | // 启动 moa 系统指标状态 暴露http接口
177 | // 包括 pprof、自定义moa状态信息、prometheus metrics
178 | go func() {
179 | hp, _ := net.ResolveTCPAddr("tcp4", serverOp.Server.BindAddress)
180 | pprofListen := fmt.Sprintf("%s:%d", hp.IP, hp.Port+1000)
181 |
182 | for _, pro := range profiles {
183 | http.HandleFunc(pro.Href, app.ServeHTTP)
184 | }
185 | log.Error(http.ListenAndServe(pprofListen, nil))
186 | if err := agent.Listen(agent.Options{ShutdownCleanup: true}); err != nil {
187 | log.Errorf("Gops Start FAIL %s ...", err)
188 | }
189 | }()
190 |
191 | //注册服务
192 | configCenter.RegisteAllServices()
193 | log.Infof("Application|Start|SUCC|%s|%s", name, serverOp.Server.BindAddress)
194 |
195 | config.TW.RepeatedTimer(60*time.Second, func(tid uint32, t time.Time) {
196 | select {
197 | case <-ctx.Done():
198 | config.TW.CancelTimer(tid)
199 | return
200 | default:
201 |
202 | }
203 |
204 | allclients := remoting.ListClients()
205 | sort.Strings(allclients)
206 | for _, inst := range app.invokeHandler.instances {
207 | removeClients := make([]string, 0, 2)
208 | inst.InvokesPerClient.Range(func(key, value interface{}) bool {
209 | clientip := key.(string)
210 | idx := sort.SearchStrings(allclients, clientip)
211 | if idx == len(allclients) || allclients[idx] != clientip {
212 | removeClients = append(removeClients, clientip)
213 | }
214 | return true
215 | })
216 | //移除
217 | for _, clientip := range removeClients {
218 | inst.InvokesPerClient.Delete(clientip)
219 | }
220 | }
221 | }, nil)
222 | return app
223 | }
224 |
225 | func (self Application) DestroyApplication() {
226 |
227 | //取消注册服务
228 | self.configCenter.Destroy()
229 |
230 | // 通过查看 moaStat 中的Connections数量来确保当前没有连接
231 | // 每秒检查一次,等待 10s
232 | checkTimes := 0
233 | for checkTimes < 9 {
234 | log.Infof("Application|DestroyApplication|WaitProcess|Times:%d|Conns:%d", checkTimes, self.moaStat.preMoaInfo.Connections)
235 | if self.moaStat.preMoaInfo.Connections == 0 {
236 | log.Infof("Application|DestroyApplication|WaitProcess|Done")
237 | break
238 | }
239 | time.Sleep(time.Second)
240 | checkTimes += 1
241 | }
242 |
243 | self.stop()
244 | time.Sleep(500 * time.Millisecond)
245 |
246 | //关闭remoting
247 | self.remoting.Shutdown()
248 | self.moaStat.Destroy()
249 | }
250 |
251 | //需要开发对应的分包
252 | func dis(self *Application, ctx *turbo.TContext) {
253 |
254 | defer func() {
255 | if err := recover(); nil != err {
256 | log.Errorf("Application|packetDispatcher|FAIL|%s", err)
257 | }
258 | }()
259 |
260 | p := ctx.Message
261 | //如果是错误的,那么久直接写出错误的响应给客户端
262 | if nil != ctx.Err {
263 | resp := turbo.NewRespPacket(p.Header.Opaque, RESP, nil)
264 | resp.PayLoad = MoaRespPacket{ErrCode: CODE_THROWABLE, Message: fmt.Sprintf("%v", ctx.Err)}
265 | //需要发送调用的错误给客户端
266 | log.Errorf("Application|Err|Process|%v", resp)
267 | ctx.Client.Write(*resp)
268 | return
269 | }
270 | //如果是get命令
271 | if p.Header.CmdType == REQ {
272 |
273 | req := p.PayLoad.(MoaRawReqPacket)
274 | //这里面根据解析包的内容得到调用不同的service获得结果
275 | req.Source = ctx.Client.RemoteAddr()
276 | req.Timeout = self.options.Clusters[self.options.Server.RunMode].ProcessTimeout
277 | //是否已经超时过期了,那么久不用执行调用了
278 | if req.CreateTime > 0 && (time.Now().UnixNano()-req.CreateTime*int64(time.Millisecond)) >= int64(req.Timeout) {
279 | log.Warnf("InvocationHandler|Invoke|Timeout|Source:%s|Timeout[%d]ms|%s|%s",
280 | req.Source, req.Timeout/time.Millisecond, req.ServiceUri, req.Params.Method)
281 | } else {
282 | //全异步
283 | timeoutCtx, cancel := context.WithTimeout(self.ctx, req.Timeout)
284 | self.invokePool.Queue(timeoutCtx, func(cctx context.Context) (interface{}, error) {
285 | defer func() {
286 | cancel()
287 | }()
288 | //设置当前的调用的属性线程上下文
289 | invokeCtx := context.WithValue(cctx, KEY_MOA_PROPERTIES, req.Properties)
290 | self.invokeHandler.Invoke(invokeCtx, req, func(resp MoaRespPacket) error {
291 | respPacker := turbo.NewRespPacket(ctx.Message.Header.Opaque, RESP, nil)
292 | respPacker.PayLoad = resp
293 | if resp.ErrCode != 0 && resp.ErrCode != CODE_SERVER_SUCC {
294 | //需要发送调用的错误给客户端
295 | log.Errorf("InvocationHandler|Invoke|FAIL|Source:%s|Timeout[%d]ms|%s|%s|%d",
296 | req.Source, req.Timeout/time.Millisecond, req.ServiceUri, req.Params.Method, resp.ErrCode)
297 | }
298 | return ctx.Client.Write(*respPacker)
299 | })
300 | return nil, nil
301 | })
302 |
303 | }
304 | //log.DebugLog("moa", "Application|packetDispatcher|SUCC|%s", *resp)
305 |
306 | } else if p.Header.CmdType == PING {
307 | //PING 协议
308 | pipo, ok := p.PayLoad.(PiPo)
309 | if ok {
310 | ctx.Client.Pong(p.Header.Opaque, pipo.Timestamp)
311 | }
312 | resp := turbo.NewRespPacket(p.Header.Opaque, PONG, nil)
313 | resp.PayLoad = pipo
314 | ctx.Client.Write(*resp)
315 | } else if p.Header.CmdType == INFO {
316 | //INFO 协议,返回服务端信息
317 | stat := make(map[string]interface{}, 2)
318 | stat["network"] = self.remoting.NetworkStat()
319 | stat["moa"] = self.moaStat.GetMoaInfo()
320 | resp := turbo.NewRespPacket(p.Header.Opaque, INFO, nil)
321 | resp.PayLoad = stat
322 | ctx.Client.Write(*resp)
323 | }
324 |
325 | }
326 |
327 | //处理Moa的状态信息
328 | func (self *Application) ServeHTTP(w http.ResponseWriter, r *http.Request) {
329 |
330 | //moa的处理
331 | if strings.HasPrefix(r.RequestURI, "/debug/moa") {
332 |
333 | if len(strings.TrimPrefix(r.RequestURI, "/debug/moa")) <= 0 {
334 | if err := indexTmpl.Execute(w, profiles); err != nil {
335 | log.Warnf("ServeHTTP|Execute|FAIL|%v|%s", err, r.RequestURI)
336 | w.WriteHeader(http.StatusInternalServerError)
337 | return
338 | }
339 | return
340 | }
341 |
342 | //moa的状态信息
343 | if strings.HasPrefix(r.RequestURI, "/debug/moa/stat") {
344 |
345 | moaInfo := self.moaStat.GetMoaInfo()
346 | rawMoaInfo, _ := json.Marshal(moaInfo)
347 | w.WriteHeader(http.StatusOK)
348 | w.Header().Set("Content-Type", "text/json")
349 | w.Write(rawMoaInfo)
350 | return
351 |
352 | } else if strings.HasPrefix(r.RequestURI, "/debug/moa/list/clients") {
353 | //列出所有的客户端
354 | clients := self.remoting.ListClients()
355 | rawClients, _ := json.Marshal(clients)
356 | w.WriteHeader(http.StatusOK)
357 | w.Header().Set("Content-Type", "text/json")
358 | w.Write(rawClients)
359 | return
360 | } else if strings.HasPrefix(r.RequestURI, "/debug/moa/list/services") {
361 | //列出所有的services
362 | serviceNames := make([]string, 0, 1)
363 | for serviceName := range self.invokeHandler.instances {
364 | serviceNames = append(serviceNames, serviceName)
365 | }
366 |
367 | rawServices, _ := json.Marshal(serviceNames)
368 | w.WriteHeader(http.StatusOK)
369 | w.Header().Set("Content-Type", "text/json")
370 | w.Write(rawServices)
371 | return
372 | } else if strings.HasPrefix(r.RequestURI, "/debug/moa/list/methods") {
373 | //列出所有的方法 /moa/list/methods?serviceName=user-profile
374 | serviceName := r.FormValue("service")
375 | if len(serviceName) > 0 {
376 | serviceInvoke := self.invokeHandler.ListInvokes(serviceName)
377 | //返回发布的方法
378 | rawMethods, _ := json.Marshal(serviceInvoke)
379 |
380 | w.WriteHeader(http.StatusOK)
381 | w.Header().Set("Content-Type", "text/json")
382 | w.Write(rawMethods)
383 | } else {
384 | w.WriteHeader(http.StatusOK)
385 | w.Header().Set("Content-Type", "text/json")
386 | w.Write([]byte("{}"))
387 | }
388 | return
389 | } else {
390 | w.WriteHeader(http.StatusNotFound)
391 | return
392 | }
393 | } else if strings.HasPrefix(r.RequestURI, "/metrics") {
394 | promhttp.Handler().ServeHTTP(w, r)
395 | } else {
396 | pprof.Index(w, r)
397 | }
398 | }
399 |
400 | var indexTmpl = template.Must(template.New("index").Parse(`
401 |
402 | /debug/moa/
403 |
409 |
410 |
411 | /debug/moa/
412 |
413 | Types of moaprofiles available:
414 |
415 | moa |
416 | {{range .}}
417 |
418 | {{.Name}} |
419 | {{.Desc}} |
420 |
421 | {{end}}
422 |
423 |
424 |
425 | `))
426 |
--------------------------------------------------------------------------------
/application_test.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "github.com/blackbeans/logx"
7 | "net"
8 | "testing"
9 | "time"
10 |
11 | "github.com/blackbeans/turbo"
12 | )
13 |
14 | type DemoResult struct {
15 | Hosts []string `json:"hosts"`
16 | Uri string `json:"uri"`
17 | }
18 |
19 | type IHello interface {
20 | GetService(serviceUri, proto, groupId string) (DemoResult, error)
21 |
22 | HelloError(text string) (DemoResult, error)
23 | // 注册
24 | RegisterService(serviceUri, hostPort, proto, groupId string, config map[string]string) (string, error)
25 | // 注销
26 | UnregisterService(serviceUri, hostPort, proto, groupId string, config map[string]string) (string, error)
27 | }
28 |
29 | type DemoParam struct {
30 | Name string
31 | }
32 |
33 | type Demo struct {
34 | hosts map[string][]string
35 | uri string
36 | }
37 |
38 | func (self Demo) GetService(serviceUri, proto, groupId string) (DemoResult, error) {
39 | result := DemoResult{}
40 | val, _ := self.hosts[serviceUri+"_"+proto+"_"+groupId]
41 | result.Hosts = val
42 | result.Uri = self.uri
43 | // fmt.Printf("GetService|SUCC|%s|%s|%s\n", serviceUri, proto, result)
44 | return result, nil
45 | }
46 |
47 | // 注册
48 | func (self Demo) RegisterService(serviceUri, hostPort, proto, groupId string, config map[string]string) (string, error) {
49 | self.hosts[serviceUri+"_"+proto+"_"+groupId] = []string{hostPort + "?timeout=1000&version=2"}
50 | // fmt.Println("RegisterService|SUCC|" + serviceUri + "|" + proto)
51 | return "SUCCESS", nil
52 | }
53 |
54 | // 注销
55 | func (self Demo) UnregisterService(serviceUri, hostPort, proto, groupId string, config map[string]string) (string, error) {
56 | delete(self.hosts, serviceUri+"_"+proto+"_"+groupId)
57 | //fmt.Println("UnregisterService|SUCC|" + serviceUri + "|" + proto)
58 | return "SUCCESS", nil
59 | }
60 |
61 | func (self Demo) HelloError(text string) (DemoResult, error) {
62 | return DemoResult{}, errors.New(text)
63 | }
64 |
65 | var tclient *turbo.TClient
66 | var app *Application
67 |
68 | func Testinit(t testing.TB) (*Application, *turbo.TClient) {
69 | if nil != tclient || nil != app {
70 | return app, tclient
71 | }
72 | demo := Demo{make(map[string][]string, 2), "/service/lookup"}
73 | inter := (*IHello)(nil)
74 | logx.InitLogger("./logs", "./conf/log.xml")
75 | app := NewApplicationWithContext(context.TODO(), "./conf/moa.toml", func() []Service {
76 | return []Service{
77 | Service{
78 | ServiceUri: "/service/lookup",
79 | Instance: demo,
80 | Interface: inter},
81 | Service{
82 | ServiceUri: "/service/moa-admin",
83 | Instance: demo,
84 | Interface: inter},
85 | }
86 | }, func(serviceUri, host string, moainfo MoaInfo) {
87 |
88 | })
89 |
90 | //创建物理连接
91 | conn, _ := func(hostport string) (*net.TCPConn, error) {
92 | //连接
93 | remoteAddr, err_r := net.ResolveTCPAddr("tcp4", hostport)
94 | if nil != err_r {
95 | log.Printf("KiteClientManager|RECONNECT|RESOLVE ADDR |FAIL|remote:%s\n", err_r)
96 | return nil, err_r
97 | }
98 | conn, err := net.DialTCP("tcp4", nil, remoteAddr)
99 | if nil != err {
100 | log.Printf("KiteClientManager|RECONNECT|%s|FAIL|%s\n", hostport, err)
101 | return nil, err
102 | }
103 |
104 | return conn, nil
105 | }("localhost:13000")
106 |
107 | config := turbo.NewTConfig(
108 | "turbo-client:localhost:28888",
109 | 10, 16*1024,
110 | 16*1024, 20000, 20000,
111 | 10*time.Second,
112 | 50*10000)
113 |
114 | tclient = turbo.NewTClient(context.Background(), conn,
115 | func() turbo.ICodec {
116 | return BinaryCodec{
117 | MaxFrameLength: turbo.MAX_PACKET_BYTES}
118 | }, func(ctx *turbo.TContext) error {
119 | ctx.Client.Attach(ctx.Message.Header.Opaque, ctx.Message.Data)
120 | return nil
121 | }, config)
122 | tclient.Start()
123 | return app, tclient
124 |
125 | }
126 |
127 | func TestApplication(t *testing.T) {
128 | reqPacket := MoaReqPacket{}
129 | reqPacket.ServiceUri = "/service/lookup"
130 | reqPacket.Params.Method = "GetService"
131 | reqPacket.Params.Args = []interface{}{"fuck", "redis", "groupId"}
132 | reqPacket.Properties = map[string]string{
133 | "LAGN": "zh-CN",
134 | }
135 |
136 | p := turbo.NewPacket(REQ, nil)
137 | p.PayLoad = reqPacket
138 | app, tclient := Testinit(t)
139 | defer func() {
140 | tclient.Shutdown()
141 | app.DestroyApplication()
142 | }()
143 | val, err := tclient.WriteAndGet(*p, 60*time.Second)
144 | if nil != err {
145 | t.Logf("WriteAndGet|FAIL|%v\n", err)
146 | t.FailNow()
147 |
148 | }
149 | t.Logf("%v\n", val)
150 |
151 | pipo := PiPo{Timestamp: time.Now().Unix()}
152 | p = turbo.NewPacket(PING, nil)
153 | p.PayLoad = pipo
154 | val, _ = tclient.WriteAndGet(*p, 5*time.Second)
155 | if nil != err {
156 | t.Logf("WriteAndGet|PING|FAIL|%v\n", err)
157 | t.FailNow()
158 | }
159 |
160 | t.Logf("Recieve|PONG|%s", val)
161 |
162 | //panic
163 |
164 | reqPacket.ServiceUri = "/service/lookup"
165 | reqPacket.Params.Method = "HelloError"
166 | reqPacket.Params.Args = []interface{}{"error test"}
167 |
168 | for i := 0; i < 10; i++ {
169 | p = turbo.NewPacket(REQ, nil)
170 | p.PayLoad = reqPacket
171 |
172 | val, err = tclient.WriteAndGet(*p, 60*time.Second)
173 | if nil != err {
174 | t.Logf("WriteAndGet|FAIL|%v\n", err)
175 | t.FailNow()
176 |
177 | }
178 |
179 | t.Logf("%v\n", string(val.([]byte)))
180 | }
181 |
182 | time.Sleep(5 * time.Second)
183 | }
184 |
185 | func BenchmarkApplication(t *testing.B) {
186 | t.StopTimer()
187 | reqPacket := MoaReqPacket{}
188 | reqPacket.ServiceUri = "/service/lookup"
189 | reqPacket.Params.Method = "GetService"
190 | reqPacket.Params.Args = []interface{}{"fuck", "redis", "groupId"}
191 | _, tclient := Testinit(t)
192 | t.StartTimer()
193 | for i := 0; i < t.N; i++ {
194 | p := turbo.NewPacket(REQ, nil)
195 | p.PayLoad = reqPacket
196 | _, err := tclient.WriteAndGet(*p, 30*time.Second)
197 | if nil != err {
198 | t.Logf("WriteAndGet|FAIL|%v\n", err)
199 | //t.FailNow()
200 | }
201 | }
202 | if nil != app {
203 | app.DestroyApplication()
204 | }
205 |
206 | }
207 |
--------------------------------------------------------------------------------
/code_enum.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | const (
4 | CODE_SERVER_SUCC = 200
5 | // Error code list
6 | CODE_THROWABLE = 300
7 | CODE_INITIALIZETION = 301
8 | CODE_SERIALIZATION = 302
9 | CODE_REMOTING = 303
10 | CODE_TIMEOUT = 304
11 |
12 | CODE_NO_URI_FOUND = 401
13 | CODE_INVALID_TARGET_URI = 402
14 | CODE_INITIALIZATION_CLIENT = 3010
15 | CODE_SERIALIZATION_CLIENT = 3020
16 | CODE_REMOTING_CLIENT = 3030
17 | CODE_TIMEOUT_CLIENT = 3040
18 | CODE_USER_CANCELLED = 305
19 |
20 | CODE_SERVICE_NOT_FOUND = 501
21 | CODE_METHOD_NOT_FOUND = 502
22 | CODE_INVOCATION_TARGET = 503
23 | CODE_THREAD_POOL_IS_FULL = 504
24 | CODE_ASYNC_SUBMIT = 505
25 | CODE_IP_NOT_ALLOWED = 506
26 | CODE_INITIALIZATION_SERVER = 3011
27 | CODE_SERIALIZATION_SERVER = 3021
28 | CODE_REMOTING_SERVER = 3031
29 | CODE_TIMEOUT_SERVER = 3041
30 |
31 | //error message list
32 | MSG_MESSAGE = "Error code [%d], error message [%s]."
33 | MSG_INITIALIZATION = "Initialization exception: %s"
34 | MSG_REMOTING = "Remoting exception: %s"
35 | MSG_SERIALIZATION = "Serialization exception: %s"
36 | MSG_TIMEOUT = "Timeout exception: %s"
37 | MSG_UNKNOWN = "Unknown exception."
38 |
39 | MSG_NO_URI_FOUND = "No uri found: %s"
40 | MSG_INVALID_TARGET_URI = "Invalid target uri: %s"
41 | MSG_PARAMS_NOT_MATCHED = "params number is not matched! %d/%d"
42 | MSG_SERVICE_NOT_FOUND = "Service not found: %s."
43 | MSG_METHOD_NOT_FOUND = "Method not found: %s."
44 | MSG_INVOCATION_TARGET = "Invocation target exception: (%s)"
45 | MSG_THREAD_POOL_IS_FULL = "Threadpool is full: %s"
46 | )
47 |
--------------------------------------------------------------------------------
/conf/cluster.yaml:
--------------------------------------------------------------------------------
1 | #集群配置
2 | clusters:
3 | - service_uri: "/service/lookup"
4 | gid: ""
5 | proto_ver: ""
6 | isPre: false
7 | hostports:
8 | - "localhost:8080"
9 | - "localhost:8081"
10 |
--------------------------------------------------------------------------------
/conf/log.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | stdout
4 | file
5 | ./logs/stdout.log
6 | [%D %T] [%L] %M
7 | true
8 | 100M
9 | 10M
10 | true
11 |
12 | INFO
13 |
14 |
15 | moa-stat
16 | file
17 | INFO
18 | ./logs/moa-stat.log
19 | [%D %T] [%L] %M
20 | true
21 | 100M
22 | 10M
23 | true
24 |
25 |
26 |
27 | moa-server
28 | file
29 | INFO
30 | ./logs/moa-server.log
31 | [%D %T] [%L] %M
32 | true
33 | 100M
34 | 10M
35 | true
36 |
37 |
38 |
39 |
40 | config_center
41 | file
42 | INFO
43 | ./logs/config_center.log
44 | [%D %T] [%L] %M
45 | true
46 | 100M
47 | 10M
48 | true
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/conf/moa.toml:
--------------------------------------------------------------------------------
1 | #当前使用的环境
2 | [server]
3 | runMode="dev"
4 | #可以指定正则表达式也可以直接:13000默认使用0.0.0.0的IP(不建议)^10\\.83\\.\\d+\\.\\d+$:13000
5 | bindAddress=":13000"
6 | compress="snappy"
7 |
8 | [client]
9 | runMode="dev"
10 | compress="snappy"
11 | selectorStrategy="random"
12 |
13 | #cluster的服务器
14 | [clusters]
15 | [clusters.dev]
16 | registry="file://./conf/cluster.yaml"
17 | processTimeout=20
18 | #最大分发处理协程数
19 | maxDispatcherSize=10
20 | #读取缓冲大小
21 | readBufferSize=16384
22 | #写入缓冲大小
23 | writeBufferSize=16384
24 | #写异步channel长度
25 | writeChannelSize=1000
26 | #读异步channel长度
27 | readChannelSize=1000
28 |
29 | [clusters.online]
30 | registry="zk://vm-bibi-zk-mq001.vm:2181,vm-bibi-zk-mq002.vm:2181,vm-bibi-zk-mq003.vm:2181"
31 | processTimeout=20
32 | #最大分发处理协程数
33 | maxDispatcherSize=100
34 | #读取缓冲大小
35 | readBufferSize=16384
36 | #写入缓冲大小
37 | writeBufferSize=16384
38 | #写异步channel长度
39 | writeChannelSize=1000
40 | #读异步channel长度
41 | readChannelSize=1000
42 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/blackbeans/go-moa
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
7 | github.com/blackbeans/go-zookeeper v0.0.0-20160315041820-e9ca0f2da2a7
8 | github.com/blackbeans/logx v0.0.0-20230518151533-7059fbb3d603
9 | github.com/blackbeans/turbo v0.0.0-20230518151841-580b848285bf
10 | github.com/cespare/xxhash/v2 v2.2.0 // indirect
11 | github.com/golang/snappy v0.0.1
12 | github.com/google/gops v0.3.7
13 | github.com/kylelemons/godebug v1.1.0 // indirect
14 | github.com/naoina/go-stringutil v0.1.0 // indirect
15 | github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
16 | github.com/opentracing/opentracing-go v1.2.0
17 | github.com/prometheus/client_golang v1.14.0
18 | github.com/prometheus/common v0.40.0 // indirect
19 | github.com/prometheus/procfs v0.9.0 // indirect
20 | github.com/sirupsen/logrus v1.9.2 // indirect
21 | github.com/uber/jaeger-client-go v2.30.0+incompatible
22 | github.com/uber/jaeger-lib v2.4.1+incompatible // indirect
23 | go.uber.org/atomic v1.10.0 // indirect
24 | golang.org/x/time v0.3.0 // indirect
25 | gopkg.in/yaml.v3 v3.0.1
26 | )
27 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
16 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
17 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
18 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
19 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
20 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
21 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
22 | cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
23 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
24 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
25 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
26 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
27 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
28 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
29 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
30 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
31 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
32 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
33 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
34 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
35 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
36 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
37 | github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
38 | github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
39 | github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
40 | github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
41 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
42 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
43 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
44 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
45 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
46 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
47 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
48 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
49 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
50 | github.com/blackbeans/go-zookeeper v0.0.0-20160315041820-e9ca0f2da2a7 h1:YxOhaefbO74E+e0XH6s+N3MNBRYHfuF+YN5VG7EncuQ=
51 | github.com/blackbeans/go-zookeeper v0.0.0-20160315041820-e9ca0f2da2a7/go.mod h1:MxVuTEjQSE8nnLyPVzYZKQhMTaZoVBxw2xnmd/awuGM=
52 | github.com/blackbeans/logx v0.0.0-20230518044926-b1a03ee70678 h1:qxOxh4kj6+1zJxDQDPZdnTBosBu/5GVwHw6mNxXpYsU=
53 | github.com/blackbeans/logx v0.0.0-20230518044926-b1a03ee70678/go.mod h1:etQRdBUB7nfCUB8XWuZeOTWvDl8Q838qAi/LBARGQwg=
54 | github.com/blackbeans/logx v0.0.0-20230518151533-7059fbb3d603 h1:+58vNTfQJpqEC+zqMIlpnxJewty3cKum2RxAbIZNkg0=
55 | github.com/blackbeans/logx v0.0.0-20230518151533-7059fbb3d603/go.mod h1:etQRdBUB7nfCUB8XWuZeOTWvDl8Q838qAi/LBARGQwg=
56 | github.com/blackbeans/turbo v0.0.0-20230518050829-9717a827290f h1:O9Rc07Ve+Xv29GWbs1te/JdDTtkss5pEd3dKeyHuNUQ=
57 | github.com/blackbeans/turbo v0.0.0-20230518050829-9717a827290f/go.mod h1:zDbzLkgQDjay3rbaWvUDo9u02R6sFGVsGzguWVhEqaU=
58 | github.com/blackbeans/turbo v0.0.0-20230518151841-580b848285bf h1:giPd3l5+BFVxirrA+I99y90CTH2I8R8Rgbdd1N8RTvM=
59 | github.com/blackbeans/turbo v0.0.0-20230518151841-580b848285bf/go.mod h1:1ivSQWNDpz968Cp3jwTOApRZcTQRSRcjIbTJQXdkP+w=
60 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
61 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
62 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
63 | github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
64 | github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
65 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
66 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
67 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
68 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
69 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
70 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
71 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
72 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
73 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
74 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
75 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
76 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
77 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
78 | github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
79 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
80 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
81 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
82 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
83 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
84 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
85 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
86 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
87 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
88 | github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
89 | github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
90 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
91 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
92 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
93 | github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
94 | github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
95 | github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
96 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
97 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
98 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
99 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
100 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
101 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
102 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
103 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
104 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
105 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
106 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
107 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
108 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
109 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
110 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
111 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
112 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
113 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
114 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
115 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
116 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
117 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
118 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
119 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
120 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
121 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
122 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
123 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
124 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
125 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
126 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
127 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
128 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
129 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
130 | github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
131 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
132 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
133 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
134 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
135 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
136 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
137 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
138 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
139 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
140 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
141 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
142 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
143 | github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
144 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
145 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
146 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
147 | github.com/google/gops v0.3.7 h1:KtVAagOM0FIq+02DiQrKBTnLhYpWBMowaufcj+W1Exw=
148 | github.com/google/gops v0.3.7/go.mod h1:bj0cwMmX1X4XIJFTjR99R5sCxNssNJ8HebFNvoQlmgY=
149 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
150 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
151 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
152 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
153 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
154 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
155 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
156 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
157 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
158 | github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
159 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
160 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
161 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
162 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
163 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
164 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
165 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
166 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
167 | github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
168 | github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
169 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
170 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
171 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
172 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
173 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
174 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
175 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
176 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
177 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
178 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
179 | github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
180 | github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro=
181 | github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
182 | github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
183 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
184 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
185 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
186 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
187 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
188 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
189 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
190 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
191 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
192 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
193 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
194 | github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
195 | github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
196 | github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
197 | github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
198 | github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
199 | github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
200 | github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ=
201 | github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw=
202 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
203 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
204 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
205 | github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
206 | github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
207 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
208 | github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
209 | github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
210 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
211 | github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
212 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
213 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
214 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
215 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
216 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
217 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
218 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
219 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
220 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
221 | github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
222 | github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
223 | github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0=
224 | github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
225 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
226 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
227 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
228 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
229 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
230 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
231 | github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
232 | github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
233 | github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
234 | github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
235 | github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
236 | github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
237 | github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
238 | github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
239 | github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
240 | github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo=
241 | github.com/onsi/ginkgo/v2 v2.8.1/go.mod h1:N1/NbDngAFcSLdyZ+/aYTYGSlq9qMCS/cNKGJjy+csc=
242 | github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
243 | github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
244 | github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
245 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
246 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
247 | github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
248 | github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
249 | github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo=
250 | github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc=
251 | github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
252 | github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
253 | github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
254 | github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM=
255 | github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
256 | github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
257 | github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
258 | github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
259 | github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
260 | github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
261 | github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
262 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
263 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
264 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
265 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
266 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
267 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
268 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
269 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
270 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
271 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
272 | github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
273 | github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
274 | github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
275 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
276 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
277 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
278 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
279 | github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
280 | github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
281 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
282 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
283 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
284 | github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
285 | github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
286 | github.com/prometheus/common v0.40.0 h1:Afz7EVRqGg2Mqqf4JuF9vdvp1pi220m55Pi9T2JnO4Q=
287 | github.com/prometheus/common v0.40.0/go.mod h1:L65ZJPSmfn/UBWLQIHV7dBrKFidB/wPlF1y5TlSt9OE=
288 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
289 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
290 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
291 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
292 | github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
293 | github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
294 | github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
295 | github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
296 | github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
297 | github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
298 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
299 | github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
300 | github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
301 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
302 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
303 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
304 | github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
305 | github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
306 | github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
307 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
308 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
309 | github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
310 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
311 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
312 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
313 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
314 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
315 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
316 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
317 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
318 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
319 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
320 | github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
321 | github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
322 | github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
323 | github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
324 | github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
325 | github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
326 | github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
327 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
328 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
329 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
330 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
331 | github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
332 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
333 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
334 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
335 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
336 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
337 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
338 | go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
339 | go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
340 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
341 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
342 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
343 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
344 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
345 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
346 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
347 | golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
348 | golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
349 | golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
350 | golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
351 | golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
352 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
353 | golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
354 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
355 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
356 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
357 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
358 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
359 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
360 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
361 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
362 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
363 | golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
364 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
365 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
366 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
367 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
368 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
369 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
370 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
371 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
372 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
373 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
374 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
375 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
376 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
377 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
378 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
379 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
380 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
381 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
382 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
383 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
384 | golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
385 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
386 | golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
387 | golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
388 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
389 | golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
390 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
391 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
392 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
393 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
394 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
395 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
396 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
397 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
398 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
399 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
400 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
401 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
402 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
403 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
404 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
405 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
406 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
407 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
408 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
409 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
410 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
411 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
412 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
413 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
414 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
415 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
416 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
417 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
418 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
419 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
420 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
421 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
422 | golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
423 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
424 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
425 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
426 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
427 | golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
428 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
429 | golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
430 | golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
431 | golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
432 | golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
433 | golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
434 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
435 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
436 | golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
437 | golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
438 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
439 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
440 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
441 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
442 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
443 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
444 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
445 | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
446 | golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
447 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
448 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
449 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
450 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
451 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
452 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
453 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
454 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
455 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
456 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
457 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
458 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
459 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
460 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
461 | golang.org/x/sys v0.0.0-20171017063910-8dbc5d05d6ed/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
462 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
463 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
464 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
465 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
466 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
467 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
468 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
469 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
470 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
471 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
472 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
473 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
474 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
475 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
476 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
477 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
478 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
479 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
480 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
481 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
482 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
483 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
484 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
485 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
486 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
487 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
488 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
489 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
490 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
491 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
492 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
493 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
494 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
495 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
496 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
497 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
498 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
499 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
500 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
501 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
502 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
503 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
504 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
505 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
506 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
507 | golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
508 | golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
509 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
510 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
511 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
512 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
513 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
514 | golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
515 | golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
516 | golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
517 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
518 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
519 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
520 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
521 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
522 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
523 | golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
524 | golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
525 | golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
526 | golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
527 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
528 | golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
529 | golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
530 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
531 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
532 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
533 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
534 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
535 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
536 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
537 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
538 | golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
539 | golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
540 | golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
541 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
542 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
543 | golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
544 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
545 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
546 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
547 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
548 | golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
549 | golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
550 | golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
551 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
552 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
553 | golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
554 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
555 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
556 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
557 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
558 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
559 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
560 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
561 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
562 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
563 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
564 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
565 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
566 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
567 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
568 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
569 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
570 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
571 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
572 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
573 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
574 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
575 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
576 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
577 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
578 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
579 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
580 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
581 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
582 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
583 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
584 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
585 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
586 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
587 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
588 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
589 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
590 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
591 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
592 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
593 | golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
594 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
595 | golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
596 | golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
597 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
598 | golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
599 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
600 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
601 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
602 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
603 | gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
604 | gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
605 | gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
606 | gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
607 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
608 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
609 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
610 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
611 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
612 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
613 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
614 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
615 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
616 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
617 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
618 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
619 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
620 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
621 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
622 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
623 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
624 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
625 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
626 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
627 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
628 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
629 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
630 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
631 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
632 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
633 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
634 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
635 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
636 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
637 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
638 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
639 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
640 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
641 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
642 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
643 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
644 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
645 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
646 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
647 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
648 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
649 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
650 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
651 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
652 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
653 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
654 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
655 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
656 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
657 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
658 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
659 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
660 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
661 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
662 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
663 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
664 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
665 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
666 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
667 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
668 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
669 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
670 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
671 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
672 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
673 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
674 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
675 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
676 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
677 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
678 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
679 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
680 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
681 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
682 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
683 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
684 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
685 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
686 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
687 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
688 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
689 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
690 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
691 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
692 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
693 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
694 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
695 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
696 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
697 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
698 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
699 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
700 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
701 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
702 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
703 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
704 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
705 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
706 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
707 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
708 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
709 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
710 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
711 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
712 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
713 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
714 | rsc.io/goversion v1.0.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
715 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
716 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
717 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
718 |
--------------------------------------------------------------------------------
/moa_codec.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "github.com/blackbeans/turbo"
7 | "github.com/golang/snappy"
8 | "github.com/opentracing/opentracing-go"
9 | "time"
10 | )
11 |
12 | const (
13 | REQ = byte(0x01)
14 | RESP = byte(0x02)
15 | PING = byte(0x03)
16 | PONG = byte(0x04)
17 | INFO = byte(0x05)
18 | )
19 |
20 | const (
21 | COMPRESS_SNAPPY = 0x01 //snappy算法
22 | )
23 |
24 | type BinaryCodec struct {
25 | MaxFrameLength int
26 | SnappyCompress bool
27 | }
28 |
29 | //snappy解压缩
30 | func Decompress(src []byte) ([]byte, error) {
31 | l, err := snappy.DecodedLen(src)
32 | if nil != err {
33 | return nil, err
34 | }
35 | if l%256 != 0 {
36 | l = (l/256 + 1) * 256
37 | }
38 | dest := make([]byte, l)
39 | decompressData, err := snappy.Decode(dest, src)
40 | return decompressData, err
41 | }
42 |
43 | //snapp压缩
44 | func Compress(src []byte) []byte {
45 | l := snappy.MaxEncodedLen(len(src))
46 | if l%256 != 0 {
47 | l = (l/256 + 1) * 256
48 | }
49 |
50 | dest := make([]byte, l)
51 | compressData := snappy.Encode(dest, src)
52 | return compressData
53 | }
54 |
55 | //反序列化
56 | //包装为packet,但是头部没有信息
57 | func (self BinaryCodec) UnmarshalPayload(p *turbo.Packet) (interface{}, error) {
58 | useSnappy := p.Header.Extension & COMPRESS_SNAPPY
59 | //使用snap
60 | if useSnappy == COMPRESS_SNAPPY {
61 | d, err := Decompress(p.Data)
62 | if nil != err {
63 | return nil, err
64 | }
65 | p.Data = d
66 | }
67 |
68 | if p.Header.CmdType == REQ {
69 | //req
70 | req, err := Wrap2MoaRawRequest(p.Data)
71 | if nil != err {
72 | return turbo.Packet{}, err
73 | }
74 | if req.CreateTime <= 0 {
75 | req.CreateTime = time.Now().UnixNano() / int64(time.Millisecond)
76 | }
77 | p.PayLoad = *req
78 | } else if p.Header.CmdType == PING || p.Header.CmdType == PONG {
79 | //ping
80 | var ping PiPo
81 | json.Unmarshal(p.Data, &ping)
82 | p.PayLoad = ping
83 | } else if p.Header.CmdType == RESP {
84 | //resp
85 | resp, err := Wrap2MoaRawResponse(p.Data)
86 | if nil != err {
87 | return p, err
88 | }
89 | p.PayLoad = *resp
90 | }
91 |
92 | return p.PayLoad, nil
93 | }
94 |
95 | func (self BinaryCodec) MarshalPayload(p *turbo.Packet) ([]byte, error) {
96 |
97 | var rawPayload []byte
98 | if p.Header.CmdType == REQ {
99 | data, err := json.Marshal(p.PayLoad)
100 | if nil != err {
101 | return nil, err
102 | }
103 | rawPayload = data
104 |
105 | } else if p.Header.CmdType == PING || p.Header.CmdType == PONG {
106 | //pong协议
107 | rawPayload, _ = json.Marshal(p.PayLoad)
108 | } else if p.Header.CmdType == RESP {
109 |
110 | resp, ok := p.PayLoad.(MoaRespPacket)
111 | if !ok {
112 | resp = MoaRespPacket{ErrCode: CODE_SERIALIZATION_SERVER,
113 | Message: "Invalid PayLoad Type Not MoaRespPacket"}
114 | }
115 | data, err := json.Marshal(resp)
116 | if nil != err {
117 | log.Errorf("BinaryCodec|MarshalPacket|Marshal|FAIL|%v", err)
118 | resp = MoaRespPacket{ErrCode: CODE_SERIALIZATION_SERVER,
119 | Message: "Invalid PayLoad Type Not MoaRespPacket"}
120 | data, _ = json.Marshal(resp)
121 | }
122 | rawPayload = data
123 | }
124 |
125 | return rawPayload, nil
126 |
127 | }
128 |
129 | type PiPo struct {
130 | Timestamp int64 `json:"timestamp"`
131 | }
132 |
133 | type MoaReqPacket struct {
134 | ServiceUri string `json:"action"`
135 | Params struct {
136 | Method string `json:"m"`
137 | Args []interface{} `json:"args"`
138 | } `json:"params"`
139 | Properties map[string]string `json:"props,omitempty"`
140 | CreateTime int64 `json:"-"` //创建时间 ms
141 | Timeout time.Duration `json:"-"`
142 | }
143 |
144 | //moa请求协议的包
145 | type MoaRawReqPacket struct {
146 | ServiceUri string `json:"action"`
147 | Params struct {
148 | Method string `json:"m"`
149 | Args []json.RawMessage `json:"args"`
150 | } `json:"params"`
151 | Properties map[string]string `json:"props,omitempty"`
152 | CreateTime int64 `json:"-"` //创建时间 ms
153 | Timeout time.Duration `json:"-"`
154 | Source string `json:"-"`
155 | }
156 |
157 | //moa响应packet
158 | type MoaRespPacket struct {
159 | ErrCode int `json:"ec"`
160 | Message string `json:"em"`
161 | CreateTime int64 `json:"-"` //创建时间 ms
162 | Result interface{} `json:"result"`
163 | }
164 |
165 | //moa响应packet
166 | type MoaRawRespPacket struct {
167 | ErrCode int `json:"ec"`
168 | Message string `json:"em"`
169 | CreateTime int64 `json:"-"` //创建时间 ms
170 | Result json.RawMessage `json:"result"`
171 | }
172 |
173 | func Wrap2MoaRawRequest(data []byte) (*MoaRawReqPacket, error) {
174 | var req MoaRawReqPacket
175 | err := json.Unmarshal(data, &req)
176 | if nil != err {
177 | return nil, err
178 | } else {
179 | return &req, nil
180 | }
181 |
182 | }
183 |
184 | func Wrap2MoaRawResponse(data []byte) (*MoaRawRespPacket, error) {
185 | var resp MoaRawRespPacket
186 | err := json.Unmarshal(data, &resp)
187 | if nil != err {
188 | return nil, err
189 | }
190 | return &resp, nil
191 | }
192 |
193 | const (
194 | KEY_MOA_PROPERTIES = "moa.props"
195 |
196 | //MOA节点选择hash值
197 | KEY_MOA_PROPERTY_HASHID = "hashid"
198 |
199 | //MOA的调用环境,可以一直带到整个调用链结束
200 | KEY_MOA_PROPERTY_ENV_PRE = "moa.env.pre"
201 | )
202 |
203 | //切记切记。在使用完之后要做移除。否则会造成内存泄露
204 | //调用 DetachGoProperties
205 | // 注:如果要修改 moa context 中信息的存储方式,需要同时修改下面的 GetSpanCtx 和 WithSpanCtx
206 | func AttachMoaProperty(ctx context.Context, key, val string) context.Context {
207 |
208 | props := ctx.Value(KEY_MOA_PROPERTIES)
209 | if nil != props {
210 | if v, ok := props.(map[string]string); ok {
211 | v[key] = val
212 | return ctx
213 | }
214 | }
215 | prop := make(map[string]string)
216 | prop[key] = val
217 | return context.WithValue(ctx, KEY_MOA_PROPERTIES, prop)
218 | }
219 |
220 | //剔除属性
221 | func DetachMoaProperty(ctx context.Context, key string) {
222 | props := ctx.Value(KEY_MOA_PROPERTIES)
223 | if nil != props {
224 | if v, ok := props.(map[string]string); ok {
225 | delete(v, key)
226 | }
227 | }
228 | }
229 |
230 | //获取moa的上下文属性
231 | func GetMoaProperty(ctx context.Context, key string) (string, bool) {
232 | props := ctx.Value(KEY_MOA_PROPERTIES)
233 | if nil != props {
234 | if v, ok := props.(map[string]string); ok {
235 | val, exist := v[key]
236 | return val, exist
237 | }
238 | }
239 | return "", false
240 | }
241 |
242 | // 从我们的 Context 中获取 SpanContext,如果没有则返回 nil
243 | // 其实是从 context 的 moa.props 中获取信息
244 | func GetSpanCtx(ctx context.Context) opentracing.SpanContext {
245 | props := ctx.Value(KEY_MOA_PROPERTIES)
246 | if props != nil {
247 | if v, ok := props.(map[string]string); ok {
248 | spanCtx, err := opentracing.GlobalTracer().Extract(opentracing.TextMap, opentracing.TextMapCarrier(v))
249 | if err != nil {
250 | return nil
251 | }
252 | return spanCtx
253 | }
254 | }
255 | return nil
256 | }
257 |
258 | // 将 SpanContext 存到我们的 Context 中,进行传递
259 | // 其实是将一个键值对设置到了 context 的 moa.props 中
260 | func WithSpanCtx(ctx context.Context, spCtx opentracing.SpanContext) context.Context {
261 | props := ctx.Value(KEY_MOA_PROPERTIES)
262 | var p map[string]string
263 | if props != nil {
264 | if v, ok := props.(map[string]string); ok {
265 | p = v
266 | } else {
267 | // KEY_MOA_PROPERTIES 中不是 map[string]string
268 | p = make(map[string]string)
269 | }
270 | } else {
271 | p = make(map[string]string)
272 | }
273 | opentracing.GlobalTracer().Inject(spCtx, opentracing.TextMap, opentracing.TextMapCarrier(p))
274 | return context.WithValue(ctx, KEY_MOA_PROPERTIES, p)
275 | }
276 |
--------------------------------------------------------------------------------
/moa_codec_test.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | _ "bytes"
5 | "encoding/json"
6 | "reflect"
7 | "testing"
8 | )
9 |
10 | type ParamsTmp struct {
11 | Method string `json:"m"`
12 | // Args []interface{} `json:"args"`
13 | Args []*json.RawMessage `json:"args"`
14 | }
15 |
16 | type User struct {
17 | Name string `json:"name"`
18 | // Args []interface{} `json:"args"`
19 | }
20 |
21 | type Request struct {
22 | ServiceUri string `json:"action"`
23 | Params struct {
24 | Method string `json:"m"`
25 | // Args []interface{} `json:"args"`
26 | Args []*json.RawMessage `json:"args"`
27 | } `json:"params"`
28 | }
29 |
30 | func BenchmarkUnmarshal(t *testing.B) {
31 | t.StopTimer()
32 | cmd := []byte("{\"action\":\"/service/user-service\",\"params\":{\"m\":\"setName\",\"args\":[\"a\",1,2,{\"name\":\"bbafa\"}]}}")
33 | t.StartTimer()
34 | var reqtmp Request
35 | for i := 0; i < t.N; i++ {
36 | var req Request
37 | json.Unmarshal(cmd, &req)
38 | // args := []interface{}{"", 0, 0, ""}
39 | // json.Unmarshal(req.Params.Args, &args)
40 | reqtmp = req
41 | }
42 | t.StopTimer()
43 |
44 | inst := reflect.New(reflect.ValueOf((*User)(nil)).Type())
45 | json.Unmarshal(*reqtmp.Params.Args[3], inst.Interface())
46 | t.Log(inst.Elem().Interface())
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/option.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "io/ioutil"
5 | "net"
6 | "os"
7 | "regexp"
8 | "strings"
9 | "time"
10 |
11 | "github.com/naoina/toml"
12 | )
13 |
14 | type StrategyType string
15 |
16 | const (
17 | STRATEGY_RANDOM = "random"
18 | STRATEGY_KETAMA = "ketama"
19 | STRATEGY_PRIORITY_RANDOM = "priority_random"
20 | )
21 |
22 | type HostPort struct {
23 | Hosts string
24 | }
25 |
26 | //配置信息
27 | type Option struct {
28 | //server配置
29 | Server struct {
30 | RunMode string
31 | BindAddress string
32 | Compress string // compres=snappy
33 | IsPre bool // 是否是预发布环境
34 | }
35 |
36 | //client配置
37 | Client struct {
38 | RunMode string
39 | Compress string // compres=snappy
40 | SelectorStrategy string //selectorstrategy="random"
41 | SlowLog *bool //是否打开slowlog ,默认打开
42 | }
43 | Clusters map[string]Cluster //各集群的配置
44 | }
45 |
46 | //----------------------------------------
47 | //Cluster配置
48 | type Cluster struct {
49 | Registry string //配置中心
50 | ProcessTimeout time.Duration //处理超时 5 s单位
51 | IdleTimeout time.Duration //链接空闲时间 5 * 60s
52 | MaxDispatcherSize int //=50//最大分发处理协程数
53 | WorkerPoolSize int //=100 //最大业务处理线程池
54 | ReadBufferSize int //=16 * 1024 //读取缓冲大小
55 | WriteBufferSize int //=16 * 1024 //写入缓冲大小
56 | WriteChannelSize int //=1000 //写异步channel长度
57 | ReadChannelSize int //=1000 //读异步channel长度
58 | FutureSize int //默认值 100 * 10000 //请求响应的容量
59 | }
60 |
61 | func LoadConfiguration(path string) (Option, error) {
62 | f, err := os.Open(path)
63 | if err != nil {
64 | return Option{}, err
65 | }
66 | defer f.Close()
67 | buff, rerr := ioutil.ReadAll(f)
68 | if nil != rerr {
69 | return Option{}, err
70 | }
71 |
72 | //读取配置
73 | var option Option
74 | err = toml.Unmarshal(buff, &option)
75 | if nil != err {
76 | return Option{}, err
77 | }
78 |
79 | slowlog := true
80 | if nil != option.Client.SlowLog {
81 | slowlog = *(option.Client.SlowLog)
82 |
83 | }
84 | option.Client.SlowLog = &slowlog
85 | clusters := make(map[string]Cluster, len(option.Clusters))
86 | //设置默认值
87 | for name, cluster := range option.Clusters {
88 | if cluster.MaxDispatcherSize <= 0 {
89 | cluster.MaxDispatcherSize = 8000 //最大分发处理协程数
90 | }
91 |
92 | if cluster.ReadBufferSize <= 0 {
93 | cluster.ReadBufferSize = 16 * 1024 //读取缓冲大小
94 | }
95 |
96 | if cluster.WriteBufferSize <= 0 {
97 | cluster.WriteBufferSize = 16 * 1024 //写入缓冲大小
98 | }
99 |
100 | if cluster.WriteChannelSize <= 0 {
101 | cluster.WriteChannelSize = 1000 //写异步channel长度
102 | }
103 |
104 | if cluster.ReadChannelSize <= 0 {
105 | cluster.ReadChannelSize = 1000 //读异步channel长度
106 | }
107 |
108 | //链接空闲时间
109 | if cluster.IdleTimeout <= 0 {
110 | cluster.IdleTimeout = 5 * 60
111 | }
112 |
113 | cluster.IdleTimeout =
114 | time.Duration(int64(cluster.IdleTimeout) * int64(time.Second))
115 | if cluster.ProcessTimeout <= 0 {
116 | cluster.ProcessTimeout = 5
117 | }
118 |
119 | //工作池子
120 | if cluster.WorkerPoolSize <= 0 {
121 | cluster.WorkerPoolSize = cluster.MaxDispatcherSize
122 | }
123 |
124 | if cluster.FutureSize <= 100*10000 {
125 | cluster.FutureSize = 100 * 10000
126 | }
127 |
128 | cluster.ProcessTimeout =
129 | time.Duration(int64(cluster.ProcessTimeout) * int64(time.Second))
130 | clusters[name] = cluster
131 | }
132 | option.Clusters = clusters
133 | return option, nil
134 |
135 | }
136 |
137 | //初始化客户端的Option
138 | func InitClientOption(option Option) Option {
139 |
140 | cluster, ok := option.Clusters[option.Client.RunMode]
141 | if ok {
142 | //默认开启snappy
143 | if len(option.Client.Compress) <= 0 {
144 | option.Client.Compress = "snappy"
145 | }
146 | } else {
147 | panic("Client RunMode Conf Not Found!")
148 | }
149 |
150 | strategy := STRATEGY_RANDOM
151 | switch strings.ToUpper(option.Client.SelectorStrategy) {
152 | case "KETAMA":
153 | strategy = STRATEGY_KETAMA
154 | case "PRIORITY_RANDOM":
155 | strategy = STRATEGY_PRIORITY_RANDOM
156 | case "RANDOM":
157 | fallthrough
158 | default:
159 | strategy = STRATEGY_RANDOM
160 | }
161 |
162 | option.Client.SelectorStrategy = strategy
163 | option.Clusters[option.Client.RunMode] = cluster
164 | return option
165 | }
166 |
167 | //初始化server的配置
168 | func InitServerOption(option Option) Option {
169 | //------------寻找匹配的网卡IP段,进行匹配
170 | split := strings.Split(option.Server.BindAddress, ":")
171 | regx := split[0]
172 |
173 | inters, err := net.Interfaces()
174 | if nil != err {
175 | panic(err)
176 | } else {
177 | hasMatched := false
178 | //如果没有IP匹配表达式则用默认的
179 | if len(regx) <= 0 {
180 | option.Server.BindAddress = "0.0.0.0:" + split[1]
181 | hasMatched = true
182 | } else {
183 | for _, inter := range inters {
184 | addrs, _ := inter.Addrs()
185 | for _, addr := range addrs {
186 | if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() {
187 | if nil != ip.IP.To4() {
188 | match, _ := regexp.MatchString(regx, ip.IP.To4().String())
189 | if match {
190 | option.Server.BindAddress = ip.IP.To4().String() + ":" + split[1]
191 | hasMatched = true
192 | break
193 | }
194 | }
195 | }
196 | }
197 | }
198 | }
199 | //没有匹配的IP直接用0.0.0.0的IP绑定
200 | if !hasMatched {
201 | for _, inter := range inters {
202 | addrs, _ := inter.Addrs()
203 | loopback := false
204 | for _, addr := range addrs {
205 | ip, ok := addr.(*net.IPNet)
206 | if ok && ip.IP.IsLoopback() {
207 | loopback = true
208 | //skipped
209 | break
210 | }
211 | }
212 |
213 | if !loopback && len(addrs) > 0 {
214 | for _, addr := range addrs {
215 | if ip, ok := addr.(*net.IPNet); ok &&
216 | !ip.IP.IsLoopback() && nil != ip.IP.To4() {
217 | option.Server.BindAddress = ip.IP.To4().String() + ":" + split[1]
218 | hasMatched = true
219 | break
220 | }
221 | }
222 | }
223 | }
224 |
225 | if !hasMatched {
226 | option.Server.BindAddress = "0.0.0.0" + ":" + split[1]
227 |
228 | }
229 | }
230 | }
231 |
232 | cluster, ok := option.Clusters[option.Server.RunMode]
233 | if ok {
234 | //默认开启snappy
235 | if len(option.Server.Compress) <= 0 {
236 | option.Server.Compress = "snappy"
237 | }
238 | } else {
239 | panic("Server RunMode Conf Not Found!")
240 | }
241 |
242 | option.Clusters[option.Server.RunMode] = cluster
243 | return option
244 | }
245 |
--------------------------------------------------------------------------------
/proxy.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 | "reflect"
8 | "strings"
9 | "sync"
10 | "time"
11 |
12 | "github.com/blackbeans/turbo"
13 | "github.com/opentracing/opentracing-go"
14 | )
15 |
16 | type MethodMeta struct {
17 | Name string
18 | Method reflect.Value
19 | ReturnType []reflect.Type
20 | ParamTypes []reflect.Type
21 | }
22 |
23 | type ServiceMeta struct {
24 | ServiceUri string `json:"service_uri"` //serviceUr对应的服务名称
25 | GroupId string `json:"gid"` //该服务的分组
26 | HostPort string `json:"hostport"` //节点
27 | ProtoVersion string `json:"proto_ver"` //协议版本
28 | IsPre bool `json:"isPre"` //是否是预发环境
29 | }
30 |
31 | type Service struct {
32 | ServiceUri string `json:"service_uri"` //serviceUr对应的服务名称
33 | GroupId string `json:"gid"` //该服务的分组
34 | IsPre bool `json:"isPre"` //是否是预发环境
35 | Interface interface{} `json:"-"`
36 | Instance interface{} `json:"-"`
37 | //方法名称反射对应的方法
38 | methods map[string]MethodMeta
39 |
40 | InvokesPerClient *sync.Map `json:"-"` //key: remoteip:port values:map[method]Count
41 | }
42 |
43 | type InvocationHandler struct {
44 | instances map[string]Service
45 | moaStat *MoaStat
46 | }
47 |
48 | var errorType = reflect.TypeOf(make([]error, 1)).Elem()
49 |
50 | func NewInvocationHandler(services []Service, moaStat *MoaStat) *InvocationHandler {
51 | instances := make(map[string]Service, len(services))
52 | //对instace进行反射获得方法
53 | for _, s := range services {
54 | inter := reflect.TypeOf(s.Interface).Elem()
55 | rv := reflect.ValueOf(s.Instance)
56 | v := reflect.TypeOf(s.Instance)
57 | impl := v.Implements(inter)
58 | if !impl {
59 | panic(fmt.Sprintf("InvocationHandler|Not Implements|%s|%s",
60 | v.String(), inter.String()))
61 | }
62 | numMethod := inter.NumMethod()
63 | s.methods = make(map[string]MethodMeta, numMethod)
64 | for i := 0; i < numMethod; i++ {
65 | mm := MethodMeta{}
66 | m := inter.Method(i)
67 | im := rv.MethodByName(m.Name)
68 | mm.Method = im
69 | mm.Name = m.Name
70 | t := m.Type
71 | fn := t.NumIn()
72 | outType := make([]reflect.Type, 0, 2)
73 | for idx := 0; idx < t.NumOut(); idx++ {
74 | outType = append(outType, t.Out(idx))
75 | }
76 | //返回值必须大于等于1个并且小于2,并且其中一个必须为error类型
77 | if t.NumOut() >= 1 && t.NumOut() <= 2 {
78 | if !t.Out(t.NumOut() - 1).Implements(errorType) {
79 | panic(
80 | fmt.Errorf("%s Method %s Last Return Type Must Be An Error! [%s]",
81 | s.ServiceUri, m.Name, t.Out(t.NumOut()-1).String()))
82 | }
83 | } else {
84 | panic(
85 | fmt.Errorf("%s Method %s Last Return Count (1<=n<=2) Type "+
86 | "Must Be More Than An Error! ",
87 | s.ServiceUri, m.Name))
88 | }
89 | mm.ReturnType = outType
90 | mm.ParamTypes = make([]reflect.Type, 0, fn)
91 | for j := 0; j < fn; j++ {
92 | f := t.In(j)
93 | mm.ParamTypes = append(mm.ParamTypes, f)
94 | }
95 | s.methods[strings.ToLower(m.Name)] = mm
96 | //单个客户端调用的情况
97 | s.InvokesPerClient = &sync.Map{}
98 | }
99 | instances[s.ServiceUri] = s
100 | log.Infof("NewInvocationHandler|InitService|SUCC|%s", s.ServiceUri)
101 | }
102 | return &InvocationHandler{instances: instances,
103 | moaStat: moaStat}
104 |
105 | }
106 |
107 | //服务调用情况
108 | func (self InvocationHandler) ListInvokes(servicename string) []InvokePerClient {
109 |
110 | service, ok := self.instances[servicename]
111 | if ok {
112 | clients := make([]InvokePerClient, 0, 10)
113 |
114 | service.InvokesPerClient.Range(func(key, value interface{}) bool {
115 | s := InvokePerClient{
116 | Client: key.(string),
117 | ServiceName: service.ServiceUri,
118 | Methods: make([]Method, 0, len(service.methods))}
119 | //clientip调用的方法及数量
120 | value.(*sync.Map).Range(func(key, value interface{}) bool {
121 | methodName := key.(string)
122 | count := value.(*turbo.Flow).Count()
123 | s.Methods = append(s.Methods, Method{Name: methodName, Count: int64(count)})
124 | return true
125 | })
126 | clients = append(clients, s)
127 | return true
128 | })
129 |
130 | return clients
131 | }
132 | return []InvokePerClient{}
133 | }
134 |
135 | var typeOfContext = reflect.TypeOf(new(context.Context)).Elem()
136 |
137 | //执行结果
138 | func (self InvocationHandler) Invoke(ctx context.Context, req MoaRawReqPacket, onCallback func(resp MoaRespPacket) error) {
139 |
140 | // tracing
141 | // 请求开始时的一些 set
142 | var (
143 | isTracing bool
144 | childSpan opentracing.Span
145 | )
146 | parentSpanCtx := GetSpanCtx(ctx) // 从当前的请求中获取 parent span
147 | if parentSpanCtx != nil { // 有parent span时我们才开启child span,否则说明调用端没有开启 tracing
148 | isTracing = true
149 | childSpan = opentracing.GlobalTracer().StartSpan(req.Params.Method, opentracing.ChildOf(parentSpanCtx)) // 从parent span中生成 child span
150 | defer childSpan.Finish() // Invoke结束时停止当前span
151 | ctx = WithSpanCtx(ctx, childSpan.Context()) // 将 child span 写入 ctx
152 |
153 | // 将入参写到 span log 中
154 | for i, arg := range req.Params.Args {
155 | v, err := json.Marshal(arg)
156 | if err == nil {
157 | childSpan.LogKV(fmt.Sprintf("param.%d", i), string(v))
158 | }
159 | }
160 | // 将 moaCtx 有关信息写到 span tag 中
161 | if props := ctx.Value(KEY_MOA_PROPERTIES); props != nil {
162 | // 从 moa.props 中获取 key value 设置到 child span 的 tag
163 | for k, v := range props.(map[string]string) {
164 | childSpan.SetTag("moa."+k, v)
165 | }
166 | }
167 | }
168 |
169 | self.moaStat.IncrRecv()
170 | now := time.Now()
171 | resp := MoaRespPacket{}
172 |
173 | //捕获运行时异常
174 | defer func() {
175 | if crash := recover(); nil != crash {
176 | self.moaStat.IncrError()
177 | resp.ErrCode = CODE_INVOCATION_TARGET
178 | resp.Message = fmt.Sprintf(MSG_INVOCATION_TARGET, fmt.Sprintf("%v", crash))
179 | log.Errorf("InvocationHandler|Invoke|Panic|%v|Source:%s|Timeout[%d]ms|%s|%s|%v", crash,
180 | req.Source, req.Timeout/time.Millisecond, req.ServiceUri, req.Source, req.Params.Method)
181 | }
182 |
183 | // 记录耗时
184 | cost := time.Now().Sub(now)
185 | self.moaStat.MoaMetrics.RpcInvokeDurationSummary.WithLabelValues(req.Params.Method).Observe(cost.Seconds())
186 | // 长耗时
187 | if cost/time.Millisecond >= 1000 {
188 | log.Warnf("InvocationHandler|Invoke|Call|Slow|Source:%s|Cost[%d]ms|%s|%s|%v",
189 | req.Source, cost/time.Millisecond, req.ServiceUri, req.Source, req.Params.Method)
190 | }
191 | // 超时了
192 | if cost >= req.Timeout {
193 | //丢弃结果
194 | log.Warnf("InvocationHandler|Invoke|Call|Source:%s|Timeout[%d]ms|Cost:%d|%s|%s|%v",
195 | req.Source, req.Timeout/time.Millisecond, cost/time.Millisecond, req.ServiceUri, req.Source, req.Params.Method)
196 | } else {
197 | // tracing
198 | // 请求响应时的一些 set
199 | if isTracing {
200 | childSpan.SetTag("resp.ec", resp.ErrCode)
201 | childSpan.SetTag("resp.em", resp.Message)
202 | rawJson, err := json.Marshal(resp.Result)
203 | if err == nil {
204 | childSpan.LogKV("resp.result", string(rawJson))
205 | }
206 | if resp.ErrCode != CODE_SERVER_SUCC {
207 | childSpan.SetTag("error", true)
208 | }
209 | }
210 |
211 | // 根据errCode设置error
212 | err := onCallback(resp)
213 | if nil != err {
214 | log.Errorf("InvocationHandler|Invoke|onCallback|%v|Source:%s|Timeout[%d]ms|%s|%s|%v", err,
215 | req.Source, req.Timeout/time.Millisecond, req.ServiceUri, req.Source, req.Params.Method)
216 | }
217 | }
218 | }()
219 |
220 | //需要对包的内容解析进行反射调用
221 | instance, ok := self.instances[req.ServiceUri]
222 | if !ok {
223 | self.moaStat.IncrError()
224 | resp.ErrCode = CODE_SERVICE_NOT_FOUND
225 | resp.Message = fmt.Sprintf(MSG_NO_URI_FOUND, req.ServiceUri)
226 | } else {
227 | m, mok := instance.methods[strings.ToLower(req.Params.Method)]
228 | if !mok {
229 | self.moaStat.IncrError()
230 | resp.ErrCode = CODE_METHOD_NOT_FOUND
231 | resp.Message = fmt.Sprintf(MSG_METHOD_NOT_FOUND, req.Params.Method)
232 | } else {
233 |
234 | countPerMethod, ok := instance.InvokesPerClient.Load(req.Source)
235 | if !ok {
236 | tmp := &sync.Map{}
237 | exist, ok := instance.InvokesPerClient.LoadOrStore(req.Source, tmp)
238 | if !ok {
239 | //么有load到则是缓存放入的
240 | countPerMethod = tmp
241 | } else {
242 | countPerMethod = exist
243 | }
244 | }
245 | flow := countPerMethod.(*sync.Map)
246 | counter, ok := flow.Load(m.Name)
247 | if !ok {
248 | tmp := &turbo.Flow{}
249 | exist, ok := flow.LoadOrStore(m.Name, tmp)
250 | if !ok {
251 | counter = tmp
252 | } else {
253 | counter = exist
254 | }
255 | }
256 |
257 | counter.(*turbo.Flow).Incr(1)
258 |
259 | paramTypes := m.ParamTypes
260 | params := make([]reflect.Value, 0, len(m.ParamTypes))
261 | if len(m.ParamTypes) > 0 {
262 | //第一个参数类型判断下是否是context,如果是那么直接使用ctx
263 | if m.ParamTypes[0].Implements(typeOfContext) {
264 | params = append(params, reflect.ValueOf(ctx))
265 | paramTypes = paramTypes[1:]
266 | }
267 | }
268 |
269 | //参数数量不对应
270 | if len(req.Params.Args) != len(paramTypes) {
271 | self.moaStat.IncrError()
272 | resp.ErrCode = CODE_SERIALIZATION
273 | resp.Message = fmt.Sprintf(MSG_PARAMS_NOT_MATCHED,
274 | len(req.Params.Args), len(m.ParamTypes))
275 | } else {
276 | //参数数量OK逐个转换为reflect.Value类型
277 | for i, arg := range req.Params.Args {
278 | f := paramTypes[i]
279 | inst := reflect.New(f)
280 | uerr := json.Unmarshal(arg, inst.Interface())
281 | if nil != uerr {
282 | resp.ErrCode = CODE_SERIALIZATION_SERVER
283 | resp.Message = fmt.Sprintf(MSG_SERIALIZATION, uerr)
284 | log.Errorf("InvocationHandler|Invoke|Unmarshal|Source:%s|%s|%s|%s|%v",
285 | req.Source, req.ServiceUri, m.Name, string(arg), uerr)
286 | break
287 | } else {
288 | params = append(params, inst.Elem())
289 | }
290 | }
291 |
292 | if resp.ErrCode != 0 && resp.ErrCode != CODE_SERVER_SUCC {
293 | self.moaStat.IncrError()
294 | } else {
295 | work := invoke(m, params...)
296 | if nil != work.err {
297 | log.Errorf("InvocationHandler|Invoke|Call|FAIL|%v|Source:%s|%s|%s|%s",
298 | work.err, req.Source, req.ServiceUri, m.Name, params)
299 | self.moaStat.IncrError()
300 | resp.ErrCode = CODE_INVOCATION_TARGET
301 | resp.Message = fmt.Sprintf(MSG_INVOCATION_TARGET, work.err)
302 | } else if r := work.values; nil != r {
303 | self.moaStat.IncrProc()
304 | resp.ErrCode = CODE_SERVER_SUCC
305 | resp.Result = r[0].Interface()
306 | //则肯定会有error
307 | if len(r) > 1 && !r[1].IsNil() {
308 | resp.Message = fmt.Sprintf("Method Invoke Error %v", r[1].Interface())
309 | }
310 | } else {
311 | //如果为空、说明是取消的任务
312 | self.moaStat.IncrError()
313 | resp.ErrCode = CODE_INVOCATION_TARGET
314 | resp.Message = fmt.Sprintf("NO Result ...")
315 | }
316 | }
317 | }
318 | }
319 | }
320 | }
321 |
322 | func invoke(m MethodMeta, params ...reflect.Value) invokeResult {
323 | ir := invokeResult{}
324 | ir.values = m.Method.Call(params)
325 | if len(m.ReturnType) <= 1 {
326 | if !ir.values[0].IsNil() {
327 | //其实就是个err
328 | ir.err = ir.values[0]
329 | }
330 | }
331 |
332 | return ir
333 | }
334 |
335 | type invokeResult struct {
336 | err interface{}
337 | values []reflect.Value
338 | }
339 |
--------------------------------------------------------------------------------
/proxy_test.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "fmt"
7 | "reflect"
8 | "testing"
9 | "time"
10 |
11 | "github.com/blackbeans/turbo"
12 |
13 | _ "fmt"
14 | )
15 |
16 | type ProxyParam struct {
17 | Name string
18 | }
19 |
20 | type ProxyResult struct {
21 | Name string
22 | Text string
23 | }
24 |
25 | type IProxyDemo interface {
26 | ProxyDemo(ctx context.Context, text string, param ProxyParam) (ProxyResult, error)
27 | ProxyDemoSlice(text string, arr []string, param ProxyParam) (ProxyResult, error)
28 | ProxyDemoComplexSlice(text string, arg2 map[string]ProxyParam, arr []*ProxyParam) (ProxyResult, error)
29 | }
30 |
31 | type DemoProxy struct {
32 | }
33 |
34 | func (self DemoProxy) ProxyDemo(ctx context.Context, text string, param ProxyParam) (ProxyResult, error) {
35 | fmt.Println("----------ProxyDemo")
36 | return ProxyResult{param.Name, text}, nil
37 | }
38 |
39 | func (self DemoProxy) ProxyDemoSlice(text string, arr []string, param ProxyParam) (ProxyResult, error) {
40 | // fmt.Println("----------ProxyDemo")
41 | return ProxyResult{param.Name, text}, nil
42 | }
43 |
44 | func (self DemoProxy) ProxyDemoComplexSlice(text string, arg2 map[string]ProxyParam, arr []*ProxyParam) (ProxyResult, error) {
45 | // fmt.Println("----------ProxyDemo")
46 | return ProxyResult{"test", text}, nil
47 | }
48 |
49 | func MoaRequest2Raw(req *MoaReqPacket) *MoaRawReqPacket {
50 | raw := &MoaRawReqPacket{}
51 | raw.ServiceUri = req.ServiceUri
52 |
53 | raw.Params.Method = req.Params.Method
54 | rawArgs := make([]json.RawMessage, 0, len(req.Params.Args))
55 | for _, a := range req.Params.Args {
56 | rw, _ := json.Marshal(a)
57 | rawArgs = append(rawArgs, json.RawMessage(rw))
58 | }
59 | raw.Params.Args = rawArgs
60 | raw.Timeout = req.Timeout
61 | return raw
62 | }
63 |
64 | func testInitMoaStat(t testing.TB) *MoaStat {
65 | return NewMoaStat("hostname",
66 | "serviceUri",
67 | turbo.NewLimitPool(context.Background(), 100),
68 | func(serviceUri, host string, moainfo MoaInfo) {},
69 | func() turbo.NetworkStat { return turbo.NetworkStat{} })
70 | }
71 |
72 | func TestInvocationHandler(t *testing.T) {
73 | stat := testInitMoaStat(t)
74 | defer stat.Destroy()
75 | handler := NewInvocationHandler([]Service{
76 | Service{
77 | ServiceUri: "demo",
78 | Instance: DemoProxy{},
79 | Interface: (*IProxyDemo)(nil)}}, stat)
80 |
81 | m, ok := handler.instances["demo"].methods["proxydemo"]
82 | if !ok {
83 | t.Fail()
84 | }
85 | t.Logf("TestInvocationHandler|Method Fields|%s", m.ParamTypes)
86 | for _, f := range m.ParamTypes {
87 | t.Logf("TestInvocationHandler|ProxyDemo|%s", f.Kind().String())
88 | if f.Kind() != reflect.String && f.Kind() != reflect.Struct && f.Kind() != reflect.Interface {
89 | t.Fail()
90 | }
91 | }
92 | }
93 |
94 | func TestInvocationInvoke(t *testing.T) {
95 | stat := testInitMoaStat(t)
96 | defer stat.Destroy()
97 | handler := NewInvocationHandler([]Service{Service{ServiceUri: "demo",
98 | Instance: DemoProxy{}, Interface: (*IProxyDemo)(nil)}}, stat)
99 | req := &MoaReqPacket{}
100 | req.ServiceUri = "demo"
101 | req.Params.Args = []interface{}{"fuck", DemoParam{"you"}}
102 | req.Params.Method = "proxydemo"
103 | req.Timeout = 5 * time.Second
104 | handler.Invoke(context.TODO(), *MoaRequest2Raw(req), func(resp MoaRespPacket) error {
105 | t.Logf("TestInvocationInvoke|Invoke|%v\n", resp)
106 | if resp.ErrCode != 200 && resp.ErrCode != 0 {
107 | t.Fail()
108 | } else {
109 | data, _ := json.Marshal(resp.Result)
110 | t.Logf("TestInvocationInvoke|Invoke|Result|%s\n", string(data))
111 | }
112 | return nil
113 | })
114 |
115 | }
116 |
117 | func TestInvokeProxyDemoSlice(t *testing.T) {
118 | stat := testInitMoaStat(t)
119 | defer stat.Destroy()
120 | handler := NewInvocationHandler([]Service{Service{ServiceUri: "demo",
121 | Instance: DemoProxy{}, Interface: (*IProxyDemo)(nil)}}, stat)
122 | req := &MoaReqPacket{}
123 | req.ServiceUri = "demo"
124 | req.Params.Args = []interface{}{"fuck", []string{"a", "b"}, ProxyParam{"you"}}
125 | req.Params.Method = "ProxyDemoSlice"
126 | req.Timeout = 5 * time.Second
127 | handler.Invoke(context.TODO(), *MoaRequest2Raw(req), func(resp MoaRespPacket) error {
128 | t.Logf("TestInvokeProxyDemoSlice|Invoke|%s\n", resp.Result)
129 | if resp.ErrCode != 200 && resp.ErrCode != 0 {
130 | t.Fail()
131 | } else {
132 | data, _ := json.Marshal(resp.Result)
133 | t.Logf("TestInvokeProxyDemoSlice|Invoke|Result|%s\n", string(data))
134 | }
135 | return nil
136 | })
137 |
138 | }
139 |
140 | func TestInvokeJsonParams(t *testing.T) {
141 | stat := testInitMoaStat(t)
142 | defer stat.Destroy()
143 | handler := NewInvocationHandler([]Service{Service{ServiceUri: "demo",
144 | Instance: DemoProxy{}, Interface: (*IProxyDemo)(nil)}}, stat)
145 |
146 | cmd := "{\"action\":\"demo\",\"params\":{\"m\":\"ProxyDemoSlice\",\"args\":[\"fuck\",[\"a\", \"b\"],{\"Name\":\"you\"}]}}"
147 | var req MoaRawReqPacket
148 | err := json.Unmarshal([]byte(cmd), &req)
149 | if nil != err {
150 | t.Error(err)
151 | }
152 | t.Log(req)
153 | req.Timeout = 5 * time.Second
154 | handler.Invoke(context.TODO(), req, func(resp MoaRespPacket) error {
155 | t.Logf("TestInvokeProxyDemoSlice|Invoke|%s\n", resp.Result)
156 | if resp.ErrCode != 200 && resp.ErrCode != 0 {
157 | t.Fail()
158 | } else {
159 | data, _ := json.Marshal(resp.Result)
160 | t.Logf("TestInvokeProxyDemoSlice|Invoke|Result|%s\n", string(data))
161 | }
162 | return nil
163 | })
164 | }
165 |
166 | func TestComplexSliceJsonParams(t *testing.T) {
167 | stat := testInitMoaStat(t)
168 | defer stat.Destroy()
169 | handler := NewInvocationHandler([]Service{
170 | Service{
171 | ServiceUri: "demo",
172 | Instance: DemoProxy{},
173 | Interface: (*IProxyDemo)(nil)}},
174 | stat)
175 |
176 | cmd := "{\"action\":\"demo\",\"params\":{\"m\":\"ProxyDemoComplexSlice\",\"args\":[\"fuck\",{\"key\":{\"Name\":\"you\"}},[{\"key\":{\"Name\":\"you\"}},{\"key\":{\"Name\":\"you\"}}]]}}"
177 | var req MoaRawReqPacket
178 | err := json.Unmarshal([]byte(cmd), &req)
179 | if nil != err {
180 | t.Error(err)
181 | }
182 |
183 | req.Timeout = 5 * time.Second
184 | handler.Invoke(context.TODO(), req, func(resp MoaRespPacket) error {
185 | t.Logf("TestInvokeProxyDemoSlice|Invoke|%v\n", resp)
186 | if resp.ErrCode != 200 && resp.ErrCode != 0 {
187 | t.Fail()
188 | } else {
189 | data, _ := json.Marshal(resp.Result)
190 | t.Logf("TestInvokeProxyDemoSlice|Invoke|Result|%s\n", string(data))
191 | }
192 | return nil
193 | })
194 | }
195 |
--------------------------------------------------------------------------------
/registry.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "bytes"
5 | "strings"
6 | )
7 |
8 | const (
9 | SCHEME_ZK = "zk://"
10 | SCHEME_FILE = "file://" //直接连接
11 | )
12 |
13 | type ConfigCenter struct {
14 | registry IRegistry
15 | services []Service
16 | hostport string
17 | }
18 |
19 | //用于创建
20 | func NewConfigCenter(registryAddr,
21 | hostport string, services []Service) *ConfigCenter {
22 |
23 | uris := make([]string, 0, 10)
24 | for _, s := range services {
25 | uris = append(uris, BuildServiceUri(s.ServiceUri, s.GroupId))
26 | }
27 | var reg IRegistry
28 | if strings.HasPrefix(registryAddr, SCHEME_ZK) {
29 | reg = NewZkRegistry(strings.TrimPrefix(registryAddr, SCHEME_ZK), uris, true)
30 | } else if strings.HasPrefix(registryAddr, SCHEME_FILE) {
31 | //本地文件配置
32 | reg = NewFileRegistry(strings.TrimPrefix(registryAddr, SCHEME_FILE), uris, true)
33 | }
34 | center := &ConfigCenter{registry: reg, services: services, hostport: hostport}
35 | // zookeeper发布一次吧
36 | center.RegisteAllServices()
37 | return center
38 | }
39 |
40 | func (self *ConfigCenter) RegisteAllServices() {
41 | //注册服务
42 | for _, s := range self.services {
43 | succ := self.RegisteService(s.ServiceUri, self.hostport, PROTOCOL, s.GroupId,
44 | ServiceMeta{
45 | ServiceUri: s.ServiceUri,
46 | GroupId: s.GroupId,
47 | IsPre: s.IsPre,
48 | ProtoVersion: PROTOCOL,
49 | HostPort: self.hostport,
50 | })
51 | if !succ {
52 | panic("ConfigCenter|RegisteAllServices|FAIL|" + s.ServiceUri)
53 | }
54 | }
55 |
56 | }
57 |
58 | func (self *ConfigCenter) RegisteService(serviceUri, hostport, protoType, groupid string, s ServiceMeta) bool {
59 | s.ServiceUri = serviceUri
60 | s.HostPort = hostport
61 | s.ProtoVersion = protoType
62 | s.GroupId = groupid
63 | return self.registry.RegisteService(serviceUri, hostport, protoType, groupid, s)
64 | }
65 |
66 | func (self *ConfigCenter) UnRegisteService(serviceUri, hostport, protoType, groupid string) bool {
67 | return self.registry.UnRegisteService(serviceUri, hostport, protoType, groupid)
68 | }
69 |
70 | func (self *ConfigCenter) GetService(serviceUri, protoType string, groupid string) ([]ServiceMeta, error) {
71 | return self.registry.GetService(serviceUri, protoType, groupid)
72 | }
73 |
74 | func (self *ConfigCenter) Destroy() {
75 | //注册服务
76 | for _, s := range self.services {
77 | succ := self.UnRegisteService(s.ServiceUri, self.hostport, PROTOCOL, s.GroupId)
78 | if succ {
79 | log.Infof("ConfigCenter|Destroy|UnRegisteService|SUCC|%s", s.ServiceUri)
80 | } else {
81 | log.Infof("ConfigCenter|Destroy|UnRegisteService|FAIL|%s", s.ServiceUri)
82 | }
83 | }
84 | self.registry.Destroy()
85 | }
86 |
87 | const (
88 | // /moa/service/v1/service/relation-service#{groupId}/localhost:13000?timeout=1000&protocol=v1
89 | ZK_MOA_ROOT_PATH = "/moa/service"
90 | ZK_ROOT = "/"
91 | ZK_PATH_DELIMITER = "/"
92 |
93 | PROTOCOL = "v1"
94 | REGISTRY_ZOOKEEPER = "zookeeper"
95 | ALL_GROUP = "*"
96 | )
97 |
98 | // 拼接字符串
99 | func concat(args ...string) string {
100 | var buffer bytes.Buffer
101 | for _, arg := range args {
102 | buffer.WriteString(arg)
103 | }
104 | return buffer.String()
105 | }
106 |
107 | func BuildServiceUri(serviceUri, groupId string) string {
108 | if len(groupId) > 0 && "*" != groupId {
109 | return concat(serviceUri, "#", groupId)
110 | } else {
111 | return serviceUri
112 | }
113 | }
114 |
115 | func UnwrapServiceUri(serviceUri string) (string, string) {
116 | if strings.IndexAny(serviceUri, "#") >= 0 {
117 | split := strings.SplitN(serviceUri, "#", 2)
118 | return split[0], split[1]
119 | } else {
120 | return serviceUri, "*"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/registry_file.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "gopkg.in/yaml.v3"
7 | "io/ioutil"
8 | "sort"
9 | "strings"
10 | )
11 |
12 | //
13 | type LocalService struct {
14 | ServiceUri string `yaml:"service_uri"` //serviceUr对应的服务名称
15 | GroupId string `yaml:"gid"` //该服务的分组
16 | ProtoVersion string `yaml:"proto_ver"` //协议版本
17 | IsPre bool `yaml:"isPre"` //是否是预发环境
18 | HostPorts []string `yaml:"hostports"` //节点
19 | }
20 |
21 | type FileRegistry struct {
22 | service []string
23 | uri2Services map[string][]ServiceMeta
24 | serverModel bool
25 | }
26 |
27 | func NewFileRegistry(yamlPath string, service []string, serverModel bool) *FileRegistry {
28 |
29 | uri2Services := make(map[string][]ServiceMeta, 2)
30 |
31 | zoo := &FileRegistry{}
32 | zoo.service = service
33 | zoo.uri2Services = uri2Services
34 | zoo.serverModel = serverModel
35 |
36 | if !serverModel {
37 | // 加载本地的配置
38 | rawYaml, err := ioutil.ReadFile(yamlPath)
39 | if nil != err {
40 | panic(err)
41 | }
42 |
43 | var localServices struct {
44 | Clusters []LocalService `yaml:"clusters"`
45 | }
46 | err = yaml.Unmarshal(rawYaml, &localServices)
47 | if nil != err {
48 | panic(err)
49 | }
50 |
51 | for _, s := range localServices.Clusters {
52 | for _, hp := range s.HostPorts {
53 | uri := BuildServiceUri(s.ServiceUri, s.GroupId)
54 | ss, ok := uri2Services[uri]
55 | if !ok {
56 | ss = []ServiceMeta{}
57 | }
58 |
59 | if len(s.ProtoVersion) <= 0 {
60 | s.ProtoVersion = PROTOCOL
61 | }
62 |
63 | uri2Services[uri] = append(ss, ServiceMeta{
64 | ServiceUri: s.ServiceUri,
65 | GroupId: s.GroupId,
66 | HostPort: hp,
67 | ProtoVersion: s.ProtoVersion,
68 | IsPre: s.IsPre,
69 | })
70 | }
71 | }
72 | } else {
73 | // server
74 |
75 | }
76 |
77 | return zoo
78 | }
79 |
80 | //获取孩子节点的数据
81 | func (self *FileRegistry) PullChildrenData(pathPrefix string, uri string, hosts ...string) ([]ServiceMeta, error) {
82 | sort.Strings(hosts)
83 | services := make([]ServiceMeta, 0, len(hosts))
84 |
85 | ss, ok := self.uri2Services[uri]
86 | if ok {
87 | for _, s := range ss {
88 | for _, host := range hosts {
89 | if strings.HasPrefix(s.HostPort, host) {
90 | services = append(services, s)
91 | }
92 | }
93 | }
94 | }
95 |
96 | return services, nil
97 | }
98 |
99 | func (self *FileRegistry) RegisteService(serviceUri, hostport, protoType, groupId string, s ServiceMeta) bool {
100 | return true
101 | }
102 |
103 | func (self *FileRegistry) UnRegisteService(serviceUri, hostport, protoType, groupId string) bool {
104 | return true
105 | }
106 |
107 | func (self *FileRegistry) GetService(serviceUri, protoType, groupId string) ([]ServiceMeta, error) {
108 |
109 | key := BuildServiceUri(serviceUri, groupId)
110 | hosts, ok := self.uri2Services[key]
111 | if !ok {
112 | if len(hosts) < 1 {
113 | return nil, errors.New(fmt.Sprintf("No Hosts! /moa/service/%s%s", protoType, serviceUri))
114 | }
115 | }
116 | validMetas := make([]ServiceMeta, 0, 2)
117 | for _, h := range hosts {
118 | if h.ProtoVersion == protoType {
119 | validMetas = append(validMetas, h)
120 | }
121 | }
122 | if len(validMetas) < 1 {
123 | return nil, errors.New(fmt.Sprintf("No Hosts! /moa/service/%s%s", protoType, serviceUri))
124 | }
125 |
126 | return validMetas, nil
127 | }
128 |
129 | //会话超时时,需要重新订阅/推送watcher
130 | func (self *FileRegistry) OnSessionExpired() {
131 |
132 | }
133 |
134 | // 用户客户端监听服务节点地址发生变化时触发
135 | func (self *FileRegistry) NodeChange(path string, eventType ZkEvent, addrs []string) {
136 |
137 | }
138 |
139 | func (self *FileRegistry) Destroy() {
140 |
141 | }
142 |
--------------------------------------------------------------------------------
/registry_file_test.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import "testing"
4 |
5 | func TestFileRegistry(t *testing.T) {
6 | registry := NewFileRegistry("./conf/cluster.yaml", []string{"/service/lookup"}, false)
7 | metas, err := registry.GetService("/service/lookup", PROTOCOL, "")
8 | if nil != err {
9 | t.FailNow()
10 | }
11 | t.Logf("/service/lookup =>%v", metas)
12 | if len(metas) < 2 {
13 | t.FailNow()
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/registry_zk.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "encoding/json"
5 | "errors"
6 | "fmt"
7 | "regexp"
8 | "sort"
9 | "sync"
10 |
11 | "github.com/blackbeans/go-zookeeper/zk"
12 | )
13 |
14 | type IRegistry interface {
15 | RegisteService(serviceUri, hostport, protoType, groupId string, s ServiceMeta) bool
16 | UnRegisteService(serviceUri, hostport, protoType, groupId string) bool
17 | GetService(serviceUri, protoType, groupId string) ([]ServiceMeta, error)
18 | Destroy()
19 | }
20 |
21 | type ZkRegistry struct {
22 | service []string
23 | zkManager *ZKManager
24 | uri2Services map[string][]ServiceMeta
25 | lock sync.RWMutex
26 | serverModel bool
27 | }
28 |
29 | func NewZkRegistry(regAddr string, service []string, serverModel bool) *ZkRegistry {
30 |
31 | zkManager := NewZKManager(regAddr)
32 | uri2Services := make(map[string][]ServiceMeta, 2)
33 |
34 | zoo := &ZkRegistry{}
35 | zoo.service = service
36 | zoo.zkManager = zkManager
37 | zoo.uri2Services = uri2Services
38 | zoo.serverModel = serverModel
39 |
40 | if !serverModel {
41 | for _, uri := range service {
42 |
43 | // 初始化,由于客户端订阅延迟,需要主动监听节点事件,然后主动从zk上拉取一次,放入缓存
44 | servicePath := concat(ZK_MOA_ROOT_PATH, ZK_PATH_DELIMITER, PROTOCOL, uri)
45 |
46 | flag := zkManager.RegisteWatcher(servicePath, zoo)
47 |
48 | log.Infof("ZkRegistry|NewZkRegistry|RegisteWather|%v|%s", flag, servicePath)
49 |
50 | hosts, _, _, err := zkManager.session.ChildrenW(servicePath)
51 | if err != nil {
52 | log.Errorf("ZkRegistry|NewZkRegistry|init uri2hosts|FAIL|%s", servicePath)
53 | } else {
54 |
55 | if services, err := zoo.PullChildrenData(servicePath, uri, hosts...); nil == err {
56 | uri2Services[uri] = services
57 | }
58 | }
59 | }
60 | } else {
61 | // server
62 | zkManager.RegisteWatcher(ZK_MOA_ROOT_PATH, zoo)
63 | }
64 |
65 | return zoo
66 | }
67 |
68 | //获取孩子节点的数据
69 | func (self *ZkRegistry) PullChildrenData(pathPrefix string, uri string, hosts ...string) ([]ServiceMeta, error) {
70 | sort.Strings(hosts)
71 | services := make([]ServiceMeta, 0, len(hosts))
72 | for _, host := range hosts {
73 | var meta ServiceMeta
74 | rawNode, _, _, err := self.zkManager.session.GetW(fmt.Sprintf("%s%s%s", pathPrefix, ZK_PATH_DELIMITER, host))
75 | if nil == err && nil != rawNode && len(rawNode) > 0 {
76 | err = json.Unmarshal(rawNode, &meta)
77 | }
78 | //这里只是兼容旧的节点服务节点
79 | if nil != err || nil == rawNode || len(rawNode) <= 0 {
80 | serviceUri, groupid := UnwrapServiceUri(uri)
81 | meta = ServiceMeta{
82 | ServiceUri: serviceUri,
83 | GroupId: groupid,
84 | HostPort: host,
85 | ProtoVersion: PROTOCOL,
86 | IsPre: false,
87 | }
88 | }
89 | services = append(services, meta)
90 | }
91 |
92 | return services, nil
93 | }
94 |
95 | func (self *ZkRegistry) RegisteService(serviceUri, hostport, protoType, groupId string, s ServiceMeta) bool {
96 | // /moa/service/v1/service/relation-service#{groupId}/localhost:13000?timeout=1000&protocol=v1
97 | // hostport = "localhost:13000" //test
98 | servicePath := concat(ZK_MOA_ROOT_PATH, ZK_PATH_DELIMITER, protoType)
99 | //has groupId
100 | servicePath = concat(servicePath, BuildServiceUri(serviceUri, groupId))
101 |
102 | svAddrPath := concat(servicePath, ZK_PATH_DELIMITER, hostport)
103 |
104 | conn := self.zkManager.session
105 |
106 | // 创建持久服务节点 /moa/service/v1/service/relation-service#{groupId}
107 | exist, _, err := conn.Exists(servicePath)
108 | if err != nil {
109 | conn.Close()
110 | panic("无法创建" + servicePath + err.Error())
111 | }
112 | if !exist {
113 | err = self.zkManager.CreateNode(conn, servicePath)
114 | if err != nil {
115 | panic("NewZkRegistry|RegisteService|FAIL|" + servicePath + "|" + err.Error())
116 | }
117 | }
118 |
119 | // 创建临时服务地址节点 /moa/service/v1/service/relation-service#{groupId}/localhost:13000?timeout=1000&protocol=v1
120 | // 先删除,后创建吧。不然zk不通知,就坐等坑爹吧。蛋碎了一地。/(ㄒoㄒ)/~~
121 |
122 | conn.Delete(svAddrPath, 0)
123 | rawService, _ := json.Marshal(s)
124 | _, err = conn.Create(svAddrPath, rawService, zk.CreateEphemeral, zk.WorldACL(zk.PermAll))
125 | if err != nil {
126 | panic("NewZkRegistry|RegisteService|FAIL|" + svAddrPath + "|" + err.Error())
127 | }
128 | log.Infof("ZkRegistry|RegisteService|SUCC|%s|%s|%s|%s", hostport, serviceUri, protoType, groupId)
129 | return true
130 | }
131 |
132 | func (self *ZkRegistry) UnRegisteService(serviceUri, hostport, protoType, groupId string) bool {
133 |
134 | servicePath := concat(ZK_MOA_ROOT_PATH, ZK_PATH_DELIMITER, protoType)
135 | //has groupId
136 | servicePath = concat(servicePath, BuildServiceUri(serviceUri, groupId), ZK_PATH_DELIMITER, hostport)
137 | // fmt.Printf("-------%s\n", servicePath)
138 | conn := self.zkManager.session
139 | if flag, _, err := conn.Exists(servicePath); err != nil {
140 | log.Errorf("ZkRegistry|UnRegisteService|ERROR|%s|%s|%s|%s|%s",
141 | err, serviceUri, hostport, protoType, groupId)
142 | return false
143 | } else {
144 | if flag {
145 | err := conn.Delete(servicePath, 0)
146 | if err != nil {
147 | log.Errorf("ZkRegistry|UnRegisteService|DEL|ERROR|%s|%s", err, servicePath)
148 | return false
149 | }
150 | }
151 | }
152 | log.Infof("ZkRegistry|UnRegisteService|SUCC|%s", servicePath)
153 | return true
154 | }
155 |
156 | func (self *ZkRegistry) GetService(serviceUri, protoType, groupId string) ([]ServiceMeta, error) {
157 | // log.Warnf( "ZkRegistry|GetService|SUCC|%s|%s|%s", serviceUri, protoType, self.addrManager.uri2Services)
158 | self.lock.RLock()
159 | defer self.lock.RUnlock()
160 | key := BuildServiceUri(serviceUri, groupId)
161 | hosts, ok := self.uri2Services[key]
162 | if !ok {
163 | if len(hosts) < 1 {
164 | return nil, errors.New(fmt.Sprintf("No Hosts! /moa/service/%s%s", protoType, serviceUri))
165 | }
166 | }
167 | return hosts, nil
168 | }
169 |
170 | //会话超时时,需要重新订阅/推送watcher
171 | func (self *ZkRegistry) OnSessionExpired() {
172 | if self.serverModel {
173 | // 服务端 需要重新推送
174 | conn := self.zkManager.session
175 | for uri, serviceMeta := range self.uri2Services {
176 | servicePath := concat(ZK_MOA_ROOT_PATH, ZK_PATH_DELIMITER, PROTOCOL, uri)
177 | for _, s := range serviceMeta {
178 | svAddrPath := concat(servicePath, ZK_PATH_DELIMITER, s.HostPort)
179 | conn.Delete(svAddrPath, 0)
180 | _, err := conn.Create(svAddrPath, nil, zk.CreateEphemeral, zk.WorldACL(zk.PermAll))
181 | if err != nil {
182 | panic("ReSubZkServer|FAIL|" + svAddrPath + "|" + err.Error())
183 | }
184 | }
185 | }
186 | log.Infof("ZkRegistry|OnSessionExpired|%v", self.serverModel)
187 | } else {
188 | // 客户端需要重新订阅
189 | conn := self.zkManager.session
190 | for _, uri := range self.service {
191 | servicePath := concat(ZK_MOA_ROOT_PATH, ZK_PATH_DELIMITER, PROTOCOL, uri)
192 | conn.ChildrenW(servicePath)
193 | }
194 | log.Infof("ZkRegistry|OnSessionExpired|%v", self.serverModel)
195 | }
196 | }
197 |
198 | // 用户客户端监听服务节点地址发生变化时触发
199 | func (self *ZkRegistry) NodeChange(path string, eventType ZkEvent, addrs []string) {
200 | reg, _ := regexp.Compile(`/moa/service/v1([^\s]*)`)
201 | uri := reg.FindAllStringSubmatch(path, -1)[0][1]
202 | needChange := true
203 | //对比变化
204 | func() {
205 | self.lock.RLock()
206 | defer self.lock.RUnlock()
207 |
208 | sort.Strings(addrs)
209 | oldAddrs, ok := self.uri2Services[uri]
210 | if ok {
211 | if len(oldAddrs) > 0 &&
212 | len(oldAddrs) == len(addrs) {
213 | for j, v := range addrs {
214 | //对比下是否相同
215 | if oldAddrs[j].HostPort == v && j == len(addrs)-1 {
216 | needChange = false
217 | break
218 | }
219 | }
220 | }
221 | }
222 | }()
223 | //变化则更新
224 | if needChange {
225 | serviceMeta, err := self.PullChildrenData(path, uri, addrs...)
226 | if nil == err {
227 | self.lock.Lock()
228 | self.uri2Services[uri] = serviceMeta
229 | self.lock.Unlock()
230 | }
231 | }
232 | log.Warnf("ZkRegistry|NodeChange|%s|%s", uri, addrs)
233 |
234 | }
235 |
236 | func (self *ZkRegistry) Destroy() {
237 | self.zkManager.Close()
238 | }
239 |
--------------------------------------------------------------------------------
/registry_zk_test.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | //
4 | //import (
5 | // "testing"
6 | // "time"
7 | //)
8 | //
9 | //func TestOldZKRegisteService(t *testing.T) {
10 | //
11 | // // t.Log("test")
12 | // regAddr := "localhost:2181"
13 | // serviceUri := "/service/bibi-profile"
14 | // protocol := "v1"
15 | // hostport := "localhost:18000"
16 | //
17 | // registry := NewZkRegistry(regAddr, []string{serviceUri}, false)
18 | //
19 | // registry.RegisteService(serviceUri, hostport, "v1", "*", ServiceMeta{
20 | // ServiceUri: serviceUri,
21 | // GroupId: "",
22 | // HostPort: hostport,
23 | // ProtoVersion: protocol,
24 | // IsPre: false,
25 | // })
26 | //
27 | // time.Sleep(10 * time.Second)
28 | // data, err := registry.GetService(serviceUri, protocol, "*")
29 | // if err != nil {
30 | // t.Fail()
31 | // t.Logf("GetService FAIL! %s", err.Error())
32 | // } else if len(data) > 0 {
33 | // t.Logf("GetService %d-> %v SUCC", len(data), data)
34 | // } else {
35 | // t.Fail()
36 | // }
37 | //
38 | // flag := registry.UnRegisteService(serviceUri, hostport, protocol, "*")
39 | // if !flag {
40 | // t.Fatalf("UnRegisteService %s Fail", serviceUri)
41 | // }
42 | //
43 | // time.Sleep(5 * time.Second)
44 | // data, err = registry.GetService(serviceUri, protocol, "*")
45 | // if err != nil {
46 | // t.Fail()
47 | // t.Logf("GetService FAIL! %s", err.Error())
48 | // } else if len(data) > 0 {
49 | // t.Fail()
50 | // t.Logf("GetService %d-> %v fail", len(data), data)
51 | // } else {
52 | // t.Logf("GetService %d-> %v SUCC", len(data), data)
53 | // }
54 | //
55 | //}
56 | //
57 | //func TestGroupZKRegisteService(t *testing.T) {
58 | //
59 | // // t.Log("test")
60 | // regAddr := "localhost:2181"
61 | // serviceUri := "/service/bibi-profile"
62 | // protocol := "v1"
63 | // hostport := "localhost:18000"
64 | // groupId := "s-mts-group"
65 | //
66 | // groupUri := BuildServiceUri("/service/bibi-profile", "s-mts-group")
67 | // registry := NewZkRegistry(regAddr, []string{groupUri}, false)
68 | //
69 | // registry.RegisteService(serviceUri, hostport, protocol, groupId, ServiceMeta{
70 | // ServiceUri: serviceUri,
71 | // GroupId: groupId,
72 | // HostPort: hostport,
73 | // ProtoVersion: protocol,
74 | // IsPre: false,
75 | // })
76 | // time.Sleep(10 * time.Second)
77 | // data, err := registry.GetService(serviceUri, protocol, groupId)
78 | // if err != nil || len(data) <= 0 {
79 | // t.Fail()
80 | // t.Logf("GetService FAIL! %s", err)
81 | // } else {
82 | // t.Logf("GetService %d-> %v SUCC", len(data), data)
83 | // }
84 | //
85 | // //different groupId
86 | // data, err = registry.GetService(serviceUri, protocol, "s-mts-group-2")
87 | // if err != nil || len(data) <= 0 {
88 | // t.Logf("No Group GetService [%s] SUCC", "s-mts-group-2")
89 | // } else {
90 | // t.Fail()
91 | // t.Logf("amazing GetService [%s] SUCC~", "s-mts-group-2")
92 | // return
93 | // }
94 | //
95 | // flag := registry.UnRegisteService(serviceUri, hostport, protocol, groupId)
96 | // if !flag {
97 | // t.Fatalf("UnRegisteService %s Fail", serviceUri)
98 | // }
99 | //
100 | // time.Sleep(10 * time.Second)
101 | // data, err = registry.GetService(serviceUri, protocol, groupId)
102 | // if err != nil {
103 | // t.Fail()
104 | // t.Logf("GetService FAIL! %s", err.Error())
105 | // } else if len(data) > 0 {
106 | // t.Fail()
107 | // t.Logf("GetService %d-> %v fail", len(data), data)
108 | // } else {
109 | // t.Logf("GetService %d-> %v SUCC", len(data), data)
110 | // }
111 | //
112 | //}
113 |
--------------------------------------------------------------------------------
/stat.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "fmt"
5 | "github.com/blackbeans/logx"
6 | "github.com/blackbeans/turbo"
7 | "github.com/prometheus/client_golang/prometheus"
8 | "github.com/prometheus/client_golang/prometheus/promauto"
9 | "sync"
10 | "sync/atomic"
11 | "time"
12 |
13 | "runtime"
14 | )
15 |
16 | const (
17 | MAX_ROTATE_SIZE = 10
18 | MOA_STAT_LOG = "moa-stat"
19 | )
20 |
21 | type Method struct {
22 | Name string `json:"name"`
23 | Count int64 `json:"count"`
24 | }
25 |
26 | type InvokePerClient struct {
27 | Client string `json:"client"`
28 | ServiceName string `json:"service_name"`
29 | Methods []Method `json:"methods"`
30 | }
31 |
32 | type MoaInfo struct {
33 | Recv int64 `json:"recv"`
34 | Proc int64 `json:"proc"`
35 | Error int64 `json:"error"`
36 | Timeout int64 `json:"timeout"`
37 | MoaInvokePool int64 `json:"invoke_gos"` //moa的调用Pool
38 | Connections int64 `json:"conns"`
39 | TotalGoroutine int64 `json:"total_gos"`
40 | }
41 |
42 | type MoaStatistic struct {
43 | Recv *turbo.Flow
44 | Proc *turbo.Flow
45 | Error *turbo.Flow
46 | Timeout *turbo.Flow
47 | }
48 |
49 | // prometheus metrics
50 | type MoaMetrics struct {
51 | // rpc请求数量
52 | RpcReceiveTotalCounter prometheus.Counter
53 | RpcProcessTotalCounter prometheus.Counter
54 | RpcErrorTotalCounter prometheus.Counter
55 | RpcTimeoutTotalCounter prometheus.Counter
56 | // rpc请求耗时
57 | RpcInvokeDurationSummary *prometheus.SummaryVec
58 | // rpc gopool用量
59 | InvokePoolMaxGauge prometheus.Gauge
60 | InvokePoolInuseGauge prometheus.Gauge
61 |
62 | cllectors []prometheus.Collector
63 | }
64 |
65 | //
66 | type MoaStat struct {
67 | preMoaInfo MoaInfo
68 | currMoaInfo *MoaStatistic
69 | invokePool *turbo.GPool
70 | RotateSize int32
71 | network func() turbo.NetworkStat
72 | MoaTicker *time.Ticker
73 | lock sync.RWMutex
74 | monitor func(serviceUri, host string, moainfo MoaInfo)
75 | hostname string
76 | serviceUri string
77 | MoaMetrics *MoaMetrics
78 | }
79 |
80 | type MoaLog interface {
81 | StartLog()
82 | Destroy()
83 | }
84 |
85 | func NewMoaStat(hostname, serviceUri string,
86 | invokePool *turbo.GPool,
87 | moniotr func(serviceUri, host string, moainfo MoaInfo), network func() turbo.NetworkStat) *MoaStat {
88 |
89 | // 初始化指标
90 | // rpc请求数量
91 | receiveTotalCounter := promauto.NewCounter(prometheus.CounterOpts{
92 | Name: "moa_server_rpc_receive_total",
93 | Help: "The total number of received rpc call of a service's moa server",
94 | })
95 | processTotalCounter := promauto.NewCounter(prometheus.CounterOpts{
96 | Name: "moa_server_rpc_process_total",
97 | Help: "The total number of processed rpc call of a service's moa server",
98 | })
99 | errorTotalCounter := promauto.NewCounter(prometheus.CounterOpts{
100 | Name: "moa_server_rpc_error_total",
101 | Help: "The total number of error rpc call of a service's moa server",
102 | })
103 | timeoutTotalCounter := promauto.NewCounter(prometheus.CounterOpts{
104 | Name: "moa_server_rpc_timeout_total",
105 | Help: "The total number of timeout rpc call of a service's moa server",
106 | })
107 | // rpc 请求耗时
108 | invokeDurationSummary := promauto.NewSummaryVec(prometheus.SummaryOpts{
109 | Name: "moa_server_rpc_invoke_duration_seconds",
110 | Help: "Duration of rpc invoke cost",
111 | Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
112 | }, []string{"method"})
113 | // rpc gopool 用量
114 | poolMaxGauge := promauto.NewGauge(prometheus.GaugeOpts{
115 | Name: "moa_server_invoke_max_pool",
116 | Help: "The max cap of invoke pool",
117 | })
118 | poolInuseGauge := promauto.NewGauge(prometheus.GaugeOpts{
119 | Name: "moa_server_invoke_inuse_pool",
120 | Help: "The current inuse invoke pool",
121 | })
122 |
123 | moaStat := &MoaStat{
124 | currMoaInfo: &MoaStatistic{
125 | Recv: &turbo.Flow{},
126 | Proc: &turbo.Flow{},
127 | Error: &turbo.Flow{},
128 | Timeout: &turbo.Flow{},
129 | },
130 | MoaMetrics: &MoaMetrics{
131 | RpcReceiveTotalCounter: receiveTotalCounter,
132 | RpcProcessTotalCounter: processTotalCounter,
133 | RpcErrorTotalCounter: errorTotalCounter,
134 | RpcTimeoutTotalCounter: timeoutTotalCounter,
135 | RpcInvokeDurationSummary: invokeDurationSummary,
136 | InvokePoolMaxGauge: poolMaxGauge,
137 | InvokePoolInuseGauge: poolInuseGauge,
138 | cllectors: []prometheus.Collector{
139 | receiveTotalCounter,
140 | processTotalCounter,
141 | errorTotalCounter,
142 | timeoutTotalCounter,
143 | invokeDurationSummary,
144 | poolMaxGauge,
145 | poolInuseGauge,
146 | },
147 | },
148 | invokePool: invokePool,
149 | RotateSize: 0,
150 | network: network,
151 | monitor: moniotr,
152 | hostname: hostname,
153 | serviceUri: serviceUri}
154 | return moaStat
155 | }
156 |
157 | func (self *MoaStat) StartLog() {
158 | ticker := time.NewTicker(time.Second * 1)
159 | self.MoaTicker = ticker
160 | go func() {
161 | defer func() {
162 | if err := recover(); nil != err {
163 | logx.GetLogger(MOA_STAT_LOG).Errorf("time.ticker|Invoke|FAIL|%v", err)
164 | // 销毁定时器
165 | self.Destroy()
166 | }
167 |
168 | }()
169 | logx.GetLogger(MOA_STAT_LOG).Infof("RECV PROC ERROR TIMEOUT Goroutine NetWork")
170 | for {
171 | <-ticker.C
172 | stat := self.network()
173 | size, invokeCap := self.invokePool.Monitor()
174 |
175 | self.MoaMetrics.InvokePoolInuseGauge.Set(float64(size))
176 | self.MoaMetrics.InvokePoolMaxGauge.Set(float64(invokeCap))
177 |
178 | self.preMoaInfo = MoaInfo{
179 | Recv: int64(self.currMoaInfo.Recv.Changes()),
180 | Proc: int64(self.currMoaInfo.Proc.Changes()),
181 | Error: int64(self.currMoaInfo.Error.Changes()),
182 | Timeout: int64(self.currMoaInfo.Timeout.Changes()),
183 | MoaInvokePool: int64(size),
184 | Connections: int64(stat.Connections),
185 | TotalGoroutine: int64(runtime.NumGoroutine()),
186 | }
187 |
188 | network := fmt.Sprintf("R:%dKB/%d W:%dKB/%d Go:%d/%d CONN:%d", stat.ReadBytes/1024,
189 | stat.ReadCount,
190 | stat.WriteBytes/1024, stat.WriteCount, stat.DisPoolSize, stat.DisPoolCap, stat.Connections)
191 |
192 | if self.RotateSize == MAX_ROTATE_SIZE {
193 | logx.GetLogger(MOA_STAT_LOG).Infof("REV PROC ERROR TIMEOUT Goroutine NetWork")
194 |
195 | logx.GetLogger(MOA_STAT_LOG).Infof("%d %d %d %d %d/%d %s",
196 | self.preMoaInfo.Recv,
197 | self.preMoaInfo.Proc,
198 | self.preMoaInfo.Error,
199 | self.preMoaInfo.Timeout,
200 | size, invokeCap, network)
201 | // self.RotateSize = 0
202 | atomic.StoreInt32(&self.RotateSize, 0)
203 | } else {
204 | logx.GetLogger(MOA_STAT_LOG).Infof("%d %d %d %d %d/%d %s",
205 | self.preMoaInfo.Recv,
206 | self.preMoaInfo.Proc,
207 | self.preMoaInfo.Error,
208 | self.preMoaInfo.Timeout,
209 | size, invokeCap, network)
210 | // self.RotateSize++
211 | atomic.AddInt32(&self.RotateSize, 1)
212 | }
213 | self.monitor(self.serviceUri, self.hostname, self.preMoaInfo)
214 | }
215 | }()
216 | }
217 |
218 | func (self *MoaStat) IncrRecv() {
219 | self.currMoaInfo.Recv.Incr(1)
220 | self.MoaMetrics.RpcReceiveTotalCounter.Inc()
221 | }
222 |
223 | func (self *MoaStat) IncrProc() {
224 | self.currMoaInfo.Proc.Incr(1)
225 | self.MoaMetrics.RpcProcessTotalCounter.Inc()
226 | }
227 |
228 | func (self *MoaStat) IncrError() {
229 | self.currMoaInfo.Error.Incr(1)
230 | self.MoaMetrics.RpcErrorTotalCounter.Inc()
231 | }
232 |
233 | func (self *MoaStat) IncrTimeout() {
234 | self.currMoaInfo.Timeout.Incr(1)
235 | self.MoaMetrics.RpcTimeoutTotalCounter.Inc()
236 | }
237 |
238 | func (self *MoaStat) GetMoaInfo() MoaInfo {
239 | return self.preMoaInfo
240 | }
241 |
242 | func (self *MoaStat) Destroy() {
243 | if nil != self.MoaTicker {
244 | self.MoaTicker.Stop()
245 | }
246 |
247 | if nil != self.MoaMetrics {
248 | for _, c := range self.MoaMetrics.cllectors {
249 | prometheus.DefaultRegisterer.Unregister(c)
250 | }
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/zk.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "github.com/blackbeans/go-zookeeper/zk"
5 | _ "net"
6 | "strings"
7 | "time"
8 | )
9 |
10 | type ZKManager struct {
11 | zkhosts string
12 | wathcers map[string]IWatcher //基本的路径--->watcher zk可以复用了
13 | session *zk.Conn
14 | eventChan <-chan zk.Event
15 | isClose bool
16 | }
17 |
18 | type ZkEvent zk.EventType
19 |
20 | const (
21 | Created ZkEvent = 1 // From Exists, Get NodeCreated (1),
22 | Deleted ZkEvent = 2 // From Exists, Get NodeDeleted (2),
23 | Changed ZkEvent = 3 // From Exists, Get NodeDataChanged (3),
24 | Child ZkEvent = 4 // From Children NodeChildrenChanged (4)
25 | )
26 |
27 | //每个watcher
28 | type IWatcher interface {
29 | OnSessionExpired()
30 | // DataChange(path string, binds []*Binding)
31 | NodeChange(path string, eventType ZkEvent, children []string)
32 | }
33 |
34 | func NewZKManager(zkhosts string) *ZKManager {
35 | zkmanager := &ZKManager{zkhosts: zkhosts, wathcers: make(map[string]IWatcher, 10)}
36 | zkmanager.Start()
37 |
38 | return zkmanager
39 | }
40 |
41 | func (self *ZKManager) Start() {
42 | if len(self.zkhosts) <= 0 {
43 | log.Warnf("使用默认zkhosts!|localhost:2181")
44 | self.zkhosts = "localhost:2181"
45 | } else {
46 | log.Infof("使用zkhosts:[%s]", self.zkhosts)
47 | }
48 |
49 | ss, eventChan, err := zk.Connect(strings.Split(self.zkhosts, ","), 5*time.Second)
50 | if nil != err {
51 | panic("连接zk失败..." + err.Error())
52 | return
53 | }
54 | self.CreateNode(ss, ZK_MOA_ROOT_PATH+ZK_PATH_DELIMITER+PROTOCOL)
55 | self.session = ss
56 | self.isClose = false
57 | self.eventChan = eventChan
58 | go self.listenEvent()
59 | }
60 |
61 | func (self *ZKManager) CreateNode(conn *zk.Conn, servicePath string) error {
62 | absolutePath := ZK_ROOT
63 | for _, path := range strings.Split(servicePath, ZK_PATH_DELIMITER) {
64 | if len(path) < 1 || path == ZK_ROOT {
65 | continue
66 | } else {
67 | if !strings.HasSuffix(absolutePath, ZK_PATH_DELIMITER) {
68 | absolutePath = concat(absolutePath, ZK_PATH_DELIMITER)
69 | }
70 | absolutePath = concat(absolutePath, path)
71 | if flag, _, err := conn.Exists(absolutePath); err != nil {
72 | log.Errorf("NewZKManager|CreateNode|FAIL|%s", servicePath)
73 | return err
74 | } else {
75 | if !flag {
76 | resp, err := conn.Create(absolutePath, []byte{}, zk.CreatePersistent, zk.WorldACL(zk.PermAll))
77 | if err != nil {
78 | conn.Close()
79 | panic("NewZKManager|CreateNode|FAIL|" + servicePath)
80 | } else {
81 | log.Infof("NewZKManager|CREATE ROOT PATH|SUCC|%s", resp)
82 | }
83 | }
84 | }
85 | }
86 | }
87 | return nil
88 | }
89 |
90 | //如果返回false则已经存在
91 | func (self *ZKManager) RegisteWatcher(rootpath string, w IWatcher) bool {
92 | _, ok := self.wathcers[rootpath]
93 | if ok {
94 | return false
95 | } else {
96 | self.wathcers[rootpath] = w
97 | return true
98 | }
99 | }
100 |
101 | //监听数据变更
102 | func (self *ZKManager) listenEvent() {
103 | for !self.isClose {
104 |
105 | //根据zk的文档 Watcher机制是无法保证可靠的,其次需要在每次处理完Watcher后要重新注册Watcher
106 | change := <-self.eventChan
107 | path := change.Path
108 | // log.Warnf( "NewZKManager|listenEvent|path|%s|%s|%s", path, change.State, change.Type)
109 | //开始检查符合的watcher
110 | watcher := func() IWatcher {
111 | for k, w := range self.wathcers {
112 | //以给定的
113 | if strings.Index(path, k) >= 0 {
114 | return w
115 | }
116 | }
117 | return nil
118 | }()
119 |
120 | //如果没有wacher那么久忽略
121 | if nil == watcher {
122 | log.Warnf("ZKManager|listenEvent|NO WATCHER|path:%s|event:%v", path, change.State)
123 | continue
124 | }
125 |
126 | switch change.Type {
127 | case zk.EventSession:
128 | if change.State == zk.StateExpired || change.State == zk.StateDisconnected {
129 | log.Warnf("ZKManager|OnSessionExpired!|Reconnect Zk ....")
130 | //session失效必须通知所有的watcher
131 | func() {
132 | for _, w := range self.wathcers {
133 | //zk链接开则需要重新链接重新推送
134 | w.OnSessionExpired()
135 | }
136 | }()
137 |
138 | }
139 | case zk.EventNodeDeleted:
140 | self.session.ExistsW(path)
141 | watcher.NodeChange(path, ZkEvent(change.Type), []string{})
142 | // log.Info("ZKManager|listenEvent|%s|%s\n", path, change)
143 |
144 | case zk.EventNodeCreated, zk.EventNodeChildrenChanged:
145 | childnodes, _, _, err := self.session.ChildrenW(path)
146 | if nil != err {
147 | log.Errorf("ZKManager|listenEvent|CD|%s|%s|%v", err, path, change.Type)
148 | } else {
149 | watcher.NodeChange(path, ZkEvent(change.Type), childnodes)
150 | // log.Info("ZKManager|listenEvent|%s|%s|%s\n", path, change, childnodes)
151 | }
152 |
153 | }
154 | }
155 | }
156 |
157 | func (self *ZKManager) Close() {
158 | self.isClose = true
159 | self.session.Close()
160 | }
161 |
--------------------------------------------------------------------------------