diff --git a/backend/pkg/database/redis.go b/backend/pkg/database/redis.go index 38388c6..4d3c841 100644 --- a/backend/pkg/database/redis.go +++ b/backend/pkg/database/redis.go @@ -11,7 +11,8 @@ import ( ) const ( - BlacklistKeyPrefix = "blacklist:token:" + BlacklistKeyPrefix = "blacklist:token:" + InspirationFlowKeyPrefix = "inspiration_flow:" ) // RedisClient Redis 客户端单例 @@ -134,4 +135,117 @@ func RemoveFromBlacklist(ctx context.Context, token string) error { key := BlacklistKeyPrefix + tokenToHash(token) return RedisClient.Del(ctx, key).Err() +} + +// InspirationFlowCacheEntry 单个展品缓存数据 +type InspirationFlowCacheEntry struct { + AssetID int64 `json:"asset_id"` + Name string `json:"name"` + CoverURL string `json:"cover_url"` + LikeCount int32 `json:"like_count"` + OwnerNickname string `json:"owner_nickname"` + Span int32 `json:"span"` + MaterialType string `json:"material_type"` +} + +// InspirationFlowCache 会话缓存结构 +type InspirationFlowCache struct { + DisplayedIDs []int64 `json:"displayed_ids"` // 已展示ID列表 + History map[int64]InspirationFlowCacheEntry `json:"history"` // 历史数据详情 +} + +// InspirationFlowKey 生成灵感瀑布流缓存 Key +func InspirationFlowKey(starID int64, sessionID string) string { + return fmt.Sprintf("%s%d:%s", InspirationFlowKeyPrefix, starID, sessionID) +} + +// GetInspirationFlowCache 获取灵感瀑布流会话缓存 +func GetInspirationFlowCache(ctx context.Context, starID int64, sessionID string) (*InspirationFlowCache, error) { + if RedisClient == nil { + return nil, fmt.Errorf("redis client is not initialized") + } + + key := InspirationFlowKey(starID, sessionID) + data, err := RedisClient.Get(ctx, key).Result() + if err == redis.Nil { + return &InspirationFlowCache{ + DisplayedIDs: []int64{}, + History: make(map[int64]InspirationFlowCacheEntry), + }, nil + } + if err != nil { + return nil, err + } + + var cache InspirationFlowCache + if err := json.Unmarshal([]byte(data), &cache); err != nil { + return nil, err + } + return &cache, nil +} + +// SaveInspirationFlowCache 保存灵感瀑布流会话缓存 +func SaveInspirationFlowCache(ctx context.Context, starID int64, sessionID string, cache *InspirationFlowCache, ttl time.Duration) error { + if RedisClient == nil { + return fmt.Errorf("redis client is not initialized") + } + + key := InspirationFlowKey(starID, sessionID) + data, err := json.Marshal(cache) + if err != nil { + return err + } + + return RedisClient.Set(ctx, key, data, ttl).Err() +} + +// AddToInspirationFlowCache 添加展品到会话缓存 +func AddToInspirationFlowCache(ctx context.Context, starID int64, sessionID string, entry InspirationFlowCacheEntry, ttl time.Duration) error { + cache, err := GetInspirationFlowCache(ctx, starID, sessionID) + if err != nil { + return err + } + + // 检查是否已存在 + for _, id := range cache.DisplayedIDs { + if id == entry.AssetID { + return nil // 已存在,跳过 + } + } + + // 添加到已展示列表 + cache.DisplayedIDs = append(cache.DisplayedIDs, entry.AssetID) + // 添加到历史详情 + if cache.History == nil { + cache.History = make(map[int64]InspirationFlowCacheEntry) + } + cache.History[entry.AssetID] = entry + + return SaveInspirationFlowCache(ctx, starID, sessionID, cache, ttl) +} + +// GetHistoryPage 获取历史数据的某一页 +func GetHistoryPage(cache *InspirationFlowCache, offset, limit int) []InspirationFlowCacheEntry { + if cache == nil || cache.History == nil { + return []InspirationFlowCacheEntry{} + } + + // 按展示顺序反向遍历(最新展示的在前面) + items := make([]InspirationFlowCacheEntry, 0) + for i := len(cache.DisplayedIDs) - 1; i >= 0; i-- { + if entry, ok := cache.History[cache.DisplayedIDs[i]]; ok { + items = append(items, entry) + } + } + + // 分页 + start := offset + end := offset + limit + if start >= len(items) { + return []InspirationFlowCacheEntry{} + } + if end > len(items) { + end = len(items) + } + return items[start:end] } \ No newline at end of file