feat: subscriptionInfo

This commit is contained in:
adlyq 2022-11-05 02:24:08 +08:00
parent 4c5853e5e7
commit dcd2417fce
4 changed files with 112 additions and 8 deletions

View file

@ -5,8 +5,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/Dreamacro/clash/common/convert" "github.com/Dreamacro/clash/common/convert"
netHttp "github.com/Dreamacro/clash/component/http"
"github.com/Dreamacro/clash/component/resource" "github.com/Dreamacro/clash/component/resource"
"github.com/Dreamacro/clash/log"
"github.com/dlclark/regexp2" "github.com/dlclark/regexp2"
"golang.org/x/net/context"
"net/http"
"runtime" "runtime"
"strings" "strings"
"time" "time"
@ -33,18 +37,20 @@ type ProxySetProvider struct {
type proxySetProvider struct { type proxySetProvider struct {
*resource.Fetcher[[]C.Proxy] *resource.Fetcher[[]C.Proxy]
proxies []C.Proxy proxies []C.Proxy
healthCheck *HealthCheck healthCheck *HealthCheck
version uint32 version uint32
subscriptionInfo *SubscriptionInfo
} }
func (pp *proxySetProvider) MarshalJSON() ([]byte, error) { func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{ return json.Marshal(map[string]any{
"name": pp.Name(), "name": pp.Name(),
"type": pp.Type().String(), "type": pp.Type().String(),
"vehicleType": pp.VehicleType().String(), "vehicleType": pp.VehicleType().String(),
"proxies": pp.Proxies(), "proxies": pp.Proxies(),
"updatedAt": pp.UpdatedAt, "updatedAt": pp.UpdatedAt,
"subscriptionInfo": pp.subscriptionInfo,
}) })
} }
@ -97,6 +103,40 @@ func (pp *proxySetProvider) setProxies(proxies []C.Proxy) {
} }
} }
func (pp *proxySetProvider) getSubscriptionInfo() {
if pp.VehicleType() != types.HTTP {
return
}
go func() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*90)
defer cancel()
resp, err := netHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(),
http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil)
if err != nil {
return
}
defer resp.Body.Close()
userInfoStr := strings.TrimSpace(resp.Header.Get("subscription-userinfo"))
if userInfoStr == "" {
resp2, err := netHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(),
http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil)
if err != nil {
return
}
defer resp2.Body.Close()
userInfoStr = strings.TrimSpace(resp2.Header.Get("subscription-userinfo"))
if userInfoStr == "" {
return
}
}
pp.subscriptionInfo, err = NewSubscriptionInfo(userInfoStr)
if err != nil {
log.Warnln("[Provider] get subscription-userinfo: %e", err)
}
}()
}
func stopProxyProvider(pd *ProxySetProvider) { func stopProxyProvider(pd *ProxySetProvider) {
pd.healthCheck.close() pd.healthCheck.close()
_ = pd.Fetcher.Destroy() _ = pd.Fetcher.Destroy()
@ -128,6 +168,7 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc
fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, filterRegs, excludeFilterReg), proxiesOnUpdate(pd)) fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, filterRegs, excludeFilterReg), proxiesOnUpdate(pd))
pd.Fetcher = fetcher pd.Fetcher = fetcher
pd.getSubscriptionInfo()
wrapper := &ProxySetProvider{pd} wrapper := &ProxySetProvider{pd}
runtime.SetFinalizer(wrapper, stopProxyProvider) runtime.SetFinalizer(wrapper, stopProxyProvider)
return wrapper, nil return wrapper, nil
@ -218,6 +259,7 @@ 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

@ -0,0 +1,54 @@
package provider
import (
"github.com/dlclark/regexp2"
"strconv"
"strings"
)
type SubscriptionInfo struct {
Upload *int
Download *int
Total *int
Expire *int
}
func NewSubscriptionInfo(str string) (si *SubscriptionInfo, err error) {
si = &SubscriptionInfo{}
str = strings.ToLower(str)
reTraffic := regexp2.MustCompile("upload=(\\d+); download=(\\d+); total=(\\d+)", 0)
reExpire := regexp2.MustCompile("expire=(\\d+)", 0)
match, err := reTraffic.FindStringMatch(str)
if err != nil || match == nil {
return nil, err
}
group := match.Groups()
tmp, err := strconv.Atoi(group[1].String())
if err != nil {
return nil, err
}
si.Upload = &tmp
tmp, err = strconv.Atoi(group[2].String())
if err != nil {
return nil, err
}
si.Download = &tmp
tmp, err = strconv.Atoi(group[3].String())
if err != nil {
return nil, err
}
si.Total = &tmp
match, _ = reExpire.FindStringMatch(str)
if match != nil {
group = match.Groups()
tmp, err = strconv.Atoi(group[1].String())
if err != nil {
return nil, err
}
si.Expire = &tmp
}
return
}

View file

@ -35,6 +35,10 @@ func (f *Fetcher[V]) Name() string {
return f.name return f.name
} }
func (f *Fetcher[V]) Vehicle() types.Vehicle {
return f.vehicle
}
func (f *Fetcher[V]) VehicleType() types.VehicleType { func (f *Fetcher[V]) VehicleType() types.VehicleType {
return f.vehicle.Type() return f.vehicle.Type()
} }

View file

@ -35,6 +35,10 @@ type HTTPVehicle struct {
path string path string
} }
func (h *HTTPVehicle) Url() string {
return h.url
}
func (h *HTTPVehicle) Type() types.VehicleType { func (h *HTTPVehicle) Type() types.VehicleType {
return types.HTTP return types.HTTP
} }