"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.clearKnownUsers = clearKnownUsers;exports.flushKnownUsers = flushKnownUsers;exports.getGroupMembers = getGroupMembers;exports.getKnownUser = getKnownUser;exports.getKnownUsersStats = getKnownUsersStats;exports.getUserGroups = getUserGroups;exports.listKnownUsers = listKnownUsers;exports.recordKnownUser = recordKnownUser;exports.removeKnownUser = removeKnownUser; var _nodeFs = _interopRequireDefault(require("node:fs")); var _nodePath = _interopRequireDefault(require("node:path"));function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };} /** * 已知用户存储 * 记录与机器人交互过的所有用户 * 支持主动消息和批量通知功能 */ // 已知用户信息接口 // 存储文件路径 const KNOWN_USERS_DIR = _nodePath.default.join( process.env.HOME || "/tmp", ".openclaw", "qqbot", "data" ); const KNOWN_USERS_FILE = _nodePath.default.join(KNOWN_USERS_DIR, "known-users.json"); // 内存缓存 let usersCache = null; // 写入节流配置 const SAVE_THROTTLE_MS = 5000; // 5秒写入一次 let saveTimer = null; let isDirty = false; /** * 确保目录存在 */ function ensureDir() { if (!_nodeFs.default.existsSync(KNOWN_USERS_DIR)) { _nodeFs.default.mkdirSync(KNOWN_USERS_DIR, { recursive: true }); } } /** * 从文件加载用户数据到缓存 */ function loadUsersFromFile() { if (usersCache !== null) { return usersCache; } usersCache = new Map(); try { if (_nodeFs.default.existsSync(KNOWN_USERS_FILE)) { const data = _nodeFs.default.readFileSync(KNOWN_USERS_FILE, "utf-8"); const users = JSON.parse(data); for (const user of users) { // 使用复合键:accountId + type + openid(群组还要加 groupOpenid) const key = makeUserKey(user); usersCache.set(key, user); } console.log(`[known-users] Loaded ${usersCache.size} users from file`); } } catch (err) { console.error(`[known-users] Failed to load users: ${err}`); usersCache = new Map(); } return usersCache; } /** * 保存用户数据到文件(节流版本) */ function saveUsersToFile() { if (!isDirty) return; if (saveTimer) { return; // 已有定时器在等待 } saveTimer = setTimeout(() => { saveTimer = null; doSaveUsersToFile(); }, SAVE_THROTTLE_MS); } /** * 实际执行保存 */ function doSaveUsersToFile() { if (!usersCache || !isDirty) return; try { ensureDir(); const users = Array.from(usersCache.values()); _nodeFs.default.writeFileSync(KNOWN_USERS_FILE, JSON.stringify(users, null, 2), "utf-8"); isDirty = false; console.log(`[known-users] Saved ${users.length} users to file`); } catch (err) { console.error(`[known-users] Failed to save users: ${err}`); } } /** * 强制立即保存(用于进程退出前) */ function flushKnownUsers() { if (saveTimer) { clearTimeout(saveTimer); saveTimer = null; } doSaveUsersToFile(); } /** * 生成用户唯一键 */ function makeUserKey(user) { const base = `${user.accountId}:${user.type}:${user.openid}`; if (user.type === "group" && user.groupOpenid) { return `${base}:${user.groupOpenid}`; } return base; } /** * 记录已知用户(收到消息时调用) * @param user 用户信息(部分字段) */ function recordKnownUser(user) { const cache = loadUsersFromFile(); const key = makeUserKey(user); const now = Date.now(); const existing = cache.get(key); if (existing) { // 更新已存在的用户 existing.lastSeenAt = now; existing.interactionCount++; if (user.nickname && user.nickname !== existing.nickname) { existing.nickname = user.nickname; } console.log(`[known-users] Updated user ${user.openid}, interactions: ${existing.interactionCount}`); } else { // 新用户 const newUser = { openid: user.openid, type: user.type, nickname: user.nickname, groupOpenid: user.groupOpenid, accountId: user.accountId, firstSeenAt: now, lastSeenAt: now, interactionCount: 1 }; cache.set(key, newUser); console.log(`[known-users] New user recorded: ${user.openid} (${user.type})`); } isDirty = true; saveUsersToFile(); } /** * 获取单个用户信息 * @param accountId 机器人账户 ID * @param openid 用户 openid * @param type 消息类型 * @param groupOpenid 群组 openid(可选) */ function getKnownUser( accountId, openid, type = "c2c", groupOpenid) { const cache = loadUsersFromFile(); const key = makeUserKey({ accountId, openid, type, groupOpenid }); return cache.get(key); } /** * 列出所有已知用户 * @param options 筛选选项 */ function listKnownUsers(options) { const cache = loadUsersFromFile(); let users = Array.from(cache.values()); // 筛选 if (options?.accountId) { users = users.filter((u) => u.accountId === options.accountId); } if (options?.type) { users = users.filter((u) => u.type === options.type); } if (options?.activeWithin) { const cutoff = Date.now() - options.activeWithin; users = users.filter((u) => u.lastSeenAt >= cutoff); } // 排序 const sortBy = options?.sortBy ?? "lastSeenAt"; const sortOrder = options?.sortOrder ?? "desc"; users.sort((a, b) => { const aVal = a[sortBy] ?? 0; const bVal = b[sortBy] ?? 0; return sortOrder === "asc" ? aVal - bVal : bVal - aVal; }); // 限制数量 if (options?.limit && options.limit > 0) { users = users.slice(0, options.limit); } return users; } /** * 获取用户统计信息 * @param accountId 机器人账户 ID(可选,不传则返回所有账户的统计) */ function getKnownUsersStats(accountId) { let users = listKnownUsers({ accountId }); const now = Date.now(); const day = 24 * 60 * 60 * 1000; return { totalUsers: users.length, c2cUsers: users.filter((u) => u.type === "c2c").length, groupUsers: users.filter((u) => u.type === "group").length, activeIn24h: users.filter((u) => now - u.lastSeenAt < day).length, activeIn7d: users.filter((u) => now - u.lastSeenAt < 7 * day).length }; } /** * 删除用户记录 * @param accountId 机器人账户 ID * @param openid 用户 openid * @param type 消息类型 * @param groupOpenid 群组 openid(可选) */ function removeKnownUser( accountId, openid, type = "c2c", groupOpenid) { const cache = loadUsersFromFile(); const key = makeUserKey({ accountId, openid, type, groupOpenid }); if (cache.has(key)) { cache.delete(key); isDirty = true; saveUsersToFile(); console.log(`[known-users] Removed user ${openid}`); return true; } return false; } /** * 清除所有用户记录 * @param accountId 机器人账户 ID(可选,不传则清除所有) */ function clearKnownUsers(accountId) { const cache = loadUsersFromFile(); let count = 0; if (accountId) { // 只清除指定账户的用户 for (const [key, user] of cache.entries()) { if (user.accountId === accountId) { cache.delete(key); count++; } } } else { // 清除所有 count = cache.size; cache.clear(); } if (count > 0) { isDirty = true; doSaveUsersToFile(); // 立即保存 console.log(`[known-users] Cleared ${count} users`); } return count; } /** * 获取用户的所有群组(某用户在哪些群里交互过) * @param accountId 机器人账户 ID * @param openid 用户 openid */ function getUserGroups(accountId, openid) { const users = listKnownUsers({ accountId, type: "group" }); return users. filter((u) => u.openid === openid && u.groupOpenid). map((u) => u.groupOpenid); } /** * 获取群组的所有成员 * @param accountId 机器人账户 ID * @param groupOpenid 群组 openid */ function getGroupMembers(accountId, groupOpenid) { return listKnownUsers({ accountId, type: "group" }). filter((u) => u.groupOpenid === groupOpenid); } /* v9-2701782a94e73239 */