Add cache_id option for Clash cache file

This commit is contained in:
世界 2023-05-09 17:58:59 +08:00
parent 6266d2df7e
commit 3741394269
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
5 changed files with 56 additions and 12 deletions

View file

@ -7,13 +7,14 @@
"experimental": { "experimental": {
"clash_api": { "clash_api": {
"external_controller": "127.0.0.1:9090", "external_controller": "127.0.0.1:9090",
"external_ui": "folder", "external_ui": "",
"external_ui_download_url": "", "external_ui_download_url": "",
"external_ui_download_detour": "", "external_ui_download_detour": "",
"secret": "", "secret": "",
"default_mode": "rule", "default_mode": "",
"store_selected": false, "store_selected": false,
"cache_file": "cache.db" "cache_file": "",
"cache_id": ""
}, },
"v2ray_api": { "v2ray_api": {
"listen": "127.0.0.1:8080", "listen": "127.0.0.1:8080",
@ -91,6 +92,12 @@ Store selected outbound for the `Selector` outbound in cache file.
Cache file path, `cache.db` will be used if empty. Cache file path, `cache.db` will be used if empty.
#### cache_id
Cache ID.
If not empty, `store_selected` will use a separate store keyed by it.
### V2Ray API Fields ### V2Ray API Fields
!!! error "" !!! error ""

View file

@ -7,13 +7,14 @@
"experimental": { "experimental": {
"clash_api": { "clash_api": {
"external_controller": "127.0.0.1:9090", "external_controller": "127.0.0.1:9090",
"external_ui": "folder", "external_ui": "",
"external_ui_download_url": "", "external_ui_download_url": "",
"external_ui_download_detour": "", "external_ui_download_detour": "",
"secret": "", "secret": "",
"default_mode": "rule", "default_mode": "",
"store_selected": false, "store_selected": false,
"cache_file": "cache.db" "cache_file": "",
"cache_id": ""
}, },
"v2ray_api": { "v2ray_api": {
"listen": "127.0.0.1:8080", "listen": "127.0.0.1:8080",
@ -89,6 +90,12 @@ Clash 中的默认模式,默认使用 `rule`。
缓存文件路径,默认使用`cache.db`。 缓存文件路径,默认使用`cache.db`。
#### cache_id
缓存 ID。
如果不为空,`store_selected` 将会使用以此为键的独立存储。
### V2Ray API 字段 ### V2Ray API 字段
!!! error "" !!! error ""

View file

@ -15,9 +15,10 @@ var _ adapter.ClashCacheFile = (*CacheFile)(nil)
type CacheFile struct { type CacheFile struct {
DB *bbolt.DB DB *bbolt.DB
cacheID []byte
} }
func Open(path string) (*CacheFile, error) { func Open(path string, cacheID string) (*CacheFile, error) {
const fileMode = 0o666 const fileMode = 0o666
options := bbolt.Options{Timeout: time.Second} options := bbolt.Options{Timeout: time.Second}
db, err := bbolt.Open(path, fileMode, &options) db, err := bbolt.Open(path, fileMode, &options)
@ -31,13 +32,39 @@ func Open(path string) (*CacheFile, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &CacheFile{db}, nil var cacheIDBytes []byte
if cacheID != "" {
cacheIDBytes = append([]byte{0}, []byte(cacheID)...)
}
return &CacheFile{db, cacheIDBytes}, nil
}
func (c *CacheFile) bucket(t *bbolt.Tx, key []byte) *bbolt.Bucket {
if c.cacheID == nil {
return t.Bucket(key)
}
bucket := t.Bucket(c.cacheID)
if bucket == nil {
return nil
}
return bucket.Bucket(key)
}
func (c *CacheFile) createBucket(t *bbolt.Tx, key []byte) (*bbolt.Bucket, error) {
if c.cacheID == nil {
return t.CreateBucketIfNotExists(key)
}
bucket, err := t.CreateBucketIfNotExists(c.cacheID)
if bucket == nil {
return nil, err
}
return bucket.CreateBucketIfNotExists(key)
} }
func (c *CacheFile) LoadSelected(group string) string { func (c *CacheFile) LoadSelected(group string) string {
var selected string var selected string
c.DB.View(func(t *bbolt.Tx) error { c.DB.View(func(t *bbolt.Tx) error {
bucket := t.Bucket(bucketSelected) bucket := c.bucket(t, bucketSelected)
if bucket == nil { if bucket == nil {
return nil return nil
} }
@ -52,7 +79,7 @@ func (c *CacheFile) LoadSelected(group string) string {
func (c *CacheFile) StoreSelected(group, selected string) error { func (c *CacheFile) StoreSelected(group, selected string) error {
return c.DB.Batch(func(t *bbolt.Tx) error { return c.DB.Batch(func(t *bbolt.Tx) error {
bucket, err := t.CreateBucketIfNotExists(bucketSelected) bucket, err := c.createBucket(t, bucketSelected)
if err != nil { if err != nil {
return err return err
} }

View file

@ -48,6 +48,7 @@ type Server struct {
storeSelected bool storeSelected bool
storeFakeIP bool storeFakeIP bool
cacheFilePath string cacheFilePath string
cacheID string
cacheFile adapter.ClashCacheFile cacheFile adapter.ClashCacheFile
externalUI string externalUI string
@ -88,6 +89,7 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
cachePath = filemanager.BasePath(ctx, cachePath) cachePath = filemanager.BasePath(ctx, cachePath)
} }
server.cacheFilePath = cachePath server.cacheFilePath = cachePath
server.cacheID = options.CacheID
} }
cors := cors.New(cors.Options{ cors := cors.New(cors.Options{
AllowedOrigins: []string{"*"}, AllowedOrigins: []string{"*"},
@ -130,7 +132,7 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
func (s *Server) PreStart() error { func (s *Server) PreStart() error {
if s.cacheFilePath != "" { if s.cacheFilePath != "" {
cacheFile, err := cachefile.Open(s.cacheFilePath) cacheFile, err := cachefile.Open(s.cacheFilePath, s.cacheID)
if err != nil { if err != nil {
return E.Cause(err, "open cache file") return E.Cause(err, "open cache file")
} }

View file

@ -10,6 +10,7 @@ type ClashAPIOptions struct {
StoreSelected bool `json:"store_selected,omitempty"` StoreSelected bool `json:"store_selected,omitempty"`
StoreFakeIP bool `json:"store_fakeip,omitempty"` StoreFakeIP bool `json:"store_fakeip,omitempty"`
CacheFile string `json:"cache_file,omitempty"` CacheFile string `json:"cache_file,omitempty"`
CacheID string `json:"cache_id,omitempty"`
} }
type SelectorOutboundOptions struct { type SelectorOutboundOptions struct {