github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/vntp2p/dial.go (about) 1 // Copyright 2019 The go-vnt Authors 2 // This file is part of the go-vnt library. 3 // 4 // The go-vnt library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-vnt library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-vnt library. If not, see <http://www.gnu.org/licenses/>. 16 17 package vntp2p 18 19 import ( 20 "context" 21 22 "errors" 23 "time" 24 25 peer "github.com/libp2p/go-libp2p-peer" 26 "github.com/vntchain/go-vnt/log" 27 ) 28 29 var ( 30 errAlreadyDialing = errors.New("already dialing") 31 errAlreadyConnected = errors.New("already connected") 32 errBlackListed = errors.New("pid blacklisted") 33 ) 34 35 type taskstate struct { 36 maxDynDials int 37 table DhtTable 38 bootnodes []peer.ID 39 lookupNode []peer.ID 40 lookupRunning bool 41 static map[peer.ID]*dialTask 42 dialmap map[peer.ID]dialFlag 43 } 44 45 type task interface { 46 Do(ctx context.Context, server *Server) 47 } 48 49 type dialTask struct { 50 flag dialFlag 51 target peer.ID 52 pid string 53 } 54 55 type lookupTask struct { 56 targets []peer.ID 57 } 58 59 type waitExpireTask struct { 60 time.Duration 61 } 62 63 func (s *taskstate) newTasks(peers map[peer.ID]*Peer) []task { 64 var newtasks []task 65 66 addDial := func(flag dialFlag, n peer.ID) bool { 67 if err := s.checkDial(n, peers); err != nil { 68 log.Trace("Skip dial peer", "id", n, "err", err) 69 return false 70 } 71 s.dialmap[n] = flag 72 newtasks = append(newtasks, &dialTask{target: n, pid: PID}) 73 return true 74 } 75 76 needDial := s.maxDynDials 77 // dial 78 79 for _, flag := range s.dialmap { 80 if flag&dynDialedDail != 0 { 81 needDial-- 82 } 83 } 84 85 // newtasks = append(newtasks, &dialTask{}) 86 for id, task := range s.static { 87 log.Trace("Will dial static peer", "pid", id) 88 if err := s.checkDial(id, peers); err == nil { 89 s.dialmap[id] = task.flag 90 newtasks = append(newtasks, task) 91 } 92 } 93 94 for _, bootnode := range s.bootnodes { 95 // fmt.Println("bootnode: ", bootnode) 96 // for k, _ := range s.dialmap { 97 // fms.Println("dialmap: ", k) 98 // } 99 100 // for k, _ := range peers { 101 // fmt.Println("peers: ", k) 102 // } 103 104 if addDial(staticDialedDail, bootnode) { 105 needDial-- 106 } 107 } 108 109 randomDial := needDial / 2 110 111 if randomDial > 0 { 112 randompeerlist := s.table.RandomPeer() 113 for i := 0; i < randomDial && i < len(randompeerlist); i++ { 114 log.Trace("Will dial random peer", "pid", randompeerlist[i]) 115 if addDial(dynDialedDail, randompeerlist[i]) { 116 needDial-- 117 } 118 } 119 } 120 121 // lookup 122 // if still need to dial more peer, create dynamic dials from random 123 // lookup results 124 i := 0 125 for ; i < len(s.lookupNode) && needDial > 0; i++ { 126 log.Trace("Will dial lookup peer", "pid", s.lookupNode[i]) 127 if addDial(dynDialedDail, s.lookupNode[i]) { 128 needDial-- 129 } 130 } 131 132 // update lookupNode, if need more, launch lookup task 133 s.lookupNode = s.lookupNode[i:] 134 if len(s.lookupNode) < needDial && !s.lookupRunning { 135 s.lookupRunning = true 136 newtasks = append(newtasks, &lookupTask{}) 137 } 138 139 // waitExpireTask 140 // newtasks = append(newtasks, &waitExpireTask{}) 141 142 if len(newtasks) == 0 { 143 newtasks = append(newtasks, &waitExpireTask{1 * time.Second}) 144 } 145 // fmt.Println("tasks: ", newtasks) 146 return newtasks 147 } 148 149 func (s *taskstate) checkDial(n peer.ID, peers map[peer.ID]*Peer) error { 150 _, dialing := s.dialmap[n] 151 switch { 152 case blacklist.exists(n): 153 return errBlackListed 154 case dialing: 155 return errAlreadyDialing 156 case peers[n] != nil: 157 return errAlreadyConnected 158 } 159 return nil 160 } 161 162 func (s *taskstate) removeStatic(n *Node) { 163 delete(s.static, n.Id) 164 } 165 166 func (s *taskstate) taskDone(t task) { 167 switch t := t.(type) { 168 case *dialTask: 169 delete(s.dialmap, t.target) 170 case *lookupTask: 171 s.lookupRunning = false 172 s.lookupNode = append(s.lookupNode, t.targets...) 173 } 174 } 175 176 func (s *taskstate) addStatic(n *Node) { 177 s.static[n.Id] = &dialTask{flag: staticDialedDail, target: n.Id, pid: PID} 178 } 179 180 func newTaskState(maxdial int, bootnodes []peer.ID, dht DhtTable) *taskstate { 181 s := &taskstate{ 182 maxDynDials: maxdial, 183 bootnodes: make([]peer.ID, len(bootnodes)), 184 dialmap: make(map[peer.ID]dialFlag), 185 static: make(map[peer.ID]*dialTask), 186 table: dht, 187 } 188 189 copy(s.bootnodes, bootnodes) 190 191 log.Debug("Task state", "bootnodes", s.bootnodes) 192 193 return s 194 } 195 196 func (t *dialTask) Do(ctx context.Context, server *Server) { 197 // 检验目的地有效 198 if !t.checkTarget() { 199 // 如果无效通过lookup获得地址 200 return 201 } 202 203 log.Trace("Dial task", "target", t.target) 204 _ = t.dial(ctx, server, t.target, t.pid) 205 } 206 207 func (t *dialTask) checkTarget() bool { 208 return t.target != "" 209 } 210 211 func (t *dialTask) dial(ctx context.Context, server *Server, target peer.ID, pid string) (err error) { 212 if err = server.SetupStream(ctx, target, pid); err != nil { 213 log.Trace("Dial failed", "error", err) 214 } 215 return 216 } 217 218 func (t *lookupTask) Do(ctx context.Context, server *Server) { 219 target := randomID() 220 peers, err := server.table.GetDhtTable().GetClosestPeers(ctx, string(target)) 221 if err != nil { 222 log.Trace("lookupTask failed", "error", err) 223 } 224 225 for p := range peers { 226 t.targets = append(t.targets, p) 227 } 228 } 229 230 func (t *waitExpireTask) Do(ctx context.Context, server *Server) { 231 time.Sleep(t.Duration) 232 }