From be04031e82ce55a86f89b93982e7f4d62aa2eadf Mon Sep 17 00:00:00 2001 From: pompurin404 Date: Fri, 23 Aug 2024 14:59:03 +0800 Subject: [PATCH] support delete backup file --- changelog.md | 4 ++ package.json | 3 +- pnpm-lock.yaml | 22 +++++-- src/main/resolve/backup.ts | 20 +++++- src/main/utils/ipc.ts | 3 +- .../settings/webdav-restore-modal.tsx | 61 ++++++++++++------- src/renderer/src/utils/ipc.ts | 4 ++ 7 files changed, 85 insertions(+), 32 deletions(-) diff --git a/changelog.md b/changelog.md index 3b80f43..97a9db3 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +### New Features + +- 支持删除 Webdav 备份文件 + ### Bug Fixes - 修复拨号网络系统代理问题 diff --git a/package.json b/package.json index 51950e5..4283fe8 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@mihomo-party/sysproxy": "^2.0.0", "adm-zip": "^0.5.15", "axios": "^1.7.3", + "dayjs": "^1.11.13", "webdav": "^5.7.1", "ws": "^8.18.0", "yaml": "^2.5.0" @@ -38,6 +39,7 @@ "@electron-toolkit/eslint-config-ts": "^2.0.0", "@electron-toolkit/tsconfig": "^1.0.1", "@nextui-org/react": "^2.4.6", + "@types/adm-zip": "^0.5.5", "@types/node": "^22.1.0", "@types/pubsub-js": "^1.8.6", "@types/react": "^18.3.3", @@ -46,7 +48,6 @@ "@vitejs/plugin-react": "^4.3.1", "apexcharts": "^3.52.0", "autoprefixer": "^10.4.20", - "dayjs": "^1.11.12", "electron": "^31.3.1", "electron-builder": "^25.0.3", "electron-vite": "^2.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1382ba..f14b64d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: axios: specifier: ^1.7.3 version: 1.7.4 + dayjs: + specifier: ^1.11.13 + version: 1.11.13 webdav: specifier: ^5.7.1 version: 5.7.1 @@ -54,6 +57,9 @@ importers: '@nextui-org/react': specifier: ^2.4.6 version: 2.4.6(@types/react@18.3.3)(framer-motion@11.3.28(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwindcss@3.4.10) + '@types/adm-zip': + specifier: ^0.5.5 + version: 0.5.5 '@types/node': specifier: ^22.1.0 version: 22.4.0 @@ -78,9 +84,6 @@ importers: autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.41) - dayjs: - specifier: ^1.11.12 - version: 1.11.12 electron: specifier: ^31.3.1 version: 31.4.0 @@ -1961,6 +1964,9 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} + '@types/adm-zip@0.5.5': + resolution: {integrity: sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -2583,8 +2589,8 @@ packages: resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} engines: {node: '>= 0.4'} - dayjs@1.11.12: - resolution: {integrity: sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} debug@4.3.6: resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} @@ -7531,6 +7537,10 @@ snapshots: '@tootallnate/once@2.0.0': {} + '@types/adm-zip@0.5.5': + dependencies: + '@types/node': 22.4.0 + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.25.3 @@ -8304,7 +8314,7 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.1 - dayjs@1.11.12: {} + dayjs@1.11.13: {} debug@4.3.6: dependencies: diff --git a/src/main/resolve/backup.ts b/src/main/resolve/backup.ts index ff80873..47f2a77 100644 --- a/src/main/resolve/backup.ts +++ b/src/main/resolve/backup.ts @@ -1,4 +1,5 @@ import { getAppConfig } from '../config' +import dayjs from 'dayjs' import AdmZip from 'adm-zip' import { appConfigPath, @@ -23,7 +24,8 @@ export async function webdavBackup(): Promise { zip.addLocalFile(overrideConfigPath()) zip.addLocalFolder(profilesDir(), 'profiles') zip.addLocalFolder(overrideDir(), 'override') - const zipFileName = `backup-${new Date().toISOString().replace(/:/g, '-')}.zip` + const date = new Date() + const zipFileName = `Backup_${dayjs(date).format('YYYY-MM-DD_HH-mm-ss')}.zip` const client = createClient(webdavUrl, { username: webdavUsername, @@ -47,8 +49,8 @@ export async function webdavRestore(filename: string): Promise { username: webdavUsername, password: webdavPassword }) - const zipData = await client.getFileContents(`/mihomo-party/${filename}`) - const zip = new AdmZip(zipData) + const zipData = await client.getFileContents(`mihomo-party/${filename}`) + const zip = new AdmZip(zipData as Buffer) zip.extractAllTo(dataDir(), true) app.relaunch() app.quit() @@ -70,3 +72,15 @@ export async function listWebdavBackups(): Promise { return files.data.map((file) => file.basename) } } + +export async function webdavDelete(filename: string): Promise { + const webdav = await import('webdav') + const createClient = webdav.createClient + const { webdavUrl = '', webdavUsername = '', webdavPassword = '' } = await getAppConfig() + + const client = createClient(webdavUrl, { + username: webdavUsername, + password: webdavPassword + }) + await client.deleteFile(`mihomo-party/${filename}`) +} diff --git a/src/main/utils/ipc.ts b/src/main/utils/ipc.ts index 70f7d66..753321d 100644 --- a/src/main/utils/ipc.ts +++ b/src/main/utils/ipc.ts @@ -52,7 +52,7 @@ import { checkUpdate, downloadAndInstallUpdate } from '../resolve/autoUpdater' import { getFilePath, openUWPTool, readTextFile, setNativeTheme, setupFirewall } from '../sys/misc' import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory' import { isPortable, setPortable } from './dirs' -import { listWebdavBackups, webdavBackup, webdavRestore } from '../resolve/backup' +import { listWebdavBackups, webdavBackup, webdavDelete, webdavRestore } from '../resolve/backup' import { getInterfaces } from '../sys/interface' import { copyEnv } from '../resolve/tray' import { registerShortcut } from '../resolve/shortcut' @@ -162,6 +162,7 @@ export function registerIpcMainHandlers(): void { ipcMain.handle('webdavBackup', ipcErrorWrapper(webdavBackup)) ipcMain.handle('webdavRestore', (_e, filename) => ipcErrorWrapper(webdavRestore)(filename)) ipcMain.handle('listWebdavBackups', ipcErrorWrapper(listWebdavBackups)) + ipcMain.handle('webdavDelete', (_e, filename) => ipcErrorWrapper(webdavDelete)(filename)) ipcMain.handle('registerShortcut', (_e, oldShortcut, newShortcut, action) => ipcErrorWrapper(registerShortcut)(oldShortcut, newShortcut, action) ) diff --git a/src/renderer/src/components/settings/webdav-restore-modal.tsx b/src/renderer/src/components/settings/webdav-restore-modal.tsx index 607d3fc..ef5520f 100644 --- a/src/renderer/src/components/settings/webdav-restore-modal.tsx +++ b/src/renderer/src/components/settings/webdav-restore-modal.tsx @@ -1,12 +1,14 @@ import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button } from '@nextui-org/react' -import { webdavRestore } from '@renderer/utils/ipc' +import { webdavDelete, webdavRestore } from '@renderer/utils/ipc' import React, { useState } from 'react' +import { MdDeleteForever } from 'react-icons/md' interface Props { filenames: string[] onClose: () => void } const WebdavRestoreModal: React.FC = (props) => { - const { filenames, onClose } = props + const { filenames: names, onClose } = props + const [filenames, setFilenames] = useState(names) const [restoring, setRestoring] = useState(false) return ( @@ -24,25 +26,42 @@ const WebdavRestoreModal: React.FC = (props) => {
还没有备份
) : ( filenames.map((filename) => ( - +
+ + +
)) )} diff --git a/src/renderer/src/utils/ipc.ts b/src/renderer/src/utils/ipc.ts index cb5f7ab..94384da 100644 --- a/src/renderer/src/utils/ipc.ts +++ b/src/renderer/src/utils/ipc.ts @@ -283,6 +283,10 @@ export async function listWebdavBackups(): Promise { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('listWebdavBackups')) } +export async function webdavDelete(filename: string): Promise { + return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('webdavDelete', filename)) +} + export async function quitApp(): Promise { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('quitApp')) }