github.com/Mrs4s/MiraiGo@v0.0.0-20240226124653-54bdd873e3fe/utils/ttl.go (about)

     1  package utils
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  )
     7  
     8  // https://github.com/Konstantin8105/SimpleTTL
     9  // entry - typical element of cache
    10  type entry[T any] struct {
    11  	expiry time.Time
    12  	value  T
    13  }
    14  
    15  // Cache - simple implementation of cache
    16  // More information: https://en.wikipedia.org/wiki/Time_to_live
    17  type Cache[T any] struct {
    18  	lock  sync.RWMutex
    19  	cache map[string]*entry[T]
    20  }
    21  
    22  // NewCache - initialization of new cache.
    23  // For avoid mistake - minimal time to live is 1 minute.
    24  // For simplification, - key is string and cache haven`t stop method
    25  func NewCache[T any](interval time.Duration) *Cache[T] {
    26  	if interval < time.Second {
    27  		interval = time.Second
    28  	}
    29  	cache := &Cache[T]{cache: make(map[string]*entry[T])}
    30  	go func() {
    31  		ticker := time.NewTicker(interval)
    32  		for {
    33  			// wait of ticker
    34  			now := <-ticker.C
    35  
    36  			// remove entry outside TTL
    37  			cache.lock.Lock()
    38  			for id, entry := range cache.cache {
    39  				if entry == nil || entry.expiry.Before(now) {
    40  					delete(cache.cache, id)
    41  				}
    42  			}
    43  			cache.lock.Unlock()
    44  		}
    45  	}()
    46  	return cache
    47  }
    48  
    49  // Count - return amount element of TTL map.
    50  func (cache *Cache[_]) Count() int {
    51  	cache.lock.RLock()
    52  	defer cache.lock.RUnlock()
    53  
    54  	return len(cache.cache)
    55  }
    56  
    57  // Get - return value from cache
    58  func (cache *Cache[T]) Get(key string) (value T, _ bool) {
    59  	cache.lock.RLock()
    60  	defer cache.lock.RUnlock()
    61  
    62  	e, ok := cache.cache[key]
    63  	if ok && e.expiry.After(time.Now()) {
    64  		return e.value, true
    65  	}
    66  	return
    67  }
    68  
    69  func (cache *Cache[T]) GetAndUpdate(key string, ttl time.Duration) (_ T, _ bool) {
    70  	cache.lock.RLock()
    71  	defer cache.lock.RUnlock()
    72  
    73  	if e, ok := cache.cache[key]; ok {
    74  		e.expiry = time.Now().Add(ttl)
    75  		return e.value, true
    76  	}
    77  	return
    78  }
    79  
    80  // Add - add key/value in cache
    81  func (cache *Cache[T]) Add(key string, value T, ttl time.Duration) {
    82  	cache.lock.Lock()
    83  	defer cache.lock.Unlock()
    84  
    85  	cache.cache[key] = &entry[T]{
    86  		value:  value,
    87  		expiry: time.Now().Add(ttl),
    88  	}
    89  }
    90  
    91  // GetKeys - return all keys of cache map
    92  func (cache *Cache[_]) GetKeys() []string {
    93  	cache.lock.RLock()
    94  	defer cache.lock.RUnlock()
    95  
    96  	keys := make([]string, len(cache.cache))
    97  	var i int
    98  	for k := range cache.cache {
    99  		keys[i] = k
   100  		i++
   101  	}
   102  	return keys
   103  }