From 239d8193838f0eaaf22af8dfe7663f045c765a9c Mon Sep 17 00:00:00 2001 From: kwaroran Date: Wed, 3 Jan 2024 02:41:28 +0900 Subject: [PATCH] [feat] add mobile writer support --- src/ts/drive/backuplocal.ts | 57 +--------------------- src/ts/storage/globalApi.ts | 95 +++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 56 deletions(-) diff --git a/src/ts/drive/backuplocal.ts b/src/ts/drive/backuplocal.ts index 9fef7705..a929bced 100644 --- a/src/ts/drive/backuplocal.ts +++ b/src/ts/drive/backuplocal.ts @@ -1,6 +1,6 @@ import { BaseDirectory, readBinaryFile, readDir, writeBinaryFile } from "@tauri-apps/api/fs"; import { alertError, alertNormal, alertStore, alertWait } from "../alert"; -import { forageStorage, isTauri } from "../storage/globalApi"; +import { LocalWriter, forageStorage, isTauri } from "../storage/globalApi"; import { decodeRisuSave, encodeRisuSave } from "../storage/risuSave"; import { get } from "svelte/store"; import { DataBase } from "../storage/database"; @@ -9,25 +9,6 @@ import { relaunch } from "@tauri-apps/api/process"; import { sleep } from "../util"; import { hubURL } from "../characterCards"; -class TauriWriter{ - path: string - firstWrite: boolean = true - constructor(path: string){ - this.path = path - } - - async write(data:Uint8Array) { - await writeBinaryFile(this.path, data, { - append: !this.firstWrite - }) - this.firstWrite = false - } - - async close(){ - // do nothing - } -} - function getBasename(data:string){ const baseNameRegex = /\\/g const splited = data.replace(baseNameRegex, '/').split('/') @@ -35,42 +16,6 @@ function getBasename(data:string){ return lasts } -class LocalWriter{ - writableStream: WritableStream - writer: WritableStreamDefaultWriter|TauriWriter - async init() { - if(isTauri){ - const filePath = await save({ - filters: [{ - name: 'Binary', - extensions: ['bin'] - }] - }); - if(!filePath){ - return false - } - this.writer = new TauriWriter(filePath) - return true - } - const streamSaver = await import('streamsaver') - this.writableStream = streamSaver.createWriteStream('risu-backup.bin') - this.writer = this.writableStream.getWriter() - return true - } - async write(name:string,data: Uint8Array){ - const encodedName = new TextEncoder().encode(getBasename(name)) - const nameLength = new Uint32Array([encodedName.byteLength]) - await this.writer.write(new Uint8Array(nameLength.buffer)) - await this.writer.write(encodedName) - const dataLength = new Uint32Array([data.byteLength]) - await this.writer.write(new Uint8Array(dataLength.buffer)) - await this.writer.write(data) - } - async close(){ - await this.writer.close() - } -} - export async function SaveLocalBackup(){ alertWait("Saving local backup...") diff --git a/src/ts/storage/globalApi.ts b/src/ts/storage/globalApi.ts index 049f04c9..bb9b77e4 100644 --- a/src/ts/storage/globalApi.ts +++ b/src/ts/storage/globalApi.ts @@ -25,6 +25,7 @@ import { updateColorScheme, updateTextTheme } from "../gui/colorscheme"; import { saveDbKei } from "../kei/backup"; import { Capacitor, CapacitorHttp } from '@capacitor/core'; import * as CapFS from '@capacitor/filesystem' +import { save } from "@tauri-apps/api/dialog"; //@ts-ignore export const isTauri = !!window.__TAURI__ @@ -1112,4 +1113,98 @@ export function getModelMaxContext(model:string):number|undefined{ } return undefined +} + +class TauriWriter{ + path: string + firstWrite: boolean = true + constructor(path: string){ + this.path = path + } + + async write(data:Uint8Array) { + await writeBinaryFile(this.path, data, { + append: !this.firstWrite + }) + this.firstWrite = false + } + + async close(){ + // do nothing + } +} + +class MobileWriter{ + path: string + firstWrite: boolean = true + constructor(path: string){ + this.path = path + } + + async write(data:Uint8Array) { + if(this.firstWrite){ + if(!await CapFS.Filesystem.checkPermissions()){ + await CapFS.Filesystem.requestPermissions() + } + await CapFS.Filesystem.writeFile({ + path: this.path, + data: Buffer.from(data).toString('base64'), + recursive: true, + directory: CapFS.Directory.Documents + }) + } + else{ + await CapFS.Filesystem.appendFile({ + path: this.path, + data: Buffer.from(data).toString('base64'), + directory: CapFS.Directory.Documents + }) + } + + this.firstWrite = false + } + + async close(){ + // do nothing + } +} + + +export class LocalWriter{ + writer: WritableStreamDefaultWriter|TauriWriter|MobileWriter + async init() { + if(isTauri){ + const filePath = await save({ + filters: [{ + name: 'Binary', + extensions: ['bin'] + }] + }); + if(!filePath){ + return false + } + this.writer = new TauriWriter(filePath) + return true + } + if(Capacitor.isNativePlatform()){ + this.writer = new MobileWriter('risu-backup.bin') + return true + } + const streamSaver = await import('streamsaver') + const writableStream = streamSaver.createWriteStream('risu-backup.bin') + this.writer = writableStream.getWriter() + return true + } + async write(name:string,data: Uint8Array){ + const encodedName = new TextEncoder().encode(getBasename(name)) + const nameLength = new Uint32Array([encodedName.byteLength]) + await this.writer.write(new Uint8Array(nameLength.buffer)) + await this.writer.write(encodedName) + const dataLength = new Uint32Array([data.byteLength]) + await this.writer.write(new Uint8Array(dataLength.buffer)) + await this.writer.write(data) + } + async close(){ + await this.writer.close() + } } \ No newline at end of file