feat: subscriptionInfo
This commit is contained in:
parent
4c5853e5e7
commit
dcd2417fce
4 changed files with 112 additions and 8 deletions
|
@ -5,8 +5,12 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"github.com/Dreamacro/clash/common/convert"
|
||||
netHttp "github.com/Dreamacro/clash/component/http"
|
||||
"github.com/Dreamacro/clash/component/resource"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"github.com/dlclark/regexp2"
|
||||
"golang.org/x/net/context"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -36,6 +40,7 @@ type proxySetProvider struct {
|
|||
proxies []C.Proxy
|
||||
healthCheck *HealthCheck
|
||||
version uint32
|
||||
subscriptionInfo *SubscriptionInfo
|
||||
}
|
||||
|
||||
func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
|
||||
|
@ -45,6 +50,7 @@ func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
|
|||
"vehicleType": pp.VehicleType().String(),
|
||||
"proxies": pp.Proxies(),
|
||||
"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) {
|
||||
pd.healthCheck.close()
|
||||
_ = 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))
|
||||
pd.Fetcher = fetcher
|
||||
|
||||
pd.getSubscriptionInfo()
|
||||
wrapper := &ProxySetProvider{pd}
|
||||
runtime.SetFinalizer(wrapper, stopProxyProvider)
|
||||
return wrapper, nil
|
||||
|
@ -218,6 +259,7 @@ func proxiesOnUpdate(pd *proxySetProvider) func([]C.Proxy) {
|
|||
return func(elm []C.Proxy) {
|
||||
pd.setProxies(elm)
|
||||
pd.version += 1
|
||||
pd.getSubscriptionInfo()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
54
adapter/provider/subscription_info.go
Normal file
54
adapter/provider/subscription_info.go
Normal 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
|
||||
}
|
|
@ -35,6 +35,10 @@ func (f *Fetcher[V]) Name() string {
|
|||
return f.name
|
||||
}
|
||||
|
||||
func (f *Fetcher[V]) Vehicle() types.Vehicle {
|
||||
return f.vehicle
|
||||
}
|
||||
|
||||
func (f *Fetcher[V]) VehicleType() types.VehicleType {
|
||||
return f.vehicle.Type()
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ type HTTPVehicle struct {
|
|||
path string
|
||||
}
|
||||
|
||||
func (h *HTTPVehicle) Url() string {
|
||||
return h.url
|
||||
}
|
||||
|
||||
func (h *HTTPVehicle) Type() types.VehicleType {
|
||||
return types.HTTP
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue