github.com/sagernet/sing-box@v1.2.7/experimental/clashapi/cachefile/cache.go (about)

     1  package cachefile
     2  
     3  import (
     4  	"os"
     5  	"time"
     6  
     7  	"github.com/sagernet/sing-box/adapter"
     8  
     9  	"go.etcd.io/bbolt"
    10  )
    11  
    12  var bucketSelected = []byte("selected")
    13  
    14  var _ adapter.ClashCacheFile = (*CacheFile)(nil)
    15  
    16  type CacheFile struct {
    17  	DB *bbolt.DB
    18  }
    19  
    20  func Open(path string) (*CacheFile, error) {
    21  	const fileMode = 0o666
    22  	options := bbolt.Options{Timeout: time.Second}
    23  	db, err := bbolt.Open(path, fileMode, &options)
    24  	switch err {
    25  	case bbolt.ErrInvalid, bbolt.ErrChecksum, bbolt.ErrVersionMismatch:
    26  		if err = os.Remove(path); err != nil {
    27  			break
    28  		}
    29  		db, err = bbolt.Open(path, 0o666, &options)
    30  	}
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	return &CacheFile{db}, nil
    35  }
    36  
    37  func (c *CacheFile) LoadSelected(group string) string {
    38  	var selected string
    39  	c.DB.View(func(t *bbolt.Tx) error {
    40  		bucket := t.Bucket(bucketSelected)
    41  		if bucket == nil {
    42  			return nil
    43  		}
    44  		selectedBytes := bucket.Get([]byte(group))
    45  		if len(selectedBytes) > 0 {
    46  			selected = string(selectedBytes)
    47  		}
    48  		return nil
    49  	})
    50  	return selected
    51  }
    52  
    53  func (c *CacheFile) StoreSelected(group, selected string) error {
    54  	return c.DB.Batch(func(t *bbolt.Tx) error {
    55  		bucket, err := t.CreateBucketIfNotExists(bucketSelected)
    56  		if err != nil {
    57  			return err
    58  		}
    59  		return bucket.Put([]byte(group), []byte(selected))
    60  	})
    61  }
    62  
    63  func (c *CacheFile) Close() error {
    64  	return c.DB.Close()
    65  }