mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-15 21:00:27 +00:00
Invalidate remote rule-set cache when URL changes
This commit is contained in:
+25
-1
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user