rdrc.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package cachefile
  2. import (
  3. "encoding/binary"
  4. "time"
  5. "github.com/sagernet/bbolt"
  6. "github.com/sagernet/sing/common/buf"
  7. "github.com/sagernet/sing/common/logger"
  8. )
  9. var bucketRDRC = []byte("rdrc2")
  10. func (c *CacheFile) StoreRDRC() bool {
  11. return c.storeRDRC
  12. }
  13. func (c *CacheFile) RDRCTimeout() time.Duration {
  14. return c.rdrcTimeout
  15. }
  16. func (c *CacheFile) LoadRDRC(transportName string, qName string, qType uint16) (rejected bool) {
  17. c.saveRDRCAccess.RLock()
  18. rejected, cached := c.saveRDRC[saveRDRCCacheKey{transportName, qName, qType}]
  19. c.saveRDRCAccess.RUnlock()
  20. if cached {
  21. return
  22. }
  23. key := buf.Get(2 + len(qName))
  24. binary.BigEndian.PutUint16(key, qType)
  25. copy(key[2:], qName)
  26. defer buf.Put(key)
  27. var deleteCache bool
  28. err := c.DB.View(func(tx *bbolt.Tx) error {
  29. bucket := c.bucket(tx, bucketRDRC)
  30. if bucket == nil {
  31. return nil
  32. }
  33. bucket = bucket.Bucket([]byte(transportName))
  34. if bucket == nil {
  35. return nil
  36. }
  37. content := bucket.Get(key)
  38. if content == nil {
  39. return nil
  40. }
  41. expiresAt := time.Unix(int64(binary.BigEndian.Uint64(content)), 0)
  42. if time.Now().After(expiresAt) {
  43. deleteCache = true
  44. return nil
  45. }
  46. rejected = true
  47. return nil
  48. })
  49. if err != nil {
  50. return
  51. }
  52. if deleteCache {
  53. c.DB.Update(func(tx *bbolt.Tx) error {
  54. bucket := c.bucket(tx, bucketRDRC)
  55. if bucket == nil {
  56. return nil
  57. }
  58. bucket = bucket.Bucket([]byte(transportName))
  59. if bucket == nil {
  60. return nil
  61. }
  62. return bucket.Delete(key)
  63. })
  64. }
  65. return
  66. }
  67. func (c *CacheFile) SaveRDRC(transportName string, qName string, qType uint16) error {
  68. return c.DB.Batch(func(tx *bbolt.Tx) error {
  69. bucket, err := c.createBucket(tx, bucketRDRC)
  70. if err != nil {
  71. return err
  72. }
  73. bucket, err = bucket.CreateBucketIfNotExists([]byte(transportName))
  74. if err != nil {
  75. return err
  76. }
  77. key := buf.Get(2 + len(qName))
  78. binary.BigEndian.PutUint16(key, qType)
  79. copy(key[2:], qName)
  80. defer buf.Put(key)
  81. expiresAt := buf.Get(8)
  82. defer buf.Put(expiresAt)
  83. binary.BigEndian.PutUint64(expiresAt, uint64(time.Now().Add(c.rdrcTimeout).Unix()))
  84. return bucket.Put(key, expiresAt)
  85. })
  86. }
  87. func (c *CacheFile) SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger) {
  88. saveKey := saveRDRCCacheKey{transportName, qName, qType}
  89. c.saveRDRCAccess.Lock()
  90. c.saveRDRC[saveKey] = true
  91. c.saveRDRCAccess.Unlock()
  92. go func() {
  93. err := c.SaveRDRC(transportName, qName, qType)
  94. if err != nil {
  95. logger.Warn("save RDRC: ", err)
  96. }
  97. c.saveRDRCAccess.Lock()
  98. delete(c.saveRDRC, saveKey)
  99. c.saveRDRCAccess.Unlock()
  100. }()
  101. }