func (dht *IpfsDHT) handleFindPeer(p peer.Peer, pmes *pb.Message) (*pb.Message, error) { resp := pb.NewMessage(pmes.GetType(), "", pmes.GetClusterLevel()) var closest []peer.Peer // if looking for self... special case where we send it on CloserPeers. if peer.ID(pmes.GetKey()).Equal(dht.self.ID()) { closest = []peer.Peer{dht.self} } else { closest = dht.betterPeersToQuery(pmes, CloserPeerCount) } if closest == nil { log.Errorf("handleFindPeer: could not find anything.") return resp, nil } var withAddresses []peer.Peer for _, p := range closest { if len(p.Addresses()) > 0 { withAddresses = append(withAddresses, p) } } for _, p := range withAddresses { log.Debugf("handleFindPeer: sending back '%s'", p) } resp.CloserPeers = pb.PeersToPBPeers(withAddresses) return resp, nil }
func (dht *IpfsDHT) handleGetProviders(p peer.Peer, pmes *pb.Message) (*pb.Message, error) { resp := pb.NewMessage(pmes.GetType(), pmes.GetKey(), pmes.GetClusterLevel()) // check if we have this value, to add ourselves as provider. log.Debugf("handling GetProviders: '%s'", u.Key(pmes.GetKey())) dsk := u.Key(pmes.GetKey()).DsKey() has, err := dht.datastore.Has(dsk) if err != nil && err != ds.ErrNotFound { log.Errorf("unexpected datastore error: %v\n", err) has = false } // setup providers providers := dht.providers.GetProviders(u.Key(pmes.GetKey())) if has { providers = append(providers, dht.self) } // if we've got providers, send thos those. if providers != nil && len(providers) > 0 { resp.ProviderPeers = pb.PeersToPBPeers(providers) } // Also send closer peers. closer := dht.betterPeersToQuery(pmes, CloserPeerCount) if closer != nil { resp.CloserPeers = pb.PeersToPBPeers(closer) } return resp, nil }
// Ping a peer, log the time it took func (dht *IpfsDHT) Ping(ctx context.Context, p peer.Peer) error { // Thoughts: maybe this should accept an ID and do a peer lookup? log.Infof("ping %s start", p) pmes := pb.NewMessage(pb.Message_PING, "", 0) _, err := dht.sendRequest(ctx, p, pmes) log.Infof("ping %s end (err = %s)", p, err) return err }
// putValueToNetwork stores the given key/value pair at the peer 'p' func (dht *IpfsDHT) putValueToNetwork(ctx context.Context, p peer.Peer, key string, rec *pb.Record) error { pmes := pb.NewMessage(pb.Message_PUT_VALUE, string(key), 0) pmes.Record = rec rpmes, err := dht.sendRequest(ctx, p, pmes) if err != nil { return err } if !bytes.Equal(rpmes.GetRecord().Value, pmes.GetRecord().Value) { return errors.New("value not put correctly") } return nil }
// putProvider sends a message to peer 'p' saying that the local node // can provide the value of 'key' func (dht *IpfsDHT) putProvider(ctx context.Context, p peer.Peer, key string) error { pmes := pb.NewMessage(pb.Message_ADD_PROVIDER, string(key), 0) // add self as the provider pmes.ProviderPeers = pb.PeersToPBPeers([]peer.Peer{dht.self}) rpmes, err := dht.sendRequest(ctx, p, pmes) if err != nil { return err } log.Debugf("%s putProvider: %s for %s", dht.self, p, u.Key(key)) if rpmes.GetKey() != pmes.GetKey() { return errors.New("provider not added correctly") } return nil }
func (dht *IpfsDHT) handleGetValue(p peer.Peer, pmes *pb.Message) (*pb.Message, error) { log.Debugf("%s handleGetValue for key: %s\n", dht.self, pmes.GetKey()) // setup response resp := pb.NewMessage(pmes.GetType(), pmes.GetKey(), pmes.GetClusterLevel()) // first, is the key even a key? key := pmes.GetKey() if key == "" { return nil, errors.New("handleGetValue but no key was provided") } // let's first check if we have the value locally. log.Debugf("%s handleGetValue looking into ds", dht.self) dskey := u.Key(pmes.GetKey()).DsKey() iVal, err := dht.datastore.Get(dskey) log.Debugf("%s handleGetValue looking into ds GOT %v", dht.self, iVal) // if we got an unexpected error, bail. if err != nil && err != ds.ErrNotFound { return nil, err } // Note: changed the behavior here to return _as much_ info as possible // (potentially all of {value, closer peers, provider}) // if we have the value, send it back if err == nil { log.Debugf("%s handleGetValue success!", dht.self) byts, ok := iVal.([]byte) if !ok { return nil, fmt.Errorf("datastore had non byte-slice value for %v", dskey) } rec := new(pb.Record) err := proto.Unmarshal(byts, rec) if err != nil { log.Error("Failed to unmarshal dht record from datastore") return nil, err } resp.Record = rec } // if we know any providers for the requested value, return those. provs := dht.providers.GetProviders(u.Key(pmes.GetKey())) if len(provs) > 0 { log.Debugf("handleGetValue returning %d provider[s]", len(provs)) resp.ProviderPeers = pb.PeersToPBPeers(provs) } // Find closest peer on given cluster to desired key and reply with that info closer := dht.betterPeersToQuery(pmes, CloserPeerCount) if closer != nil { for _, p := range closer { log.Debugf("handleGetValue returning closer peer: '%s'", p) if len(p.Addresses()) < 1 { log.Critical("no addresses on peer being sent!") } } resp.CloserPeers = pb.PeersToPBPeers(closer) } return resp, nil }
func (dht *IpfsDHT) findProvidersSingle(ctx context.Context, p peer.Peer, key u.Key, level int) (*pb.Message, error) { pmes := pb.NewMessage(pb.Message_GET_PROVIDERS, string(key), level) return dht.sendRequest(ctx, p, pmes) }
// findPeerSingle asks peer 'p' if they know where the peer with id 'id' is func (dht *IpfsDHT) findPeerSingle(ctx context.Context, p peer.Peer, id peer.ID, level int) (*pb.Message, error) { pmes := pb.NewMessage(pb.Message_FIND_NODE, string(id), level) return dht.sendRequest(ctx, p, pmes) }
// getValueSingle simply performs the get value RPC with the given parameters func (dht *IpfsDHT) getValueSingle(ctx context.Context, p peer.Peer, key u.Key, level int) (*pb.Message, error) { pmes := pb.NewMessage(pb.Message_GET_VALUE, string(key), level) return dht.sendRequest(ctx, p, pmes) }