koishi 官方提供了一个较为友好的文档。介绍如何合理的进行永久化的存储操作。官方文档
在大多数持久化场景下,要存储的数据都是与实例相关、且不会被占用的文件。
这种情况下,我们建议将数据存放于实例目录下的特定目录中。根据数据的用途,这个目录可以是:
data
:存放数据文件 (可以在不同实例间迁移)。cache
:存放缓存文件 (没有迁移价值的持久化数据)。temp
:存放临时文件 (非持久化数据,下一次启动即会失效)。
强调!官方是推荐使用数据库的,但若不想使用该方案,也可以自行在协议规范的指定目录下创建自己的数据文件夹和对应数据文件。
你可以按着数据文件的特征。放在指定的位置。例如:data 文件目录就是提供给插件存放对应数据的,
这样做的好处是,当你需要迁移插件的用户数据时,只需要将 data
目录复制到新的实例目录下即可
ctx.baseDir
koishi 提供了一个 ctx.baseDir
的值用于获取 koishi实例的根目录的绝对位置。推荐使用该属性并搭配使用 path.join 进行根路径的拼接。
具体代码可参考如下:
1. 将存放和创建的操作封装成工具包
import * as fs from 'fs/promises';
async function setOrCreateFile(path: string, data: string): Promise<void> {
try {
await fs.writeFile(path, data);
} catch (error) {
await createDirectoryPath(path);
await fs.writeFile(path, data);
}
}
async function getOrCreateFile(path: string): Promise<string> {
try {
await fs.access(path);
return await fs.readFile(path, 'utf-8');
} catch (error) {
await createDirectoryPath(path);
await fs.writeFile(path, '{}');
return await fs.readFile(path, 'utf-8');
}
}
async function createDirectoryPath(filePath: string): Promise<void> {
const lastIndex = filePath.lastIndexOf('/');
const directoryPath = filePath.substring(0, lastIndex);
await fs.mkdir(directoryPath, { recursive: true });
}
export { setOrCreateFile, getOrCreateFile };
2. 插件去 引用这个包,并复写包的实际业务
import { Context, Schema } from 'koishi'
import fs from 'fs/promises'
import path from 'path'
import { getOrCreateFile, setOrCreateFile } from './fileUtils';
export interface Config {
fishData: string,
achieveData: string,
}
export const Config: Schema<Config> = Schema.object({
fishData: Schema.string().default('/data/fishData/data.json').description('玩家数据存放路径'),
achieveData: Schema.string().default('/data/fishData/achieveData.json').description('玩家成就数据存放路径')
})
export function apply(ctx: Context, config: Config) {
// 写入 koishi 下的目标路径文件
async function setBaseDirStoreData(upath: string, data: object) {
return await setOrCreateFile(path.join(ctx.baseDir, upath), JSON.stringify(data));
}
// 获取 koishi 下的目标路径文件
async function getBaseDirStoreData(upath: string) {
return JSON.parse(await getOrCreateFile(path.join(ctx.baseDir, upath)));
}
}