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 }