utils.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package updater
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "os"
  8. "time"
  9. mihomoHttp "github.com/metacubex/mihomo/component/http"
  10. C "github.com/metacubex/mihomo/constant"
  11. "golang.org/x/exp/constraints"
  12. )
  13. func downloadForBytes(url string) ([]byte, error) {
  14. ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
  15. defer cancel()
  16. resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil)
  17. if err != nil {
  18. return nil, err
  19. }
  20. defer resp.Body.Close()
  21. return io.ReadAll(resp.Body)
  22. }
  23. func saveFile(bytes []byte, path string) error {
  24. return os.WriteFile(path, bytes, 0o644)
  25. }
  26. // LimitReachedError records the limit and the operation that caused it.
  27. type LimitReachedError struct {
  28. Limit int64
  29. }
  30. // Error implements the [error] interface for *LimitReachedError.
  31. //
  32. // TODO(a.garipov): Think about error string format.
  33. func (lre *LimitReachedError) Error() string {
  34. return fmt.Sprintf("attempted to read more than %d bytes", lre.Limit)
  35. }
  36. // limitedReader is a wrapper for [io.Reader] limiting the input and dealing
  37. // with errors package.
  38. type limitedReader struct {
  39. r io.Reader
  40. limit int64
  41. n int64
  42. }
  43. // Read implements the [io.Reader] interface.
  44. func (lr *limitedReader) Read(p []byte) (n int, err error) {
  45. if lr.n == 0 {
  46. return 0, &LimitReachedError{
  47. Limit: lr.limit,
  48. }
  49. }
  50. p = p[:Min(lr.n, int64(len(p)))]
  51. n, err = lr.r.Read(p)
  52. lr.n -= int64(n)
  53. return n, err
  54. }
  55. // LimitReader wraps Reader to make it's Reader stop with ErrLimitReached after
  56. // n bytes read.
  57. func LimitReader(r io.Reader, n int64) (limited io.Reader, err error) {
  58. if n < 0 {
  59. return nil, &updateError{Message: "limit must be non-negative"}
  60. }
  61. return &limitedReader{
  62. r: r,
  63. limit: n,
  64. n: n,
  65. }, nil
  66. }
  67. // Min returns the smaller of x or y.
  68. func Min[T constraints.Integer | ~string](x, y T) (res T) {
  69. if x < y {
  70. return x
  71. }
  72. return y
  73. }