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"
|
"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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
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
|
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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue