// Package cache provides caching for the API Gateway. package cache import ( "context" "crypto/sha256" "encoding/hex" "encoding/json" "time" "github.com/redis/go-redis/v9" "go.uber.org/zap" ) // Config for cache manager type Config struct { RedisAddr string RedisPassword string RedisDB int DefaultTTL time.Duration MaxEntrySize int KeyPrefix string } // Manager handles caching operations type Manager struct { client *redis.Client config Config logger *zap.Logger } // NewManager creates a cache manager func NewManager(cfg Config, logger *zap.Logger) (*Manager, error) { client := redis.NewClient(&redis.Options{ Addr: cfg.RedisAddr, Password: cfg.RedisPassword, DB: cfg.RedisDB, }) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := client.Ping(ctx).Err(); err != nil { return nil, err } return &Manager{ client: client, config: cfg, logger: logger, }, nil } // GenerateKey creates cache key from request func (m *Manager) GenerateKey(parts ...string) string { h := sha256.New() for _, p := range parts { h.Write([]byte(p)) } return m.config.KeyPrefix + hex.EncodeToString(h.Sum(nil)) } // Get retrieves cached value func (m *Manager) Get(ctx context.Context, key string) (interface{}, bool) { data, err := m.client.Get(ctx, key).Bytes() if err != nil { return nil, false } var result interface{} if err := json.Unmarshal(data, &result); err != nil { return nil, false } return result, true } // Set stores value in cache func (m *Manager) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error { data, err := json.Marshal(value) if err != nil { return err } if len(data) > m.config.MaxEntrySize { m.logger.Warn("Cache entry exceeds max size", zap.String("key", key)) return nil } if ttl == 0 { ttl = m.config.DefaultTTL } return m.client.Set(ctx, key, data, ttl).Err() } // Delete removes value from cache func (m *Manager) Delete(ctx context.Context, key string) error { return m.client.Del(ctx, key).Err() } // Close closes Redis connection func (m *Manager) Close() error { return m.client.Close() }