github.com/annwntech/go-micro/v2@v2.9.5/network/node.go (about) 1 package network 2 3 import ( 4 "container/list" 5 "errors" 6 "sync" 7 "time" 8 9 pb "github.com/annwntech/go-micro/v2/network/service/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 // nodeError tracks node errors 25 type nodeError struct { 26 sync.RWMutex 27 count int 28 msg error 29 } 30 31 // Increment increments node error count 32 func (e *nodeError) Update(err error) { 33 e.Lock() 34 defer e.Unlock() 35 36 e.count++ 37 e.msg = err 38 } 39 40 // Count returns node error count 41 func (e *nodeError) Count() int { 42 e.RLock() 43 defer e.RUnlock() 44 45 return e.count 46 } 47 48 func (e *nodeError) Msg() string { 49 e.RLock() 50 defer e.RUnlock() 51 52 if e.msg != nil { 53 return e.msg.Error() 54 } 55 56 return "" 57 } 58 59 // status returns node status 60 type status struct { 61 sync.RWMutex 62 err *nodeError 63 } 64 65 // newStatus creates 66 func newStatus() *status { 67 return &status{ 68 err: new(nodeError), 69 } 70 } 71 72 func newPeerStatus(peer *pb.Peer) *status { 73 status := &status{ 74 err: new(nodeError), 75 } 76 77 // if Node.Status is nil, return empty status 78 if peer.Node.Status == nil { 79 return status 80 } 81 82 // if peer.Node.Status.Error is NOT nil, update status fields 83 if err := peer.Node.Status.GetError(); err != nil { 84 status.err.count = int(peer.Node.Status.Error.Count) 85 status.err.msg = errors.New(peer.Node.Status.Error.Msg) 86 } 87 88 return status 89 } 90 91 func (s *status) Error() Error { 92 s.RLock() 93 defer s.RUnlock() 94 95 return &nodeError{ 96 count: s.err.count, 97 msg: s.err.msg, 98 } 99 } 100 101 // node is network node 102 type node struct { 103 sync.RWMutex 104 // id is node id 105 id string 106 // address is node address 107 address string 108 // link on which we communicate with the peer 109 link string 110 // peers are nodes with direct link to this node 111 peers map[string]*node 112 // network returns the node network 113 network Network 114 // lastSeen keeps track of node lifetime and updates 115 lastSeen time.Time 116 // lastSync keeps track of node last sync request 117 lastSync time.Time 118 // err tracks node status 119 status *status 120 } 121 122 // Id is node ide 123 func (n *node) Id() string { 124 return n.id 125 } 126 127 // Address returns node address 128 func (n *node) Address() string { 129 return n.address 130 } 131 132 // Network returns node network 133 func (n *node) Network() Network { 134 return n.network 135 } 136 137 // Status returns node status 138 func (n *node) Status() Status { 139 n.RLock() 140 defer n.RUnlock() 141 142 return &status{ 143 err: &nodeError{ 144 count: n.status.err.count, 145 msg: n.status.err.msg, 146 }, 147 } 148 } 149 150 // walk walks the node graph until some condition is met 151 func (n *node) walk(until func(peer *node) bool, action func(parent, peer *node)) map[string]*node { 152 // track the visited nodes 153 visited := make(map[string]*node) 154 // queue of the nodes to visit 155 queue := list.New() 156 157 // push node to the back of queue 158 queue.PushBack(n) 159 // mark the node as visited 160 visited[n.id] = n 161 162 // keep iterating over the queue until its empty 163 for queue.Len() > 0 { 164 // pop the node from the front of the queue 165 qnode := queue.Front() 166 if until(qnode.Value.(*node)) { 167 return visited 168 } 169 // iterate through all of the node peers 170 // mark the visited nodes; enqueue the non-visted 171 for id, peer := range qnode.Value.(*node).peers { 172 action(qnode.Value.(*node), peer) 173 if _, ok := visited[id]; !ok { 174 visited[id] = peer 175 queue.PushBack(peer) 176 } 177 } 178 // remove the node from the queue 179 queue.Remove(qnode) 180 } 181 182 return visited 183 } 184 185 // AddPeer adds a new peer to node topology 186 // It returns false if the peer already exists 187 func (n *node) AddPeer(peer *node) error { 188 n.Lock() 189 defer n.Unlock() 190 191 // get node topology: we need to check if the peer 192 // we are trying to add is already in our graph 193 top := n.getTopology(MaxDepth) 194 195 untilFoundPeer := func(n *node) bool { 196 return n.id == peer.id 197 } 198 199 justWalk := func(paent, node *node) {} 200 201 visited := top.walk(untilFoundPeer, justWalk) 202 203 peerNode, inTop := visited[peer.id] 204 205 if _, ok := n.peers[peer.id]; !ok { 206 if inTop { 207 // just create a new edge to the existing peer 208 // but make sure you update the peer link 209 peerNode.link = peer.link 210 n.peers[peer.id] = peerNode 211 return nil 212 } 213 n.peers[peer.id] = peer 214 return nil 215 } 216 217 return ErrPeerExists 218 } 219 220 // DeletePeer deletes a peer from node peers 221 // It returns true if the peer has been deleted 222 func (n *node) DeletePeer(id string) bool { 223 n.Lock() 224 defer n.Unlock() 225 226 delete(n.peers, id) 227 228 return true 229 } 230 231 // UpdatePeer updates a peer if it already exists 232 // It returns error if the peer does not exist 233 func (n *node) UpdatePeer(peer *node) error { 234 n.Lock() 235 defer n.Unlock() 236 237 if _, ok := n.peers[peer.id]; ok { 238 n.peers[peer.id] = peer 239 return nil 240 } 241 242 return ErrPeerNotFound 243 } 244 245 // RefreshPeer updates node last seen timestamp 246 // It returns false if the peer has not been found. 247 func (n *node) RefreshPeer(id, link string, now time.Time) error { 248 n.Lock() 249 defer n.Unlock() 250 251 peer, ok := n.peers[id] 252 if !ok { 253 return ErrPeerNotFound 254 } 255 256 // set peer link 257 peer.link = link 258 // set last seen 259 peer.lastSeen = now 260 261 return nil 262 } 263 264 // RefreshSync refreshes nodes sync time 265 func (n *node) RefreshSync(now time.Time) error { 266 n.Lock() 267 defer n.Unlock() 268 269 n.lastSync = now 270 271 return nil 272 } 273 274 // Nodes returns a slice of all nodes in the whole node topology 275 func (n *node) Nodes() []Node { 276 // we need to freeze the network graph here 277 // otherwise we might get inconsisten results 278 n.RLock() 279 defer n.RUnlock() 280 281 // NOTE: this should never be true 282 untilNoMorePeers := func(node *node) bool { 283 return node == nil 284 } 285 justWalk := func(parent, node *node) {} 286 287 visited := n.walk(untilNoMorePeers, justWalk) 288 289 nodes := make([]Node, 0, len(visited)) 290 // collect all the nodes and return them 291 for _, node := range visited { 292 nodes = append(nodes, node) 293 } 294 295 return nodes 296 } 297 298 // GetPeerNode returns a node from node MaxDepth topology 299 // It returns nil if the peer was not found 300 func (n *node) GetPeerNode(id string) *node { 301 // get node topology up to MaxDepth 302 top := n.Topology(MaxDepth) 303 304 untilFoundPeer := func(n *node) bool { 305 return n.id == id 306 } 307 justWalk := func(paent, node *node) {} 308 309 visited := top.walk(untilFoundPeer, justWalk) 310 311 peerNode, ok := visited[id] 312 if !ok { 313 return nil 314 } 315 316 return peerNode 317 } 318 319 // DeletePeerNode removes peer node from node topology 320 func (n *node) DeletePeerNode(id string) error { 321 n.Lock() 322 defer n.Unlock() 323 324 untilNoMorePeers := func(node *node) bool { 325 return node == nil 326 } 327 328 deleted := make(map[string]*node) 329 deletePeer := func(parent, node *node) { 330 if node.id != n.id && node.id == id { 331 delete(parent.peers, node.id) 332 deleted[node.id] = node 333 } 334 } 335 336 n.walk(untilNoMorePeers, deletePeer) 337 338 if _, ok := deleted[id]; !ok { 339 return ErrPeerNotFound 340 } 341 342 return nil 343 } 344 345 // PrunePeer prunes the peers with the given id 346 func (n *node) PrunePeer(id string) { 347 n.Lock() 348 defer n.Unlock() 349 350 untilNoMorePeers := func(node *node) bool { 351 return node == nil 352 } 353 354 prunePeer := func(parent, node *node) { 355 if node.id != n.id && node.id == id { 356 delete(parent.peers, node.id) 357 } 358 } 359 360 n.walk(untilNoMorePeers, prunePeer) 361 } 362 363 // PruneStalePeerNodes prunes the peers that have not been seen for longer than pruneTime 364 // It returns a map of the the nodes that got pruned 365 func (n *node) PruneStalePeers(pruneTime time.Duration) map[string]*node { 366 n.Lock() 367 defer n.Unlock() 368 369 untilNoMorePeers := func(node *node) bool { 370 return node == nil 371 } 372 373 pruned := make(map[string]*node) 374 pruneStalePeer := func(parent, node *node) { 375 if node.id != n.id && time.Since(node.lastSeen) > PruneTime { 376 delete(parent.peers, node.id) 377 pruned[node.id] = node 378 } 379 } 380 381 n.walk(untilNoMorePeers, pruneStalePeer) 382 383 return pruned 384 } 385 386 // getTopology traverses node graph and builds node topology 387 // NOTE: this function is not thread safe 388 func (n *node) getTopology(depth uint) *node { 389 // make a copy of yourself 390 node := &node{ 391 id: n.id, 392 address: n.address, 393 peers: make(map[string]*node), 394 network: n.network, 395 status: n.status, 396 lastSeen: n.lastSeen, 397 } 398 399 // return if we reach requested depth or we have no more peers 400 if depth == 0 || len(n.peers) == 0 { 401 return node 402 } 403 404 // decrement the depth 405 depth-- 406 407 // iterate through our peers and update the node peers 408 for _, peer := range n.peers { 409 nodePeer := peer.getTopology(depth) 410 if _, ok := node.peers[nodePeer.id]; !ok { 411 node.peers[nodePeer.id] = nodePeer 412 } 413 } 414 415 return node 416 } 417 418 // Topology returns a copy of the node topology down to given depth 419 // NOTE: the returned node is a node graph - not a single node 420 func (n *node) Topology(depth uint) *node { 421 n.RLock() 422 defer n.RUnlock() 423 424 return n.getTopology(depth) 425 } 426 427 // Peers returns node peers up to MaxDepth 428 func (n *node) Peers() []Node { 429 n.RLock() 430 defer n.RUnlock() 431 432 peers := make([]Node, 0, len(n.peers)) 433 for _, nodePeer := range n.peers { 434 peer := nodePeer.getTopology(MaxDepth) 435 peers = append(peers, peer) 436 } 437 438 return peers 439 } 440 441 // UnpackPeerTopology unpacks pb.Peer into node topology of given depth 442 func UnpackPeerTopology(pbPeer *pb.Peer, lastSeen time.Time, depth uint) *node { 443 peerNode := &node{ 444 id: pbPeer.Node.Id, 445 address: pbPeer.Node.Address, 446 peers: make(map[string]*node), 447 status: newPeerStatus(pbPeer), 448 lastSeen: lastSeen, 449 } 450 451 // return if have either reached the depth or have no more peers 452 if depth == 0 || len(pbPeer.Peers) == 0 { 453 return peerNode 454 } 455 456 // decrement the depth 457 depth-- 458 459 peers := make(map[string]*node) 460 for _, pbPeer := range pbPeer.Peers { 461 peer := UnpackPeerTopology(pbPeer, lastSeen, depth) 462 peers[pbPeer.Node.Id] = peer 463 } 464 465 peerNode.peers = peers 466 467 return peerNode 468 } 469 470 func peerProtoTopology(peer Node, depth uint) *pb.Peer { 471 node := &pb.Node{ 472 Id: peer.Id(), 473 Address: peer.Address(), 474 Status: &pb.Status{ 475 Error: &pb.Error{ 476 Count: uint32(peer.Status().Error().Count()), 477 Msg: peer.Status().Error().Msg(), 478 }, 479 }, 480 } 481 482 // set the network name if network is not nil 483 if peer.Network() != nil { 484 node.Network = peer.Network().Name() 485 } 486 487 pbPeers := &pb.Peer{ 488 Node: node, 489 Peers: make([]*pb.Peer, 0), 490 } 491 492 // return if we reached the end of topology or depth 493 if depth == 0 || len(peer.Peers()) == 0 { 494 return pbPeers 495 } 496 497 // decrement the depth 498 depth-- 499 500 // iterate through peers of peers aka pops 501 for _, pop := range peer.Peers() { 502 peer := peerProtoTopology(pop, depth) 503 pbPeers.Peers = append(pbPeers.Peers, peer) 504 } 505 506 return pbPeers 507 } 508 509 // PeersToProto returns node peers graph encoded into protobuf 510 func PeersToProto(node Node, depth uint) *pb.Peer { 511 // network node aka root node 512 pbNode := &pb.Node{ 513 Id: node.Id(), 514 Address: node.Address(), 515 Status: &pb.Status{ 516 Error: &pb.Error{ 517 Count: uint32(node.Status().Error().Count()), 518 Msg: node.Status().Error().Msg(), 519 }, 520 }, 521 } 522 523 // set the network name if network is not nil 524 if node.Network() != nil { 525 pbNode.Network = node.Network().Name() 526 } 527 528 // we will build proto topology into this 529 pbPeers := &pb.Peer{ 530 Node: pbNode, 531 Peers: make([]*pb.Peer, 0), 532 } 533 534 for _, peer := range node.Peers() { 535 pbPeer := peerProtoTopology(peer, depth) 536 pbPeers.Peers = append(pbPeers.Peers, pbPeer) 537 } 538 539 return pbPeers 540 }