cache.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package cachefile
  2. import (
  3. "net/netip"
  4. "os"
  5. "sync"
  6. "time"
  7. "github.com/sagernet/sing-box/adapter"
  8. "go.etcd.io/bbolt"
  9. )
  10. var bucketSelected = []byte("selected")
  11. var _ adapter.ClashCacheFile = (*CacheFile)(nil)
  12. type CacheFile struct {
  13. DB *bbolt.DB
  14. cacheID []byte
  15. saveAccess sync.RWMutex
  16. saveCache map[netip.Addr]string
  17. }
  18. func Open(path string, cacheID string) (*CacheFile, error) {
  19. const fileMode = 0o666
  20. options := bbolt.Options{Timeout: time.Second}
  21. db, err := bbolt.Open(path, fileMode, &options)
  22. switch err {
  23. case bbolt.ErrInvalid, bbolt.ErrChecksum, bbolt.ErrVersionMismatch:
  24. if err = os.Remove(path); err != nil {
  25. break
  26. }
  27. db, err = bbolt.Open(path, 0o666, &options)
  28. }
  29. if err != nil {
  30. return nil, err
  31. }
  32. var cacheIDBytes []byte
  33. if cacheID != "" {
  34. cacheIDBytes = append([]byte{0}, []byte(cacheID)...)
  35. }
  36. return &CacheFile{
  37. DB: db,
  38. cacheID: cacheIDBytes,
  39. saveCache: make(map[netip.Addr]string),
  40. }, nil
  41. }
  42. func (c *CacheFile) bucket(t *bbolt.Tx, key []byte) *bbolt.Bucket {
  43. if c.cacheID == nil {
  44. return t.Bucket(key)
  45. }
  46. bucket := t.Bucket(c.cacheID)
  47. if bucket == nil {
  48. return nil
  49. }
  50. return bucket.Bucket(key)
  51. }
  52. func (c *CacheFile) createBucket(t *bbolt.Tx, key []byte) (*bbolt.Bucket, error) {
  53. if c.cacheID == nil {
  54. return t.CreateBucketIfNotExists(key)
  55. }
  56. bucket, err := t.CreateBucketIfNotExists(c.cacheID)
  57. if bucket == nil {
  58. return nil, err
  59. }
  60. return bucket.CreateBucketIfNotExists(key)
  61. }
  62. func (c *CacheFile) LoadSelected(group string) string {
  63. var selected string
  64. c.DB.View(func(t *bbolt.Tx) error {
  65. bucket := c.bucket(t, bucketSelected)
  66. if bucket == nil {
  67. return nil
  68. }
  69. selectedBytes := bucket.Get([]byte(group))
  70. if len(selectedBytes) > 0 {
  71. selected = string(selectedBytes)
  72. }
  73. return nil
  74. })
  75. return selected
  76. }
  77. func (c *CacheFile) StoreSelected(group, selected string) error {
  78. return c.DB.Batch(func(t *bbolt.Tx) error {
  79. bucket, err := c.createBucket(t, bucketSelected)
  80. if err != nil {
  81. return err
  82. }
  83. return bucket.Put([]byte(group), []byte(selected))
  84. })
  85. }
  86. func (c *CacheFile) Close() error {
  87. return c.DB.Close()
  88. }