fetcher/fetcher_s3.go
func (s *S3) Fetch() (io.Reader, error) {
	//delay fetches after first
	if s.delay {
		time.Sleep(s.Interval)
	}
	s.delay = true
	//status check using HEAD
	head, err := s.client.HeadObject(&s3.HeadObjectInput{Bucket: &s.Bucket, Key: &s.Key})
	if err != nil {
		return nil, fmt.Errorf("HEAD request failed (%s)", err)
	}
	if s.lastETag == *head.ETag {
		return nil, nil //skip, file match
	}
	s.lastETag = *head.ETag
	//binary fetch using GET
	get, err := s.client.GetObject(&s3.GetObjectInput{Bucket: &s.Bucket, Key: &s.Key})
	if err != nil {
		return nil, fmt.Errorf("GET request failed (%s)", err)
	}
	//extract gz files
	if strings.HasSuffix(s.Key, ".gz") && aws.StringValue(get.ContentEncoding) != "gzip" {
		return gzip.NewReader(get.Body)
	}
	//success!
	return get.Body, nil
}
func (s *S3) Fetch() (io.Reader, error) {
	//delay fetches after first
	if s.delay {
		time.Sleep(s.Interval)
	}
	s.delay = true
	//status check using HEAD
	head, err := s.client.HeadObject(&s3.HeadObjectInput{Bucket: &s.Bucket, Key: &s.Key})
	if err != nil {
		return nil, fmt.Errorf("HEAD request failed (%s)", err)
	}
	if s.lastETag == *head.ETag {
		return nil, nil //skip, file match
	}
	s.lastETag = *head.ETag
	//binary fetch using GET
	get, err := s.client.GetObject(&s3.GetObjectInput{Bucket: &s.Bucket, Key: &s.Key})
	if err != nil {
		return nil, fmt.Errorf("GET request failed (%s)", err)
	}
	//extract gz files
	if strings.HasSuffix(s.Key, ".gz") && aws.StringValue(get.ContentEncoding) != "gzip" {
		return gzip.NewReader(get.Body)
	}
	//success!
	return get.Body, nil
}
// Fetch the binary from S3