dubbo.apache.org/dubbo-go/v3@v3.1.1/registry/etcdv3/listener.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package etcdv3 19 20 import ( 21 "strings" 22 "sync" 23 ) 24 25 import ( 26 gxchan "github.com/dubbogo/gost/container/chan" 27 "github.com/dubbogo/gost/log/logger" 28 29 perrors "github.com/pkg/errors" 30 ) 31 32 import ( 33 "dubbo.apache.org/dubbo-go/v3/common" 34 "dubbo.apache.org/dubbo-go/v3/config_center" 35 "dubbo.apache.org/dubbo-go/v3/registry" 36 "dubbo.apache.org/dubbo-go/v3/remoting" 37 ) 38 39 type dataListener struct { 40 interestedURL []*common.URL 41 listener config_center.ConfigurationListener 42 } 43 44 // NewRegistryDataListener creates a data listener for etcd 45 func NewRegistryDataListener(listener config_center.ConfigurationListener) *dataListener { 46 return &dataListener{listener: listener} 47 } 48 49 // AddInterestedURL adds a registration @url to listen 50 func (l *dataListener) AddInterestedURL(url *common.URL) { 51 l.interestedURL = append(l.interestedURL, url) 52 } 53 54 // DataChange processes the data change event from registry center of etcd 55 func (l *dataListener) DataChange(eventType remoting.Event) bool { 56 index := strings.Index(eventType.Path, "/providers/") 57 if index == -1 { 58 logger.Warnf("Listen with no url, event.path={%v}", eventType.Path) 59 return false 60 } 61 url := eventType.Path[index+len("/providers/"):] 62 serviceURL, err := common.NewURL(url) 63 if err != nil { 64 logger.Warnf("Listen NewURL(r{%s}) = error{%v}", eventType.Path, err) 65 return false 66 } 67 68 for _, v := range l.interestedURL { 69 if serviceURL.URLEqual(v) { 70 l.listener.Process( 71 &config_center.ConfigChangeEvent{ 72 Key: eventType.Path, 73 Value: serviceURL, 74 ConfigType: eventType.Action, 75 }, 76 ) 77 return true 78 } 79 } 80 return false 81 } 82 83 type configurationListener struct { 84 registry *etcdV3Registry 85 events *gxchan.UnboundedChan 86 closeOnce sync.Once 87 } 88 89 // NewConfigurationListener for listening the event of etcdv3. 90 func NewConfigurationListener(reg *etcdV3Registry) *configurationListener { 91 // add a new waiter 92 reg.WaitGroup().Add(1) 93 return &configurationListener{registry: reg, events: gxchan.NewUnboundedChan(32)} 94 } 95 96 // Process data change event from config center of etcd 97 func (l *configurationListener) Process(configType *config_center.ConfigChangeEvent) { 98 l.events.In() <- configType 99 } 100 101 // Next returns next service event once received 102 func (l *configurationListener) Next() (*registry.ServiceEvent, error) { 103 for { 104 select { 105 case <-l.registry.Done(): 106 logger.Warnf("listener's etcd client connection is broken, so etcd event listener exit now.") 107 return nil, perrors.New("listener stopped") 108 109 case val := <-l.events.Out(): 110 e, _ := val.(*config_center.ConfigChangeEvent) 111 logger.Infof("got etcd event %#v", e) 112 if e.ConfigType == remoting.EventTypeDel && l.registry.client.Valid() { 113 select { 114 case <-l.registry.Done(): 115 logger.Warnf("update @result{%s}. But its connection to registry is invalid", e.Value) 116 default: 117 } 118 continue 119 } 120 return ®istry.ServiceEvent{Action: e.ConfigType, Service: e.Value.(*common.URL)}, nil 121 } 122 } 123 } 124 125 // Close etcd registry center 126 func (l *configurationListener) Close() { 127 l.closeOnce.Do(func() { 128 l.registry.WaitGroup().Done() 129 }) 130 }