gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/network/node.go (about) 1 package network 2 3 import ( 4 "container/list" 5 "errors" 6 "sync" 7 "time" 8 9 pb "gitee.com/liuxuezhan/go-micro-v1.18.0/network/proto" 10 ) 11 12 var ( 13 // MaxDepth defines max depth of peer topology 14 MaxDepth uint = 3 15 ) 16 17 var ( 18 // ErrPeerExists is returned when adding a peer which already exists 19 ErrPeerExists = errors.New("peer already exists") 20 // ErrPeerNotFound is returned when a peer could not be found in node topology 21 ErrPeerNotFound = errors.New("peer not found") 22 ) 23 24 // node is network node 25 type node struct { 26 sync.RWMutex 27 // id is node id 28 id string 29 // address is node address 30 address string 31 // peers are nodes with direct link to this node 32 peers map[string]*node 33 // network returns the node network 34 network Network 35 // lastSeen keeps track of node lifetime and updates 36 lastSeen time.Time 37 } 38 39 // Id is node ide 40 func (n *node) Id() string { 41 return n.id 42 } 43 44 // Address returns node address 45 func (n *node) Address() string { 46 return n.address 47 } 48 49 // Network returns node network 50 func (n *node) Network() Network { 51 return n.network 52 } 53 54 // walk walks the node graph until some condition is met 55 func (n *node) walk(until func(peer *node) bool, action func(parent, peer *node)) map[string]*node { 56 // track the visited nodes 57 visited := make(map[string]*node) 58 // queue of the nodes to visit 59 queue := list.New() 60 61 // push node to the back of queue 62 queue.PushBack(n) 63 // mark the node as visited 64 visited[n.id] = n 65 66 // keep iterating over the queue until its empty 67 for queue.Len() > 0 { 68 // pop the node from the front of the queue 69 qnode := queue.Front() 70 if until(qnode.Value.(*node)) { 71 return visited 72 } 73 // iterate through all of the node peers 74 // mark the visited nodes; enqueue the non-visted 75 for id, peer := range qnode.Value.(*node).peers { 76 if _, ok := visited[id]; !ok { 77 visited[id] = peer 78 action(qnode.Value.(*node), peer) 79 queue.PushBack(peer) 80 } 81 } 82 // remove the node from the queue 83 queue.Remove(qnode) 84 } 85 86 return visited 87 } 88 89 // AddPeer adds a new peer to node topology 90 // It returns false if the peer already exists 91 func (n *node) AddPeer(peer *node) error { 92 n.Lock() 93 defer n.Unlock() 94 95 if _, ok := n.peers[peer.id]; !ok { 96 n.peers[peer.id] = peer 97 return nil 98 } 99 100 return ErrPeerExists 101 } 102 103 // DeletePeer deletes a peer from node peers 104 // It returns true if the peer has been deleted 105 func (n *node) DeletePeer(id string) bool { 106 n.Lock() 107 defer n.Unlock() 108 109 delete(n.peers, id) 110 111 return true 112 } 113 114 // UpdatePeer updates a peer if it already exists 115 // It returns error if the peer does not exist 116 func (n *node) UpdatePeer(peer *node) error { 117 n.Lock() 118 defer n.Unlock() 119 120 if _, ok := n.peers[peer.id]; ok { 121 n.peers[peer.id] = peer 122 return nil 123 } 124 125 return ErrPeerNotFound 126 } 127 128 // RefreshPeer updates node timestamp 129 // It returns false if the peer has not been found. 130 func (n *node) RefreshPeer(id string, now time.Time) error { 131 n.Lock() 132 defer n.Unlock() 133 134 peer, ok := n.peers[id] 135 if !ok { 136 return ErrPeerNotFound 137 } 138 139 if peer.lastSeen.Before(now) { 140 peer.lastSeen = now 141 } 142 143 return nil 144 } 145 146 // Nodes returns a slice of all nodes in the whole node topology 147 func (n *node) Nodes() []Node { 148 // we need to freeze the network graph here 149 // otherwise we might get inconsisten results 150 n.RLock() 151 defer n.RUnlock() 152 153 // NOTE: this should never be true 154 untilNoMorePeers := func(node *node) bool { 155 return node == nil 156 } 157 justWalk := func(parent, node *node) {} 158 159 visited := n.walk(untilNoMorePeers, justWalk) 160 161 nodes := make([]Node, 0, len(visited)) 162 // collect all the nodes and return them 163 for _, node := range visited { 164 nodes = append(nodes, node) 165 } 166 167 return nodes 168 } 169 170 // GetPeerNode returns a node from node MaxDepth topology 171 // It returns nil if the peer was not found 172 func (n *node) GetPeerNode(id string) *node { 173 // get node topology up to MaxDepth 174 top := n.Topology(MaxDepth) 175 176 untilFoundPeer := func(n *node) bool { 177 return n.id == id 178 } 179 justWalk := func(paent, node *node) {} 180 181 visited := top.walk(untilFoundPeer, justWalk) 182 183 peerNode, ok := visited[id] 184 if !ok { 185 return nil 186 } 187 188 return peerNode 189 } 190 191 // DeletePeerNode removes peer node from node topology 192 func (n *node) DeletePeerNode(id string) error { 193 n.Lock() 194 defer n.Unlock() 195 196 untilNoMorePeers := func(node *node) bool { 197 return node == nil 198 } 199 200 deleted := make(map[string]*node) 201 deletePeer := func(parent, node *node) { 202 if node.id != n.id && node.id == id { 203 delete(parent.peers, node.id) 204 deleted[node.id] = node 205 } 206 } 207 208 n.walk(untilNoMorePeers, deletePeer) 209 210 if _, ok := deleted[id]; !ok { 211 return ErrPeerNotFound 212 } 213 214 return nil 215 } 216 217 // PruneStalePeerNodes prune the peers that have not been seen for longer than given time 218 // It returns a map of the the nodes that got pruned 219 func (n *node) PruneStalePeers(pruneTime time.Duration) map[string]*node { 220 n.Lock() 221 defer n.Unlock() 222 223 untilNoMorePeers := func(node *node) bool { 224 return node == nil 225 } 226 227 pruned := make(map[string]*node) 228 pruneStalePeer := func(parent, node *node) { 229 if node.id != n.id && time.Since(node.lastSeen) > PruneTime { 230 delete(parent.peers, node.id) 231 pruned[node.id] = node 232 } 233 } 234 235 n.walk(untilNoMorePeers, pruneStalePeer) 236 237 return pruned 238 } 239 240 // getTopology traverses node graph and builds node topology 241 // NOTE: this function is not thread safe 242 func (n *node) getTopology(depth uint) *node { 243 // make a copy of yourself 244 node := &node{ 245 id: n.id, 246 address: n.address, 247 peers: make(map[string]*node), 248 network: n.network, 249 lastSeen: n.lastSeen, 250 } 251 252 // return if we reach requested depth or we have no more peers 253 if depth == 0 || len(n.peers) == 0 { 254 return node 255 } 256 257 // decrement the depth 258 depth-- 259 260 // iterate through our peers and update the node peers 261 for _, peer := range n.peers { 262 nodePeer := peer.getTopology(depth) 263 if _, ok := node.peers[nodePeer.id]; !ok { 264 node.peers[nodePeer.id] = nodePeer 265 } 266 } 267 268 return node 269 } 270 271 // Topology returns a copy of the node topology down to given depth 272 // NOTE: the returned node is a node graph - not a single node 273 func (n *node) Topology(depth uint) *node { 274 n.RLock() 275 defer n.RUnlock() 276 277 return n.getTopology(depth) 278 } 279 280 // Peers returns node peers up to MaxDepth 281 func (n *node) Peers() []Node { 282 n.RLock() 283 defer n.RUnlock() 284 285 peers := make([]Node, 0, len(n.peers)) 286 for _, nodePeer := range n.peers { 287 peer := nodePeer.getTopology(MaxDepth) 288 peers = append(peers, peer) 289 } 290 291 return peers 292 } 293 294 // UnpackPeerTopology unpacks pb.Peer into node topology of given depth 295 func UnpackPeerTopology(pbPeer *pb.Peer, lastSeen time.Time, depth uint) *node { 296 peerNode := &node{ 297 id: pbPeer.Node.Id, 298 address: pbPeer.Node.Address, 299 peers: make(map[string]*node), 300 lastSeen: lastSeen, 301 } 302 303 // return if have either reached the depth or have no more peers 304 if depth == 0 || len(pbPeer.Peers) == 0 { 305 return peerNode 306 } 307 308 // decrement the depth 309 depth-- 310 311 peers := make(map[string]*node) 312 for _, pbPeer := range pbPeer.Peers { 313 peer := UnpackPeerTopology(pbPeer, lastSeen, depth) 314 peers[pbPeer.Node.Id] = peer 315 } 316 317 peerNode.peers = peers 318 319 return peerNode 320 } 321 322 func peerProtoTopology(peer Node, depth uint) *pb.Peer { 323 node := &pb.Node{ 324 Id: peer.Id(), 325 Address: peer.Address(), 326 } 327 328 // set the network name if network is not nil 329 if peer.Network() != nil { 330 node.Network = peer.Network().Name() 331 } 332 333 pbPeers := &pb.Peer{ 334 Node: node, 335 Peers: make([]*pb.Peer, 0), 336 } 337 338 // return if we reached the end of topology or depth 339 if depth == 0 || len(peer.Peers()) == 0 { 340 return pbPeers 341 } 342 343 // decrement the depth 344 depth-- 345 346 // iterate through peers of peers aka pops 347 for _, pop := range peer.Peers() { 348 peer := peerProtoTopology(pop, depth) 349 pbPeers.Peers = append(pbPeers.Peers, peer) 350 } 351 352 return pbPeers 353 } 354 355 // PeersToProto returns node peers graph encoded into protobuf 356 func PeersToProto(node Node, depth uint) *pb.Peer { 357 // network node aka root node 358 pbNode := &pb.Node{ 359 Id: node.Id(), 360 Address: node.Address(), 361 } 362 363 // set the network name if network is not nil 364 if node.Network() != nil { 365 pbNode.Network = node.Network().Name() 366 } 367 368 // we will build proto topology into this 369 pbPeers := &pb.Peer{ 370 Node: pbNode, 371 Peers: make([]*pb.Peer, 0), 372 } 373 374 for _, peer := range node.Peers() { 375 pbPeer := peerProtoTopology(peer, depth) 376 pbPeers.Peers = append(pbPeers.Peers, pbPeer) 377 } 378 379 return pbPeers 380 }