fix: Login

This commit is contained in:
手瓜一十雪 2024-07-22 14:18:04 +08:00
parent cf9f785193
commit 186668c075
5 changed files with 12 additions and 685 deletions

View File

@ -1,36 +0,0 @@
import { sleep } from '@/common/utils/helper';
import { logError } from './log';
type AsyncQueueTask = (() => void) | (()=>Promise<void>);
// 2024.7.13 废弃
export class AsyncQueue {
private tasks: (AsyncQueueTask)[] = [];
public addTask(task: AsyncQueueTask) {
this.tasks.push(task);
// console.log('addTask', this.tasks.length);
if (this.tasks.length === 1) {
this.runQueue().then().catch(()=>{});
}
}
private async runQueue() {
// console.log('runQueue', this.tasks.length);
while (this.tasks.length > 0) {
const task = this.tasks[0];
// console.log('typeof task', typeof task);
try {
const taskRet = task();
// console.log('type of taskRet', typeof taskRet, taskRet);
if (taskRet instanceof Promise) {
await taskRet;
}
} catch (e) {
// console.error(e);
logError(e);
}
this.tasks.shift();
await sleep(100);
}
}
}

View File

@ -1,161 +0,0 @@
import { logError, logDebug } from '@/common/utils/log';
type group_id = number;
type user_id = number;
class cacheNode<T> {
value: T;
groupId: group_id;
userId: user_id;
prev: cacheNode<T> | null;
next: cacheNode<T> | null;
timestamp: number;
constructor(groupId: group_id, userId: user_id, value: T) {
this.groupId = groupId;
this.userId = userId;
this.value = value;
this.prev = null;
this.next = null;
this.timestamp = Date.now();
}
}
type cache<T, K = { [key: user_id]: cacheNode<T> }> = { [key: group_id]: K };
type removeObject<T> = cache<T, { userId: user_id, value: T }[]>
class LRU<T> {
private maxAge: number;
private maxSize: number;
private currentSize: number;
private cache: cache<T>;
private head: cacheNode<T> | null = null;
private tail: cacheNode<T> | null = null;
private onFuncs: ((node: removeObject<T>) => void)[] = [];
constructor(maxAge: number = 6e4 * 3, maxSize: number = 1e4) {
this.maxAge = maxAge;
this.maxSize = maxSize;
this.cache = Object.create(null);
this.currentSize = 0;
if (maxSize == 0) return;
setInterval(() => this.removeExpired(), this.maxAge);
}
// 移除LRU节点
private removeLRUNode(node: cacheNode<T>) {
logDebug(
'removeLRUNode',
node.groupId,
node.userId,
node.value,
this.currentSize
);
node.prev = node.next = null;
delete this.cache[node.groupId][node.userId];
this.removeNode(node);
this.onFuncs.forEach((func) => func({ [node.groupId]: [node] }));
this.currentSize--;
}
public on(func: (node: removeObject<T>) => void) {
this.onFuncs.push(func);
}
private removeExpired() {
const now = Date.now();
let current = this.tail;
let totalNodeNum = 0;
const removeObject: cache<T, { userId: user_id, value: T }[]> = {};
while (current && now - current.timestamp > this.maxAge) {
// 收集节点
if (!removeObject[current.groupId]) removeObject[current.groupId] = [];
removeObject[current.groupId].push({ userId: current.userId, value: current.value });
// 删除LRU节点
delete this.cache[current.groupId][current.userId];
current = current.prev;
totalNodeNum++;
this.currentSize--;
}
if (!totalNodeNum) return;
// 跟新链表指向
if (current) { current.next = null; } else { this.head = null; }
this.tail = current;
this.onFuncs.forEach(func => func(removeObject));
}
private addNode(node: cacheNode<T>) {
node.next = this.head;
if (this.head) this.head.prev = node;
if (!this.tail) this.tail = node;
this.head = node;
}
private removeNode(node: cacheNode<T>) {
if (node.prev) node.prev.next = node.next;
if (node.next) node.next.prev = node.prev;
if (node === this.head) this.head = node.next;
if (node === this.tail) this.tail = node.prev;
}
private moveToHead(node: cacheNode<T>) {
if (this.head === node) return;
this.removeNode(node);
this.addNode(node);
node.prev = null;
}
public set(groupId: group_id, userId: user_id, value: T) {
if (!this.cache[groupId]) {
this.cache[groupId] = Object.create(null);
}
const groupObject = this.cache[groupId];
if (groupObject[userId]) {
const node = groupObject[userId];
node.value = value;
node.timestamp = Date.now();
this.moveToHead(node);
} else {
const node = new cacheNode(groupId, userId, value);
groupObject[userId] = node;
this.currentSize++;
this.addNode(node);
if (this.currentSize > this.maxSize) {
const tail = this.tail!;
this.removeLRUNode(tail);
}
}
}
public get(groupId: group_id): { userId: user_id; value: T }[];
public get(groupId: group_id, userId: user_id): null | { userId: user_id; value: T };
public get(groupId: group_id, userId?: user_id): any {
const groupObject = this.cache[groupId];
if (!groupObject) return userId === undefined ? [] : null;
if (userId === undefined) {
return Object.entries(groupObject).map(([userId, { value }]) => ({
userId: Number(userId),
value,
}));
}
if (groupObject[userId]) {
return { userId, value: groupObject[userId].value };
}
return null;
}
}
export default LRU;

