From f8f19f737948eaca5d24ef9f6ecd2755a5734f15 Mon Sep 17 00:00:00 2001 From: HapeLee <63206378+HapeLee@users.noreply.github.com> Date: Sat, 30 May 2026 01:16:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=87=E4=BB=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/help/AppWebDav.kt | 13 +++-- .../java/io/legado/app/help/WebDavManager.kt | 13 +++-- .../java/io/legado/app/help/storage/Backup.kt | 8 +-- .../io/legado/app/help/storage/Restore.kt | 51 ++++++++++--------- 4 files changed, 47 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/AppWebDav.kt b/app/src/main/java/io/legado/app/help/AppWebDav.kt index 61b1f10b4..76665c26e 100644 --- a/app/src/main/java/io/legado/app/help/AppWebDav.kt +++ b/app/src/main/java/io/legado/app/help/AppWebDav.kt @@ -9,7 +9,9 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookProgress import io.legado.app.exception.NoStackTraceException import io.legado.app.help.config.AppConfig +import io.legado.app.help.config.LocalConfig import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.BackupRestoreLock import io.legado.app.help.storage.Restore import io.legado.app.lib.webdav.Authorization import io.legado.app.lib.webdav.WebDav @@ -122,10 +124,13 @@ object AppWebDav { suspend fun restoreWebDav(name: String) { authorization?.let { val webDav = WebDav(rootWebDavUrl + name, it) - webDav.downloadTo(Backup.zipFilePath, true) - FileUtils.delete(Backup.backupPath) - ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath) - Restore.restoreLocked(Backup.backupPath) + BackupRestoreLock.withLock { + webDav.downloadTo(Backup.zipFilePath, true) + FileUtils.delete(Backup.backupPath) + ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath) + Restore.restoreUnzipped(Backup.backupPath) + LocalConfig.lastBackup = System.currentTimeMillis() + } } } diff --git a/app/src/main/java/io/legado/app/help/WebDavManager.kt b/app/src/main/java/io/legado/app/help/WebDavManager.kt index ac7df6e64..21d569d98 100644 --- a/app/src/main/java/io/legado/app/help/WebDavManager.kt +++ b/app/src/main/java/io/legado/app/help/WebDavManager.kt @@ -8,7 +8,9 @@ import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookProgress import io.legado.app.exception.NoStackTraceException import io.legado.app.help.config.AppConfig +import io.legado.app.help.config.LocalConfig import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.BackupRestoreLock import io.legado.app.help.storage.Restore import io.legado.app.lib.webdav.Authorization import io.legado.app.lib.webdav.WebDav @@ -137,10 +139,13 @@ class WebDavManager( val auth = requireAuthorization() val rootUrl = buildRootUrl(configFlow.value) val webDav = WebDav(rootUrl + name, auth) - webDav.downloadTo(Backup.zipFilePath, true) - FileUtils.delete(Backup.backupPath) - ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath) - Restore.restoreLocked(Backup.backupPath) + BackupRestoreLock.withLock { + webDav.downloadTo(Backup.zipFilePath, true) + FileUtils.delete(Backup.backupPath) + ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath) + Restore.restoreUnzipped(Backup.backupPath) + LocalConfig.lastBackup = System.currentTimeMillis() + } } suspend fun hasBackUp(backUpName: String): Boolean { diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 06e8427c3..fed46fe2a 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -34,8 +34,6 @@ import io.legado.app.utils.writeToOutputStream import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.ensureActive -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import splitties.init.appCtx import java.io.File @@ -58,8 +56,6 @@ object Backup { private const val TAG = "Backup" - private val mutex = Mutex() - private val backupFileNames by lazy { arrayOf( "bookshelf.json", @@ -107,7 +103,7 @@ object Backup { fun autoBack(context: Context) { if (shouldBackup()) { Coroutine.async { - mutex.withLock { + BackupRestoreLock.withLock { if (shouldBackup()) { val backupZipFileName = getNowZipFileName() if (!AppWebDav.hasBackUp(backupZipFileName)) { @@ -124,7 +120,7 @@ object Backup { } suspend fun backupLocked(context: Context, path: String?, mode: String = "both") { - mutex.withLock { + BackupRestoreLock.withLock { withContext(IO) { backup(context, path, mode) } diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index befe16466..dab27caae 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -55,8 +55,6 @@ import io.legado.app.utils.openInputStream import io.legado.app.utils.toastOnUi import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.delay -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import org.koin.core.component.KoinComponent import org.koin.core.component.inject @@ -70,40 +68,45 @@ import java.io.FileInputStream object Restore : KoinComponent { private val settingsRepository: SettingsRepository by inject() - private val mutex = Mutex() - private const val TAG = "Restore" suspend fun restore(context: Context, uri: Uri) { - LogUtils.d(TAG, "开始恢复备份 uri:$uri") - kotlin.runCatching { - FileUtils.delete(Backup.backupPath) - if (uri.isContentScheme()) { - DocumentFile.fromSingleUri(context, uri)!!.openInputStream()!!.use { - ZipUtils.unZipToPath(it, Backup.backupPath) + BackupRestoreLock.withLock { + LogUtils.d(TAG, "开始恢复备份 uri:$uri") + val unzipResult = kotlin.runCatching { + FileUtils.delete(Backup.backupPath) + if (uri.isContentScheme()) { + DocumentFile.fromSingleUri(context, uri)!!.openInputStream()!!.use { + ZipUtils.unZipToPath(it, Backup.backupPath) + } + } else { + ZipUtils.unZipToPath(File(uri.path!!), Backup.backupPath) + } + }.onFailure { + AppLog.put("复制解压文件出错\n${it.localizedMessage}", it) + } + if (unzipResult.isSuccess) { + kotlin.runCatching { + restoreUnzipped(Backup.backupPath) + LocalConfig.lastBackup = System.currentTimeMillis() + }.onFailure { + appCtx.toastOnUi("恢复备份出错\n${it.localizedMessage}") + AppLog.put("恢复备份出错\n${it.localizedMessage}", it) } - } else { - ZipUtils.unZipToPath(File(uri.path!!), Backup.backupPath) } - }.onFailure { - AppLog.put("复制解压文件出错\n${it.localizedMessage}", it) - return - } - kotlin.runCatching { - restoreLocked(Backup.backupPath) - LocalConfig.lastBackup = System.currentTimeMillis() - }.onFailure { - appCtx.toastOnUi("恢复备份出错\n${it.localizedMessage}") - AppLog.put("恢复备份出错\n${it.localizedMessage}", it) } } suspend fun restoreLocked(path: String) { - mutex.withLock { - restore(path) + BackupRestoreLock.withLock { + restoreUnzipped(path) } } + internal suspend fun restoreUnzipped(path: String) { + restore(path) + } + private suspend fun restore(path: String) { val aes = BackupAES() fileToListT(path, "bookshelf.json")?.let {