package server import ( "sync" "time" ) const postCacheTTL = 5 * time.Minute const postCacheMaxItems = 10000 type ttlCacheEntry struct { value any exp time.Time } type ttlCache struct { mu sync.Mutex items map[string]ttlCacheEntry ttl time.Duration maxItems int } func newTTLCache(ttl time.Duration) *ttlCache { return &ttlCache{ items: make(map[string]ttlCacheEntry), ttl: ttl, maxItems: postCacheMaxItems, } } func (c *ttlCache) get(key string) (any, bool) { c.mu.Lock() defer c.mu.Unlock() e, ok := c.items[key] if !ok { return nil, false } if time.Now().After(e.exp) { delete(c.items, key) return nil, false } return e.value, true } func (c *ttlCache) set(key string, value any) { c.mu.Lock() defer c.mu.Unlock() if len(c.items) >= c.maxItems { // Evict the oldest expired entry, or if none expired, the first one. var oldestKey string var oldestTime time.Time first := true for k, e := range c.items { if first || e.exp.Before(oldestTime) { oldestKey = k oldestTime = e.exp first = false } } if oldestKey != "" { delete(c.items, oldestKey) } } c.items[key] = ttlCacheEntry{value: value, exp: time.Now().Add(c.ttl)} } // cachedFetch returns the cached value for key or calls fetch to obtain it, // storing the result in the cache before returning. The zero value is returned // on fetch error and not cached. func cachedFetch[T any](c *ttlCache, key string, fetch func() (T, error)) (T, error) { if v, ok := c.get(key); ok { if typed, ok := v.(T); ok { return typed, nil } } val, err := fetch() if err != nil { var zero T return zero, err } c.set(key, val) return val, nil } type latestCacheValue struct { posts []*GetPostResponsePost aid string }