Invalidate remote rule-set cache when URL changes

This commit is contained in:
世界
2026-08-30 17:41:46 +08:00
parent 7d84f7d3e0
commit e6b7c6ca75
2 changed files with 43 additions and 8 deletions
+25 -1
View File
@@ -61,11 +61,12 @@ type SavedBinary struct {
Content []byte Content []byte
LastUpdated time.Time LastUpdated time.Time
LastEtag string LastEtag string
URLHash []byte
} }
func (s *SavedBinary) MarshalBinary() ([]byte, error) { func (s *SavedBinary) MarshalBinary() ([]byte, error) {
var buffer bytes.Buffer var buffer bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, uint8(1)) err := binary.Write(&buffer, binary.BigEndian, uint8(2))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -89,6 +90,14 @@ func (s *SavedBinary) MarshalBinary() ([]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = varbin.WriteUvarint(&buffer, uint64(len(s.URLHash)))
if err != nil {
return nil, err
}
_, err = buffer.Write(s.URLHash)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil return buffer.Bytes(), nil
} }
@@ -130,6 +139,21 @@ func (s *SavedBinary) UnmarshalBinary(data []byte) error {
return err return err
} }
s.LastEtag = string(etagBytes) s.LastEtag = string(etagBytes)
if version < 2 {
return nil
}
urlHashLength, err := binary.ReadUvarint(reader)
if err != nil {
return err
}
if urlHashLength > uint64(reader.Len()) {
return E.New("invalid url hash length: ", urlHashLength)
}
s.URLHash = make([]byte, urlHashLength)
_, err = io.ReadFull(reader, s.URLHash)
if err != nil {
return err
}
return nil return nil
} }
+18 -7
View File
@@ -3,6 +3,7 @@ package rule
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/sha256"
"io" "io"
"net/http" "net/http"
"path/filepath" "path/filepath"
@@ -38,6 +39,7 @@ type RemoteRuleSet struct {
outbound adapter.OutboundManager outbound adapter.OutboundManager
tag string tag string
url string url string
urlHash [32]byte
initialPath string initialPath string
options option.RuleSet options option.RuleSet
updateInterval time.Duration updateInterval time.Duration
@@ -66,13 +68,15 @@ func NewRemoteRuleSet(ctx context.Context, logger logger.ContextLogger, tag stri
initialPath = filemanager.BasePath(ctx, strings.ReplaceAll(options.RemoteOptions.InitialPath, C.RuleSetTagPlaceholder, tag)) initialPath = filemanager.BasePath(ctx, strings.ReplaceAll(options.RemoteOptions.InitialPath, C.RuleSetTagPlaceholder, tag))
initialPath, _ = filepath.Abs(initialPath) initialPath, _ = filepath.Abs(initialPath)
} }
url := strings.ReplaceAll(options.RemoteOptions.URL, C.RuleSetTagPlaceholder, tag)
return &RemoteRuleSet{ return &RemoteRuleSet{
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
outbound: service.FromContext[adapter.OutboundManager](ctx), outbound: service.FromContext[adapter.OutboundManager](ctx),
logger: logger, logger: logger,
tag: tag, tag: tag,
url: strings.ReplaceAll(options.RemoteOptions.URL, C.RuleSetTagPlaceholder, tag), url: url,
urlHash: sha256.Sum256([]byte(url)),
initialPath: initialPath, initialPath: initialPath,
options: options, options: options,
updateInterval: updateInterval, updateInterval: updateInterval,
@@ -97,13 +101,18 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter.
startContext.Register(transport) startContext.Register(transport)
s.httpClient = &http.Client{Transport: transport} s.httpClient = &http.Client{Transport: transport}
if s.cacheFile != nil { if s.cacheFile != nil {
if savedSet := s.cacheFile.LoadRuleSet(s.tag); savedSet != nil { savedSet := s.cacheFile.LoadRuleSet(s.tag)
err = s.loadBytes(savedSet.Content) if savedSet != nil {
if err != nil { if len(savedSet.URLHash) > 0 && !bytes.Equal(savedSet.URLHash, s.urlHash[:]) {
s.logger.Warn(E.Cause(err, "restore cached rule-set, will refetch")) s.logger.Info("cached rule-set was downloaded from another URL, will refetch")
} else { } else {
s.lastUpdated = savedSet.LastUpdated err = s.loadBytes(savedSet.Content)
s.lastEtag = savedSet.LastEtag if err != nil {
s.logger.Warn(E.Cause(err, "restore cached rule-set, will refetch"))
} else {
s.lastUpdated = savedSet.LastUpdated
s.lastEtag = savedSet.LastEtag
}
} }
} }
} }
@@ -249,6 +258,7 @@ func (s *RemoteRuleSet) fetch(ctx context.Context, isStart bool) error {
savedRuleSet := s.cacheFile.LoadRuleSet(s.tag) savedRuleSet := s.cacheFile.LoadRuleSet(s.tag)
if savedRuleSet != nil { if savedRuleSet != nil {
savedRuleSet.LastUpdated = s.lastUpdated savedRuleSet.LastUpdated = s.lastUpdated
savedRuleSet.URLHash = s.urlHash[:]
err = s.cacheFile.SaveRuleSet(s.tag, savedRuleSet) err = s.cacheFile.SaveRuleSet(s.tag, savedRuleSet)
if err != nil { if err != nil {
s.logger.Error("save rule-set updated time: ", err) s.logger.Error("save rule-set updated time: ", err)
@@ -279,6 +289,7 @@ func (s *RemoteRuleSet) fetch(ctx context.Context, isStart bool) error {
LastUpdated: s.lastUpdated, LastUpdated: s.lastUpdated,
Content: content, Content: content,
LastEtag: s.lastEtag, LastEtag: s.lastEtag,
URLHash: s.urlHash[:],
}) })
if err != nil { if err != nil {
s.logger.Error("save rule-set cache: ", err) s.logger.Error("save rule-set cache: ", err)