diff --git a/src/data/ChatBean.ts b/src/data/ChatBean.ts index 4aaa459..919e8ce 100644 --- a/src/data/ChatBean.ts +++ b/src/data/ChatBean.ts @@ -1,3 +1,4 @@ export default class ChatBean { declare id: string + declare settings: string } diff --git a/src/data/FileManager.ts b/src/data/FileManager.ts index 18a47e0..8cac9e9 100644 --- a/src/data/FileManager.ts +++ b/src/data/FileManager.ts @@ -2,7 +2,7 @@ import { DatabaseSync } from "node:sqlite" import { Buffer } from "node:buffer" import path from 'node:path' import crypto from 'node:crypto' -import fs from 'node:fs/promises' +import fs_sync from 'node:fs' import { fileTypeFromBuffer } from 'file-type' @@ -12,7 +12,9 @@ export default class FileManager { declare name: string declare hash: string declare mime: string - declare chatid: string + declare chatid: string | null + declare upload_time: number + declare last_used_time: number } static File = class { @@ -20,6 +22,10 @@ export default class FileManager { constructor(bean: FileManager.FileBean) { this.bean = bean } + private setAttr(key: string, value: unknown): void { + FileManager.database.prepare(`UPDATE ${FileManager.table_name} SET ${key} = ? WHERE count = ?`).run(value, this.bean.count) + this.bean[key] = value + } getMime(): string { return this.bean.mime } @@ -37,11 +43,18 @@ export default class FileManager { this.bean.hash ) } - getChatId(): string { + getChatId(): string | null { return this.bean.chatid } - async readAsync(): Buffer { - return await fs.readFile(this.getFilePath()) + getUploadTime(): number { + return this.bean.upload_time + } + getLastUsedTime(): number { + return this.bean.last_used_time + } + readSync(): Buffer { + this.setAttr("last_used_time", Date.now()) + return fs_sync.readFileSync(this.getFilePath()) } } @@ -55,7 +68,7 @@ export default class FileManager { /* 文件名称 */ name TEXT NOT NULL, /* 文件哈希 */ hash TEXT NOT NULL, /* MIME 类型 */ mime TEXT NOT NULL, - /* 来源 Chat */ chatid TEXT NOT NULL, + /* 来源 Chat, 可為空 */ chatid TEXT, /* 上传时间 */ upload_time INT8 NOT NULL, /* 最后使用时间 */ last_used_time INT8 NOT NULL ); @@ -63,10 +76,16 @@ export default class FileManager { return db } - static async uploadFile(fileName: string, data: Buffer, chatId: string) { + static uploadFile(fileName: string, data: Buffer, chatId: string | null) { const hash = crypto.createHash('sha256').update(data).digest('hex') + try { + return FileManager.findByHash(hash) + } catch(_e) { + // Do nothing... + } + const mime = fileTypeFromBuffer(data) - await fs.writeFile( + fs_sync.writeFileSync( path.join( config.data_path, "files", diff --git a/src/data/User.ts b/src/data/User.ts index a0babbb..097c486 100644 --- a/src/data/User.ts +++ b/src/data/User.ts @@ -8,6 +8,8 @@ import chalk from 'chalk' import config from '../config.ts' import UserBean from './UserBean.ts' +import FileManager from './FileManager.ts' + /** * User.ts - Wrapper and manager * Wrap with UserBean to directly update database @@ -25,7 +27,7 @@ export default class User { /* 注册时间, 时间戳 */ registered_time INT8 NOT NULL, /* 用戶名, 可選 */ username TEXT, /* 昵称 */ nickname TEXT NOT NULL, - /* 头像, 可选 */ avatar BLOB, + /* 头像, 可选 */ avatar_file_hash TEXT, /* 设置 */ settings TEXT NOT NULL ); `) @@ -43,7 +45,7 @@ export default class User { } static create(userName: string | null, nickName: string, avatar: Buffer | null): User { - return new User( + const user = new User( User.findAllBeansByCondition( 'count = ?', User.database.prepare(`INSERT INTO ${User.table_name} ( @@ -51,18 +53,20 @@ export default class User { registered_time, username, nickname, - avatar, + avatar_file_hash, settings ) VALUES (?, ?, ?, ?, ?, ?);`).run( crypto.randomUUID(), Date.now(), userName, nickName, - avatar, + null, "{}" ).lastInsertRowid )[0] ) + avatar && user.setAvatar(avatar) + return user } private static findAllBeansByCondition(condition: string, ...args: unknown[]): UserBean[] { @@ -94,7 +98,7 @@ export default class User { User.database.prepare(`UPDATE ${User.table_name} SET ${key} = ? WHERE count = ?`).run(value, this.bean.count) this.bean[key] = value } - getUserName(): string { + getUserName(): string | null { return this.bean.username } setUserName(userName: string): void { @@ -106,11 +110,11 @@ export default class User { setNickName(nickName: string): void { this.setAttr("nickname", nickName) } - getAvatar(): Uint8Array { - return this.bean.avatar + getAvatar(): Buffer | null { + return FileManager.findByHash(this.bean.avatar_file_hash)?.readSync() } setAvatar(avatar: Buffer): void { - this.setAttr("avatar", avatar) + this.setAttr("avatar_file_hash", FileManager.uploadFile(`avatar_user_${this.bean.count}`, avatar).getHash()) } getSettings(): User.Settings { diff --git a/src/data/UserBean.ts b/src/data/UserBean.ts index 9809170..12c6c30 100644 --- a/src/data/UserBean.ts +++ b/src/data/UserBean.ts @@ -1,8 +1,8 @@ export default class UserBean { declare count: number - declare username: string + declare username: string | null declare registered_time: number declare nickname: string - declare avatar: Uint8Array + declare avatar_file_hash: string | null declare settings: string }