github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/routing/dht/lookup.go (about) 1 package dht 2 3 import ( 4 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 5 key "github.com/ipfs/go-ipfs/blocks/key" 6 notif "github.com/ipfs/go-ipfs/notifications" 7 peer "github.com/ipfs/go-ipfs/p2p/peer" 8 kb "github.com/ipfs/go-ipfs/routing/kbucket" 9 pset "github.com/ipfs/go-ipfs/util/peerset" 10 ) 11 12 // Required in order for proper JSON marshaling 13 func pointerizePeerInfos(pis []peer.PeerInfo) []*peer.PeerInfo { 14 out := make([]*peer.PeerInfo, len(pis)) 15 for i, p := range pis { 16 np := p 17 out[i] = &np 18 } 19 return out 20 } 21 22 // Kademlia 'node lookup' operation. Returns a channel of the K closest peers 23 // to the given key 24 func (dht *IpfsDHT) GetClosestPeers(ctx context.Context, key key.Key) (<-chan peer.ID, error) { 25 e := log.EventBegin(ctx, "getClosestPeers", &key) 26 tablepeers := dht.routingTable.NearestPeers(kb.ConvertKey(key), AlphaValue) 27 if len(tablepeers) == 0 { 28 return nil, kb.ErrLookupFailure 29 } 30 31 out := make(chan peer.ID, KValue) 32 peerset := pset.NewLimited(KValue) 33 34 for _, p := range tablepeers { 35 select { 36 case out <- p: 37 case <-ctx.Done(): 38 return nil, ctx.Err() 39 } 40 peerset.Add(p) 41 } 42 43 // since the query doesnt actually pass our context down 44 // we have to hack this here. whyrusleeping isnt a huge fan of goprocess 45 parent := ctx 46 query := dht.newQuery(key, func(ctx context.Context, p peer.ID) (*dhtQueryResult, error) { 47 // For DHT query command 48 notif.PublishQueryEvent(parent, ¬if.QueryEvent{ 49 Type: notif.SendingQuery, 50 ID: p, 51 }) 52 53 closer, err := dht.closerPeersSingle(ctx, key, p) 54 if err != nil { 55 log.Debugf("error getting closer peers: %s", err) 56 return nil, err 57 } 58 59 var filtered []peer.PeerInfo 60 for _, clp := range closer { 61 if kb.Closer(clp, dht.self, key) && peerset.TryAdd(clp) { 62 select { 63 case out <- clp: 64 case <-ctx.Done(): 65 return nil, ctx.Err() 66 } 67 filtered = append(filtered, dht.peerstore.PeerInfo(clp)) 68 } 69 } 70 71 // For DHT query command 72 notif.PublishQueryEvent(parent, ¬if.QueryEvent{ 73 Type: notif.PeerResponse, 74 ID: p, 75 Responses: pointerizePeerInfos(filtered), 76 }) 77 78 return &dhtQueryResult{closerPeers: filtered}, nil 79 }) 80 81 go func() { 82 defer close(out) 83 defer e.Done() 84 // run it! 85 _, err := query.Run(ctx, tablepeers) 86 if err != nil { 87 log.Debugf("closestPeers query run error: %s", err) 88 } 89 }() 90 91 return out, nil 92 } 93 94 func (dht *IpfsDHT) closerPeersSingle(ctx context.Context, key key.Key, p peer.ID) ([]peer.ID, error) { 95 pmes, err := dht.findPeerSingle(ctx, p, peer.ID(key)) 96 if err != nil { 97 return nil, err 98 } 99 100 var out []peer.ID 101 for _, pbp := range pmes.GetCloserPeers() { 102 pid := peer.ID(pbp.GetId()) 103 if pid != dht.self { // dont add self 104 dht.peerstore.AddAddrs(pid, pbp.Addresses(), peer.TempAddrTTL) 105 out = append(out, pid) 106 } 107 } 108 return out, nil 109 }