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