github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/simulations/connect.go (about)

     1  //  Copyright 2018 The go-ethereum Authors
     2  //  Copyright 2019 The go-aigar Authors
     3  //  This file is part of the go-aigar library.
     4  //
     5  //  The go-aigar library is free software: you can redistribute it and/or modify
     6  //  it under the terms of the GNU Lesser General Public License as published by
     7  //  the Free Software Foundation, either version 3 of the License, or
     8  //  (at your option) any later version.
     9  //
    10  //  The go-aigar library is distributed in the hope that it will be useful,
    11  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  //  GNU Lesser General Public License for more details.
    14  //
    15  //  You should have received a copy of the GNU Lesser General Public License
    16  //  along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package simulations
    19  
    20  import (
    21  	"errors"
    22  	"strings"
    23  
    24  	"github.com/AigarNetwork/aigar/p2p/enode"
    25  )
    26  
    27  var (
    28  	ErrNodeNotFound = errors.New("node not found")
    29  )
    30  
    31  // ConnectToLastNode connects the node with provided NodeID
    32  // to the last node that is up, and avoiding connection to self.
    33  // It is useful when constructing a chain network topology
    34  // when Network adds and removes nodes dynamically.
    35  func (net *Network) ConnectToLastNode(id enode.ID) (err error) {
    36  	net.lock.Lock()
    37  	defer net.lock.Unlock()
    38  
    39  	ids := net.getUpNodeIDs()
    40  	l := len(ids)
    41  	if l < 2 {
    42  		return nil
    43  	}
    44  	last := ids[l-1]
    45  	if last == id {
    46  		last = ids[l-2]
    47  	}
    48  	return net.connectNotConnected(last, id)
    49  }
    50  
    51  // ConnectToRandomNode connects the node with provided NodeID
    52  // to a random node that is up.
    53  func (net *Network) ConnectToRandomNode(id enode.ID) (err error) {
    54  	net.lock.Lock()
    55  	defer net.lock.Unlock()
    56  
    57  	selected := net.getRandomUpNode(id)
    58  	if selected == nil {
    59  		return ErrNodeNotFound
    60  	}
    61  	return net.connectNotConnected(selected.ID(), id)
    62  }
    63  
    64  // ConnectNodesFull connects all nodes one to another.
    65  // It provides a complete connectivity in the network
    66  // which should be rarely needed.
    67  func (net *Network) ConnectNodesFull(ids []enode.ID) (err error) {
    68  	net.lock.Lock()
    69  	defer net.lock.Unlock()
    70  
    71  	if ids == nil {
    72  		ids = net.getUpNodeIDs()
    73  	}
    74  	for i, lid := range ids {
    75  		for _, rid := range ids[i+1:] {
    76  			if err = net.connectNotConnected(lid, rid); err != nil {
    77  				return err
    78  			}
    79  		}
    80  	}
    81  	return nil
    82  }
    83  
    84  // ConnectNodesChain connects all nodes in a chain topology.
    85  // If ids argument is nil, all nodes that are up will be connected.
    86  func (net *Network) ConnectNodesChain(ids []enode.ID) (err error) {
    87  	net.lock.Lock()
    88  	defer net.lock.Unlock()
    89  
    90  	return net.connectNodesChain(ids)
    91  }
    92  
    93  func (net *Network) connectNodesChain(ids []enode.ID) (err error) {
    94  	if ids == nil {
    95  		ids = net.getUpNodeIDs()
    96  	}
    97  	l := len(ids)
    98  	for i := 0; i < l-1; i++ {
    99  		if err := net.connectNotConnected(ids[i], ids[i+1]); err != nil {
   100  			return err
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  // ConnectNodesRing connects all nodes in a ring topology.
   107  // If ids argument is nil, all nodes that are up will be connected.
   108  func (net *Network) ConnectNodesRing(ids []enode.ID) (err error) {
   109  	net.lock.Lock()
   110  	defer net.lock.Unlock()
   111  
   112  	if ids == nil {
   113  		ids = net.getUpNodeIDs()
   114  	}
   115  	l := len(ids)
   116  	if l < 2 {
   117  		return nil
   118  	}
   119  	if err := net.connectNodesChain(ids); err != nil {
   120  		return err
   121  	}
   122  	return net.connectNotConnected(ids[l-1], ids[0])
   123  }
   124  
   125  // ConnectNodesStar connects all nodes into a star topology
   126  // If ids argument is nil, all nodes that are up will be connected.
   127  func (net *Network) ConnectNodesStar(ids []enode.ID, center enode.ID) (err error) {
   128  	net.lock.Lock()
   129  	defer net.lock.Unlock()
   130  
   131  	if ids == nil {
   132  		ids = net.getUpNodeIDs()
   133  	}
   134  	for _, id := range ids {
   135  		if center == id {
   136  			continue
   137  		}
   138  		if err := net.connectNotConnected(center, id); err != nil {
   139  			return err
   140  		}
   141  	}
   142  	return nil
   143  }
   144  
   145  func (net *Network) connectNotConnected(oneID, otherID enode.ID) error {
   146  	return ignoreAlreadyConnectedErr(net.connect(oneID, otherID))
   147  }
   148  
   149  func ignoreAlreadyConnectedErr(err error) error {
   150  	if err == nil || strings.Contains(err.Error(), "already connected") {
   151  		return nil
   152  	}
   153  	return err
   154  }