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  }