gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/sync/leader/etcd/etcd.go (about) 1 package etcd 2 3 import ( 4 "context" 5 "log" 6 "path" 7 "strings" 8 9 client "github.com/coreos/etcd/clientv3" 10 cc "github.com/coreos/etcd/clientv3/concurrency" 11 "gitee.com/liuxuezhan/go-micro-v1.18.0/sync/leader" 12 ) 13 14 type etcdLeader struct { 15 opts leader.Options 16 path string 17 client *client.Client 18 } 19 20 type etcdElected struct { 21 s *cc.Session 22 e *cc.Election 23 id string 24 } 25 26 func (e *etcdLeader) Elect(id string, opts ...leader.ElectOption) (leader.Elected, error) { 27 var options leader.ElectOptions 28 for _, o := range opts { 29 o(&options) 30 } 31 32 // make path 33 path := path.Join(e.path, strings.Replace(id, "/", "-", -1)) 34 35 s, err := cc.NewSession(e.client) 36 if err != nil { 37 return nil, err 38 } 39 40 l := cc.NewElection(s, path) 41 42 if err := l.Campaign(context.TODO(), id); err != nil { 43 return nil, err 44 } 45 46 return &etcdElected{ 47 e: l, 48 id: id, 49 }, nil 50 } 51 52 func (e *etcdLeader) Follow() chan string { 53 ch := make(chan string) 54 55 s, err := cc.NewSession(e.client) 56 if err != nil { 57 return ch 58 } 59 60 l := cc.NewElection(s, e.path) 61 ech := l.Observe(context.Background()) 62 63 go func() { 64 for r := range ech { 65 ch <- string(r.Kvs[0].Value) 66 } 67 }() 68 69 return ch 70 } 71 72 func (e *etcdLeader) String() string { 73 return "etcd" 74 } 75 76 func (e *etcdElected) Reelect() error { 77 return e.e.Campaign(context.TODO(), e.id) 78 } 79 80 func (e *etcdElected) Revoked() chan bool { 81 ch := make(chan bool, 1) 82 ech := e.e.Observe(context.Background()) 83 84 go func() { 85 for r := range ech { 86 if string(r.Kvs[0].Value) != e.id { 87 ch <- true 88 close(ch) 89 return 90 } 91 } 92 }() 93 94 return ch 95 } 96 97 func (e *etcdElected) Resign() error { 98 return e.e.Resign(context.Background()) 99 } 100 101 func (e *etcdElected) Id() string { 102 return e.id 103 } 104 105 func NewLeader(opts ...leader.Option) leader.Leader { 106 var options leader.Options 107 for _, o := range opts { 108 o(&options) 109 } 110 111 var endpoints []string 112 113 for _, addr := range options.Nodes { 114 if len(addr) > 0 { 115 endpoints = append(endpoints, addr) 116 } 117 } 118 119 if len(endpoints) == 0 { 120 endpoints = []string{"http://127.0.0.1:2379"} 121 } 122 123 // TODO: parse addresses 124 c, err := client.New(client.Config{ 125 Endpoints: endpoints, 126 }) 127 if err != nil { 128 log.Fatal(err) 129 } 130 131 return &etcdLeader{ 132 path: "/micro/leader", 133 client: c, 134 opts: options, 135 } 136 }