// 消息历史记录管理器 - 微信小程序专用 // 处理消息历史记录的本地缓存、分页加载、存储优化等 const apiClient = require('./api-client.js'); /** * 消息历史记录管理器 * 功能: * 1. 消息历史记录缓存 * 2. 分页加载优化 * 3. 存储空间管理 * 4. 消息去重和排序 * 5. 离线消息处理 * 6. 数据压缩存储 */ class MessageHistoryManager { constructor() { this.isInitialized = false; // 历史记录配置 this.historyConfig = { // 每页消息数量 pageSize: 20, // 本地缓存的最大消息数量(每个会话) maxCachedMessages: 500, // 缓存过期时间(毫秒) cacheExpireTime: 24 * 60 * 60 * 1000, // 24小时 // 存储压缩阈值(字节) compressionThreshold: 1024, // 自动清理间隔(毫秒) cleanupInterval: 60 * 60 * 1000, // 1小时 // 预加载页数 preloadPages: 2 }; // 消息缓存 Map this.messageCache = new Map(); // 加载状态 Map this.loadingStates = new Map(); // 存储统计 this.storageStats = { totalSize: 0, messageCount: 0, conversationCount: 0, lastCleanup: 0 }; // 清理定时器 this.cleanupTimer = null; this.init(); } // 初始化历史记录管理器 async init() { if (this.isInitialized) return; console.log('📚 初始化消息历史记录管理器...'); try { // 加载缓存的消息 await this.loadCachedMessages(); // 计算存储统计 this.calculateStorageStats(); // 启动定时清理 this.startCleanupTimer(); this.isInitialized = true; console.log('✅ 消息历史记录管理器初始化完成'); } catch (error) { console.error('❌ 消息历史记录管理器初始化失败:', error); } } // 获取会话消息历史 async getConversationHistory(conversationId, options = {}) { try { console.log('📚 获取会话消息历史:', conversationId); const { page = 1, pageSize = this.historyConfig.pageSize, forceRefresh = false, loadDirection = 'up' // 'up' 向上加载更早的消息, 'down' 向下加载更新的消息 } = options; // 获取或创建消息缓存 let messageCache = this.getMessageCache(conversationId); if (!messageCache) { messageCache = this.createMessageCache(conversationId); } // 检查是否需要从服务器加载 const needServerLoad = forceRefresh || this.shouldLoadFromServer(messageCache, page, pageSize, loadDirection); if (needServerLoad) { // 从服务器加载消息 const serverResult = await this.loadMessagesFromServer( conversationId, page, pageSize, loadDirection, messageCache ); if (!serverResult.success) { return serverResult; } } // 从缓存获取消息 const messages = this.getMessagesFromCache(messageCache, page, pageSize, loadDirection); return { success: true, data: { messages: messages, page: page, pageSize: pageSize, total: messageCache.totalCount, hasMore: this.hasMoreMessages(messageCache, page, pageSize, loadDirection), cached: !needServerLoad } }; } catch (error) { console.error('❌ 获取会话消息历史失败:', error); return { success: false, error: error.message }; } } // 预加载消息 async preloadMessages(conversationId, currentPage = 1) { try { console.log('📚 预加载消息:', conversationId); const preloadPromises = []; // 预加载后续页面 for (let i = 1; i <= this.historyConfig.preloadPages; i++) { const nextPage = currentPage + i; preloadPromises.push( this.getConversationHistory(conversationId, { page: nextPage, loadDirection: 'up' }) ); } // 并行执行预加载 await Promise.allSettled(preloadPromises); console.log('✅ 消息预加载完成'); } catch (error) { console.error('❌ 消息预加载失败:', error); } } // 添加新消息到缓存 addMessageToCache(conversationId, message) { try { let messageCache = this.getMessageCache(conversationId); if (!messageCache) { messageCache = this.createMessageCache(conversationId); } // 检查消息是否已存在 const existingIndex = messageCache.messages.findIndex(m => m.id === message.id); if (existingIndex !== -1) { // 更新现有消息 messageCache.messages[existingIndex] = message; } else { // 添加新消息(按时间排序) const insertIndex = this.findInsertIndex(messageCache.messages, message); messageCache.messages.splice(insertIndex, 0, message); messageCache.totalCount++; } // 限制缓存大小 this.limitCacheSize(messageCache); // 更新缓存时间 messageCache.lastUpdated = Date.now(); // 保存到本地存储 this.saveMessageCache(conversationId, messageCache); console.log('📚 消息已添加到缓存:', message.id); } catch (error) { console.error('❌ 添加消息到缓存失败:', error); } } // 更新消息状态 updateMessageInCache(conversationId, messageId, updates) { try { const messageCache = this.getMessageCache(conversationId); if (!messageCache) return false; const messageIndex = messageCache.messages.findIndex(m => m.id === messageId); if (messageIndex === -1) return false; // 更新消息 messageCache.messages[messageIndex] = { ...messageCache.messages[messageIndex], ...updates }; // 更新缓存时间 messageCache.lastUpdated = Date.now(); // 保存到本地存储 this.saveMessageCache(conversationId, messageCache); console.log('📚 消息状态已更新:', messageId); return true; } catch (error) { console.error('❌ 更新消息状态失败:', error); return false; } } // 删除消息 deleteMessageFromCache(conversationId, messageId) { try { const messageCache = this.getMessageCache(conversationId); if (!messageCache) return false; const messageIndex = messageCache.messages.findIndex(m => m.id === messageId); if (messageIndex === -1) return false; // 删除消息 messageCache.messages.splice(messageIndex, 1); messageCache.totalCount--; // 更新缓存时间 messageCache.lastUpdated = Date.now(); // 保存到本地存储 this.saveMessageCache(conversationId, messageCache); console.log('📚 消息已从缓存删除:', messageId); return true; } catch (error) { console.error('❌ 删除消息失败:', error); return false; } } // 从服务器加载消息 async loadMessagesFromServer(conversationId, page, pageSize, loadDirection, messageCache) { try { // 设置加载状态 this.setLoadingState(conversationId, true); // 计算请求参数 const requestParams = this.calculateRequestParams( messageCache, page, pageSize, loadDirection ); // 调用API const response = await apiClient.request({ url: '/api/v1/messages/history', method: 'GET', data: { conversationId: conversationId, ...requestParams } }); if (response.success) { // 处理返回的消息 const messages = response.data.messages || []; const total = response.data.total || 0; // 更新缓存 this.updateCacheWithServerData(messageCache, messages, total, loadDirection); // 保存到本地存储 this.saveMessageCache(conversationId, messageCache); console.log(`📚 从服务器加载了 ${messages.length} 条消息`); return { success: true }; } else { throw new Error(response.error || '加载消息失败'); } } catch (error) { console.error('❌ 从服务器加载消息失败:', error); return { success: false, error: error.message }; } finally { this.setLoadingState(conversationId, false); } } // 计算请求参数 calculateRequestParams(messageCache, page, pageSize, loadDirection) { const params = { pageSize: pageSize }; if (loadDirection === 'up') { // 向上加载更早的消息 if (messageCache.messages.length > 0) { const oldestMessage = messageCache.messages[messageCache.messages.length - 1]; params.beforeTimestamp = oldestMessage.timestamp; } } else { // 向下加载更新的消息 if (messageCache.messages.length > 0) { const newestMessage = messageCache.messages[0]; params.afterTimestamp = newestMessage.timestamp; } } return params; } // 更新缓存数据 updateCacheWithServerData(messageCache, newMessages, total, loadDirection) { if (loadDirection === 'up') { // 向上加载:添加到数组末尾(更早的消息) messageCache.messages.push(...newMessages); } else { // 向下加载:添加到数组开头(更新的消息) messageCache.messages.unshift(...newMessages); } // 去重和排序 this.deduplicateAndSortMessages(messageCache); // 更新总数 messageCache.totalCount = Math.max(total, messageCache.messages.length); // 限制缓存大小 this.limitCacheSize(messageCache); // 更新时间戳 messageCache.lastUpdated = Date.now(); } // 消息去重和排序 deduplicateAndSortMessages(messageCache) { // 去重 const uniqueMessages = new Map(); messageCache.messages.forEach(message => { uniqueMessages.set(message.id, message); }); // 排序(最新的在前面) messageCache.messages = Array.from(uniqueMessages.values()) .sort((a, b) => b.timestamp - a.timestamp); } // 查找插入位置 findInsertIndex(messages, newMessage) { for (let i = 0; i < messages.length; i++) { if (newMessage.timestamp > messages[i].timestamp) { return i; } } return messages.length; } // 限制缓存大小 limitCacheSize(messageCache) { if (messageCache.messages.length > this.historyConfig.maxCachedMessages) { // 保留最新的消息 const keepCount = Math.floor(this.historyConfig.maxCachedMessages * 0.8); messageCache.messages = messageCache.messages.slice(0, keepCount); console.log(`📚 缓存大小已限制到 ${keepCount} 条消息`); } } // 获取消息缓存 getMessageCache(conversationId) { return this.messageCache.get(conversationId); } // 创建消息缓存 createMessageCache(conversationId) { const cache = { conversationId: conversationId, messages: [], totalCount: 0, lastUpdated: Date.now(), loadedPages: new Set(), hasMoreUp: true, hasMoreDown: false }; this.messageCache.set(conversationId, cache); return cache; } // 从缓存获取消息 getMessagesFromCache(messageCache, page, pageSize, loadDirection) { const startIndex = (page - 1) * pageSize; const endIndex = startIndex + pageSize; return messageCache.messages.slice(startIndex, endIndex); } // 检查是否有更多消息 hasMoreMessages(messageCache, page, pageSize, loadDirection) { if (loadDirection === 'up') { return messageCache.hasMoreUp && (page * pageSize) < messageCache.totalCount; } else { return messageCache.hasMoreDown; } } // 检查是否需要从服务器加载 shouldLoadFromServer(messageCache, page, pageSize, loadDirection) { // 如果缓存为空,需要加载 if (messageCache.messages.length === 0) { return true; } // 如果请求的页面超出缓存范围,需要加载 const startIndex = (page - 1) * pageSize; const endIndex = startIndex + pageSize; if (endIndex > messageCache.messages.length && messageCache.hasMoreUp) { return true; } // 如果缓存过期,需要刷新 const cacheAge = Date.now() - messageCache.lastUpdated; if (cacheAge > this.historyConfig.cacheExpireTime) { return true; } return false; } // 设置加载状态 setLoadingState(conversationId, loading) { this.loadingStates.set(conversationId, { loading: loading, timestamp: Date.now() }); } // 获取加载状态 getLoadingState(conversationId) { const state = this.loadingStates.get(conversationId); return state ? state.loading : false; } // 保存消息缓存到本地存储 saveMessageCache(conversationId, messageCache) { try { const cacheKey = `message_cache_${conversationId}`; const cacheData = this.compressMessageCache(messageCache); wx.setStorageSync(cacheKey, cacheData); } catch (error) { console.error('❌ 保存消息缓存失败:', error); } } // 加载缓存的消息 async loadCachedMessages() { try { const storageInfo = wx.getStorageInfoSync(); const cacheKeys = storageInfo.keys.filter(key => key.startsWith('message_cache_')); for (const key of cacheKeys) { try { const conversationId = key.replace('message_cache_', ''); const cacheData = wx.getStorageSync(key); if (cacheData) { const messageCache = this.decompressMessageCache(cacheData); this.messageCache.set(conversationId, messageCache); } } catch (error) { console.error(`❌ 加载缓存失败 [${key}]:`, error); // 删除损坏的缓存 wx.removeStorageSync(key); } } console.log(`📚 加载了 ${this.messageCache.size} 个会话的消息缓存`); } catch (error) { console.error('❌ 加载缓存消息失败:', error); } } // 压缩消息缓存 compressMessageCache(messageCache) { try { const data = JSON.stringify(messageCache); // 如果数据较大,可以考虑压缩 if (data.length > this.historyConfig.compressionThreshold) { // 这里可以实现压缩算法 // 目前直接返回原数据 return { compressed: false, data: messageCache }; } return { compressed: false, data: messageCache }; } catch (error) { console.error('❌ 压缩消息缓存失败:', error); return { compressed: false, data: messageCache }; } } // 解压消息缓存 decompressMessageCache(cacheData) { try { if (cacheData.compressed) { // 这里可以实现解压算法 return cacheData.data; } return cacheData.data; } catch (error) { console.error('❌ 解压消息缓存失败:', error); return null; } } // 计算存储统计 calculateStorageStats() { let totalSize = 0; let messageCount = 0; for (const [conversationId, cache] of this.messageCache) { messageCount += cache.messages.length; // 估算缓存大小 const cacheSize = JSON.stringify(cache).length; totalSize += cacheSize; } this.storageStats = { totalSize: totalSize, messageCount: messageCount, conversationCount: this.messageCache.size, lastCleanup: Date.now() }; } // 启动定时清理 startCleanupTimer() { if (this.cleanupTimer) { clearInterval(this.cleanupTimer); } this.cleanupTimer = setInterval(() => { this.performCleanup(); }, this.historyConfig.cleanupInterval); } // 执行清理 performCleanup() { try { console.log('📚 执行消息缓存清理...'); const now = Date.now(); let cleanedCount = 0; for (const [conversationId, cache] of this.messageCache) { // 清理过期缓存 const cacheAge = now - cache.lastUpdated; if (cacheAge > this.historyConfig.cacheExpireTime * 2) { this.messageCache.delete(conversationId); wx.removeStorageSync(`message_cache_${conversationId}`); cleanedCount++; } } // 更新统计 this.calculateStorageStats(); console.log(`📚 清理完成,删除了 ${cleanedCount} 个过期缓存`); } catch (error) { console.error('❌ 消息缓存清理失败:', error); } } // 清除会话缓存 clearConversationCache(conversationId) { this.messageCache.delete(conversationId); wx.removeStorageSync(`message_cache_${conversationId}`); console.log('📚 已清除会话缓存:', conversationId); } // 清除所有缓存 clearAllCache() { for (const conversationId of this.messageCache.keys()) { wx.removeStorageSync(`message_cache_${conversationId}`); } this.messageCache.clear(); this.calculateStorageStats(); console.log('📚 已清除所有消息缓存'); } // 获取存储统计 getStorageStats() { this.calculateStorageStats(); return { ...this.storageStats }; } // 获取会话统计 getConversationStats(conversationId) { const cache = this.getMessageCache(conversationId); if (!cache) { return null; } return { messageCount: cache.messages.length, totalCount: cache.totalCount, lastUpdated: cache.lastUpdated, cacheAge: Date.now() - cache.lastUpdated, hasMoreUp: cache.hasMoreUp, hasMoreDown: cache.hasMoreDown }; } // 重置管理器 reset() { this.clearAllCache(); this.loadingStates.clear(); if (this.cleanupTimer) { clearInterval(this.cleanupTimer); this.cleanupTimer = null; } } // 销毁管理器 destroy() { this.reset(); this.isInitialized = false; } } // 创建全局实例 const messageHistoryManager = new MessageHistoryManager(); module.exports = messageHistoryManager;