don't remove outbounds if the a provider fails

This commit is contained in:
jebbs 2022-10-16 08:39:40 +08:00
parent 22b79b297f
commit 2da163d59b

View File

@ -64,10 +64,9 @@ func NewSubscription(ctx context.Context, router adapter.Router, logger log.Cont
exclude *regexp.Regexp exclude *regexp.Regexp
include *regexp.Regexp include *regexp.Regexp
) )
if p.Tag != "" { // required for outbounds clean up
tag = p.Tag if p.Tag == "" {
} else { return nil, E.New("tag of provider [", i, "] is required")
tag = F.ToString(i)
} }
if p.URL == "" { if p.URL == "" {
return nil, E.New("missing URL for provider [", tag, "]") return nil, E.New("missing URL for provider [", tag, "]")
@ -117,7 +116,7 @@ func NewSubscription(ctx context.Context, router adapter.Router, logger log.Cont
// Start starts the service. // Start starts the service.
func (s *Subscription) Start() error { func (s *Subscription) Start() error {
go s.fetchLoop() go s.refreshLoop()
return nil return nil
} }
@ -129,7 +128,7 @@ func (s *Subscription) Close() error {
return nil return nil
} }
func (s *Subscription) fetchLoop() { func (s *Subscription) refreshLoop() {
ticker := time.NewTicker(s.interval) ticker := time.NewTicker(s.interval)
defer ticker.Stop() defer ticker.Stop()
@ -146,16 +145,26 @@ L:
} }
func (s *Subscription) refresh() { func (s *Subscription) refresh() {
opts, err := s.fetch() client, err := s.client()
if err != nil { if err != nil {
s.logger.Error("fetch subscription: ", err) s.logger.Error("client: ", err)
}
// outbounds before refresh
outbounds := s.router.Outbounds()
for _, provider := range s.providers {
opts, err := s.fetch(client, provider)
if err != nil {
s.logger.Warn("fetch provider [", provider.tag, "]: ", err)
continue
}
s.logger.Info(len(opts), " links found from provider [", provider.tag, "]")
s.updateOutbounds(provider, opts, outbounds)
} }
s.updateOutbounds(opts)
} }
func (s *Subscription) updateOutbounds(opts []*option.Outbound) { func (s *Subscription) updateOutbounds(provider *subscriptionProvider, opts []*option.Outbound, outbounds []adapter.Outbound) {
outbounds := s.router.Outbounds()
knownOutbounds := make(map[string]struct{}) knownOutbounds := make(map[string]struct{})
removeCount := 0
for _, opt := range opts { for _, opt := range opts {
tag := opt.Tag tag := opt.Tag
knownOutbounds[tag] = struct{}{} knownOutbounds[tag] = struct{}{}
@ -172,7 +181,7 @@ func (s *Subscription) updateOutbounds(opts []*option.Outbound) {
s.logger.Info("created outbound [", tag, "]") s.logger.Info("created outbound [", tag, "]")
} }
// remove outbounds that are not in the latest list // remove outbounds that are not in the latest list
tagPrefix := s.tag + "." tagPrefix := s.tag + "." + provider.tag
for _, outbound := range outbounds { for _, outbound := range outbounds {
tag := outbound.Tag() tag := outbound.Tag()
if !strings.HasPrefix(tag, tagPrefix) { if !strings.HasPrefix(tag, tagPrefix) {
@ -181,37 +190,27 @@ func (s *Subscription) updateOutbounds(opts []*option.Outbound) {
if _, ok := knownOutbounds[tag]; ok { if _, ok := knownOutbounds[tag]; ok {
continue continue
} }
removeCount++
s.router.RemoveOutbound(tag) s.router.RemoveOutbound(tag)
} }
if removeCount > 0 {
s.logger.Info(removeCount, " outbounds removed for [", tagPrefix, "]")
}
} }
func (s *Subscription) fetch() ([]*option.Outbound, error) { func (s *Subscription) fetch(client *http.Client, provider *subscriptionProvider) ([]*option.Outbound, error) {
client, err := s.client() opts := make([]*option.Outbound, 0)
links, err := s.fetchProvider(client, provider)
if err != nil { if err != nil {
return nil, err return nil, err
} }
opts := make([]*option.Outbound, 0) for _, link := range links {
for i, provider := range s.providers { opt := link.Options()
var tag string if !selectedByTag(opt.Tag, provider) {
if provider.tag != "" {
tag = provider.tag
} else {
tag = F.ToString(i)
}
links, err := s.fetchProvider(client, provider)
if err != nil {
s.logger.Warn("fetch provider [", tag, "]: ", err)
continue continue
} }
s.logger.Info(len(links), " links found from provider [", tag, "]") s.applyOptions(opt, provider)
for _, link := range links { opts = append(opts, opt)
opt := link.Options()
if !selectedByTag(opt.Tag, provider) {
continue
}
s.applyOptions(opt, provider)
opts = append(opts, opt)
}
} }
return opts, nil return opts, nil
} }