future.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. package future
  2. import (
  3. "bytes"
  4. "crypto/sha256"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "math/rand"
  9. "net/http"
  10. "time"
  11. )
  12. func Seed() {
  13. rand.Seed(time.Now().UTC().UnixNano())
  14. }
  15. func ComputeId(content io.Reader) (string, error) {
  16. h := sha256.New()
  17. if _, err := io.Copy(h, content); err != nil {
  18. return "", err
  19. }
  20. return fmt.Sprintf("%x", h.Sum(nil)[:8]), nil
  21. }
  22. func HumanDuration(d time.Duration) string {
  23. if seconds := int(d.Seconds()); seconds < 1 {
  24. return "Less than a second"
  25. } else if seconds < 60 {
  26. return fmt.Sprintf("%d seconds", seconds)
  27. } else if minutes := int(d.Minutes()); minutes == 1 {
  28. return "About a minute"
  29. } else if minutes < 60 {
  30. return fmt.Sprintf("%d minutes", minutes)
  31. } else if hours := int(d.Hours()); hours == 1 {
  32. return "About an hour"
  33. } else if hours < 48 {
  34. return fmt.Sprintf("%d hours", hours)
  35. } else if hours < 24*7*2 {
  36. return fmt.Sprintf("%d days", hours/24)
  37. } else if hours < 24*30*3 {
  38. return fmt.Sprintf("%d weeks", hours/24/7)
  39. } else if hours < 24*365*2 {
  40. return fmt.Sprintf("%d months", hours/24/30)
  41. }
  42. return fmt.Sprintf("%d years", d.Hours()/24/365)
  43. }
  44. func randomBytes() io.Reader {
  45. return bytes.NewBuffer([]byte(fmt.Sprintf("%x", rand.Int())))
  46. }
  47. func RandomId() string {
  48. id, _ := ComputeId(randomBytes()) // can't fail
  49. return id
  50. }
  51. func Go(f func() error) chan error {
  52. ch := make(chan error)
  53. go func() {
  54. ch <- f()
  55. }()
  56. return ch
  57. }
  58. // Pv wraps an io.Reader such that it is passed through unchanged,
  59. // but logs the number of bytes copied (comparable to the unix command pv)
  60. func Pv(src io.Reader, info io.Writer) io.Reader {
  61. var totalBytes int
  62. data := make([]byte, 2048)
  63. r, w := io.Pipe()
  64. go func() {
  65. for {
  66. if n, err := src.Read(data); err != nil {
  67. w.CloseWithError(err)
  68. return
  69. } else {
  70. totalBytes += n
  71. fmt.Fprintf(info, "--> %d bytes\n", totalBytes)
  72. if _, err = w.Write(data[:n]); err != nil {
  73. return
  74. }
  75. }
  76. }
  77. }()
  78. return r
  79. }
  80. // Request a given URL and return an io.Reader
  81. func Download(url string, stderr io.Writer) (*http.Response, error) {
  82. var resp *http.Response
  83. var err error = nil
  84. if resp, err = http.Get(url); err != nil {
  85. return nil, err
  86. }
  87. if resp.StatusCode >= 400 {
  88. return nil, errors.New("Got HTTP status code >= 400: " + resp.Status)
  89. }
  90. return resp, nil
  91. }
  92. // Reader with progress bar
  93. type progressReader struct {
  94. reader io.ReadCloser // Stream to read from
  95. output io.Writer // Where to send progress bar to
  96. read_total int // Expected stream length (bytes)
  97. read_progress int // How much has been read so far (bytes)
  98. last_update int // How many bytes read at least update
  99. }
  100. func (r *progressReader) Read(p []byte) (n int, err error) {
  101. read, err := io.ReadCloser(r.reader).Read(p)
  102. r.read_progress += read
  103. // Only update progress for every 1% read
  104. update_every := int(0.01 * float64(r.read_total))
  105. if r.read_progress - r.last_update > update_every || r.read_progress == r.read_total {
  106. fmt.Fprintf(r.output, "%d/%d (%.0f%%)\r",
  107. r.read_progress,
  108. r.read_total,
  109. float64(r.read_progress) / float64(r.read_total) * 100)
  110. r.last_update = r.read_progress
  111. }
  112. // Send newline when complete
  113. if err == io.EOF {
  114. fmt.Fprintf(r.output, "\n")
  115. }
  116. return read, err
  117. }
  118. func (r *progressReader) Close() error {
  119. return io.ReadCloser(r.reader).Close()
  120. }
  121. func ProgressReader(r io.ReadCloser, size int, output io.Writer) *progressReader {
  122. return &progressReader{r, output, size, 0, 0}
  123. }