cache.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package cachefile
  2. import (
  3. "os"
  4. "sync"
  5. "time"
  6. "github.com/metacubex/mihomo/component/profile"
  7. C "github.com/metacubex/mihomo/constant"
  8. "github.com/metacubex/mihomo/log"
  9. "github.com/sagernet/bbolt"
  10. )
  11. var (
  12. initOnce sync.Once
  13. fileMode os.FileMode = 0o666
  14. defaultCache *CacheFile
  15. bucketSelected = []byte("selected")
  16. bucketFakeip = []byte("fakeip")
  17. )
  18. // CacheFile store and update the cache file
  19. type CacheFile struct {
  20. DB *bbolt.DB
  21. }
  22. func (c *CacheFile) SetSelected(group, selected string) {
  23. if !profile.StoreSelected.Load() {
  24. return
  25. } else if c.DB == nil {
  26. return
  27. }
  28. err := c.DB.Batch(func(t *bbolt.Tx) error {
  29. bucket, err := t.CreateBucketIfNotExists(bucketSelected)
  30. if err != nil {
  31. return err
  32. }
  33. return bucket.Put([]byte(group), []byte(selected))
  34. })
  35. if err != nil {
  36. log.Warnln("[CacheFile] write cache to %s failed: %s", c.DB.Path(), err.Error())
  37. return
  38. }
  39. }
  40. func (c *CacheFile) SelectedMap() map[string]string {
  41. if !profile.StoreSelected.Load() {
  42. return nil
  43. } else if c.DB == nil {
  44. return nil
  45. }
  46. mapping := map[string]string{}
  47. c.DB.View(func(t *bbolt.Tx) error {
  48. bucket := t.Bucket(bucketSelected)
  49. if bucket == nil {
  50. return nil
  51. }
  52. c := bucket.Cursor()
  53. for k, v := c.First(); k != nil; k, v = c.Next() {
  54. mapping[string(k)] = string(v)
  55. }
  56. return nil
  57. })
  58. return mapping
  59. }
  60. func (c *CacheFile) PutFakeip(key, value []byte) error {
  61. if c.DB == nil {
  62. return nil
  63. }
  64. err := c.DB.Batch(func(t *bbolt.Tx) error {
  65. bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
  66. if err != nil {
  67. return err
  68. }
  69. return bucket.Put(key, value)
  70. })
  71. if err != nil {
  72. log.Warnln("[CacheFile] write cache to %s failed: %s", c.DB.Path(), err.Error())
  73. }
  74. return err
  75. }
  76. func (c *CacheFile) DelFakeipPair(ip, host []byte) error {
  77. if c.DB == nil {
  78. return nil
  79. }
  80. err := c.DB.Batch(func(t *bbolt.Tx) error {
  81. bucket, err := t.CreateBucketIfNotExists(bucketFakeip)
  82. if err != nil {
  83. return err
  84. }
  85. err = bucket.Delete(ip)
  86. if len(host) > 0 {
  87. if err := bucket.Delete(host); err != nil {
  88. return err
  89. }
  90. }
  91. return err
  92. })
  93. if err != nil {
  94. log.Warnln("[CacheFile] write cache to %s failed: %s", c.DB.Path(), err.Error())
  95. }
  96. return err
  97. }
  98. func (c *CacheFile) GetFakeip(key []byte) []byte {
  99. if c.DB == nil {
  100. return nil
  101. }
  102. tx, err := c.DB.Begin(false)
  103. if err != nil {
  104. return nil
  105. }
  106. defer tx.Rollback()
  107. bucket := tx.Bucket(bucketFakeip)
  108. if bucket == nil {
  109. return nil
  110. }
  111. return bucket.Get(key)
  112. }
  113. func (c *CacheFile) FlushFakeIP() error {
  114. err := c.DB.Batch(func(t *bbolt.Tx) error {
  115. bucket := t.Bucket(bucketFakeip)
  116. if bucket == nil {
  117. return nil
  118. }
  119. return t.DeleteBucket(bucketFakeip)
  120. })
  121. return err
  122. }
  123. func (c *CacheFile) Close() error {
  124. return c.DB.Close()
  125. }
  126. func initCache() {
  127. options := bbolt.Options{Timeout: time.Second}
  128. db, err := bbolt.Open(C.Path.Cache(), fileMode, &options)
  129. switch err {
  130. case bbolt.ErrInvalid, bbolt.ErrChecksum, bbolt.ErrVersionMismatch:
  131. if err = os.Remove(C.Path.Cache()); err != nil {
  132. log.Warnln("[CacheFile] remove invalid cache file error: %s", err.Error())
  133. break
  134. }
  135. log.Infoln("[CacheFile] remove invalid cache file and create new one")
  136. db, err = bbolt.Open(C.Path.Cache(), fileMode, &options)
  137. }
  138. if err != nil {
  139. log.Warnln("[CacheFile] can't open cache file: %s", err.Error())
  140. }
  141. defaultCache = &CacheFile{
  142. DB: db,
  143. }
  144. }
  145. // Cache return singleton of CacheFile
  146. func Cache() *CacheFile {
  147. initOnce.Do(initCache)
  148. return defaultCache
  149. }