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