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  }