gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/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 "gitee.com/liuxuezhan/go-micro-v1.18.0/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 NewSource(opts ...source.Option) source.Source { 80 options := source.NewOptions(opts...) 81 82 var endpoints []string 83 84 // check if there are any addrs 85 addrs, ok := options.Context.Value(addressKey{}).([]string) 86 if ok { 87 for _, a := range addrs { 88 addr, port, err := net.SplitHostPort(a) 89 if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" { 90 port = "2379" 91 addr = a 92 endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port)) 93 } else if err == nil { 94 endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port)) 95 } 96 } 97 } 98 99 if len(endpoints) == 0 { 100 endpoints = []string{"localhost:2379"} 101 } 102 103 // check dial timeout option 104 dialTimeout, ok := options.Context.Value(dialTimeoutKey{}).(time.Duration) 105 if !ok { 106 dialTimeout = 3 * time.Second // default dial timeout 107 } 108 109 config := cetcd.Config{ 110 Endpoints: endpoints, 111 DialTimeout: dialTimeout, 112 } 113 114 u, ok := options.Context.Value(authKey{}).(*authCreds) 115 if ok { 116 config.Username = u.Username 117 config.Password = u.Password 118 } 119 120 // use default config 121 client, err := cetcd.New(config) 122 123 prefix := DefaultPrefix 124 sp := "" 125 f, ok := options.Context.Value(prefixKey{}).(string) 126 if ok { 127 prefix = f 128 } 129 130 if b, ok := options.Context.Value(stripPrefixKey{}).(bool); ok && b { 131 sp = prefix 132 } 133 134 return &etcd{ 135 prefix: prefix, 136 stripPrefix: sp, 137 opts: options, 138 client: client, 139 cerr: err, 140 } 141 }