github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/kad_lookup.go (about)

     1  // Copyright (C) 2013-2018, The MetaCurrency Project (Eric Harris-Braun, Arthur Brock, et. al.)
     2  // Use of this source code is governed by GPLv3 found in the LICENSE file
     3  //
     4  // This code is adapted from the libp2p project, specifically:
     5  // https://github.com/libp2p/go-libp2p-kad-dht/lookup.go
     6  // The ipfs use of kademlia is substantially different than that needed by holochain so we remove
     7  // parts we don't need and add others.
     8  
     9  package holochain
    10  
    11  import (
    12  	"context"
    13  	. "github.com/holochain/holochain-proto/hash"
    14  	peer "github.com/libp2p/go-libp2p-peer"
    15  	pstore "github.com/libp2p/go-libp2p-peerstore"
    16  	//	notif "github.com/libp2p/go-libp2p-routing/notifications"
    17  	"errors"
    18  )
    19  
    20  var ErrEmptyRoutingTable = errors.New("routing table empty")
    21  
    22  func toPeerInfos(ps []peer.ID) []*pstore.PeerInfo {
    23  	out := make([]*pstore.PeerInfo, len(ps))
    24  	for i, p := range ps {
    25  		out[i] = &pstore.PeerInfo{ID: p}
    26  	}
    27  	return out
    28  }
    29  
    30  // Kademlia 'node lookup' operation. Returns a channel of the K closest peers
    31  // to the given key
    32  func (node *Node) GetClosestPeers(ctx context.Context, key Hash) (<-chan peer.ID, error) {
    33  	node.log.Logf("Finding peers close to %v", key)
    34  	tablepeers := node.routingTable.NearestPeers(key, AlphaValue)
    35  	if len(tablepeers) == 0 {
    36  		return nil, ErrEmptyRoutingTable
    37  	}
    38  
    39  	out := make(chan peer.ID, KValue)
    40  
    41  	// since the query doesn't actually pass our context down
    42  	// we have to hack this here. whyrusleeping isnt a huge fan of goprocess
    43  	//parent := ctx
    44  	query := node.newQuery(key, func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) {
    45  		// For DHT query command
    46  		/*notif.PublishQueryEvent(parent, &notif.QueryEvent{
    47  			Type: notif.SendingQuery,
    48  			ID:   p,
    49  		})*/
    50  
    51  		closer, err := node.closerPeersSingle(ctx, key, p)
    52  		if err != nil {
    53  			node.log.Logf("error getting closer peers: %s", err)
    54  			return nil, err
    55  		}
    56  		node.log.Logf("closerPeers: %v\n", closer)
    57  		peerinfos := toPeerInfos(closer)
    58  
    59  		// For DHT query command
    60  		/*notif.PublishQueryEvent(parent, &notif.QueryEvent{
    61  			Type:      notif.PeerResponse,
    62  			ID:        p,
    63  			Responses: peerinfos, // todo: remove need for this pointerize thing
    64  		})*/
    65  
    66  		return &dhtQueryResult{closerPeers: peerinfos}, nil
    67  	})
    68  
    69  	go func() {
    70  		defer close(out)
    71  		// run it!
    72  		res, err := query.Run(ctx, tablepeers)
    73  		if err != nil {
    74  			node.log.Logf("closestPeers query run error: %v", err)
    75  		}
    76  
    77  		if res != nil && res.finalSet != nil {
    78  			node.log.Logf("closestPeers have %d in final set", res.finalSet.Size())
    79  			// include self
    80  			sorted := SortClosestPeers(append(res.finalSet.Peers(), node.HashAddr), key)
    81  			if len(sorted) > KValue {
    82  				sorted = sorted[:KValue]
    83  			}
    84  
    85  			for _, p := range sorted {
    86  				out <- p
    87  			}
    88  		}
    89  	}()
    90  
    91  	return out, nil
    92  }
    93  
    94  func (node *Node) closerPeersSingle(ctx context.Context, key Hash, p peer.ID) ([]peer.ID, error) {
    95  	closerPeers, err := node.findPeerSingle(ctx, p, key)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	var out []peer.ID
   101  	for _, pinfo := range closerPeers {
   102  		if pinfo.ID != node.HashAddr { // dont add self
   103  			// TODO: what about the time to live of this peer???
   104  			node.peerstore.AddAddrs(pinfo.ID, pinfo.Addrs, pstore.TempAddrTTL)
   105  			out = append(out, pinfo.ID)
   106  		}
   107  	}
   108  	return out, nil
   109  }