diff --git a/option/rule_set.go b/option/rule_set.go index 8e367e69a5..7af7fae8d3 100644 --- a/option/rule_set.go +++ b/option/rule_set.go @@ -74,9 +74,9 @@ type LocalRuleSet struct { } type RemoteRuleSet struct { - URL string `json:"url"` - DownloadDetour string `json:"download_detour,omitempty"` - UpdateInterval Duration `json:"update_interval,omitempty"` + URL Listable[string] `json:"url"` + DownloadDetour string `json:"download_detour,omitempty"` + UpdateInterval Duration `json:"update_interval,omitempty"` } type _HeadlessRule struct { diff --git a/route/rule_set.go b/route/rule_set.go index f644fb406f..bf745866e3 100644 --- a/route/rule_set.go +++ b/route/rule_set.go @@ -20,6 +20,9 @@ func NewRuleSet(ctx context.Context, router adapter.Router, logger logger.Contex case C.RuleSetTypeLocal: return NewLocalRuleSet(router, options) case C.RuleSetTypeRemote: + if len(options.RemoteOptions.URL) == 0 { + return nil, E.New("missing urls") + } return NewRemoteRuleSet(ctx, router, logger, options), nil default: return nil, E.New("unknown rule set type: ", options.Type) diff --git a/route/rule_set_remote.go b/route/rule_set_remote.go index a14c6fe543..d0f25e1c76 100644 --- a/route/rule_set_remote.go +++ b/route/rule_set_remote.go @@ -184,7 +184,18 @@ func (s *RemoteRuleSet) loopUpdate() { } func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext adapter.RuleSetStartContext) error { - s.logger.Debug("updating rule-set ", s.options.Tag, " from URL: ", s.options.RemoteOptions.URL) + var err error + for _, url := range s.options.RemoteOptions.URL { + err = s.fetchURL(ctx, url, startContext) + if err == nil { + return nil + } + } + return err +} + +func (s *RemoteRuleSet) fetchURL(ctx context.Context, url string, startContext adapter.RuleSetStartContext) error { + s.logger.Debug("updating rule-set ", s.options.Tag, " from URL: ", url) var httpClient *http.Client if startContext != nil { httpClient = startContext.HTTPClient(s.options.RemoteOptions.DownloadDetour, s.dialer) @@ -199,7 +210,7 @@ func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext adapter.Rule }, } } - request, err := http.NewRequest("GET", s.options.RemoteOptions.URL, nil) + request, err := http.NewRequest("GET", url, nil) if err != nil { return err }