github.com/annwntech/go-micro/v2@v2.9.5/config/source/etcd/etcd.go (about) 1 package etcd 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "time" 8 9 cetcd "github.com/coreos/etcd/clientv3" 10 "github.com/coreos/etcd/mvcc/mvccpb" 11 "github.com/annwntech/go-micro/v2/config/source" 12 ) 13 14 // Currently a single etcd reader 15 type etcd struct { 16 prefix string 17 stripPrefix string 18 opts source.Options 19 client *cetcd.Client 20 cerr error 21 } 22 23 var ( 24 DefaultPrefix = "/micro/config/" 25 ) 26 27 func (c *etcd) Read() (*source.ChangeSet, error) { 28 if c.cerr != nil { 29 return nil, c.cerr 30 } 31 32 rsp, err := c.client.Get(context.Background(), c.prefix, cetcd.WithPrefix()) 33 if err != nil { 34 return nil, err 35 } 36 37 if rsp == nil || len(rsp.Kvs) == 0 { 38 return nil, fmt.Errorf("source not found: %s", c.prefix) 39 } 40 41 kvs := make([]*mvccpb.KeyValue, 0, len(rsp.Kvs)) 42 for _, v := range rsp.Kvs { 43 kvs = append(kvs, (*mvccpb.KeyValue)(v)) 44 } 45 46 data := makeMap(c.opts.Encoder, kvs, c.stripPrefix) 47 48 b, err := c.opts.Encoder.Encode(data) 49 if err != nil { 50 return nil, fmt.Errorf("error reading source: %v", err) 51 } 52 53 cs := &source.ChangeSet{ 54 Timestamp: time.Now(), 55 Source: c.String(), 56 Data: b, 57 Format: c.opts.Encoder.String(), 58 } 59 cs.Checksum = cs.Sum() 60 61 return cs, nil 62 } 63 64 func (c *etcd) String() string { 65 return "etcd" 66 } 67 68 func (c *etcd) Watch() (source.Watcher, error) { 69 if c.cerr != nil { 70 return nil, c.cerr 71 } 72 cs, err := c.Read() 73 if err != nil { 74 return nil, err 75 } 76 return newWatcher(c.prefix, c.stripPrefix, c.client.Watcher, cs, c.opts) 77 } 78 79 func (c *etcd) Write(cs *source.ChangeSet) error { 80 return nil 81 } 82 83 func NewSource(opts ...source.Option) source.Source { 84 options := source.NewOptions(opts...) 85 86 var endpoints []string 87 88 // check if there are any addrs 89 addrs, ok := options.Context.Value(addressKey{}).([]string) 90 if ok { 91 for _, a := range addrs { 92 addr, port, err := net.SplitHostPort(a) 93 if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { 94 port = "2379" 95 addr = a 96 endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port)) 97 } else if err == nil { 98 endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port)) 99 } 100 } 101 } 102 103 if len(endpoints) == 0 { 104 endpoints = []string{"localhost:2379"} 105 } 106 107 // check dial timeout option 108 dialTimeout, ok := options.Context.Value(dialTimeoutKey{}).(time.Duration) 109 if !ok { 110 dialTimeout = 3 * time.Second // default dial timeout 111 } 112 113 config := cetcd.Config{ 114 Endpoints: endpoints, 115 DialTimeout: dialTimeout, 116 } 117 118 u, ok := options.Context.Value(authKey{}).(*authCreds) 119 if ok { 120 config.Username = u.Username 121 config.Password = u.Password 122 } 123 124 // use default config 125 client, err := cetcd.New(config) 126 127 prefix := DefaultPrefix 128 sp := "" 129 f, ok := options.Context.Value(prefixKey{}).(string) 130 if ok { 131 prefix = f 132 } 133 134 if b, ok := options.Context.Value(stripPrefixKey{}).(bool); ok && b { 135 sp = prefix 136 } 137 138 return &etcd{ 139 prefix: prefix, 140 stripPrefix: sp, 141 opts: options, 142 client: client, 143 cerr: err, 144 } 145 }