Skip to content
This repository was archived by the owner on Nov 2, 2018. It is now read-only.

[WIP] Single download by uid endpoint #3163

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions modules/renter.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ type DownloadInfo struct {
StartTime time.Time `json:"starttime"` // The time when the download was started.
StartTimeUnix int64 `json:"starttimeunix"` // The time when the download was started in unix format.
TotalDataTransferred uint64 `json:"totaldatatransferred"` // Total amount of data transferred, including negotiation, etc.
UID string `json:"uid"` // unique identifier that can be used to retrieve a specific download info.
}

// FileUploadParams contains the information used by the Renter to upload a
Expand Down Expand Up @@ -335,6 +336,11 @@ type Renter interface {
// began.
CurrentPeriod() types.BlockHeight

// DownloadByUID retrieves the download with the specified uid. It returns a
// DownloadInfo object and true if the object was found. Otherwise it returns
// false.
DownloadByUID(uid string) (DownloadInfo, bool)

// PeriodSpending returns the amount spent on contracts in the current
// billing period.
PeriodSpending() ContractorSpending
Expand Down
54 changes: 51 additions & 3 deletions modules/renter/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ package renter
// heap.

import (
"encoding/hex"
"fmt"
"os"
"path/filepath"
Expand All @@ -134,6 +135,7 @@ import (
"github.com/NebulousLabs/Sia/modules"
"github.com/NebulousLabs/Sia/persist"
"github.com/NebulousLabs/Sia/types"
"github.com/NebulousLabs/fastrand"

"github.com/NebulousLabs/errors"
)
Expand Down Expand Up @@ -168,6 +170,7 @@ type (
staticPriority uint64 // Downloads with higher priority will complete first.

// Utilities.
uid string
log *persist.Logger // Same log as the renter.
memoryManager *memoryManager // Same memoryManager used across the renter.
mu sync.Mutex // Unique to the download object.
Expand Down Expand Up @@ -374,6 +377,8 @@ func (r *Renter) managedNewDownload(params downloadParams) (*download, error) {

log: r.log,
memoryManager: r.memoryManager,

uid: hex.EncodeToString(fastrand.Bytes(8)),
}

// Determine which chunks to download.
Expand Down Expand Up @@ -476,14 +481,56 @@ func (r *Renter) managedNewDownload(params downloadParams) (*download, error) {
return d, nil
}

// DownloadByUID retrieves the download with the specified uid. It returns a
// DownloadInfo object and true if the object was found. Otherwise it returns
// false.
func (r *Renter) DownloadByUID(uid string) (modules.DownloadInfo, bool) {
r.downloadHistoryMu.Lock()
defer r.downloadHistoryMu.Unlock()

for i := range r.downloadHistory {
if r.downloadHistory[i].uid != uid {
continue
}
// Order from most recent to least recent.
d := r.downloadHistory[i]
d.mu.Lock() // Lock required for d.endTime only.
download := modules.DownloadInfo{
Destination: d.destinationString,
DestinationType: d.staticDestinationType,
Length: d.staticLength,
Offset: d.staticOffset,
SiaPath: d.staticSiaPath,

Completed: d.staticComplete(),
EndTime: d.endTime,
Received: atomic.LoadUint64(&d.atomicDataReceived),
StartTime: d.staticStartTime,
StartTimeUnix: d.staticStartTime.UnixNano(),
TotalDataTransferred: atomic.LoadUint64(&d.atomicTotalDataTransferred),
UID: d.uid,
}
// Release download lock before calling d.Err(), which will acquire the
// lock. The error needs to be checked separately because we need to
// know if it's 'nil' before grabbing the error string.
d.mu.Unlock()
if d.Err() != nil {
download.Error = d.Err().Error()
} else {
download.Error = ""
}
return download, true
}
return modules.DownloadInfo{}, false
}

// DownloadHistory returns the list of downloads that have been performed. Will
// include downloads that have not yet completed. Downloads will be roughly,
// but not precisely, sorted according to start time.
//
// TODO: Currently the DownloadHistory only contains downloads from this
// session, does not contain downloads that were executed for the purposes of
// repairing, and has no way to clear the download history if it gets long or
// unwieldy. It's not entirely certain which of the missing features are
// session and does not contain downloads that were executed for the purposes of
// repairing. It's not entirely certain which of the missing features are
// actually desirable, please consult core team + app dev community before
// deciding what to implement.
func (r *Renter) DownloadHistory() []modules.DownloadInfo {
Expand All @@ -508,6 +555,7 @@ func (r *Renter) DownloadHistory() []modules.DownloadInfo {
StartTime: d.staticStartTime,
StartTimeUnix: d.staticStartTime.UnixNano(),
TotalDataTransferred: atomic.LoadUint64(&d.atomicTotalDataTransferred),
UID: d.uid,
}
// Release download lock before calling d.Err(), which will acquire the
// lock. The error needs to be checked separately because we need to
Expand Down
7 changes: 7 additions & 0 deletions node/api/client/renter.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ func (c *Client) RenterClearDownloadsRangePost(after, before time.Time) (err err
return
}

// RenterDownloadByUID requests the /renter/downloads endpoint to get the
// history of a single download with the specified UID.
func (c *Client) RenterDownloadByUID(uid string) (di api.DownloadInfo, err error) {
err = c.get(fmt.Sprintf("/renter/downloads?uid=%s", uid), &di)
return
}

// RenterDownloadsGet requests the /renter/downloads resource
func (c *Client) RenterDownloadsGet() (rdq api.RenterDownloadQueue, err error) {
err = c.get("/renter/downloads", &rdq)
Expand Down
33 changes: 32 additions & 1 deletion node/api/renter.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ type (
StartTime time.Time `json:"starttime"` // The time when the download was started.
StartTimeUnix int64 `json:"starttimeunix"` // The time when the download was started in unix format.
TotalDataTransferred uint64 `json:"totaldatatransferred"` // The total amount of data transferred, including negotiation, overdrive etc.
UID string `json:"uid"` // unique identifier that can be used to retrieve a specific download info.
}
)

Expand Down Expand Up @@ -439,7 +440,36 @@ func (api *API) renterClearDownloadsHandler(w http.ResponseWriter, req *http.Req
}

// renterDownloadsHandler handles the API call to request the download queue.
func (api *API) renterDownloadsHandler(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
func (api *API) renterDownloadsHandler(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
// If a specific uid was specified we return a single download.
uid := req.FormValue("uid")
if uid != "" {
di, ok := api.renter.DownloadByUID(uid)
if !ok {
WriteError(w, Error{"Couldn't find download for specified UID"}, http.StatusBadRequest)
return
}
WriteJSON(w, DownloadInfo{
Destination: di.Destination,
DestinationType: di.DestinationType,
Filesize: di.Length,
Length: di.Length,
Offset: di.Offset,
SiaPath: di.SiaPath,

Completed: di.Completed,
EndTime: di.EndTime,
Error: di.Error,
Received: di.Received,
StartTime: di.StartTime,
StartTimeUnix: di.StartTimeUnix,
TotalDataTransferred: di.TotalDataTransferred,
UID: di.UID,
})
return
}

// Otherwise we return the whole history.
var downloads []DownloadInfo
for _, di := range api.renter.DownloadHistory() {
downloads = append(downloads, DownloadInfo{
Expand All @@ -457,6 +487,7 @@ func (api *API) renterDownloadsHandler(w http.ResponseWriter, _ *http.Request, _
StartTime: di.StartTime,
StartTimeUnix: di.StartTimeUnix,
TotalDataTransferred: di.TotalDataTransferred,
UID: di.UID,
})
}
WriteJSON(w, RenterDownloadQueue{
Expand Down
11 changes: 11 additions & 0 deletions siatest/renter/renter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,17 @@ func testClearDownloadHistory(t *testing.T, tg *siatest.TestGroup) {
}
numDownloads = len(rdg.Downloads)

// Make sure that we can also individually grab all the downloads.
for _, di := range rdg.Downloads {
d, err := r.RenterDownloadByUID(di.UID)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(d, di) {
t.Fatal("download infos are not equal")
}
}

// Check removing one download from history
// Remove First Download
timestamp := rdg.Downloads[0].StartTime
Expand Down