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 }