🧱 Chunk is a download manager for slow and unstable servers
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Moves progress files to `~/.chunk`

authored by

Eduardo Cuducos and committed by
GitHub
02999cdd d4114619

+37 -13
+37 -13
progress.go
··· 1 1 package chunk 2 2 3 3 import ( 4 + "crypto/md5" 4 5 "encoding/gob" 5 6 "fmt" 6 7 "os" 8 + "os/user" 7 9 "path/filepath" 8 10 "sync" 9 11 "sync/atomic" 10 12 ) 11 13 12 - const progressFilePrefix = ".chunk-progress-" 14 + const defaultChunkDir = ".chunk" 15 + 16 + // get the chunk directory under user's home directory 17 + // TODO: make it configurable (maybe an envvar?) 18 + func getChunkDirectory() (string, error) { 19 + u, err := user.Current() 20 + if err != nil { 21 + return "", fmt.Errorf("could not get current user: %w", err) 22 + } 23 + d := filepath.Join(u.HomeDir, defaultChunkDir) 24 + if err := os.MkdirAll(d, 0755); err != nil { 25 + return "", fmt.Errorf("could not create chunk's directory %s: %w", d, err) 26 + } 27 + return d, nil 28 + } 13 29 14 30 type progress struct { 15 31 // path for persistence of this progress file ··· 99 115 for idx := range p.Chunks { 100 116 s, err := p.shouldDownload(idx) 101 117 if err != nil { 102 - return false, fmt.Errorf("error checking if chunk is done: %w", err) 118 + return false, fmt.Errorf("error checking if chunk #%d for %s done: %w", idx+1, p.URL, err) 103 119 } 104 120 if s { 105 121 return false, nil ··· 110 126 111 127 // removes this progress file it the download is done 112 128 func (p *progress) close() error { 113 - ok, err := p.isDone() 129 + done, err := p.isDone() 114 130 if err != nil { 115 - return fmt.Errorf("error checking if donwload is done: %w", err) 116 - } 117 - if !ok { 118 - return nil 131 + return fmt.Errorf("error checking if %s is done: %w", p.URL, err) 119 132 } 120 - if err := os.Remove(p.path); err != nil && !os.IsNotExist(err) { 121 - return fmt.Errorf("error cleaning up progress files %s: %w", p.path, err) 133 + if done { 134 + if err := os.Remove(p.path); err != nil && !os.IsNotExist(err) { 135 + return fmt.Errorf("error cleaning up progress file %s: %w", p.path, err) 136 + } 122 137 } 123 138 return nil // Either not empty or error, suits both cases 124 139 } 125 140 126 141 func newProgress(path, url string, chunkSize int64, chunks int, restart bool) (*progress, error) { 127 - absPath, err := filepath.Abs(path) 142 + dir, err := getChunkDirectory() 128 143 if err != nil { 129 - return nil, fmt.Errorf("error getting absolute path for %s: %w", path, err) 144 + return nil, fmt.Errorf("could not get chunk's directory: %w", err) 130 145 } 146 + abs, err := filepath.Abs(path) 147 + if err != nil { 148 + return nil, fmt.Errorf("could not get the download absolute path: %w", err) 149 + } 150 + hash := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%s|%s", url, abs)))) 151 + 152 + // file name is a hash of the URL and local file path, plus the file name 153 + // in an human-readable way for debugging purposes 154 + name := fmt.Sprintf("%s-%s", hash, filepath.Base(path)) 131 155 p := progress{ 132 - path: filepath.Join(filepath.Dir(absPath), progressFilePrefix+filepath.Base(absPath)), 156 + path: filepath.Join(dir, name), 133 157 URL: url, 134 - Path: absPath, 158 + Path: abs, 135 159 ChunkSize: chunkSize, 136 160 Chunks: make([]uint32, chunks), 137 161 }