数据备份&恢复

close #126
This commit is contained in:
目棃
2024-09-29 10:15:05 +08:00
parent 14a15ab4fd
commit 911aeed9ea
4 changed files with 134 additions and 63 deletions

View File

@@ -4,6 +4,10 @@
* @since Beta v0.6.0
*/
import { path } from "@tauri-apps/api";
import { exists, mkdir, readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
import TGLogger from "../../../utils/TGLogger.js";
import { timestampToDate } from "../../../utils/toolFunc.js";
import TGSqlite from "../index.js";
@@ -120,6 +124,51 @@ async function saveAccount(data: TGApp.App.Account.User): Promise<void> {
);
}
/**
* @description 备份用户数据
* @since Beta v0.6.0
* @param {string} dir - 备份目录
* @returns {Promise<void>}
*/
async function backUpAccount(dir: string): Promise<void> {
if (!(await exists(dir))) {
await TGLogger.Warn("不存在指定的账户备份目录,即将创建");
await mkdir(dir, { recursive: true });
}
const accounts = await getAllAccount();
await writeTextFile(`${dir}${path.sep()}accounts.json`, JSON.stringify(accounts, null, 2));
await TGLogger.Info("账户数据备份完成");
}
/**
* @description 恢复用户数据
* @since Beta v0.6.0
* @param {string} dir
* @returns {Promise<boolean>}
*/
async function restoreAccount(dir: string): Promise<boolean> {
if (!(await exists(dir))) {
await TGLogger.Warn("不存在指定的账户备份目录");
return false;
}
try {
const filePath = `${dir}${path.sep()}accounts.json`;
if (!(await exists(filePath))) {
await TGLogger.Warn("不存在指定的账户备份文件");
return false;
}
const data = await readTextFile(filePath);
const accounts: TGApp.App.Account.User[] = JSON.parse(data);
for (const account of accounts) {
await saveAccount(account);
}
} catch (e) {
await TGLogger.Error(`[UserAccount][restoreAccount] ${e}`);
return false;
}
return true;
}
/**
* @description 复制cookie
* @since Beta v0.6.0
@@ -236,6 +285,8 @@ const TSUserAccount = {
saveAccount,
copy: copyCookie,
deleteAccount,
backup: backUpAccount,
restore: restoreAccount,
},
game: {
getAccount: getGameAccount,

View File

@@ -306,22 +306,23 @@ async function backupUiaf(dir: string, uid?: number): Promise<void> {
async function restoreUiaf(dir: string): Promise<boolean> {
if (!(await exists(dir))) return false;
const filesRead = await readDir(dir);
const files = filesRead.filter((item) => item.name.includes("UIAF_") && item.isFile);
// 校验 UIAF_xxx.json 文件
const fileRegex = /^UIAF_\d+\.json$/;
const files = filesRead.filter((item) => item.isFile && fileRegex.test(item.name));
if (files.length === 0) return false;
for (const file of files) {
try {
// todo 完善正则判断
const reg = /UIAF_(\d+).json/;
if (!file.name.match(reg)) return false;
const uid: number = Number(file.name.match(reg)![0]);
const uid = parseInt(file.name.replace("UIAF_", "").replace(".json", ""));
const filePath = `${dir}${path.sep()}${file.name}`;
const data: TGApp.Plugins.UIAF.Achievement[] = JSON.parse(await readTextFile(filePath));
await TSUserAchi.mergeUiaf(data, uid);
} catch (e) {
await TGLogger.Error(`[UIAF][RESTORE] 恢复成就数据${file.name} `);
await TGLogger.Error(`${e}`);
return false;
}
}
return false;
return true;
}
/**

View File

@@ -4,7 +4,12 @@
* @since Beta v0.6.0
*/
import { path } from "@tauri-apps/api";
import { exists, mkdir, readDir } from "@tauri-apps/plugin-fs";
import { AppCharacterData, AppWeaponData } from "../../../data/index.js";
import TGLogger from "../../../utils/TGLogger.js";
import { exportUigfData, readUigfData, verifyUigfData } from "../../../utils/UIGF.js";
import TGSqlite from "../index.js";
type gachaItemTypeRes =
@@ -177,6 +182,62 @@ async function mergeUIGF4(data: TGApp.Plugins.UIGF.GachaHk4e): Promise<void> {
}
}
/**
* @description 备份祈愿数据
* @since Beta v0.6.0
* @param {string} dir - 备份目录
* @returns {Promise<void>}
*/
async function backUpUigf(dir: string): Promise<void> {
if (!(await exists(dir))) {
await TGLogger.Warn("不存在指定的祈愿备份目录,即将创建");
await mkdir(dir, { recursive: true });
}
const uidList = await getUidList();
for (const uid of uidList) {
const dataGacha = await getGachaRecords(uid);
const savePath = `${dir}${path.sep()}UIGF_${uid}.json`;
await exportUigfData(uid, dataGacha, savePath);
}
await TGLogger.Info("祈愿数据备份完成");
}
/**
* @description 恢复祈愿数据
* @since Beta v0.6.0
* @param {string} dir - 备份目录
* @returns {Promise<boolean>}
*/
async function restoreUigf(dir: string): Promise<boolean> {
if (!(await exists(dir))) {
await TGLogger.Warn("不存在指定的祈愿备份目录");
return false;
}
const filesRead = await readDir(dir);
// 校验 UIGF_xxx.json 文件
const fileRegex = /^UIGF_\d+\.json$/;
const files = filesRead.filter((item) => item.isFile && fileRegex.test(item.name));
if (files.length === 0) return false;
try {
for (const file of files) {
const filePath = `${dir}${path.sep()}${file.name}`;
const check = await verifyUigfData(filePath);
if (!check) {
await TGLogger.Warn(`UIGF数据校验失败${filePath}`);
continue;
}
const data = await readUigfData(filePath);
const uid = data.info.uid;
await mergeUIGF(uid, data.list);
}
} catch (e) {
await TGLogger.Error(`恢复祈愿数据失败${dir}`);
await TGLogger.Error(typeof e === "string" ? e : JSON.stringify(e));
return false;
}
return true;
}
const TSUserGacha = {
getUidList,
getGachaCheck,
@@ -185,6 +246,8 @@ const TSUserGacha = {
deleteGachaRecords,
mergeUIGF,
mergeUIGF4,
backUpUigf,
restoreUigf,
};
export default TSUserGacha;