gitee.com/aurawing/surguard-go@v0.3.1-0.20240409071558-96509a61ecf3/device/zookeeper.go (about) 1 package device 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "sort" 7 "strings" 8 "sync" 9 "time" 10 11 "github.com/go-zookeeper/zk" 12 ) 13 14 type ZkDiscovery struct { 15 conn *zk.Conn 16 device *Device 17 children []string 18 childrenData map[string]string 19 root string 20 exitCh chan chan bool 21 sync.RWMutex 22 } 23 24 func (zkCli *ZkDiscovery) GetData(pk NoisePublicKey) (string, error) { 25 path := fmt.Sprintf("%s/%s", zkCli.root, hex.EncodeToString(pk[:])) 26 data, _, err := zkCli.conn.Get(path) 27 if err != nil { 28 zkCli.device.log.Errorf("ZooKeeper: failed to get data of path %s: %s", path, err) 29 return "", err 30 } 31 return string(data), nil 32 } 33 34 func (zkCli *ZkDiscovery) ExistPeer(pk NoisePublicKey) (bool, error) { 35 pathExist, _, err := zkCli.conn.Exists(fmt.Sprintf("%s/%s", zkCli.root, hex.EncodeToString(pk[:]))) 36 if err != nil { 37 return false, err 38 } 39 return pathExist, nil 40 } 41 42 func (zkCli *ZkDiscovery) AddPeer(pk NoisePublicKey, endPoints string) error { 43 var flags int32 = zk.FlagEphemeral 44 // 获取访问控制权限 45 acls := zk.WorldACL(zk.PermAll) 46 path, err := zkCli.conn.Create(fmt.Sprintf("%s/%s", zkCli.root, hex.EncodeToString(pk[:])), []byte(endPoints), flags, acls) 47 if err != nil { 48 zkCli.device.log.Errorf("ZooKeeper: create peer connection failed: %s", err) 49 return err 50 } 51 zkCli.device.log.Verbosef("ZooKeeper: create peer connection with path: %s->%s", path, endPoints) 52 return nil 53 } 54 55 func (zkCli *ZkDiscovery) RemovePeer(pk NoisePublicKey) error { 56 _, sate, _ := zkCli.conn.Get(fmt.Sprintf("%s/%s", zkCli.root, hex.EncodeToString(pk[:]))) 57 err := zkCli.conn.Delete(fmt.Sprintf("%s/%s", zkCli.root, hex.EncodeToString(pk[:])), sate.Version) 58 if err != nil { 59 zkCli.device.log.Errorf("ZooKeeper: remove peer connection failed: %s", err) 60 return err 61 } 62 return nil 63 } 64 65 func CreateZkDiscovery(urls string, device *Device, root string) (*ZkDiscovery, error) { 66 zkServers := strings.Split(urls, ",") 67 zkPath := root // 监控的ZooKeeper路径 68 69 // 连接到ZooKeeper服务器 70 conn, _, err := zk.Connect(zkServers, time.Second*5) 71 if err != nil { 72 return nil, err 73 } 74 zkCli := &ZkDiscovery{conn: conn, device: device, root: zkPath, childrenData: make(map[string]string), exitCh: make(chan chan bool)} 75 76 //创建/surguard路径 77 pathExist, _, err := zkCli.conn.Exists(zkCli.root) 78 if err != nil { 79 zkCli.device.log.Errorf("ZooKeeper: check existence of root path failed: %s", err) 80 return nil, err 81 } 82 if !pathExist { 83 var flags int32 = 0 84 // 获取访问控制权限 85 acls := zk.WorldACL(zk.PermAll) 86 _, err := zkCli.conn.Create(zkCli.root, []byte{}, flags, acls) 87 if err != nil { 88 pathExist, _, err2 := zkCli.conn.Exists(zkCli.root) 89 if err2 != nil { 90 return nil, err2 91 } 92 if !pathExist { 93 return nil, err 94 } 95 } 96 } 97 98 // 创建Watcher 99 paths, _, childCh, err := zkCli.conn.ChildrenW(zkCli.root) 100 if err != nil { 101 zkCli.device.log.Errorf("ZooKeeper: get and check existence of child path failed: %s", err) 102 return nil, err 103 } 104 // for i, _ := range paths { 105 // paths[i] = strings.Split(paths[i], "-")[1] 106 // paths[i] = paths[i][0:66] 107 // } 108 initialMap := make(map[string]string) 109 for _, path := range paths { 110 data, _, err := zkCli.conn.Get(fmt.Sprintf("%s/%s", zkCli.root, path)) 111 if err != nil { 112 zkCli.device.log.Errorf("ZooKeeper: failed to get data of path %s: %s", path, err) 113 continue 114 } 115 pkb, err := hex.DecodeString(path) 116 if err != nil { 117 zkCli.device.log.Errorf("ZooKeeper: failed to decode path %s: %s", path, err) 118 continue 119 } 120 if device.staticIdentity.publicKey.Equals(NoisePublicKey(pkb)) { 121 continue 122 } 123 zkCli.device.AddPeer(NoisePublicKey(pkb), string(data)) 124 zkCli.children = append(zkCli.children, path) 125 zkCli.childrenData[path] = string(data) 126 initialMap[path] = string(data) 127 } 128 129 zkCli.device.zkChangedCallback(initialMap, nil) 130 131 // 启动监控子节点变化的协程 132 go func() { 133 var ch chan bool 134 OUTER: 135 for { 136 select { 137 case ch = <-zkCli.exitCh: 138 break OUTER 139 case event := <-childCh: 140 //zkCli.device.log.Verbosef("Event type: %s", event.Type) 141 if event.Type == zk.EventNodeChildrenChanged { 142 // 获取更新后的子节点列表 143 newChildren, _, newChildCh, err := conn.ChildrenW(zkCli.root) 144 if err != nil { 145 zkCli.device.log.Errorf("ZooKeeper: error when watch children on path %s: %s", zkCli.root, err) 146 } 147 // for i, _ := range newChildren { 148 // newChildren[i] = strings.Split(newChildren[i], "-")[1] 149 // newChildren[i] = newChildren[i][0:66] 150 // } 151 sort.Strings(newChildren) // 按字典顺序排序 152 153 // 查找新增的节点 154 addedNodes := diff(newChildren, zkCli.children) 155 //zkCli.device.log.Verbosef("ZooKeeper: Added nodes: %s", strings.Join(addedNodes, ", ")) 156 157 // 查找删除的节点 158 deletedNodes := diff(zkCli.children, newChildren) 159 //zkCli.device.log.Verbosef("ZooKeeper: Deleted nodes: %s", strings.Join(deletedNodes, ", ")) 160 161 addedMap := make(map[string]string) 162 deletedMap := make(map[string]string) 163 for _, delPath := range deletedNodes { 164 delPK, err := hex.DecodeString(delPath) 165 if err != nil { 166 zkCli.device.log.Errorf("ZooKeeper: decode public key from delete path %s failed: %s", delPath, err) 167 continue 168 } 169 if device.staticIdentity.publicKey.Equals(NoisePublicKey(delPK)) { 170 zkCli.device.log.Errorf("ZooKeeper: delete current node: %s", delPath) 171 continue 172 } 173 zkCli.device.DeletePeer(NoisePublicKey(delPK)) 174 delData := zkCli.childrenData[delPath] 175 deletedMap[delPath] = zkCli.childrenData[delPath] 176 delete(zkCli.childrenData, delPath) 177 zkCli.device.log.Verbosef("ZooKeeper: Deleted node: %s->%s", delPath, delData) 178 } 179 180 for _, addPath := range addedNodes { 181 addPK, err := hex.DecodeString(addPath) 182 if err != nil { 183 zkCli.device.log.Errorf("ZooKeeper: decode public key from added path %s failed: %s", addPath, err) 184 continue 185 } 186 if device.staticIdentity.publicKey.Equals(NoisePublicKey(addPK)) { 187 zkCli.device.log.Errorf("ZooKeeper: add current node: %s", addPath) 188 continue 189 } 190 data, _, err := zkCli.conn.Get(fmt.Sprintf("%s/%s", zkCli.root, addPath)) 191 if err != nil { 192 zkCli.device.log.Errorf("ZooKeeper: failed to get endpoint of add path %s: %s", addPath, err) 193 continue 194 } 195 zkCli.device.AddPeer(NoisePublicKey(addPK), string(data)) 196 zkCli.childrenData[addPath] = string(data) 197 addedMap[addPath] = string(data) 198 zkCli.device.log.Verbosef("ZooKeeper: Added node: %s->%s", addPath, zkCli.childrenData[addPath]) 199 } 200 201 // 更新子节点列表和Watcher 202 zkCli.children = newChildren 203 childCh = newChildCh 204 zkCli.device.zkChangedCallback(addedMap, deletedMap) 205 } 206 } 207 } 208 ch <- true 209 }() 210 return zkCli, nil 211 } 212 213 func (zkCli *ZkDiscovery) Close() { 214 ch := make(chan bool) 215 zkCli.exitCh <- ch 216 <-ch 217 } 218 219 // diff 返回a和b之间的差异元素(即a有但b没有的元素) 220 func diff(a, b []string) []string { 221 var diff []string 222 for _, x := range a { 223 i := sort.SearchStrings(b, x) 224 if i == len(b) || b[i] != x { 225 diff = append(diff, x) 226 } 227 } 228 return diff 229 }