github.com/metacubex/mihomo@v1.18.5/component/updater/utils.go (about)

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