package cache import ( "fmt" ) // 缓存键前缀常量 const ( // 帖子相关 PrefixPostList = "posts:list" PrefixPost = "posts:detail" // HotRankZSet 热门榜(有序集合,member=post_id,score=归一化热度,仅存 TopN) HotRankZSet = "posts:hot:zset" // HotRankTopIDs 热门榜有序 post_id 列表(JSON []string,供分层缓存本地层命中) HotRankTopIDs = "posts:hot:top_ids" // 会话相关 PrefixConversationList = "conversations:list" PrefixConversationDetail = "conversations:detail" // 群组相关 PrefixGroupMembers = "groups:members" PrefixGroupInfo = "groups:info" // 未读数相关 PrefixUnreadSystem = "unread:system" PrefixUnreadConversation = "unread:conversation" PrefixUnreadDetail = "unread:detail" // 已读位置相关(OpenIM 风格:缓存 hasReadSeq,用于 O(1) 未读数计算) PrefixUserReadSeq = "user_read_seq" // 用户相关 PrefixUserInfo = "users:info" PrefixUserMe = "users:me" // 频道相关(全量列表一条缓存,供 /channels、帖子 channel 填充共用) PrefixChannelsAllList = "channels:all_list" // 消息缓存相关 keyPrefixMsgHash = "msg_hash" // 消息详情 Hash keyPrefixMsgIndex = "msg_index" // 消息索引 Sorted Set keyPrefixMsgCount = "msg_count" // 消息计数 keyPrefixMsgSeq = "msg_seq" // Seq 计数器 keyPrefixMsgPage = "msg_page" // 分页缓存 keyPrefixMsgIdempotent = "msg_idem" // 消息幂等键 // 帖子创建幂等键前缀(clientRequestID -> 已创建的 postID) keyPrefixPostIdempotent = "post_idem" ) // PostListKey 生成帖子列表缓存键 // postType: 帖子类型 (hot, follow, latest) // page: 页码 // pageSize: 每页数量 // userID: 用户维度(仅在个性化列表如 follow 场景使用) // HotRankZSetKey 热门榜 Redis ZSET 逻辑键(仅存 TopN,会经 normalizeKey 加前缀) func HotRankZSetKey() string { return HotRankZSet } // HotRankTopIDsKey 热门榜 Top 顺序 ID 列表键(会经 normalizeKey 加前缀) func HotRankTopIDsKey() string { return HotRankTopIDs } func HotRankZSetChannelKey(channelID string) string { return fmt.Sprintf("%s:ch:%s", HotRankZSet, channelID) } func HotRankTopIDsChannelKey(channelID string) string { return fmt.Sprintf("%s:ch:%s", HotRankTopIDs, channelID) } func PostListKey(postType string, userID string, page, pageSize int) string { if userID == "" { return fmt.Sprintf("%s:%s:%d:%d", PrefixPostList, postType, page, pageSize) } return fmt.Sprintf("%s:%s:%s:%d:%d", PrefixPostList, postType, userID, page, pageSize) } // PostDetailKey 生成帖子详情缓存键 func PostDetailKey(postID string) string { return fmt.Sprintf("%s:%s", PrefixPost, postID) } // ConversationListKey 生成会话列表缓存键 func ConversationListKey(userID string, page, pageSize int) string { return fmt.Sprintf("%s:%s:%d:%d", PrefixConversationList, userID, page, pageSize) } // GroupMembersKey 生成群组成员缓存键 func GroupMembersKey(groupID string, page, pageSize int) string { return fmt.Sprintf("%s:%s:page:%d:size:%d", PrefixGroupMembers, groupID, page, pageSize) } // UnreadSystemKey 生成系统消息未读数缓存键 func UnreadSystemKey(userID string) string { return fmt.Sprintf("%s:%s", PrefixUnreadSystem, userID) } // UnreadConversationKey 生成会话未读总数缓存键 func UnreadConversationKey(userID string) string { return fmt.Sprintf("%s:%s", PrefixUnreadConversation, userID) } // UnreadDetailKey 生成单个会话未读数缓存键 func UnreadDetailKey(userID, conversationID string) string { return fmt.Sprintf("%s:%s:%s", PrefixUnreadDetail, userID, conversationID) } // ChannelsAllListKey 频道全量列表缓存键(含未启用,供 MapByIDs 解析历史帖子 channel) func ChannelsAllListKey() string { return PrefixChannelsAllList } // InvalidateChannelList 失效频道列表缓存(管理端增删改频道后调用) func InvalidateChannelList(c Cache) { c.Delete(ChannelsAllListKey()) } // InvalidatePostList 失效帖子列表缓存 func InvalidatePostList(cache Cache) { cache.DeleteByPrefix(PrefixPostList) } // InvalidatePostDetail 失效帖子详情缓存 func InvalidatePostDetail(cache Cache, postID string) { cache.Delete(PostDetailKey(postID)) } // InvalidateConversationList 失效会话列表缓存 func InvalidateConversationList(cache Cache, userID string) { cache.DeleteByPrefix(PrefixConversationList + ":" + userID + ":") } // InvalidateGroupMembers 失效群组成员缓存 func InvalidateGroupMembers(cache Cache, groupID string) { cache.DeleteByPrefix(PrefixGroupMembers + ":" + groupID) } // InvalidateUnreadSystem 失效系统消息未读数缓存 func InvalidateUnreadSystem(cache Cache, userID string) { cache.Delete(UnreadSystemKey(userID)) } // InvalidateUnreadConversation 失效会话未读数缓存 func InvalidateUnreadConversation(cache Cache, userID string) { cache.Delete(UnreadConversationKey(userID)) } // InvalidateUnreadDetail 失效单个会话未读数缓存 func InvalidateUnreadDetail(cache Cache, userID, conversationID string) { cache.Delete(UnreadDetailKey(userID, conversationID)) } // ============================================================ // 消息缓存 Key 生成函数 // ============================================================ // MessageHashKey 消息详情 Hash key func MessageHashKey(convID string) string { return fmt.Sprintf("%s:%s", keyPrefixMsgHash, convID) } // MessageIndexKey 消息索引 Sorted Set key func MessageIndexKey(convID string) string { return fmt.Sprintf("%s:%s", keyPrefixMsgIndex, convID) } // MessageCountKey 消息计数 key func MessageCountKey(convID string) string { return fmt.Sprintf("%s:%s", keyPrefixMsgCount, convID) } // MessageSeqKey Seq 计数器 key func MessageSeqKey(convID string) string { return fmt.Sprintf("%s:%s", keyPrefixMsgSeq, convID) } // MessagePageKey 分页缓存 key func MessagePageKey(convID string, page, pageSize int) string { return fmt.Sprintf("%s:%s:%d:%d", keyPrefixMsgPage, convID, page, pageSize) } // InvalidateMessagePages 失效会话消息分页缓存 func InvalidateMessagePages(cache Cache, conversationID string) { cache.DeleteByPrefix(fmt.Sprintf("%s:%s:", keyPrefixMsgPage, conversationID)) } // MessageIdempotentKey 消息幂等键 (clientMsgID -> server MsgID) func MessageIdempotentKey(senderID, clientMsgID string) string { return fmt.Sprintf("%s:%s:%s", keyPrefixMsgIdempotent, senderID, clientMsgID) } // PostCreateIdempotentKey 帖子创建幂等键 (userID + clientRequestID -> postID) // 用于在 SetNX 原子抢占期间识别同一客户端请求的重试,避免重复发帖。 func PostCreateIdempotentKey(userID, clientRequestID string) string { return fmt.Sprintf("%s:%s:%s", keyPrefixPostIdempotent, userID, clientRequestID) } // UserReadSeqKey 用户已读位置缓存键(OpenIM 风格 SEQ_USER_READ:{convID}:{userID}) func UserReadSeqKey(convID, userID string) string { return fmt.Sprintf("%s:%s:%s", PrefixUserReadSeq, convID, userID) }