Clash.Meta/component/resource/vehicle.go

167 lines
3.2 KiB
Go
Raw Normal View History

package resource
2019-12-08 12:17:24 +08:00
import (
"context"
2023-07-16 11:10:07 +08:00
"errors"
2021-10-09 20:35:06 +08:00
"io"
2019-12-08 12:17:24 +08:00
"net/http"
2021-10-09 20:35:06 +08:00
"os"
2024-09-22 13:57:57 +08:00
"path/filepath"
2019-12-08 12:17:24 +08:00
"time"
2023-07-16 11:10:07 +08:00
"github.com/metacubex/mihomo/common/utils"
2023-11-03 21:01:45 +08:00
mihomoHttp "github.com/metacubex/mihomo/component/http"
2024-09-22 11:36:31 +08:00
"github.com/metacubex/mihomo/component/profile/cachefile"
2023-11-03 21:01:45 +08:00
types "github.com/metacubex/mihomo/constant/provider"
2019-12-08 12:17:24 +08:00
)
2024-09-22 13:57:57 +08:00
const (
DefaultHttpTimeout = time.Second * 20
fileMode os.FileMode = 0o666
dirMode os.FileMode = 0o755
)
var (
etag = false
)
func ETag() bool {
return etag
}
func SetETag(b bool) {
etag = b
}
2024-09-22 13:57:57 +08:00
func safeWrite(path string, buf []byte) error {
dir := filepath.Dir(path)
if _, err := os.Stat(dir); os.IsNotExist(err) {
if err := os.MkdirAll(dir, dirMode); err != nil {
return err
}
}
return os.WriteFile(path, buf, fileMode)
}
2019-12-08 12:17:24 +08:00
type FileVehicle struct {
path string
}
func (f *FileVehicle) Type() types.VehicleType {
return types.File
2019-12-08 12:17:24 +08:00
}
func (f *FileVehicle) Path() string {
return f.path
}
func (f *FileVehicle) Url() string {
return "file://" + f.path
}
func (f *FileVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []byte, hash utils.HashType, err error) {
2024-09-22 11:36:31 +08:00
buf, err = os.ReadFile(f.path)
if err != nil {
return
}
hash = utils.MakeHash(buf)
2024-09-22 11:36:31 +08:00
return
2019-12-08 12:17:24 +08:00
}
func (f *FileVehicle) Proxy() string {
return ""
}
2024-09-22 13:57:57 +08:00
func (f *FileVehicle) Write(buf []byte) error {
return safeWrite(f.path, buf)
}
2019-12-08 12:17:24 +08:00
func NewFileVehicle(path string) *FileVehicle {
return &FileVehicle{path: path}
}
type HTTPVehicle struct {
2024-09-22 13:57:57 +08:00
url string
path string
proxy string
header http.Header
timeout time.Duration
2019-12-08 12:17:24 +08:00
}
2022-11-05 02:24:08 +08:00
func (h *HTTPVehicle) Url() string {
return h.url
}
func (h *HTTPVehicle) Type() types.VehicleType {
return types.HTTP
2019-12-08 12:17:24 +08:00
}
func (h *HTTPVehicle) Path() string {
return h.path
}
func (h *HTTPVehicle) Proxy() string {
return h.proxy
}
2024-09-22 13:57:57 +08:00
func (h *HTTPVehicle) Write(buf []byte) error {
return safeWrite(h.path, buf)
}
func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []byte, hash utils.HashType, err error) {
2024-09-22 13:57:57 +08:00
ctx, cancel := context.WithTimeout(ctx, h.timeout)
2019-12-08 12:17:24 +08:00
defer cancel()
2024-09-22 11:36:31 +08:00
header := h.header
setIfNoneMatch := false
if etag && oldHash.IsValid() {
2024-09-23 19:25:35 +08:00
etagWithHash := cachefile.Cache().GetETagWithHash(h.url)
if oldHash.Equal(etagWithHash.Hash) && etagWithHash.ETag != "" {
2024-09-22 11:36:31 +08:00
if header == nil {
header = http.Header{}
} else {
header = header.Clone()
}
2024-09-23 19:25:35 +08:00
header.Set("If-None-Match", etagWithHash.ETag)
2024-09-22 11:36:31 +08:00
setIfNoneMatch = true
}
}
resp, err := mihomoHttp.HttpRequestWithProxy(ctx, h.url, http.MethodGet, header, nil, h.proxy)
if err != nil {
2024-09-22 11:36:31 +08:00
return
}
defer resp.Body.Close()
2023-07-16 11:43:18 +08:00
if resp.StatusCode < 200 || resp.StatusCode > 299 {
2024-09-22 11:36:31 +08:00
if setIfNoneMatch && resp.StatusCode == http.StatusNotModified {
return nil, oldHash, nil
}
err = errors.New(resp.Status)
return
2023-07-16 11:10:07 +08:00
}
2024-09-22 11:36:31 +08:00
buf, err = io.ReadAll(resp.Body)
2019-12-08 12:17:24 +08:00
if err != nil {
2024-09-22 11:36:31 +08:00
return
2019-12-08 12:17:24 +08:00
}
hash = utils.MakeHash(buf)
if etag {
2024-09-23 19:25:35 +08:00
cachefile.Cache().SetETagWithHash(h.url, cachefile.EtagWithHash{
Hash: hash,
ETag: resp.Header.Get("ETag"),
Time: time.Now(),
})
}
2024-09-22 11:36:31 +08:00
return
2019-12-08 12:17:24 +08:00
}
2024-09-22 13:57:57 +08:00
func NewHTTPVehicle(url string, path string, proxy string, header http.Header, timeout time.Duration) *HTTPVehicle {
2024-09-22 11:36:31 +08:00
return &HTTPVehicle{
2024-09-22 13:57:57 +08:00
url: url,
path: path,
proxy: proxy,
header: header,
timeout: timeout,
2024-09-22 11:36:31 +08:00
}
2019-12-08 12:17:24 +08:00
}