github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/renter/contractor/downloader.go (about) 1 package contractor 2 3 import ( 4 "errors" 5 6 "github.com/NebulousLabs/Sia/crypto" 7 "github.com/NebulousLabs/Sia/modules" 8 "github.com/NebulousLabs/Sia/modules/renter/proto" 9 ) 10 11 // An Downloader retrieves sectors from with a host. It requests one sector at 12 // a time, and revises the file contract to transfer money to the host 13 // proportional to the data retrieved. 14 type Downloader interface { 15 // Sector retrieves the sector with the specified Merkle root, and revises 16 // the underlying contract to pay the host proportionally to the data 17 // retrieve. 18 Sector(root crypto.Hash) ([]byte, error) 19 20 // Close terminates the connection to the host. 21 Close() error 22 } 23 24 // A hostDownloader retrieves sectors by calling the download RPC on a host. 25 // It implements the Downloader interface. hostDownloaders are NOT thread- 26 // safe; calls to Sector must be serialized. 27 type hostDownloader struct { 28 downloader *proto.Downloader 29 contractor *Contractor 30 } 31 32 // Sector retrieves the sector with the specified Merkle root, and revises 33 // the underlying contract to pay the host proportionally to the data 34 // retrieve. 35 func (hd *hostDownloader) Sector(root crypto.Hash) ([]byte, error) { 36 oldSpending := hd.downloader.DownloadSpending 37 contract, sector, err := hd.downloader.Sector(root) 38 if err != nil { 39 return nil, err 40 } 41 delta := hd.downloader.DownloadSpending.Sub(oldSpending) 42 43 hd.contractor.mu.Lock() 44 hd.contractor.downloadSpending = hd.contractor.downloadSpending.Add(delta) 45 hd.contractor.contracts[contract.ID] = contract 46 hd.contractor.saveSync() 47 hd.contractor.mu.Unlock() 48 49 return sector, nil 50 } 51 52 // Close cleanly terminates the download loop with the host and closes the 53 // connection. 54 func (hd *hostDownloader) Close() error { return hd.downloader.Close() } 55 56 // Downloader initiates the download request loop with a host, and returns a 57 // Downloader. 58 func (c *Contractor) Downloader(contract modules.RenterContract) (Downloader, error) { 59 c.mu.RLock() 60 height := c.blockHeight 61 c.mu.RUnlock() 62 if height > contract.FileContract.WindowStart { 63 return nil, errors.New("contract has already ended") 64 } 65 host, ok := c.hdb.Host(contract.NetAddress) 66 if !ok { 67 return nil, errors.New("no record of that host") 68 } 69 if host.DownloadBandwidthPrice.Cmp(maxDownloadPrice) > 0 { 70 return nil, errTooExpensive 71 } 72 73 // create downloader 74 d, err := proto.NewDownloader(host, contract) 75 if err != nil { 76 return nil, err 77 } 78 79 return &hostDownloader{ 80 downloader: d, 81 contractor: c, 82 }, nil 83 }