|
| 1 | +package progressreader |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + devspacecontext "github.com/loft-sh/devspace/pkg/devspace/context" |
| 6 | + "io" |
| 7 | + "time" |
| 8 | +) |
| 9 | + |
| 10 | +// ProgressReader wraps an existing io.ReadCloser. |
| 11 | +type ProgressReader struct { |
| 12 | + io.ReadCloser |
| 13 | + Ctx devspacecontext.Context |
| 14 | + total int64 // Total # of bytes transferred |
| 15 | + transferEnd time.Time |
| 16 | + transferStart time.Time |
| 17 | + transferStep time.Time |
| 18 | +} |
| 19 | + |
| 20 | +// Override Read method in order to print some progress |
| 21 | +// during reading. |
| 22 | +func (r *ProgressReader) Read(p []byte) (int, error) { |
| 23 | + if r.transferStart.IsZero() { |
| 24 | + // initialize start timer |
| 25 | + r.transferStart = time.Now() |
| 26 | + } |
| 27 | + |
| 28 | + curr, err := r.ReadCloser.Read(p) |
| 29 | + r.total += int64(curr) |
| 30 | + |
| 31 | + if err == nil { |
| 32 | + // initialize the transfer current step, or check if at least 1s is passed |
| 33 | + // in order to not spam progress updates too much |
| 34 | + if r.transferStep.IsZero() || time.Now().Second() >= (r.transferStep.Second()+3) { |
| 35 | + r.transferStep = time.Now() |
| 36 | + |
| 37 | + r.Ctx.Log().Info("Uploaded " + toHumanReadable(r.total) + " " + r.Rate()+ "\r") |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | + if err == io.EOF { |
| 42 | + r.transferEnd = time.Now() |
| 43 | + } |
| 44 | + |
| 45 | + return curr, err |
| 46 | +} |
| 47 | + |
| 48 | +// Rate returns the rate of progress in b/s |
| 49 | +func (r *ProgressReader) Rate() string { |
| 50 | + end := r.transferEnd |
| 51 | + if end.IsZero() { |
| 52 | + end = time.Now() |
| 53 | + } |
| 54 | + return toHumanReadable(int64((float64(r.total)/(end.Sub(r.transferStart).Seconds())))) + "/s" |
| 55 | +} |
| 56 | + |
| 57 | +// convert bytes input to a human readable format (Gb,Mb,Kb,b) |
| 58 | +func toHumanReadable(input int64) string { |
| 59 | + conversion := float64(input / 1024) |
| 60 | + |
| 61 | + if conversion < 0 { |
| 62 | + return fmt.Sprintf("%d b", input) |
| 63 | + } |
| 64 | + |
| 65 | + if conversion < 1000 { |
| 66 | + return fmt.Sprintf("%.2f Kb", conversion) |
| 67 | + } |
| 68 | + |
| 69 | + conversion = conversion / 1024 |
| 70 | + if conversion < 1000 { |
| 71 | + return fmt.Sprintf("%.2f Mb", conversion) |
| 72 | + } |
| 73 | + |
| 74 | + return fmt.Sprintf("%.2f Gb", conversion/1024) |
| 75 | +} |
0 commit comments