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
LastUpdated time.Time
LastEtag string
URLHash []byte
}
func (s *SavedBinary) MarshalBinary() ([]byte, error) {
var buffer bytes.Buffer
err := binary.Write(&buffer, binary.BigEndian, uint8(1))
err := binary.Write(&buffer, binary.BigEndian, uint8(2))
if err != nil {
return nil, err
}
@@ -89,6 +90,14 @@ func (s *SavedBinary) MarshalBinary() ([]byte, error) {
if err != nil {
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
}
@@ -130,6 +139,21 @@ func (s *SavedBinary) UnmarshalBinary(data []byte) error {
return err
}
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
}
+13 -2
View File
@@ -3,6 +3,7 @@ package rule
import (
"bytes"
"context"
"crypto/sha256"
"io"
"net/http"
"path/filepath"
@@ -38,6 +39,7 @@ type RemoteRuleSet struct {
outbound adapter.OutboundManager
tag string
url string
urlHash [32]byte
initialPath string
options option.RuleSet
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, _ = filepath.Abs(initialPath)
}
url := strings.ReplaceAll(options.RemoteOptions.URL, C.RuleSetTagPlaceholder, tag)
return &RemoteRuleSet{
ctx: ctx,
cancel: cancel,
outbound: service.FromContext[adapter.OutboundManager](ctx),
logger: logger,
tag: tag,
url: strings.ReplaceAll(options.RemoteOptions.URL, C.RuleSetTagPlaceholder, tag),
url: url,
urlHash: sha256.Sum256([]byte(url)),
initialPath: initialPath,
options: options,
updateInterval: updateInterval,
@@ -97,7 +101,11 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter.
startContext.Register(transport)
s.httpClient = &http.Client{Transport: transport}
if s.cacheFile != nil {
if savedSet := s.cacheFile.LoadRuleSet(s.tag); savedSet != nil {
savedSet := s.cacheFile.LoadRuleSet(s.tag)
if savedSet != nil {
if len(savedSet.URLHash) > 0 && !bytes.Equal(savedSet.URLHash, s.urlHash[:]) {
s.logger.Info("cached rule-set was downloaded from another URL, will refetch")
} else {
err = s.loadBytes(savedSet.Content)
if err != nil {
s.logger.Warn(E.Cause(err, "restore cached rule-set, will refetch"))
@@ -107,6 +115,7 @@ func (s *RemoteRuleSet) StartContext(ctx context.Context, startContext *adapter.
}
}
}
}
var loadedFromInitialPath bool
if s.lastUpdated.IsZero() && s.initialPath != "" {
var content []byte
@@ -249,6 +258,7 @@ func (s *RemoteRuleSet) fetch(ctx context.Context, isStart bool) error {
savedRuleSet := s.cacheFile.LoadRuleSet(s.tag)
if savedRuleSet != nil {
savedRuleSet.LastUpdated = s.lastUpdated
savedRuleSet.URLHash = s.urlHash[:]
err = s.cacheFile.SaveRuleSet(s.tag, savedRuleSet)
if err != nil {
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,
Content: content,
LastEtag: s.lastEtag,
URLHash: s.urlHash[:],
})
if err != nil {
s.logger.Error("save rule-set cache: ", err)