├── .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 | 416 | {{range .}} 417 | 418 | 419 | 420 | 421 | {{end}} 422 |
moa
{{.Name}}

{{.Desc}}

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 | --------------------------------------------------------------------------------