mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
apply filter and dial options
This commit is contained in:
parent
fe69f1580d
commit
53790153b0
@ -11,5 +11,6 @@ type SubscriptionServiceOptions struct {
|
|||||||
type SubscriptionProviderOptions struct {
|
type SubscriptionProviderOptions struct {
|
||||||
Tag string `json:"tag,omitempty"`
|
Tag string `json:"tag,omitempty"`
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Excludes []string `json:"excludes,omitempty"`
|
Exclude string `json:"exclude,omitempty"`
|
||||||
|
Include string `json:"include,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@ -27,15 +28,53 @@ type Subscription struct {
|
|||||||
|
|
||||||
parentCtx context.Context
|
parentCtx context.Context
|
||||||
logFactory log.Factory
|
logFactory log.Factory
|
||||||
options option.SubscriptionServiceOptions
|
|
||||||
|
interval time.Duration
|
||||||
|
downloadDetour string `json:"download_detour,omitempty"`
|
||||||
|
dialerOptions option.DialerOptions
|
||||||
|
providers []*subscriptionProvider
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type subscriptionProvider struct {
|
||||||
|
Tag string `json:"tag,omitempty"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Exclude *regexp.Regexp `json:"exclude,omitempty"`
|
||||||
|
Include *regexp.Regexp `json:"include,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// NewSubscription creates a new subscription service.
|
// NewSubscription creates a new subscription service.
|
||||||
func NewSubscription(ctx context.Context, router adapter.Router, logger log.ContextLogger, logFactory log.Factory, options option.Service) (*Subscription, error) {
|
func NewSubscription(ctx context.Context, router adapter.Router, logger log.ContextLogger, logFactory log.Factory, options option.Service) (*Subscription, error) {
|
||||||
ctx2, cancel := context.WithCancel(ctx)
|
ctx2, cancel := context.WithCancel(ctx)
|
||||||
|
providers := make([]*subscriptionProvider, 0, len(options.SubscriptionOptions.Providers))
|
||||||
|
for _, p := range options.SubscriptionOptions.Providers {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
exclude *regexp.Regexp
|
||||||
|
include *regexp.Regexp
|
||||||
|
)
|
||||||
|
if p.Exclude != "" {
|
||||||
|
exclude, err = regexp.Compile(p.Exclude)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.Include != "" {
|
||||||
|
include, err = regexp.Compile(p.Include)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
providers = append(providers, &subscriptionProvider{
|
||||||
|
Tag: p.Tag,
|
||||||
|
URL: p.URL,
|
||||||
|
Exclude: exclude,
|
||||||
|
Include: include,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return &Subscription{
|
return &Subscription{
|
||||||
myServiceAdapter: myServiceAdapter{
|
myServiceAdapter: myServiceAdapter{
|
||||||
router: router,
|
router: router,
|
||||||
@ -43,7 +82,10 @@ func NewSubscription(ctx context.Context, router adapter.Router, logger log.Cont
|
|||||||
logger: logger,
|
logger: logger,
|
||||||
tag: options.Tag,
|
tag: options.Tag,
|
||||||
},
|
},
|
||||||
options: options.SubscriptionOptions,
|
interval: time.Duration(options.SubscriptionOptions.Interval),
|
||||||
|
downloadDetour: options.SubscriptionOptions.DownloadDetour,
|
||||||
|
providers: providers,
|
||||||
|
dialerOptions: options.SubscriptionOptions.DialerOptions,
|
||||||
parentCtx: ctx,
|
parentCtx: ctx,
|
||||||
logFactory: logFactory,
|
logFactory: logFactory,
|
||||||
ctx: ctx2,
|
ctx: ctx2,
|
||||||
@ -66,7 +108,7 @@ func (s *Subscription) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Subscription) fetchLoop() {
|
func (s *Subscription) fetchLoop() {
|
||||||
ticker := time.NewTicker(time.Duration(s.options.Interval))
|
ticker := time.NewTicker(s.interval)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
if err := s.fetch(); err != nil {
|
if err := s.fetch(); err != nil {
|
||||||
@ -90,7 +132,7 @@ func (s *Subscription) fetch() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i, provider := range s.options.Providers {
|
for i, provider := range s.providers {
|
||||||
var tag string
|
var tag string
|
||||||
if provider.Tag != "" {
|
if provider.Tag != "" {
|
||||||
tag = provider.Tag
|
tag = provider.Tag
|
||||||
@ -104,9 +146,11 @@ func (s *Subscription) fetch() error {
|
|||||||
}
|
}
|
||||||
s.logger.Info(len(links), " links found from provider [", tag, "]")
|
s.logger.Info(len(links), " links found from provider [", tag, "]")
|
||||||
for _, link := range links {
|
for _, link := range links {
|
||||||
// TODO: filter links
|
|
||||||
opt := link.Options()
|
opt := link.Options()
|
||||||
s.applyOptions(opt, &provider)
|
if !applyFilter(opt.Tag, provider) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s.applyOptions(opt, provider)
|
||||||
outbound, err := outbound.New(
|
outbound, err := outbound.New(
|
||||||
s.parentCtx,
|
s.parentCtx,
|
||||||
s.router,
|
s.router,
|
||||||
@ -123,12 +167,46 @@ func (s *Subscription) fetch() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Subscription) applyOptions(options *option.Outbound, provider *option.SubscriptionProviderOptions) {
|
func applyFilter(tag string, provider *subscriptionProvider) bool {
|
||||||
options.Tag = s.tag + provider.Tag + options.Tag
|
if provider.Exclude != nil && provider.Exclude.MatchString(tag) {
|
||||||
// TODO: implement me
|
return false
|
||||||
|
}
|
||||||
|
if provider.Include == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return provider.Include.MatchString(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Subscription) fetchProvider(client *http.Client, provider option.SubscriptionProviderOptions) ([]link.Link, error) {
|
func (s *Subscription) applyOptions(options *option.Outbound, provider *subscriptionProvider) error {
|
||||||
|
options.Tag = s.tag + "." + provider.Tag + "." + options.Tag
|
||||||
|
switch options.Type {
|
||||||
|
case C.TypeSocks:
|
||||||
|
options.SocksOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeHTTP:
|
||||||
|
options.HTTPOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeShadowsocks:
|
||||||
|
options.ShadowsocksOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeVMess:
|
||||||
|
options.VMessOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeTrojan:
|
||||||
|
options.TrojanOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeWireGuard:
|
||||||
|
options.WireGuardOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeHysteria:
|
||||||
|
options.HysteriaOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeTor:
|
||||||
|
options.TorOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeSSH:
|
||||||
|
options.SSHOptions.DialerOptions = s.dialerOptions
|
||||||
|
case C.TypeShadowTLS:
|
||||||
|
options.ShadowTLSOptions.DialerOptions = s.dialerOptions
|
||||||
|
default:
|
||||||
|
return E.New("unknown outbound type: ", options.Type)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Subscription) fetchProvider(client *http.Client, provider *subscriptionProvider) ([]link.Link, error) {
|
||||||
req, err := http.NewRequestWithContext(s.ctx, http.MethodGet, provider.URL, nil)
|
req, err := http.NewRequestWithContext(s.ctx, http.MethodGet, provider.URL, nil)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -157,10 +235,10 @@ func (s *Subscription) fetchProvider(client *http.Client, provider option.Subscr
|
|||||||
|
|
||||||
func (s *Subscription) client() (*http.Client, error) {
|
func (s *Subscription) client() (*http.Client, error) {
|
||||||
var detour adapter.Outbound
|
var detour adapter.Outbound
|
||||||
if s.options.DownloadDetour != "" {
|
if s.downloadDetour != "" {
|
||||||
outbound, loaded := s.router.Outbound(s.options.DownloadDetour)
|
outbound, loaded := s.router.Outbound(s.downloadDetour)
|
||||||
if !loaded {
|
if !loaded {
|
||||||
return nil, E.New("detour outbound not found: ", s.options.DownloadDetour)
|
return nil, E.New("detour outbound not found: ", s.downloadDetour)
|
||||||
}
|
}
|
||||||
detour = outbound
|
detour = outbound
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user