use static file instead of cache file

(cherry picked from commit 6279d7268408d0999707e3a4bebdc0c9ccb51c1e)
This commit is contained in:
PuerNya 2024-08-13 05:56:16 +08:00 committed by CHIZI-0618
parent 66dbd0165b
commit 0a59285020
4 changed files with 235 additions and 281 deletions

View File

@ -17,8 +17,8 @@ type _RuleSet struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Tag string `json:"tag"` Tag string `json:"tag"`
Format string `json:"format,omitempty"` Format string `json:"format,omitempty"`
Path string `json:"path,omitempty"`
InlineOptions PlainRuleSet `json:"-"` InlineOptions PlainRuleSet `json:"-"`
LocalOptions LocalRuleSet `json:"-"`
RemoteOptions RemoteRuleSet `json:"-"` RemoteOptions RemoteRuleSet `json:"-"`
} }
@ -31,7 +31,7 @@ func (r RuleSet) MarshalJSON() ([]byte, error) {
r.Type = "" r.Type = ""
v = r.InlineOptions v = r.InlineOptions
case C.RuleSetTypeLocal: case C.RuleSetTypeLocal:
v = r.LocalOptions v = nil
case C.RuleSetTypeRemote: case C.RuleSetTypeRemote:
v = r.RemoteOptions v = r.RemoteOptions
default: default:
@ -58,6 +58,7 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
} }
} else { } else {
r.Format = "" r.Format = ""
r.Path = ""
} }
var v any var v any
switch r.Type { switch r.Type {
@ -65,7 +66,7 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
r.Type = C.RuleSetTypeInline r.Type = C.RuleSetTypeInline
v = &r.InlineOptions v = &r.InlineOptions
case C.RuleSetTypeLocal: case C.RuleSetTypeLocal:
v = &r.LocalOptions v = nil
case C.RuleSetTypeRemote: case C.RuleSetTypeRemote:
v = &r.RemoteOptions v = &r.RemoteOptions
default: default:
@ -78,10 +79,6 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
return nil return nil
} }
type LocalRuleSet struct {
Path string `json:"path,omitempty"`
}
type RemoteRuleSet struct { type RemoteRuleSet struct {
URL string `json:"url"` URL string `json:"url"`
DownloadDetour string `json:"download_detour,omitempty"` DownloadDetour string `json:"download_detour,omitempty"`

155
route/rule_set_abstract.go Normal file
View File

@ -0,0 +1,155 @@
package route
import (
"bytes"
"io"
"os"
"strings"
"time"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/srs"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/common/rw"
"go4.org/netipx"
)
type abstractRuleSet struct {
router adapter.Router
logger logger.ContextLogger
tag string
path string
format string
rules []adapter.HeadlessRule
metadata adapter.RuleSetMetadata
lastUpdated time.Time
refs atomic.Int32
}
func (s *abstractRuleSet) Name() string {
return s.tag
}
func (s *abstractRuleSet) String() string {
return strings.Join(F.MapToString(s.rules), " ")
}
func (s *abstractRuleSet) getPath(path string) (string, error) {
if path == "" {
path = s.tag
switch s.format {
case C.RuleSetFormatSource, "":
path += ".json"
case C.RuleSetFormatBinary:
path += ".srs"
}
}
if rw.IsDir(path) {
return "", E.New("rule_set path is a directory: ", path)
}
return path, nil
}
func (s *abstractRuleSet) Metadata() adapter.RuleSetMetadata {
return s.metadata
}
func (s *abstractRuleSet) ExtractIPSet() []*netipx.IPSet {
return common.FlatMap(s.rules, extractIPSetFromRule)
}
func (s *abstractRuleSet) IncRef() {
s.refs.Add(1)
}
func (s *abstractRuleSet) DecRef() {
if s.refs.Add(-1) < 0 {
panic("rule-set: negative refs")
}
}
func (s *abstractRuleSet) Cleanup() {
if s.refs.Load() == 0 {
s.rules = nil
}
}
func (s *abstractRuleSet) loadFromFile(path string) error {
file, err := os.Open(path)
if err != nil {
return err
}
content, err := io.ReadAll(file)
if err != nil {
return err
}
err = s.loadBytes(content)
if err != nil {
return err
}
fs, _ := file.Stat()
s.lastUpdated = fs.ModTime()
return nil
}
func (s *abstractRuleSet) loadBytes(content []byte) error {
var (
plainRuleSet option.PlainRuleSet
err error
)
switch s.format {
case C.RuleSetFormatSource:
var compat option.PlainRuleSetCompat
compat, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
if err != nil {
return err
}
plainRuleSet, err = compat.Upgrade()
if err != nil {
return err
}
case C.RuleSetFormatBinary:
plainRuleSet, err = srs.Read(bytes.NewReader(content), false)
if err != nil {
return err
}
default:
return E.New("unknown rule-set format: ", s.format)
}
return s.reloadRules(plainRuleSet.Rules)
}
func (s *abstractRuleSet) reloadRules(headlessRules []option.HeadlessRule) error {
rules := make([]adapter.HeadlessRule, len(headlessRules))
var err error
for i, ruleOptions := range headlessRules {
rules[i], err = NewHeadlessRule(s.router, ruleOptions)
if err != nil {
return E.Cause(err, "parse rule_set.rules.[", i, "]")
}
}
var metadata adapter.RuleSetMetadata
metadata.ContainsProcessRule = hasHeadlessRule(headlessRules, isProcessHeadlessRule)
metadata.ContainsWIFIRule = hasHeadlessRule(headlessRules, isWIFIHeadlessRule)
metadata.ContainsIPCIDRRule = hasHeadlessRule(headlessRules, isIPCIDRHeadlessRule)
s.rules = rules
s.metadata = metadata
return nil
}
func (s *abstractRuleSet) Match(metadata *adapter.InboundContext) bool {
for _, rule := range s.rules {
if rule.Match(metadata) {
return true
}
}
return false
}

View File

@ -2,46 +2,33 @@ package route
import ( import (
"context" "context"
"os"
"path/filepath" "path/filepath"
"strings"
"github.com/sagernet/fswatch" "github.com/sagernet/fswatch"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/srs"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/common/x/list" "github.com/sagernet/sing/common/x/list"
"github.com/sagernet/sing/service/filemanager"
"go4.org/netipx"
) )
var _ adapter.RuleSet = (*LocalRuleSet)(nil) var _ adapter.RuleSet = (*LocalRuleSet)(nil)
type LocalRuleSet struct { type LocalRuleSet struct {
router adapter.Router abstractRuleSet
logger logger.Logger watcher *fswatch.Watcher
tag string
rules []adapter.HeadlessRule
metadata adapter.RuleSetMetadata
fileFormat string
watcher *fswatch.Watcher
refs atomic.Int32
} }
func NewLocalRuleSet(ctx context.Context, router adapter.Router, logger logger.Logger, options option.RuleSet) (*LocalRuleSet, error) { func NewLocalRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) (*LocalRuleSet, error) {
ruleSet := &LocalRuleSet{ ruleSet := &LocalRuleSet{
router: router, abstractRuleSet: abstractRuleSet{
logger: logger, router: router,
tag: options.Tag, logger: logger,
fileFormat: options.Format, tag: options.Tag,
},
} }
if options.Type == C.RuleSetTypeInline { if options.Type == C.RuleSetTypeInline {
if len(options.InlineOptions.Rules) == 0 { if len(options.InlineOptions.Rules) == 0 {
@ -51,40 +38,36 @@ func NewLocalRuleSet(ctx context.Context, router adapter.Router, logger logger.L
if err != nil { if err != nil {
return nil, err return nil, err
} }
} else { return ruleSet, nil
err := ruleSet.reloadFile(filemanager.BasePath(ctx, options.LocalOptions.Path))
if err != nil {
return nil, err
}
} }
if options.Type == C.RuleSetTypeLocal { ruleSet.path = options.Path
var watcher *fswatch.Watcher ruleSet.format = options.Format
filePath, _ := filepath.Abs(options.LocalOptions.Path) path, err := ruleSet.getPath(options.Path)
watcher, err := fswatch.NewWatcher(fswatch.Options{ if err != nil {
Path: []string{filePath}, return nil, err
Callback: func(path string) {
uErr := ruleSet.reloadFile(path)
if uErr != nil {
logger.Error(E.Cause(uErr, "reload rule-set ", options.Tag))
}
},
})
if err != nil {
return nil, err
}
ruleSet.watcher = watcher
} }
err = ruleSet.loadFromFile(path)
if err != nil {
return nil, err
}
var watcher *fswatch.Watcher
filePath, _ := filepath.Abs(path)
watcher, err = fswatch.NewWatcher(fswatch.Options{
Path: []string{filePath},
Callback: func(path string) {
uErr := ruleSet.loadFromFile(path)
if uErr != nil {
logger.ErrorContext(log.ContextWithNewID(context.Background()), E.Cause(uErr, "reload rule-set ", options.Tag))
}
},
})
if err != nil {
return nil, err
}
ruleSet.watcher = watcher
return ruleSet, nil return ruleSet, nil
} }
func (s *LocalRuleSet) Name() string {
return s.tag
}
func (s *LocalRuleSet) String() string {
return strings.Join(F.MapToString(s.rules), " ")
}
func (s *LocalRuleSet) StartContext(ctx context.Context, startContext adapter.RuleSetStartContext) error { func (s *LocalRuleSet) StartContext(ctx context.Context, startContext adapter.RuleSetStartContext) error {
if s.watcher != nil { if s.watcher != nil {
err := s.watcher.Start() err := s.watcher.Start()
@ -95,83 +78,10 @@ func (s *LocalRuleSet) StartContext(ctx context.Context, startContext adapter.Ru
return nil return nil
} }
func (s *LocalRuleSet) reloadFile(path string) error {
var plainRuleSet option.PlainRuleSet
switch s.fileFormat {
case C.RuleSetFormatSource, "":
content, err := os.ReadFile(path)
if err != nil {
return err
}
compat, err := json.UnmarshalExtended[option.PlainRuleSetCompat](content)
if err != nil {
return err
}
plainRuleSet, err = compat.Upgrade()
if err != nil {
return err
}
case C.RuleSetFormatBinary:
setFile, err := os.Open(path)
if err != nil {
return err
}
plainRuleSet, err = srs.Read(setFile, false)
if err != nil {
return err
}
default:
return E.New("unknown rule-set format: ", s.fileFormat)
}
return s.reloadRules(plainRuleSet.Rules)
}
func (s *LocalRuleSet) reloadRules(headlessRules []option.HeadlessRule) error {
rules := make([]adapter.HeadlessRule, len(headlessRules))
var err error
for i, ruleOptions := range headlessRules {
rules[i], err = NewHeadlessRule(s.router, ruleOptions)
if err != nil {
return E.Cause(err, "parse rule_set.rules.[", i, "]")
}
}
var metadata adapter.RuleSetMetadata
metadata.ContainsProcessRule = hasHeadlessRule(headlessRules, isProcessHeadlessRule)
metadata.ContainsWIFIRule = hasHeadlessRule(headlessRules, isWIFIHeadlessRule)
metadata.ContainsIPCIDRRule = hasHeadlessRule(headlessRules, isIPCIDRHeadlessRule)
s.rules = rules
s.metadata = metadata
return nil
}
func (s *LocalRuleSet) PostStart() error { func (s *LocalRuleSet) PostStart() error {
return nil return nil
} }
func (s *LocalRuleSet) Metadata() adapter.RuleSetMetadata {
return s.metadata
}
func (s *LocalRuleSet) ExtractIPSet() []*netipx.IPSet {
return common.FlatMap(s.rules, extractIPSetFromRule)
}
func (s *LocalRuleSet) IncRef() {
s.refs.Add(1)
}
func (s *LocalRuleSet) DecRef() {
if s.refs.Add(-1) < 0 {
panic("rule-set: negative refs")
}
}
func (s *LocalRuleSet) Cleanup() {
if s.refs.Load() == 0 {
s.rules = nil
}
}
func (s *LocalRuleSet) RegisterCallback(callback adapter.RuleSetUpdateCallback) *list.Element[adapter.RuleSetUpdateCallback] { func (s *LocalRuleSet) RegisterCallback(callback adapter.RuleSetUpdateCallback) *list.Element[adapter.RuleSetUpdateCallback] {
return nil return nil
} }
@ -183,12 +93,3 @@ func (s *LocalRuleSet) Close() error {
s.rules = nil s.rules = nil
return common.Close(common.PtrOrNil(s.watcher)) return common.Close(common.PtrOrNil(s.watcher))
} }
func (s *LocalRuleSet) Match(metadata *adapter.InboundContext) bool {
for _, rule := range s.rules {
if rule.Match(metadata) {
return true
}
}
return false
}

View File

@ -1,54 +1,45 @@
package route package route
import ( import (
"bytes"
"context" "context"
"io" "io"
"net" "net"
"net/http" "net/http"
"os"
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/srs"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format" F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/json"
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/x/list" "github.com/sagernet/sing/common/x/list"
"github.com/sagernet/sing/service" "github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/pause" "github.com/sagernet/sing/service/pause"
"go4.org/netipx"
) )
var _ adapter.RuleSet = (*RemoteRuleSet)(nil) var _ adapter.RuleSet = (*RemoteRuleSet)(nil)
type RemoteRuleSet struct { type RemoteRuleSet struct {
abstractRuleSet
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
router adapter.Router path string
logger logger.ContextLogger options option.RemoteRuleSet
options option.RuleSet
metadata adapter.RuleSetMetadata
updateInterval time.Duration updateInterval time.Duration
dialer N.Dialer dialer N.Dialer
rules []adapter.HeadlessRule
lastUpdated time.Time
lastEtag string lastEtag string
updateTicker *time.Ticker updateTicker *time.Ticker
pauseManager pause.Manager pauseManager pause.Manager
callbackAccess sync.Mutex callbackAccess sync.Mutex
callbacks list.List[adapter.RuleSetUpdateCallback] callbacks list.List[adapter.RuleSetUpdateCallback]
refs atomic.Int32
} }
func NewRemoteRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) *RemoteRuleSet { func NewRemoteRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) *RemoteRuleSet {
@ -60,30 +51,31 @@ func NewRemoteRuleSet(ctx context.Context, router adapter.Router, logger logger.
updateInterval = 24 * time.Hour updateInterval = 24 * time.Hour
} }
return &RemoteRuleSet{ return &RemoteRuleSet{
abstractRuleSet: abstractRuleSet{
router: router,
logger: logger,
tag: options.Tag,
format: options.Format,
},
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
router: router, path: options.Path,
logger: logger, options: options.RemoteOptions,
options: options,
updateInterval: updateInterval, updateInterval: updateInterval,
pauseManager: service.FromContext[pause.Manager](ctx), pauseManager: service.FromContext[pause.Manager](ctx),
} }
} }
func (s *RemoteRuleSet) Name() string {
return s.options.Tag
}
func (s *RemoteRuleSet) String() string { func (s *RemoteRuleSet) String() string {
return strings.Join(F.MapToString(s.rules), " ") return strings.Join(F.MapToString(s.rules), " ")
} }
func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext adapter.RuleSetStartContext) error { func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext adapter.RuleSetStartContext) error {
var dialer N.Dialer var dialer N.Dialer
if s.options.RemoteOptions.DownloadDetour != "" { if s.options.DownloadDetour != "" {
outbound, loaded := s.router.Outbound(s.options.RemoteOptions.DownloadDetour) outbound, loaded := s.router.Outbound(s.options.DownloadDetour)
if !loaded { if !loaded {
return E.New("download_detour not found: ", s.options.RemoteOptions.DownloadDetour) return E.New("download_detour not found: ", s.options.DownloadDetour)
} }
dialer = outbound dialer = outbound
} else { } else {
@ -94,21 +86,14 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext adapter.R
dialer = outbound dialer = outbound
} }
s.dialer = dialer s.dialer = dialer
cacheFile := service.FromContext[adapter.CacheFile](s.ctx) if path, err := s.getPath(s.path); err == nil {
if cacheFile != nil { s.path = path
if savedSet := cacheFile.LoadRuleSet(s.options.Tag); savedSet != nil { s.loadFromFile(path)
err := s.loadBytes(savedSet.Content)
if err != nil {
return E.Cause(err, "restore cached rule-set")
}
s.lastUpdated = savedSet.LastUpdated
s.lastEtag = savedSet.LastEtag
}
} }
if s.lastUpdated.IsZero() { if s.lastUpdated.IsZero() {
err := s.fetchOnce(ctx, startContext) err := s.fetchOnce(ctx, startContext)
if err != nil { if err != nil {
return E.Cause(err, "initial rule-set: ", s.options.Tag) return E.Cause(err, "initial rule-set: ", s.tag)
} }
} }
s.updateTicker = time.NewTicker(s.updateInterval) s.updateTicker = time.NewTicker(s.updateInterval)
@ -120,30 +105,6 @@ func (s *RemoteRuleSet) PostStart() error {
return nil return nil
} }
func (s *RemoteRuleSet) Metadata() adapter.RuleSetMetadata {
return s.metadata
}
func (s *RemoteRuleSet) ExtractIPSet() []*netipx.IPSet {
return common.FlatMap(s.rules, extractIPSetFromRule)
}
func (s *RemoteRuleSet) IncRef() {
s.refs.Add(1)
}
func (s *RemoteRuleSet) DecRef() {
if s.refs.Add(-1) < 0 {
panic("rule-set: negative refs")
}
}
func (s *RemoteRuleSet) Cleanup() {
if s.refs.Load() == 0 {
s.rules = nil
}
}
func (s *RemoteRuleSet) RegisterCallback(callback adapter.RuleSetUpdateCallback) *list.Element[adapter.RuleSetUpdateCallback] { func (s *RemoteRuleSet) RegisterCallback(callback adapter.RuleSetUpdateCallback) *list.Element[adapter.RuleSetUpdateCallback] {
s.callbackAccess.Lock() s.callbackAccess.Lock()
defer s.callbackAccess.Unlock() defer s.callbackAccess.Unlock()
@ -157,40 +118,10 @@ func (s *RemoteRuleSet) UnregisterCallback(element *list.Element[adapter.RuleSet
} }
func (s *RemoteRuleSet) loadBytes(content []byte) error { func (s *RemoteRuleSet) loadBytes(content []byte) error {
var ( err := s.abstractRuleSet.loadBytes(content)
plainRuleSet option.PlainRuleSet if err != nil {
err error return err
)
switch s.options.Format {
case C.RuleSetFormatSource:
var compat option.PlainRuleSetCompat
compat, err = json.UnmarshalExtended[option.PlainRuleSetCompat](content)
if err != nil {
return err
}
plainRuleSet, err = compat.Upgrade()
if err != nil {
return err
}
case C.RuleSetFormatBinary:
plainRuleSet, err = srs.Read(bytes.NewReader(content), false)
if err != nil {
return err
}
default:
return E.New("unknown rule-set format: ", s.options.Format)
} }
rules := make([]adapter.HeadlessRule, len(plainRuleSet.Rules))
for i, ruleOptions := range plainRuleSet.Rules {
rules[i], err = NewHeadlessRule(s.router, ruleOptions)
if err != nil {
return E.Cause(err, "parse rule_set.rules.[", i, "]")
}
}
s.metadata.ContainsProcessRule = hasHeadlessRule(plainRuleSet.Rules, isProcessHeadlessRule)
s.metadata.ContainsWIFIRule = hasHeadlessRule(plainRuleSet.Rules, isWIFIHeadlessRule)
s.metadata.ContainsIPCIDRRule = hasHeadlessRule(plainRuleSet.Rules, isIPCIDRHeadlessRule)
s.rules = rules
s.callbackAccess.Lock() s.callbackAccess.Lock()
callbacks := s.callbacks.Array() callbacks := s.callbacks.Array()
s.callbackAccess.Unlock() s.callbackAccess.Unlock()
@ -202,12 +133,7 @@ func (s *RemoteRuleSet) loadBytes(content []byte) error {
func (s *RemoteRuleSet) loopUpdate() { func (s *RemoteRuleSet) loopUpdate() {
if time.Since(s.lastUpdated) > s.updateInterval { if time.Since(s.lastUpdated) > s.updateInterval {
err := s.fetchOnce(s.ctx, nil) s.update()
if err != nil {
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
} else if s.refs.Load() == 0 {
s.rules = nil
}
} }
for { for {
runtime.GC() runtime.GC()
@ -216,21 +142,26 @@ func (s *RemoteRuleSet) loopUpdate() {
return return
case <-s.updateTicker.C: case <-s.updateTicker.C:
s.pauseManager.WaitActive() s.pauseManager.WaitActive()
err := s.fetchOnce(s.ctx, nil) s.update()
if err != nil {
s.logger.Error("fetch rule-set ", s.options.Tag, ": ", err)
} else if s.refs.Load() == 0 {
s.rules = nil
}
} }
} }
} }
func (s *RemoteRuleSet) update() {
ctx := log.ContextWithNewID(s.ctx)
err := s.fetchOnce(ctx, nil)
if err != nil {
s.logger.ErrorContext(ctx, "fetch rule-set ", s.tag, ": ", err)
} else if s.refs.Load() == 0 {
s.rules = nil
}
}
func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext adapter.RuleSetStartContext) error { 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) s.logger.DebugContext(ctx, "updating rule-set ", s.tag, " from URL: ", s.options.URL)
var httpClient *http.Client var httpClient *http.Client
if startContext != nil { if startContext != nil {
httpClient = startContext.HTTPClient(s.options.RemoteOptions.DownloadDetour, s.dialer) httpClient = startContext.HTTPClient(s.options.DownloadDetour, s.dialer)
} else { } else {
httpClient = &http.Client{ httpClient = &http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
@ -242,7 +173,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", s.options.URL, nil)
if err != nil { if err != nil {
return err return err
} }
@ -257,19 +188,8 @@ func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext adapter.Rule
case http.StatusOK: case http.StatusOK:
case http.StatusNotModified: case http.StatusNotModified:
s.lastUpdated = time.Now() s.lastUpdated = time.Now()
cacheFile := service.FromContext[adapter.CacheFile](s.ctx) os.Chtimes(s.path, s.lastUpdated, s.lastUpdated)
if cacheFile != nil { s.logger.InfoContext(ctx, "update rule-set ", s.tag, ": not modified")
savedRuleSet := cacheFile.LoadRuleSet(s.options.Tag)
if savedRuleSet != nil {
savedRuleSet.LastUpdated = s.lastUpdated
err = cacheFile.SaveRuleSet(s.options.Tag, savedRuleSet)
if err != nil {
s.logger.Error("save rule-set updated time: ", err)
return nil
}
}
}
s.logger.Info("update rule-set ", s.options.Tag, ": not modified")
return nil return nil
default: default:
return E.New("unexpected status: ", response.Status) return E.New("unexpected status: ", response.Status)
@ -290,18 +210,8 @@ func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext adapter.Rule
s.lastEtag = eTagHeader s.lastEtag = eTagHeader
} }
s.lastUpdated = time.Now() s.lastUpdated = time.Now()
cacheFile := service.FromContext[adapter.CacheFile](s.ctx) os.WriteFile(s.path, content, 0o666)
if cacheFile != nil { s.logger.InfoContext(ctx, "updated rule-set ", s.tag)
err = cacheFile.SaveRuleSet(s.options.Tag, &adapter.SavedRuleSet{
LastUpdated: s.lastUpdated,
Content: content,
LastEtag: s.lastEtag,
})
if err != nil {
s.logger.Error("save rule-set cache: ", err)
}
}
s.logger.Info("updated rule-set ", s.options.Tag)
return nil return nil
} }
@ -311,12 +221,3 @@ func (s *RemoteRuleSet) Close() error {
s.cancel() s.cancel()
return nil return nil
} }
func (s *RemoteRuleSet) Match(metadata *adapter.InboundContext) bool {
for _, rule := range s.rules {
if rule.Match(metadata) {
return true
}
}
return false
}