备份问题

This commit is contained in:
HapeLee committed 2026-05-30 01:16:23 +08:00
1 parent b408ba580a
commit f8f19f7379
4 files changed
+26 -17

No files matched your search

@@ -9,7 +9,9 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookProgress import io.legado.app.data.entities.BookProgress
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.config.AppConfig 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.Backup
import io.legado.app.help.storage.BackupRestoreLock
import io.legado.app.help.storage.Restore import io.legado.app.help.storage.Restore
import io.legado.app.lib.webdav.Authorization import io.legado.app.lib.webdav.Authorization
import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.WebDav
@@ -122,10 +124,13 @@ object AppWebDav {
suspend fun restoreWebDav(name: String) { suspend fun restoreWebDav(name: String) {
authorization?.let { authorization?.let {
val webDav = WebDav(rootWebDavUrl + name, it) val webDav = WebDav(rootWebDavUrl + name, it)
BackupRestoreLock.withLock {
webDav.downloadTo(Backup.zipFilePath, true) webDav.downloadTo(Backup.zipFilePath, true)
FileUtils.delete(Backup.backupPath) FileUtils.delete(Backup.backupPath)
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath) ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
Restore.restoreLocked(Backup.backupPath) Restore.restoreUnzipped(Backup.backupPath)
LocalConfig.lastBackup = System.currentTimeMillis()
}
} }
} }
@@ -8,7 +8,9 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookProgress import io.legado.app.data.entities.BookProgress
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.config.AppConfig 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.Backup
import io.legado.app.help.storage.BackupRestoreLock
import io.legado.app.help.storage.Restore import io.legado.app.help.storage.Restore
import io.legado.app.lib.webdav.Authorization import io.legado.app.lib.webdav.Authorization
import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.WebDav
@@ -137,10 +139,13 @@ class WebDavManager(
val auth = requireAuthorization() val auth = requireAuthorization()
val rootUrl = buildRootUrl(configFlow.value) val rootUrl = buildRootUrl(configFlow.value)
val webDav = WebDav(rootUrl + name, auth) val webDav = WebDav(rootUrl + name, auth)
BackupRestoreLock.withLock {
webDav.downloadTo(Backup.zipFilePath, true) webDav.downloadTo(Backup.zipFilePath, true)
FileUtils.delete(Backup.backupPath) FileUtils.delete(Backup.backupPath)
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath) ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
Restore.restoreLocked(Backup.backupPath) Restore.restoreUnzipped(Backup.backupPath)
LocalConfig.lastBackup = System.currentTimeMillis()
}
} }
suspend fun hasBackUp(backUpName: String): Boolean { suspend fun hasBackUp(backUpName: String): Boolean {
@@ -34,8 +34,6 @@ import io.legado.app.utils.writeToOutputStream
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
@@ -58,8 +56,6 @@ object Backup {
private const val TAG = "Backup" private const val TAG = "Backup"
private val mutex = Mutex()
private val backupFileNames by lazy { private val backupFileNames by lazy {
arrayOf( arrayOf(
"bookshelf.json", "bookshelf.json",
@@ -107,7 +103,7 @@ object Backup {
fun autoBack(context: Context) { fun autoBack(context: Context) {
if (shouldBackup()) { if (shouldBackup()) {
Coroutine.async { Coroutine.async {
mutex.withLock { BackupRestoreLock.withLock {
if (shouldBackup()) { if (shouldBackup()) {
val backupZipFileName = getNowZipFileName() val backupZipFileName = getNowZipFileName()
if (!AppWebDav.hasBackUp(backupZipFileName)) { if (!AppWebDav.hasBackUp(backupZipFileName)) {
@@ -124,7 +120,7 @@ object Backup {
} }
suspend fun backupLocked(context: Context, path: String?, mode: String = "both") { suspend fun backupLocked(context: Context, path: String?, mode: String = "both") {
mutex.withLock { BackupRestoreLock.withLock {
withContext(IO) { withContext(IO) {
backup(context, path, mode) backup(context, path, mode)
} }
@@ -55,8 +55,6 @@ import io.legado.app.utils.openInputStream
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent import org.koin.core.component.KoinComponent
import org.koin.core.component.inject import org.koin.core.component.inject
@@ -70,13 +68,12 @@ import java.io.FileInputStream
object Restore : KoinComponent { object Restore : KoinComponent {
private val settingsRepository: SettingsRepository by inject() private val settingsRepository: SettingsRepository by inject()
private val mutex = Mutex()
private const val TAG = "Restore" private const val TAG = "Restore"
suspend fun restore(context: Context, uri: Uri) { suspend fun restore(context: Context, uri: Uri) {
BackupRestoreLock.withLock {
LogUtils.d(TAG, "开始恢复备份 uri:$uri") LogUtils.d(TAG, "开始恢复备份 uri:$uri")
kotlin.runCatching { val unzipResult = kotlin.runCatching {
FileUtils.delete(Backup.backupPath) FileUtils.delete(Backup.backupPath)
if (uri.isContentScheme()) { if (uri.isContentScheme()) {
DocumentFile.fromSingleUri(context, uri)!!.openInputStream()!!.use { DocumentFile.fromSingleUri(context, uri)!!.openInputStream()!!.use {
@@ -87,23 +84,29 @@ object Restore : KoinComponent {
} }
}.onFailure { }.onFailure {
AppLog.put("复制解压文件出错\n${it.localizedMessage}", it) AppLog.put("复制解压文件出错\n${it.localizedMessage}", it)
return
} }
if (unzipResult.isSuccess) {
kotlin.runCatching { kotlin.runCatching {
restoreLocked(Backup.backupPath) restoreUnzipped(Backup.backupPath)
LocalConfig.lastBackup = System.currentTimeMillis() LocalConfig.lastBackup = System.currentTimeMillis()
}.onFailure { }.onFailure {
appCtx.toastOnUi("恢复备份出错\n${it.localizedMessage}") appCtx.toastOnUi("恢复备份出错\n${it.localizedMessage}")
AppLog.put("恢复备份出错\n${it.localizedMessage}", it) AppLog.put("恢复备份出错\n${it.localizedMessage}", it)
} }
} }
}
}
suspend fun restoreLocked(path: String) { suspend fun restoreLocked(path: String) {
mutex.withLock { BackupRestoreLock.withLock {
restore(path) restoreUnzipped(path)
} }
} }
internal suspend fun restoreUnzipped(path: String) {
restore(path)
}
private suspend fun restore(path: String) { private suspend fun restore(path: String) {
val aes = BackupAES() val aes = BackupAES()
fileToListT<Book>(path, "bookshelf.json")?.let { fileToListT<Book>(path, "bookshelf.json")?.let {