View File

@ -25,6 +25,7 @@ class LimitedHashTable<K, V> {
// console.log(this.valueToKey);
// console.log('---------------');
while (this.keyToValue.size > this.maxSize || this.valueToKey.size > this.maxSize) {
console.log(this.keyToValue.size > this.maxSize, this.valueToKey.size > this.maxSize);
const oldestKey = this.keyToValue.keys().next().value;
this.valueToKey.delete(this.keyToValue.get(oldestKey)!);
this.keyToValue.delete(oldestKey);

View File

@ -1,477 +0,0 @@
// import { ElementType, FileElement, PicElement, PttElement, RawMessage, VideoElement } from '../../core/src/entities';
// import sqlite3 from 'sqlite3';
// import { log, logDebug, logError } from '@/common/utils/log';
// import { NTQQMsgApi } from '@/core';
// import LRU from '@/common/utils/LRUCache';
// export interface IRember {
// last_sent_time: number;
// join_time: number;
// user_id: number;
// }
// type DBMsg = {
// id: number,
// shortId: number,
// longId: string,
// seq: number,
// peerUid: string,
// chatType: number,
// }
// type DBFile = {
// name: string; // 文件名
// path: string;
// url: string;
// size: number;
// uuid: string;
// msgId: string;
// elementId: string;
// element: PicElement | VideoElement | FileElement | PttElement;
// elementType: ElementType.PIC | ElementType.VIDEO | ElementType.FILE | ElementType.PTT;
// }
// class DBUtilBase {
// protected db: sqlite3.Database | undefined;
// async init(dbPath: string) {
// if (this.db) {
// return;
// }
// return new Promise<void>((resolve, reject) => {
// this.db = new sqlite3.Database(dbPath, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
// if (err) {
// logError('Could not connect to database', err);
// reject(err);
// return;
// }
// this.createTable();
// resolve();
// });
// });
// }
// protected createTable() {
// throw new Error('Method not implemented.');
// }
// close() {
// this.db?.close();
// }
// }
// class DBUtil extends DBUtilBase {
// private msgCache: Map<string | number, RawMessage> = new Map<string | number, RawMessage>();
// private globalMsgShortId = -2147483640;
// private groupIds: number[] = [];
// private LURCache = new LRU<number>();
// private LastSentCache = new (class {
// private cache: { gid: number; uid: number }[] = [];
// private maxSize: number;
// constructor(maxSize: number = 50000) {
// 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;
// }
// })();
// constructor() {
// super();
// const interval = 1000 * 60 * 10; // 10分钟清理一次缓存
// setInterval(() => {
// logDebug('清理消息缓存');
// this.msgCache.forEach((msg, key) => {
// if ((Date.now() - parseInt(msg.msgTime) * 1000) > interval) {
// this.msgCache.delete(key);
// }
// });
// }, interval);
// }
// async init(dbPath: string) {
// await super.init(dbPath);
// this.globalMsgShortId = await this.getCurrentMaxShortId();
// // 初始化群缓存列表
// this.db!.serialize(() => {
// const sql = 'SELECT * FROM sqlite_master WHERE type=\'table\'';
// this.db!.all(sql, [], (err, rows: { name: string }[]) => {
// if (err) return logError(err);
// rows.forEach((row) => this.groupIds.push(parseInt(row.name)));
// //logDebug(`已加载 ${groupIds.length} 个群`);
// });
// });
// this.LURCache.on(async (nodeObject) => {
// Object.entries(nodeObject).forEach(async ([_groupId, datas]) => {
// const userIds = datas.map(v => v.userId);
// const groupId = Number(_groupId);
// logDebug('插入发言时间', _groupId);
// await this.createGroupInfoTimeTableIfNotExist(groupId);
// const needCreatUsers = await this.getNeedCreatList(groupId, userIds);
// const updateList = needCreatUsers.length > 0 ? datas.filter(user => !needCreatUsers.includes(user.userId)) : datas;
// const insertList = needCreatUsers.map(userId => datas.find(e => userId == e.userId)!);
// logDebug('updateList', updateList);
// logDebug('insertList', insertList);
// if (insertList.length) {
// const insertSql = `INSERT INTO "${groupId}" (last_sent_time, user_id) VALUES ${insertList.map(() => '(?, ?)').join(', ')};`;
// this.db!.all(insertSql, insertList.map(v => [v.value, v.userId]).flat(), err => {
// if (err) {
// logError(`群 ${groupId} 插入失败`);
// logError(`更新Sql : ${insertSql}`);
// }
// });
// }
// if (updateList.length) {
// const updateSql =
// `UPDATE "${groupId}" SET last_sent_time = CASE ` +
// updateList.map(v => `WHEN user_id = ${v.userId} THEN ${v.value}`).join(' ') +
// ' ELSE last_sent_time END WHERE user_id IN ' +
// `(${updateList.map(v => v.userId).join(', ')});`;
// this.db!.all(updateSql, [], err => {
// if (err) {
// logError(`群 ${groupId} 跟新失败`);
// logError(`更新Sql : ${updateSql}`);
// }
// });
// }
// });
// });
// }
// async getNeedCreatList(groupId: number, userIds: number[]) {
// // 获取缓存中没有的
// const unhas = userIds.filter(userId => !this.LastSentCache.get(groupId, userId));
// if (unhas.length == 0) {
// logDebug('缓存全部命中');
// return [];
// }
// logDebug('缓存未全部命中');
// const sql = `SELECT * FROM "${groupId}" WHERE user_id IN (${unhas.map(() => '?').join(',')})`;
// return new Promise<number[]>((resolve) => {
// this.db!.all(sql, unhas, (err, rows: { user_id: number }[]) => {
// const has = rows.map(v => v.user_id);
// const needCreatUsers = unhas.filter(userId => !has.includes(userId));
// if (needCreatUsers.length == 0) {
// logDebug('数据库全部命中');
// } else {
// logDebug('数据库未全部命中');
// }
// resolve(needCreatUsers);
// });
// });
// }
// async createGroupInfoTimeTableIfNotExist(groupId: number) {
// const createTableSQL = (groupId: number) =>
// `CREATE TABLE IF NOT EXISTS "${groupId}" (
// user_id INTEGER,
// last_sent_time INTEGER,
// join_time INTEGER,
// PRIMARY KEY (user_id)
// );`;
// if (this.groupIds.includes(groupId)) {
// return;
// }
// return new Promise((resolve, reject) => {
// const sql = createTableSQL(groupId);
// this.db!.all(sql, (err) => {
// if (err) {
// reject(err);
// return;
// }
// this.groupIds.push(groupId);
// resolve(true);
// });
// });
// }
// protected createTable() {
// // 消息记录
// const createTableSQL = `
// CREATE TABLE IF NOT EXISTS msgs (
// id INTEGER PRIMARY KEY AUTOINCREMENT,
// shortId INTEGER NOT NULL UNIQUE,
// longId TEXT NOT NULL UNIQUE,
// seq INTEGER NOT NULL,
// peerUid TEXT NOT NULL,
// chatType INTEGER NOT NULL
// )`;
// this.db!.run(createTableSQL, function (err) {
// if (err) {
// logError('Could not create table msgs', err.stack);
// }
// });
// // 文件缓存
// const createFileTableSQL = `
// CREATE TABLE IF NOT EXISTS files (
// id INTEGER PRIMARY KEY AUTOINCREMENT,
// name TEXT NOT NULL,
// path TEXT NOT NULL,
// url TEXT,
// size INTEGER NOT NULL,
// uuid TEXT,
// elementType INTEGER,
// element TEXT NOT NULL,
// elementId TEXT NOT NULL,
// msgId TEXT NOT NULL
// )`;
// this.db!.run(createFileTableSQL, function (err) {
// if (err) {
// logError('Could not create table files', err);
// }
// });
// }
// private async getCurrentMaxShortId() {
// return new Promise<number>((resolve, reject) => {
// this.db!.get('SELECT MAX(shortId) as maxId FROM msgs', (err, row: { maxId: number }) => {
// if (err) {
// logDebug('Could not get max short id, Use default -2147483640', err);
// return resolve(-2147483640);
// }
// logDebug('数据库中消息最大短id', row?.maxId);
// resolve(row?.maxId ?? -2147483640);
// });
// });
// }
// private async getMsg(query: string, params: any[]) {
// const stmt = this.db!.prepare(query);
// return new Promise<RawMessage | null>((resolve, reject) => {
// stmt.get(...params, (err: any, row: DBMsg) => {
// // log("getMsg", row, err);
// if (err) {
// logError('Could not get msg', err, query, params);
// return resolve(null);
// }
// if (!row) {
// // logDebug('不存在数据库中的消息,不进行处理', query, params);
// resolve(null);
// return;
// }
// const msgId = row.longId;
// NTQQMsgApi.getMsgsByMsgId({ peerUid: row.peerUid, chatType: row.chatType }, [msgId]).then(res => {
// const msg = res.msgList[0];
// if (!msg) {
// resolve(null);
// return;
// }
// msg.id = row.shortId;
// resolve(msg);
// }).catch(e => {
// resolve(null);
// });
// });
// });
// }
// async getMsgByShortId(shortId: number): Promise<RawMessage | null> {
// if (this.msgCache.has(shortId)) {
// return this.msgCache.get(shortId)!;
// }
// const getStmt = 'SELECT * FROM msgs WHERE shortId = ?';
// return this.getMsg(getStmt, [shortId]);
// }
// async getMsgByLongId(longId: string): Promise<RawMessage | null> {
// if (this.msgCache.has(longId)) {
// return this.msgCache.get(longId)!;
// }
// return this.getMsg('SELECT * FROM msgs WHERE longId = ?', [longId]);
// }
// async getMsgBySeq(peerUid: string, seq: string): Promise<RawMessage | null> {
// const stmt = 'SELECT * FROM msgs WHERE peerUid = ? AND seq = ?';
// return this.getMsg(stmt, [peerUid, seq]);
// }
// async addMsg(msg: RawMessage, update = true): Promise<number> {
// const existMsg = await this.getMsgByLongId(msg.msgId);
// if (existMsg) {
// // logDebug('消息已存在,更新数据库', msg.msgId);
// if (update) this.updateMsg(msg).then();
// return existMsg.id!;
// }
// const stmt = this.db!.prepare('INSERT INTO msgs (shortId, longId, seq, peerUid, chatType) VALUES (?, ?, ?, ?, ?)');
// // const runAsync = promisify(stmt.run.bind(stmt));
// const shortId = ++this.globalMsgShortId;
// msg.id = shortId;
// //logDebug(`记录消息到数据库, 消息长id: ${msg.msgId}, 短id: ${msg.id}`);
// this.msgCache.set(shortId, msg);
// this.msgCache.set(msg.msgId, msg);
// stmt.run(this.globalMsgShortId, msg.msgId, msg.msgSeq.toString(), msg.peerUid, msg.chatType, (err: any) => {
// if (err) {
// if (err.errno === 19) {
// this.getMsgByLongId(msg.msgId).then((msg: RawMessage | null) => {
// if (msg) {
// this.msgCache.set(shortId, msg);
// this.msgCache.set(msg.msgId, msg);
// // logDebug('获取消息短id成功', msg.id);
// } else {
// logError('db could not get msg by long id', err);
// }
// }).catch(e => logError('db getMsgByLongId error', e));
// } else {
// logError('db could not add msg', err);
// }
// }
// });
// return shortId;
// }
// async updateMsg(msg: RawMessage) {
// const existMsg = this.msgCache.get(msg.msgId);
// if (existMsg) {
// Object.assign(existMsg, msg);
// }
// //logDebug(`更新消息, shortId:${msg.id}, seq: ${msg.msgSeq}, msgId: ${msg.msgId}`);
// const stmt = this.db!.prepare('UPDATE msgs SET seq=? WHERE longId=?');
// stmt.run(msg.msgSeq, msg.msgId, (err: any) => {
// if (err) {
// logError('updateMsg db error', err);
// }
// });
// }
// async addFileCache(file: DBFile) {
// const stmt = this.db!.prepare('INSERT INTO files (name, path, url, size, uuid, elementType ,element, elementId, msgId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
// return new Promise((resolve, reject) => {
// stmt.run(file.name, file.path, file.url, file.size, file.uuid,
// file.elementType,
// JSON.stringify(file.element),
// file.elementId,
// file.msgId,
// function (err: any) {
// if (err) {
// logError('db could not add file', err);
// reject(err);
// }
// resolve(null);
// });
// });
// }
// private async getFileCache(query: string, params: any[]) {
// const stmt = this.db!.prepare(query);
// return new Promise<DBFile | null>((resolve, reject) => {
// stmt.get(...params, (err: any, row: DBFile & { element: string }) => {
// if (err) {
// logError('db could not get file cache', err);
// reject(err);
// }
// if (row) {
// row.element = JSON.parse(row.element);
// }
// resolve(row);
// });
// });
// }
// async getFileCacheByName(name: string): Promise<DBFile | null> {
// return this.getFileCache('SELECT * FROM files WHERE name = ?', [name]);
// }
// async getFileCacheByUuid(uuid: string): Promise<DBFile | null> {
// return this.getFileCache('SELECT * FROM files WHERE uuid = ?', [uuid]);
// }
// // todo: 是否所有的文件都有uuid语音消息有没有uuid
// async updateFileCache(file: DBFile) {
// const stmt = this.db!.prepare('UPDATE files SET path = ?, url = ? WHERE uuid = ?');
// return new Promise((resolve, reject) => {
// stmt.run(file.path, file.url, file.uuid, function (err: any) {
// if (err) {
// logError('db could not update file cache', err);
// reject(err);
// }
// resolve(null);
// });
// });
// }
// async getLastSentTimeAndJoinTime(
// groupId: number
// ): Promise<IRember[]> {
// logDebug('读取发言时间', groupId);
// return new Promise<IRember[]>((resolve, reject) => {
// this.db!.all(`SELECT * FROM "${groupId}" `, (err, rows: IRember[]) => {
// const cache = this.LURCache.get(groupId).map(e => ({ user_id: e.userId, last_sent_time: e.value }));
// if (err) {
// logError('查询发言时间失败', groupId);
// return resolve(cache.map(e => ({ ...e, join_time: 0 })));
// }
// Object.assign(rows, cache);
// logDebug('查询发言时间成功', groupId, rows);
// resolve(rows);
// });
// });
// }
// insertLastSentTime(
// groupId: number,
// userId: number,
// time: number
// ) {
// this.LURCache.set(groupId, userId, time);
// }
// async insertJoinTime(
// groupId: number,
// userId: number,
// time: number
// ) {
// await this.createGroupInfoTimeTableIfNotExist(groupId);
// this.db!.all(
// `INSERT OR REPLACE INTO "${groupId}" (user_id, last_sent_time, join_time) VALUES (?,?,?)`,
// [userId, time, time],
// (err) => {
// if (err)
// logError(err),
// Promise.reject(),
// logError('插入入群时间失败', userId, groupId);
// }
// );
// }
// }
// // export const dbUtil = new DBUtil();

View File

@ -84,15 +84,15 @@ export class NapCatCore {
fs.mkdirSync(dataPath, { recursive: true });
logDebug('本账号数据/缓存目录:', dataPath);
// dbUtil.init(path.resolve(dataPath, `./${arg.uin}-v2.db`)).then(() => {
// this.initDataListener();
// this.onLoginSuccessFuncList.map(cb => {
// new Promise((resolve, reject) => {
// const result = cb(arg.uin, arg.uid);
// if (result instanceof Promise) {
// result.then(resolve).catch(reject);
// }
// }).then();
// });
this.initDataListener();
this.onLoginSuccessFuncList.map(cb => {
new Promise((resolve, reject) => {
const result = cb(arg.uin, arg.uid);
if (result instanceof Promise) {
result.then(resolve).catch(reject);
}
}).then();
});
// }).catch((e) => {
// logError('数据库初始化失败', e);
// });
@ -474,9 +474,9 @@ export class NapCatCore {
const loginList = await this.loginService.getLoginList();
return loginList;
}
checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined ) : boolean {
checkAdminEvent(groupCode: string, memberNew: GroupMember, memberOld: GroupMember | undefined): boolean {
if (memberNew.role !== memberOld?.role) {
log(`${groupCode} ${memberNew.nick} 角色变更为 ${memberNew.role === 3 ? '管理员' : '群员' }`);
log(`${groupCode} ${memberNew.nick} 角色变更为 ${memberNew.role === 3 ? '管理员' : '群员'}`);
return true;
}
return false;