/** * PostManager - 帖子管理核心模块 * * 架构特点: * - 使用 CachedManager 基类,消除重复的缓存/去重逻辑 * - 支持 Sources 模式进行分页加载 */ import { Post } from '../types'; import { postService } from '../services/postService'; import { CacheEvent } from './cacheBus'; import { CachedManager, CacheEntry, createCacheEntry, isCacheExpired } from './baseManager'; import { IPostListPagedSource, PostListTab, createRemotePostListSource, RemotePostListSourceKind, POST_LIST_PAGE_SIZE, } from './postListSources'; // ==================== 类型定义 ==================== interface PostListPayload { key: string; posts: Post[]; } interface PostDetailPayload { postId: string; post: Post | null; } interface PostManagerSnapshot { listKeys: string[]; detailKeys: string[]; } type PostManagerEvent = | CacheEvent | CacheEvent | CacheEvent | CacheEvent<{ error: unknown; context: string }>; // ==================== 常量 ==================== const LIST_TTL = 30 * 1000; const DETAIL_TTL = 60 * 1000; // ==================== Manager 实现 ==================== class PostManager extends CachedManager { /** 详情缓存 */ private detailCache = new Map>(); protected getSnapshot(): PostManagerSnapshot { return { listKeys: [...this.memoryCache.keys()], detailKeys: [...this.detailCache.keys()], }; } // ==================== 列表相关 ==================== private listKey(type: string, page: number, pageSize: number): string { return `list:${type}:${page}:${pageSize}`; } /** * 获取帖子列表(传统分页模式) */ async getPosts( type: PostListTab = 'hot', page = 1, pageSize = POST_LIST_PAGE_SIZE, forceRefresh = false ): Promise { const key = this.listKey(type, page, pageSize); // 检查有效缓存 if (!forceRefresh && this.hasValidCache(key)) { return this.getFromCache(key)!; } // 过期缓存:后台刷新,立即返回旧数据 if (!forceRefresh && this.hasExpiredCache(key)) { this.refreshPostsInBackground(key, type, page, pageSize); return this.getFromCache(key)!; } // 无缓存:发起请求 return this.dedupe(`posts:${key}`, async () => { const response = await postService.getPosts(page, pageSize, type); const posts = response.list || []; this.setCache(key, posts, LIST_TTL); this.notify({ type: 'list_updated', payload: { key, posts }, timestamp: Date.now(), }); return posts; }); } private refreshPostsInBackground( key: string, type: PostListTab, page: number, pageSize: number ): void { this.dedupe(`posts:bg:${key}`, async () => { const response = await postService.getPosts(page, pageSize, type); const posts = response.list || []; this.setCache(key, posts, LIST_TTL); this.notify({ type: 'list_updated', payload: { key, posts }, timestamp: Date.now(), }); return posts; }).catch((error) => { this.notify({ type: 'error', payload: { error, context: 'refreshPostsInBackground' }, timestamp: Date.now(), }); }); } /** * 创建帖子列表数据源(用于 Sources 模式) */ createPostListSource( options: { tab?: PostListTab; channelId?: string; pageSize?: number } = {}, kind: RemotePostListSourceKind = 'cursor' ): IPostListPagedSource { return createRemotePostListSource(kind, options); } // ==================== 详情相关 ==================== /** * 获取帖子详情 */ async getPostDetail(postId: string, forceRefresh = false): Promise { const cached = this.detailCache.get(postId); // 有效缓存 if (!forceRefresh && cached && !isCacheExpired(cached)) { return cached.data; } // 过期缓存:后台刷新 if (!forceRefresh && cached && isCacheExpired(cached) && cached.data) { this.refreshPostDetailInBackground(postId); return cached.data; } // 无缓存:发起请求 return this.dedupe(`posts:detail:${postId}`, async () => { const post = await postService.getPost(postId); this.detailCache.set(postId, createCacheEntry(post, DETAIL_TTL)); this.notify({ type: 'detail_updated', payload: { postId, post }, timestamp: Date.now(), }); return post; }); } private refreshPostDetailInBackground(postId: string): void { this.dedupe(`posts:detail:bg:${postId}`, async () => { const post = await postService.getPost(postId); this.detailCache.set(postId, createCacheEntry(post, DETAIL_TTL)); this.notify({ type: 'detail_updated', payload: { postId, post }, timestamp: Date.now(), }); return post; }).catch((error) => { this.notify({ type: 'error', payload: { error, context: 'refreshPostDetailInBackground' }, timestamp: Date.now(), }); }); } // ==================== 缓存管理 ==================== /** * 使缓存失效 */ invalidate(postId?: string): void { if (postId) { this.detailCache.delete(postId); return; } this.clearCache(); this.detailCache.clear(); } /** * 清除所有数据 */ clear(): void { this.clearCache(); this.detailCache.clear(); this.clearPendingRequests(); } } export const postManager = new PostManager();