Files
risuai/src/ts/storage/autoStorage.ts
2024-11-02 01:46:21 +09:00

181 lines
6.4 KiB
TypeScript

import localforage from "localforage"
import { isNodeServer, replaceDbResources } from "../globalApi.svelte"
import { NodeStorage } from "./nodeStorage"
import { OpfsStorage } from "./opfsStorage"
import { alertInput, alertSelect, alertStore } from "../alert"
import { getDatabase, type Database } from "./database.svelte"
import { AccountStorage } from "./accountStorage"
import { decodeRisuSave, encodeRisuSaveLegacy } from "./risuSave";
import { language } from "src/lang"
import { MobileStorage } from "./mobileStorage"
import { Capacitor } from "@capacitor/core"
export class AutoStorage{
isAccount:boolean = false
realStorage:LocalForage|NodeStorage|OpfsStorage|AccountStorage|MobileStorage
async setItem(key:string, value:Uint8Array):Promise<string|null> {
await this.Init()
if(this.isAccount){
return await (this.realStorage as AccountStorage).setItem(key, value)
}
await this.realStorage.setItem(key, value)
return null
}
async getItem(key:string):Promise<Buffer> {
await this.Init()
return await this.realStorage.getItem(key)
}
async keys():Promise<string[]>{
await this.Init()
return await this.realStorage.keys()
}
async removeItem(key:string){
await this.Init()
return await this.realStorage.removeItem(key)
}
async checkAccountSync(){
let db = getDatabase()
if(this.isAccount){
return true
}
if(localStorage.getItem('dosync') === 'avoid'){
return false
}
if((localStorage.getItem('dosync') === 'sync' || db.account?.useSync) && (localStorage.getItem('accountst') !== 'able')){
const keys = await this.realStorage.keys()
let i = 0;
const accountStorage = new AccountStorage()
const a = accountStorage.getItem('database/database.bin')
if(a){
const sel = await alertSelect([language.loadDataFromAccount, language.saveCurrentDataToAccount])
if(sel === "0"){
this.realStorage = accountStorage
alertStore.set({
type: "none",
msg: ""
})
localStorage.setItem('accountst', 'able')
localStorage.setItem('fallbackRisuToken',JSON.stringify(db.account))
this.isAccount = true
return true
}
}
const confirm = await alertInput(`to overwrite your data, type "RISUAI"`)
if(confirm !== "RISUAI"){
localStorage.setItem('dosync', 'avoid')
return false
}
let replaced:{[key:string]:string} = {}
for(const key of keys){
alertStore.set({
type: "wait",
msg: `Migrating your data...(${i}/${keys.length})`
})
const rkey = await accountStorage.setItem(key,await this.realStorage.getItem(key))
if(rkey !== key){
replaced[key] = rkey
}
i += 1
}
const dba = replaceDbResources(db, replaced)
const comp = encodeRisuSaveLegacy(dba, 'compression')
//try decoding
try {
const z:Database = await decodeRisuSave(comp)
if(z.formatversion){
await accountStorage.setItem('database/database.bin', comp)
}
} catch (error) {}
this.realStorage = accountStorage
alertStore.set({
type: "none",
msg: ""
})
localStorage.setItem('accountst', 'able')
localStorage.setItem('fallbackRisuToken',JSON.stringify(db.account))
this.isAccount = true
await localforage.clear()
return true
}
else if(localStorage.getItem('accountst') === 'able'){
localStorage.setItem('accountst', 'able')
this.realStorage = new AccountStorage()
this.isAccount = true
}
return false
}
private async Init(){
if(!this.realStorage){
if(localStorage.getItem('accountst') === 'able'){
this.realStorage = new AccountStorage()
this.isAccount = true
return
}
if(Capacitor.isNativePlatform()){
this.realStorage = new MobileStorage()
return
}
if(isNodeServer){
console.log("using node storage")
this.realStorage = new NodeStorage()
return
}
else if(window.navigator?.storage?.getDirectory &&
FileSystemFileHandle?.prototype?.createWritable &&
localStorage.getItem('opfs_flag!') === "able"){
console.log("using opfs storage")
const forage = localforage.createInstance({
name: "risuai"
})
const i = await forage.getItem("database/database.bin")
if((!i) || (await forage.getItem("migrated"))){
this.realStorage = new OpfsStorage()
return
}
else if(!(await forage.getItem("denied_opfs"))){
console.log("migrating")
const keys = await forage.keys()
let i = 0;
const opfs = new OpfsStorage()
for(const key of keys){
alertStore.set({
type: "wait",
msg: `Migrating your data...(${i}/${keys.length})`
})
await opfs.setItem(key,await forage.getItem(key))
i += 1
}
this.realStorage = opfs
alertStore.set({
type: "none",
msg: ""
})
await forage.setItem("migrated", true)
return
}
}
console.log("using forage storage")
this.realStorage = localforage.createInstance({
name: "risuai"
})
}
}
listItem = this.keys
}