Skip to content

Commit

Permalink
downloader: before/after request hooks (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
mmetc authored Nov 15, 2024
1 parent 0405542 commit 96985e9
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ linters-settings:
# If lower than 0, disable the check.
# Default: 40
# lower this after refactoring
statements: 111
statements: 112

govet:
enable-all: true
Expand Down
52 changes: 43 additions & 9 deletions downloader/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ type Downloader struct {
ifModifiedSince bool
lastModified bool
compareContent bool
beforeRequest func(*http.Request)
afterRequest func(*http.Response)
}

// New creates a new downloader for the given URL.
Expand Down Expand Up @@ -189,6 +191,20 @@ func (d *Downloader) LimitDownloadSize(size int64) *Downloader {
return d
}

// BeforeRequest sets a function to run before making the HTTP request.
// This can be used to add headers, show user feedback, etc.
func (d *Downloader) BeforeRequest(fn func(*http.Request)) *Downloader {
d.beforeRequest = fn
return d
}

// AfterRequest sets a function to run after the HTTP request has been made.
// This can be used to check the response, save cookies, etc.
func (d *Downloader) AfterRequest(fn func(*http.Response)) *Downloader {
d.afterRequest = fn
return d
}

// getDestInfo returns the modification time and file mode of the destination file.
func (d *Downloader) getDestInfo() (time.Time, fs.FileMode) {
dstInfo, err := os.Stat(d.destPath)
Expand Down Expand Up @@ -455,6 +471,22 @@ func compareFiles(file1, file2 string) (bool, error) {
}
}

// getETag returns the ETag to send with If-None-Match, only if the destination file exists.
func (d *Downloader) getETag(destModTime time.Time) (string, error) {
etag := ""
// the destination could have been deleted leaving an .etag
if d.etagFn != nil && (destModTime != time.Time{}) {
var err error

etag, err = (*d.etagFn)(d.destPath)
if err != nil {
return "", err
}
}

return etag, nil
}

// Download downloads the file from the URL to the destination path.
// Returns true if the file was downloaded, false if it was already up to date.
func (d *Downloader) Download(ctx context.Context, url string) (bool, error) {
Expand All @@ -467,15 +499,9 @@ func (d *Downloader) Download(ctx context.Context, url string) (bool, error) {

destModTime, destFileMode := d.getDestInfo()

etag := ""
// only add If-None-Match if destPath exists, it could have been deleted leaving an .etag
if d.etagFn != nil && (destModTime != time.Time{}) {
var err error

etag, err = (*d.etagFn)(d.destPath)
if err != nil {
d.logger.Warnf("Failed to get etag: %s", err)
}
etag, err := d.getETag(destModTime)
if err != nil {
d.logger.Warnf("Failed to get etag: %s", err)
}

uptodate, err := d.isLocalFresh(ctx, url, destModTime, etag)
Expand Down Expand Up @@ -504,11 +530,19 @@ func (d *Downloader) Download(ctx context.Context, url string) (bool, error) {
d.logger.Trace("If-None-Match: ", etag)
}

if d.beforeRequest != nil {
d.beforeRequest(req)
}

resp, err := d.httpClient.Do(req)
if err != nil {
return false, fmt.Errorf("failed http request for %s: %w", url, err)
}

if d.afterRequest != nil {
d.afterRequest(resp)
}

defer resp.Body.Close()

switch resp.StatusCode {
Expand Down

0 comments on commit 96985e9

Please sign in to comment.