(ctx ...context.Context)
| 217 | } |
| 218 | |
| 219 | func (pd *ParallelDownload) Do(ctx ...context.Context) error { |
| 220 | err := pd.ensure() |
| 221 | if err != nil { |
| 222 | return err |
| 223 | } |
| 224 | for i := 0; i < pd.concurrency; i++ { |
| 225 | go pd.startWorker(ctx...) |
| 226 | } |
| 227 | resp := pd.client.Head(pd.url).Do(ctx...) |
| 228 | if resp.Err != nil { |
| 229 | return resp.Err |
| 230 | } |
| 231 | if resp.ContentLength <= 0 { |
| 232 | return fmt.Errorf("bad content length: %d", resp.ContentLength) |
| 233 | } |
| 234 | pd.lastIndex = int(math.Ceil(float64(resp.ContentLength)/float64(pd.segmentSize))) - 1 |
| 235 | pd.wg.Add(1) |
| 236 | go pd.mergeFile() |
| 237 | go func() { |
| 238 | pd.wg.Wait() |
| 239 | close(pd.wgDoneCh) |
| 240 | }() |
| 241 | totalBytes := resp.ContentLength |
| 242 | start := int64(0) |
| 243 | for i := 0; ; i++ { |
| 244 | end := start + (pd.segmentSize - 1) |
| 245 | if end > (totalBytes - 1) { |
| 246 | end = totalBytes - 1 |
| 247 | } |
| 248 | task := &downloadTask{ |
| 249 | index: i, |
| 250 | rangeStart: start, |
| 251 | rangeEnd: end, |
| 252 | } |
| 253 | pd.taskCh <- task |
| 254 | if end < (totalBytes - 1) { |
| 255 | start = end + 1 |
| 256 | continue |
| 257 | } |
| 258 | break |
| 259 | } |
| 260 | select { |
| 261 | case <-pd.wgDoneCh: |
| 262 | if pd.client.DebugLog { |
| 263 | if pd.filename != "" { |
| 264 | pd.client.log.Debugf("download completed from %s to %s", pd.url, pd.filename) |
| 265 | } else { |
| 266 | pd.client.log.Debugf("download completed for %s", pd.url) |
| 267 | } |
| 268 | } |
| 269 | close(pd.doneCh) |
| 270 | case err := <-pd.errCh: |
| 271 | return err |
| 272 | } |
| 273 | return nil |
| 274 | } |
| 275 | |
| 276 | func (pd *ParallelDownload) getOutputFile() (io.Writer, error) { |
no test coverage detected