From 14d2558f09c9ffb1cabb96207743c9f4f0270220 Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 27 Dec 2023 21:42:23 +0900 Subject: [PATCH] [feat] add kei backup --- src/lib/Setting/Pages/UserSettings.svelte | 9 +- src/ts/kei/backup.ts | 100 ++++++++++++++++++++++ src/ts/kei/kei.ts | 9 ++ src/ts/storage/database.ts | 3 + src/ts/storage/globalApi.ts | 2 + 5 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 src/ts/kei/backup.ts create mode 100644 src/ts/kei/kei.ts diff --git a/src/lib/Setting/Pages/UserSettings.svelte b/src/lib/Setting/Pages/UserSettings.svelte index 5a6c8c00..7b1ee877 100644 --- a/src/lib/Setting/Pages/UserSettings.svelte +++ b/src/lib/Setting/Pages/UserSettings.svelte @@ -4,11 +4,13 @@ import { loadRisuAccountData, saveRisuAccountData } from "src/ts/drive/accounter"; import { DataBase } from "src/ts/storage/database"; import Check from "src/lib/UI/GUI/CheckInput.svelte"; - import { alertConfirm } from "src/ts/alert"; + import { alertConfirm, alertNormal } from "src/ts/alert"; import { forageStorage, isNodeServer, isTauri } from "src/ts/storage/globalApi"; import { unMigrationAccount } from "src/ts/storage/accountStorage"; import { checkDriver } from "src/ts/drive/drive"; - import { LoadLocalBackup, SaveLocalBackup } from "src/ts/drive/backuplocal"; + import { LoadLocalBackup, SaveLocalBackup } from "src/ts/drive/backuplocal"; + import Button from "src/lib/UI/GUI/Button.svelte"; + import { autoServerBackup } from "src/ts/kei/backup"; let openIframe = false let openIframeURL = '' let popup:Window = null @@ -120,7 +122,6 @@ {/if} {/if} - {:else} {language.notLoggedIn} {/if} + + {#if openIframe}
diff --git a/src/ts/kei/backup.ts b/src/ts/kei/backup.ts new file mode 100644 index 00000000..a83d91e5 --- /dev/null +++ b/src/ts/kei/backup.ts @@ -0,0 +1,100 @@ +import { get } from "svelte/store" +import { alertNormal, alertSelect } from "../alert" +import { keiServerURL } from "./kei" +import { DataBase, setDatabase } from "../storage/database" + +export async function autoServerBackup(){ + const db = get(DataBase) + const res = await fetch(keiServerURL() + '/autobackup/list', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + token: db.account.token + }) + }) + if(res.status === 200){ + const json = await res.json() + if(json.activated){ + alertNormal("Auto backup is now activated in your account. Now it would backup automaticly, and you can now restore your data from the backup server.") + db.account.kei = true + return + } + const backups:[string,string][] = json.backups + let pointer = 0 + while(true){ + const slices = backups.slice(pointer, pointer + 5) + const menu = slices.map((backup) => backup[0]) + menu.push("Next") + menu.push("Previous") + menu.push("Cancel") + const selectIndex = parseInt(await alertSelect(menu)) + const selected = menu[selectIndex] + if(selected === "Cancel"){ + break + } + else if(selected === "Next"){ + pointer += 5 + if(pointer >= backups.length){ + pointer = 0 + } + } + else if(selected === "Previous"){ + pointer -= 5 + if(pointer < 0){ + pointer = Math.floor(backups.length / 5) * 5 + } + } + else{ + const backup = backups.find((backup) => backup[0] === selected) + if(backup){ + const res = await fetch(keiServerURL() + '/autobackup/restore', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + token: db.account.token, + backup: backup[1] + }) + }) + if(res.status === 200){ + setDatabase(await res.json()) + alertNormal("Successfully restored!") + } + else{ + alertNormal("Error: " + res.text()) + } + } + } + } + } + else if(res.status === 401){ + alertNormal("You need to activate Risu-Kei in your account, or host your Risu-Kei server from github to use this feature.") + } + else{ + alertNormal("Error: " + res.text()) + } +} + +let lastKeiSave = 0 +export async function saveDbKei() { + let db = get(DataBase) + if(db.account.kei){ + if(Date.now() - lastKeiSave < 60000 * 5){ + return + } + lastKeiSave = Date.now() + fetch(keiServerURL() + '/autobackup/save', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + token: db.account.token, + database: db + }) + }) + } +} \ No newline at end of file diff --git a/src/ts/kei/kei.ts b/src/ts/kei/kei.ts new file mode 100644 index 00000000..648820ba --- /dev/null +++ b/src/ts/kei/kei.ts @@ -0,0 +1,9 @@ +import { get } from "svelte/store"; +import { hubURL } from "../characterCards"; +import { DataBase } from "../storage/database"; + +export function keiServerURL(){ + const db = get(DataBase) + if(db.keiServerURL) return db.keiServerURL; + return hubURL + "/kei"; +} \ No newline at end of file diff --git a/src/ts/storage/database.ts b/src/ts/storage/database.ts index 0c34570a..f6e0d5c9 100644 --- a/src/ts/storage/database.ts +++ b/src/ts/storage/database.ts @@ -368,6 +368,7 @@ export function setDatabase(data:Database){ sendName: false, utilOverride: false } + data.keiServerURL ??= '' changeLanguage(data.language) DataBase.set(data) @@ -509,6 +510,7 @@ export interface Database{ expires_in?: number } useSync?:boolean + kei?:boolean }, classicMaxWidth: boolean, useChatSticker:boolean, @@ -572,6 +574,7 @@ export interface Database{ chainOfThought?:boolean genTime:number proomptSettings: ProomptSettings + keiServerURL:string } export interface customscript{ diff --git a/src/ts/storage/globalApi.ts b/src/ts/storage/globalApi.ts index 390926f9..5164e20b 100644 --- a/src/ts/storage/globalApi.ts +++ b/src/ts/storage/globalApi.ts @@ -22,6 +22,7 @@ import { decodeRisuSave, encodeRisuSave } from "./risuSave"; import { AutoStorage } from "./autoStorage"; import { updateAnimationSpeed } from "../gui/animation"; import { updateColorScheme, updateTextTheme } from "../gui/colorscheme"; +import { saveDbKei } from "../kei/backup"; //@ts-ignore export const isTauri = !!window.__TAURI__ @@ -243,6 +244,7 @@ export async function saveDb(){ } savetrys = 0 } + await saveDbKei() await sleep(500) } catch (error) { if(savetrys > 4){