// GetBlock attempts to retrieve a particular block from peers, within timeout. func (bs *BitSwap) GetBlock(k u.Key, timeout time.Duration) ( *blocks.Block, error) { u.DOut("Bitswap GetBlock: '%s'\n", k.Pretty()) begin := time.Now() tleft := timeout - time.Now().Sub(begin) provs_ch := bs.routing.FindProvidersAsync(k, 20, timeout) valchan := make(chan []byte) after := time.After(tleft) // TODO: when the data is received, shut down this for loop ASAP go func() { for p := range provs_ch { go func(pr *peer.Peer) { blk, err := bs.getBlock(k, pr, tleft) if err != nil { u.PErr("getBlock returned: %v\n", err) return } select { case valchan <- blk: default: } }(p) } }() select { case blkdata := <-valchan: close(valchan) return blocks.NewBlock(blkdata) case <-after: return nil, u.ErrTimeout } }
// GetBlock retrieves a particular block from the service, // Getting it from the datastore using the key (hash). func (s *BlockService) GetBlock(k u.Key) (*blocks.Block, error) { u.DOut("BlockService GetBlock: '%s'\n", k.Pretty()) dsk := ds.NewKey(string(k)) datai, err := s.Datastore.Get(dsk) if err == nil { u.DOut("Blockservice: Got data in datastore.\n") bdata, ok := datai.([]byte) if !ok { return nil, fmt.Errorf("data associated with %s is not a []byte", k) } return &blocks.Block{ Multihash: mh.Multihash(k), Data: bdata, }, nil } else if err == ds.ErrNotFound && s.Remote != nil { u.DOut("Blockservice: Searching bitswap.\n") blk, err := s.Remote.GetBlock(k, time.Second*5) if err != nil { return nil, err } return blk, nil } else { u.DOut("Blockservice GetBlock: Not found.\n") return nil, u.ErrNotFound } }
func (bs *BitSwap) getBlock(k u.Key, p *peer.Peer, timeout time.Duration) ([]byte, error) { u.DOut("[%s] getBlock '%s' from [%s]\n", bs.peer.ID.Pretty(), k.Pretty(), p.ID.Pretty()) message := newMessage() message.AppendWanted(k) after := time.After(timeout) resp := bs.listener.Listen(string(k), 1, timeout) bs.meschan.Outgoing <- message.ToSwarm(p) select { case resp_mes := <-resp: return resp_mes.Data, nil case <-after: u.PErr("getBlock for '%s' timed out.\n", k.Pretty()) return nil, u.ErrTimeout } }