chore: change subscription-userinfo retrieval

This commit is contained in:
xishang0128 2024-10-20 06:01:02 +08:00
parent ca3f1ebae6
commit 95af5f7325
7 changed files with 92 additions and 49 deletions

View File

@ -1,11 +1,9 @@
package provider package provider
import ( import (
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http"
"reflect" "reflect"
"runtime" "runtime"
"strings" "strings"
@ -14,7 +12,7 @@ import (
"github.com/metacubex/mihomo/adapter" "github.com/metacubex/mihomo/adapter"
"github.com/metacubex/mihomo/common/convert" "github.com/metacubex/mihomo/common/convert"
"github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/common/utils"
mihomoHttp "github.com/metacubex/mihomo/component/http" "github.com/metacubex/mihomo/component/profile/cachefile"
"github.com/metacubex/mihomo/component/resource" "github.com/metacubex/mihomo/component/resource"
C "github.com/metacubex/mihomo/constant" C "github.com/metacubex/mihomo/constant"
types "github.com/metacubex/mihomo/constant/provider" types "github.com/metacubex/mihomo/constant/provider"
@ -80,7 +78,9 @@ func (pp *proxySetProvider) Initial() error {
if err != nil { if err != nil {
return err return err
} }
pp.getSubscriptionInfo() if subscriptionInfo := cachefile.Cache().GetSubscriptionInfo(pp.Name()); subscriptionInfo != "" {
pp.SetSubscriptionInfo(subscriptionInfo)
}
pp.closeAllConnections() pp.closeAllConnections()
return nil return nil
} }
@ -117,35 +117,14 @@ func (pp *proxySetProvider) setProxies(proxies []C.Proxy) {
} }
} }
func (pp *proxySetProvider) getSubscriptionInfo() { func (pp *proxySetProvider) SetSubscriptionInfo(userInfo string) {
if pp.VehicleType() != types.HTTP { pp.subscriptionInfo = NewSubscriptionInfo(userInfo)
return }
}
go func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
resp, err := mihomoHttp.HttpRequestWithProxy(ctx, pp.Vehicle().Url(),
http.MethodGet, nil, nil, pp.Vehicle().Proxy())
if err != nil {
return
}
defer resp.Body.Close()
userInfoStr := strings.TrimSpace(resp.Header.Get("subscription-userinfo")) func (pp *proxySetProvider) SetProvider(provider types.ProxyProvider) {
if userInfoStr == "" { if httpVehicle, ok := pp.Vehicle().(*resource.HTTPVehicle); ok {
resp2, err := mihomoHttp.HttpRequestWithProxy(ctx, pp.Vehicle().Url(), httpVehicle.SetProvider(provider)
http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil, pp.Vehicle().Proxy()) }
if err != nil {
return
}
defer resp2.Body.Close()
userInfoStr = strings.TrimSpace(resp2.Header.Get("subscription-userinfo"))
if userInfoStr == "" {
return
}
}
pp.subscriptionInfo = NewSubscriptionInfo(userInfoStr)
}()
} }
func (pp *proxySetProvider) closeAllConnections() { func (pp *proxySetProvider) closeAllConnections() {
@ -196,6 +175,9 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc
fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg, dialerProxy, override), proxiesOnUpdate(pd)) fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg, dialerProxy, override), proxiesOnUpdate(pd))
pd.Fetcher = fetcher pd.Fetcher = fetcher
wrapper := &ProxySetProvider{pd} wrapper := &ProxySetProvider{pd}
if httpVehicle, ok := vehicle.(*resource.HTTPVehicle); ok {
httpVehicle.SetProvider(wrapper)
}
runtime.SetFinalizer(wrapper, (*ProxySetProvider).Close) runtime.SetFinalizer(wrapper, (*ProxySetProvider).Close)
return wrapper, nil return wrapper, nil
} }
@ -205,16 +187,21 @@ func (pp *ProxySetProvider) Close() error {
return pp.proxySetProvider.Close() return pp.proxySetProvider.Close()
} }
func (pp *ProxySetProvider) SetProvider(provider types.ProxyProvider) {
pp.proxySetProvider.SetProvider(provider)
}
// CompatibleProvider for auto gc // CompatibleProvider for auto gc
type CompatibleProvider struct { type CompatibleProvider struct {
*compatibleProvider *compatibleProvider
} }
type compatibleProvider struct { type compatibleProvider struct {
name string name string
healthCheck *HealthCheck healthCheck *HealthCheck
proxies []C.Proxy subscriptionInfo *SubscriptionInfo
version uint32 proxies []C.Proxy
version uint32
} }
func (cp *compatibleProvider) MarshalJSON() ([]byte, error) { func (cp *compatibleProvider) MarshalJSON() ([]byte, error) {
@ -284,6 +271,10 @@ func (cp *compatibleProvider) Close() error {
return nil return nil
} }
func (cp *compatibleProvider) SetSubscriptionInfo(userInfo string) {
cp.subscriptionInfo = NewSubscriptionInfo(userInfo)
}
func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) { func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) {
if len(proxies) == 0 { if len(proxies) == 0 {
return nil, errors.New("provider need one proxy at least") return nil, errors.New("provider need one proxy at least")
@ -313,7 +304,6 @@ func proxiesOnUpdate(pd *proxySetProvider) func([]C.Proxy) {
return func(elm []C.Proxy) { return func(elm []C.Proxy) {
pd.setProxies(elm) pd.setProxies(elm)
pd.version += 1 pd.version += 1
pd.getSubscriptionInfo()
} }
} }

View File

@ -16,8 +16,7 @@ type SubscriptionInfo struct {
} }
func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo) { func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo) {
userinfo = strings.ToLower(userinfo) userinfo = strings.ReplaceAll(strings.ToLower(userinfo), " ", "")
userinfo = strings.ReplaceAll(userinfo, " ", "")
si = new(SubscriptionInfo) si = new(SubscriptionInfo)
for _, field := range strings.Split(userinfo, ";") { for _, field := range strings.Split(userinfo, ";") {

View File

@ -17,9 +17,10 @@ var (
fileMode os.FileMode = 0o666 fileMode os.FileMode = 0o666
defaultCache *CacheFile defaultCache *CacheFile
bucketSelected = []byte("selected") bucketSelected = []byte("selected")
bucketFakeip = []byte("fakeip") bucketFakeip = []byte("fakeip")
bucketETag = []byte("etag") bucketETag = []byte("etag")
bucketSubscriptionInfo = []byte("subscriptioninfo")
) )
// CacheFile store and update the cache file // CacheFile store and update the cache file

View File

@ -0,0 +1,41 @@
package cachefile
import (
"github.com/metacubex/mihomo/log"
"github.com/metacubex/bbolt"
)
func (c *CacheFile) SetSubscriptionInfo(name string, userInfo string) {
if c.DB == nil {
return
}
err := c.DB.Batch(func(t *bbolt.Tx) error {
bucket, err := t.CreateBucketIfNotExists(bucketSubscriptionInfo)
if err != nil {
return err
}
return bucket.Put([]byte(name), []byte(userInfo))
})
if err != nil {
log.Warnln("[CacheFile] write cache to %s failed: %s", c.DB.Path(), err.Error())
return
}
}
func (c *CacheFile) GetSubscriptionInfo(name string) (userInfo string) {
if c.DB == nil {
return
}
c.DB.View(func(t *bbolt.Tx) error {
if bucket := t.Bucket(bucketSubscriptionInfo); bucket != nil {
if v := bucket.Get([]byte(name)); v != nil {
userInfo = string(v)
}
}
return nil
})
return
}

View File

@ -84,11 +84,12 @@ func NewFileVehicle(path string) *FileVehicle {
} }
type HTTPVehicle struct { type HTTPVehicle struct {
url string url string
path string path string
proxy string proxy string
header http.Header header http.Header
timeout time.Duration timeout time.Duration
provider types.ProxyProvider
} }
func (h *HTTPVehicle) Url() string { func (h *HTTPVehicle) Url() string {
@ -111,6 +112,10 @@ func (h *HTTPVehicle) Write(buf []byte) error {
return safeWrite(h.path, buf) return safeWrite(h.path, buf)
} }
func (h *HTTPVehicle) SetProvider(provider types.ProxyProvider) {
h.provider = provider
}
func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []byte, hash utils.HashType, err error) { func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []byte, hash utils.HashType, err error) {
ctx, cancel := context.WithTimeout(ctx, h.timeout) ctx, cancel := context.WithTimeout(ctx, h.timeout)
defer cancel() defer cancel()
@ -133,6 +138,12 @@ func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []b
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
if subscriptionInfo := resp.Header.Get("subscription-userinfo"); h.provider != nil && subscriptionInfo != "" {
cachefile.Cache().SetSubscriptionInfo(h.provider.Name(), subscriptionInfo)
h.provider.SetSubscriptionInfo(subscriptionInfo)
}
if resp.StatusCode < 200 || resp.StatusCode > 299 { if resp.StatusCode < 200 || resp.StatusCode > 299 {
if setIfNoneMatch && resp.StatusCode == http.StatusNotModified { if setIfNoneMatch && resp.StatusCode == http.StatusNotModified {
return nil, oldHash, nil return nil, oldHash, nil

View File

@ -213,6 +213,8 @@ func (at AdapterType) String() string {
return "WireGuard" return "WireGuard"
case Tuic: case Tuic:
return "Tuic" return "Tuic"
case Ssh:
return "Ssh"
case Relay: case Relay:
return "Relay" return "Relay"
@ -224,8 +226,6 @@ func (at AdapterType) String() string {
return "URLTest" return "URLTest"
case LoadBalance: case LoadBalance:
return "LoadBalance" return "LoadBalance"
case Ssh:
return "Ssh"
default: default:
return "Unknown" return "Unknown"
} }

View File

@ -81,6 +81,7 @@ type ProxyProvider interface {
Version() uint32 Version() uint32
RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint)
HealthCheckURL() string HealthCheckURL() string
SetSubscriptionInfo(userInfo string)
} }
// RuleProvider interface // RuleProvider interface