package track1 import ( "sync" "time" ) // InMemoryCache is a simple in-memory cache // In production, use Redis for distributed caching type InMemoryCache struct { items map[string]*cacheItem mu sync.RWMutex } // cacheItem represents a cached item type cacheItem struct { value []byte expiresAt time.Time } // NewInMemoryCache creates a new in-memory cache func NewInMemoryCache() *InMemoryCache { cache := &InMemoryCache{ items: make(map[string]*cacheItem), } // Start cleanup goroutine go cache.cleanup() return cache } // Get retrieves a value from cache func (c *InMemoryCache) Get(key string) ([]byte, error) { c.mu.RLock() defer c.mu.RUnlock() item, exists := c.items[key] if !exists { return nil, ErrCacheMiss } if time.Now().After(item.expiresAt) { return nil, ErrCacheMiss } return item.value, nil } // Set stores a value in cache with TTL func (c *InMemoryCache) Set(key string, value []byte, ttl time.Duration) error { c.mu.Lock() defer c.mu.Unlock() c.items[key] = &cacheItem{ value: value, expiresAt: time.Now().Add(ttl), } return nil } // cleanup removes expired items func (c *InMemoryCache) cleanup() { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() for range ticker.C { c.mu.Lock() now := time.Now() for key, item := range c.items { if now.After(item.expiresAt) { delete(c.items, key) } } c.mu.Unlock() } } // ErrCacheMiss is returned when a cache key is not found var ErrCacheMiss = &CacheError{Message: "cache miss"} // CacheError represents a cache error type CacheError struct { Message string } func (e *CacheError) Error() string { return e.Message }