| package cache |
|
|
| import ( |
| "context" |
| "crypto/sha256" |
| "encoding/hex" |
| "path/filepath" |
| "sync/atomic" |
| "time" |
|
|
| "github.com/redis/go-redis/v9" |
| "github.com/router-for-me/CLIProxyAPI/v6/internal/config" |
| ) |
|
|
| |
| type CachedResponse struct { |
| StatusCode int `json:"s"` |
| Headers map[string]string `json:"h"` |
| Body []byte `json:"b"` |
| CachedAt time.Time `json:"t"` |
| Model string `json:"m"` |
| } |
|
|
| |
| type CacheStats struct { |
| Hits int64 `json:"hits"` |
| Misses int64 `json:"misses"` |
| Size int64 `json:"size"` |
| } |
|
|
| |
| type ResponseCache interface { |
| Get(ctx context.Context, key string) (*CachedResponse, bool) |
| Set(ctx context.Context, key string, resp *CachedResponse, ttl time.Duration) error |
| Delete(ctx context.Context, pattern string) error |
| Stats() CacheStats |
| Close() error |
| } |
|
|
| |
| func ResponseCacheKey(model string, body []byte) string { |
| h := sha256.New() |
| h.Write([]byte(model)) |
| h.Write([]byte{0}) |
| h.Write(body) |
| return hex.EncodeToString(h.Sum(nil)) |
| } |
|
|
| |
| func ShouldCache(cfg config.ResponseCacheConfig, model string, isStreaming bool, responseSize int) bool { |
| if !cfg.Enabled { |
| return false |
| } |
| if isStreaming && cfg.ExcludeStreaming { |
| return false |
| } |
| if cfg.MaxResponseSizeKB > 0 && responseSize > cfg.MaxResponseSizeKB*1024 { |
| return false |
| } |
| for _, pattern := range cfg.ExcludeModels { |
| if matched, _ := filepath.Match(pattern, model); matched { |
| return false |
| } |
| } |
| return true |
| } |
|
|
| |
| func NewResponseCache(cfg config.ResponseCacheConfig, client redis.UniversalClient) ResponseCache { |
| if client != nil { |
| return newRedisResponseCache(cfg, client) |
| } |
| return newMemoryResponseCache(cfg) |
| } |
|
|
| |
| type responseCacheStats struct { |
| hits atomic.Int64 |
| misses atomic.Int64 |
| } |
|
|
| func (s *responseCacheStats) recordHit() { s.hits.Add(1) } |
| func (s *responseCacheStats) recordMiss() { s.misses.Add(1) } |
|
|