diff --git a/src/onebot11/action/group/LastSendAndJoinRemberLRU.ts b/src/onebot11/action/group/LastSendAndJoinRemberLRU.ts new file mode 100644 index 00000000..2abf0124 --- /dev/null +++ b/src/onebot11/action/group/LastSendAndJoinRemberLRU.ts @@ -0,0 +1,188 @@ +import sqlite3 from "sqlite3"; +import { logError, logDebug } from "@/common/utils/log"; +import { selfInfo } from "@/core/data"; +import { ob11Config } from "@/onebot11/config"; +import LRU from "./LRUCache"; +import path from "path"; + +const dbPath = path.join( + ob11Config.getConfigDir(), + `lastSendAndJoinRember_${selfInfo.uin}.db` +); +const remberDb = new sqlite3.Database(dbPath); + +// 初始化全部的群到内存中 +const groupIds: number[] = []; +remberDb.serialize(() => { + const sql = `SELECT * FROM sqlite_master WHERE type='table'`; + remberDb.all(sql, [], (err, rows: { name: string }[]) => { + if (err) return logError(err); + rows.forEach((row) => groupIds.push(parseInt(row.name))); + logDebug(`已加载 ${groupIds.length} 个群`); + console.log(groupIds); + }); +}); + +const createTableSQL = (groupId: number) => + `CREATE TABLE IF NOT EXISTS "${groupId}" ( + user_id INTEGER, + last_sent_time INTEGER, + join_time INTEGER, + PRIMARY KEY (user_id) + );`; + +async function createTableIfNotExist(groupId: number) { + // 未开启本地记录 + if (!ob11Config.localDB) return; + + logDebug("检测数据表存在", groupId); + if (groupIds.includes(groupId)) { + logDebug("数据表已存在", groupId); + return; + } + + logDebug("创建数据表", groupId); + return new Promise((resolve, reject) => { + const sql = createTableSQL(groupId); + remberDb.all(sql, (err) => { + if (err) { + logError("数据表创建失败", err); + reject(err); + return; + } + groupIds.push(groupId); + logDebug("数据表创建成功", groupId); + resolve(true); + }); + }); +} + +// 入群记录 +export async function insertJoinTime( + groupId: number, + userId: number, + time: number +) { + // 未开启本地记录 + if (!ob11Config.localDB) return; + + logDebug("插入入群时间", userId, groupId); + await createTableIfNotExist(groupId); + remberDb.all( + `INSERT OR REPLACE INTO "${groupId}" (user_id, last_sent_time, join_time) VALUES (?,?,?)`, + [userId, time, time], + (err) => { + if (err) + logError(err), + Promise.reject(), + console.log("插入入群时间失败", userId, groupId); + } + ); +} + +// 发言记录 +const LURCache = new LRU(); +const LastSentCache = new (class { + private cache: { gid: number; uid: number }[] = []; + private maxSize: number; + + constructor(maxSize: number = 5000) { + this.maxSize = maxSize; + } + + get(gid: number, uid: number): boolean { + const exists = this.cache.some( + (entry) => entry.gid === gid && entry.uid === uid + ); + if (!exists) { + this.cache.push({ gid, uid }); + if (this.cache.length > this.maxSize) { + this.cache.shift(); + } + } + + return exists; + } +})(); + +LURCache.on(async (node) => { + const { value: time, groupId, userId } = node; + + logDebug("插入发言时间", userId, groupId); + await createTableIfNotExist(groupId); + + const method = await getDataSetMethod(groupId, userId); + logDebug("插入发言时间方法判断", userId, groupId, method); + + const sql = + method == "update" + ? `UPDATE "${groupId}" SET last_sent_time = ? WHERE user_id = ?` + : `INSERT INTO "${groupId}" (last_sent_time, user_id) VALUES (?, ?)`; + + remberDb.all(sql, [time, userId], (err) => { + if (err) { + return logError("插入/更新发言时间失败", userId, groupId); + } + logDebug("插入/更新发言时间成功", userId, groupId); + }); +}); + +async function getDataSetMethod(groupId: number, userId: number) { + // 缓存记录 + if (LastSentCache.get(groupId, userId)) { + logDebug("缓存命中", userId, groupId); + return "update"; + } + + // 数据库判断 + return new Promise<"insert" | "update">((resolve, reject) => { + remberDb.all( + `SELECT * FROM "${groupId}" WHERE user_id = ?`, + [userId], + (err, rows) => { + if (err) { + logError("查询发言时间存在失败", userId, groupId, err); + return logError("插入发言时间失败", userId, groupId, err); + } + + if (rows.length === 0) { + logDebug("查询发言时间不存在", userId, groupId); + return resolve("insert"); + } + + logDebug("查询发言时间存在", userId, groupId); + resolve("update"); + } + ); + }); +} + +interface IRember { + last_sent_time: number; + join_time: number; + user_id: number; +} +export async function getLastSentTimeAndJoinTime( + groupId: number +): Promise { + logDebug("读取发言时间", groupId); + return new Promise((resolve, reject) => { + remberDb.all(`SELECT * FROM "${groupId}" `, (err, rows: IRember[]) => { + if (err) { + logError("查询发言时间失败", groupId); + return resolve([]); + } + logDebug("查询发言时间成功", groupId, rows); + resolve(rows); + }); + }); +} + +export function insertLastSentTime( + groupId: number, + userId: number, + time: number +) { + if (!ob11Config.localDB) return; + LURCache.set(groupId, userId,time) +}