diff --git a/.gitignore b/.gitignore index ccce7c6..8eb3824 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ yarn-error.log* .vscode/* /dist/ /logs/ +/private/ diff --git a/src/services/redis/redis.ts b/src/services/redis/redis.ts index 8051c4e..429f7f0 100644 --- a/src/services/redis/redis.ts +++ b/src/services/redis/redis.ts @@ -4,6 +4,7 @@ import tools from '../../utils/core/tool'; import config from '../../utils/core/config'; import redisTool from '../../utils/redis/redisTools'; import IUser from '../../types/user'; +import Persistence from '../../utils/redis/persistence'; class RedisService { private client!: Redis; @@ -107,6 +108,34 @@ class RedisService { return redisTool.reviveDates(deserialized); } + public async persistUser(user: T): Promise { + try { + await this.setObject(`user:${user.qq}`, user); + await Persistence.writeDataLocal(user.name, user); + } catch (err) { + logger.error(err); + } + } + + public async fetchUser( + qq: string, + username: string + ): Promise { + try { + const fromRedis = await this.getObject(`user:${qq}`); + if (fromRedis) return fromRedis; + const fromLocal = await Persistence.readDataLocal(username); + if (fromLocal) { + await this.setObject(`user:${qq}`, fromLocal); + return fromLocal; + } + logger.error(`用户${username},qq${qq}不存在!`); + return undefined; + } catch (err) { + logger.error(err); + } + } + public async test(): Promise { const testData: IUser = { name: 'Jerry', @@ -117,6 +146,9 @@ class RedisService { }; let test = redisTool.reviveDates(testData); logger.debug(test); + await this.setObject('test', test); + const push = await this.getObject('test'); + logger.debug(push); } } diff --git a/src/utils/core/path.ts b/src/utils/core/path.ts index b274b7e..8f776ab 100644 --- a/src/utils/core/path.ts +++ b/src/utils/core/path.ts @@ -33,6 +33,7 @@ class PathManager { log: path.join(this.baseDir, 'logs'), config: path.join(this.baseDir, 'config'), temp: path.join(this.baseDir, 'temp'), + userData: path.join(this.baseDir, 'private/data'), }; return type ? mappings[type] : this.baseDir; @@ -44,10 +45,13 @@ class PathManager { public init(): void { const logPath = this.get('log'); const imagePath = this.get('images'); + const dataPath = this.get('userData'); fc.createDir(logPath, false); fc.createDir(imagePath, false); + fc.createDir(dataPath, false); logger.debug(`日志目录初始化: ${logPath}`); logger.debug(`图像目录初始化: ${imagePath}`); + logger.debug(`用户数据目录初始化: ${dataPath}`); } /** @@ -70,7 +74,7 @@ class PathManager { } } -type PathType = 'root' | 'public' | 'images' | 'log' | 'config' | 'temp'; +type PathType = 'root' | 'public' | 'images' | 'log' | 'config' | 'temp' | 'userData'; const paths = PathManager.getInstance(); export default paths; diff --git a/src/utils/redis/persistence.ts b/src/utils/redis/persistence.ts new file mode 100644 index 0000000..d3e76c9 --- /dev/null +++ b/src/utils/redis/persistence.ts @@ -0,0 +1,46 @@ +import path from 'path'; +import paths from '../core/path'; +import fc from '../core/file'; +import logger from '../core/logger'; +import fs from 'fs/promises'; + +class Persistence { + private static getUserDataPath(username: string): string { + return path.join(paths.get('userData'), username, 'data.json'); + } + + private static async ensureUserPath(username: string): Promise { + const userPath = path.join(paths.get('userData'), username); + try { + await fc.createDir(userPath, false); + } catch (err) { + logger.error(err); + } + } + + public static async writeDataLocal(username: string, data: T): Promise { + await this.ensureUserPath(username); + const filePath = this.getUserDataPath(username); + + try { + await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf-8'); + logger.debug(`用户数据已持久化到本地${filePath}`); + } catch (err) { + logger.error(err); + } + } + + public static async readDataLocal(username: string): Promise { + const filePath = this.getUserDataPath(username); + + try { + const data = await fs.readFile(filePath, 'utf-8'); + return JSON.parse(data) as T; + } catch (err) { + logger.error(err); + return undefined; + } + } +} + +export default Persistence;