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  }