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  }