mirror of
https://github.com/openlibrecommunity/olcng.git
synced 2026-07-03 14:05:17 +02:00
Refactor WebDAV backup path and file name handling
This commit is contained in:
@@ -9,7 +9,9 @@ object AppConfig {
|
||||
|
||||
/** Directory names used in the app's file system. */
|
||||
const val DIR_ASSETS = "assets"
|
||||
const val DIR_BACKUPS = "backups"
|
||||
|
||||
const val WEBDAV_BACKUP_DIR = "backups"
|
||||
const val WEBDAV_BACKUP_FILE_NAME = "backup_ng.zip"
|
||||
|
||||
/** Legacy configuration keys. */
|
||||
const val ANG_CONFIG = "ang_config"
|
||||
|
||||
@@ -35,18 +35,18 @@ object WebDavManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a local file to a remote relative path under the configured remoteBasePath.
|
||||
* The provided `remoteRelativePath` should be relative (e.g. "backup_ng.zip").
|
||||
* Upload a local file to a remote file name under the configured remoteBasePath.
|
||||
* The provided `remoteFileName` should be a file name (e.g. "backup_ng.zip").
|
||||
* The method will attempt to create parent directories via MKCOL before PUT.
|
||||
*
|
||||
* @param localFile File to upload.
|
||||
* @param remoteRelativePath Remote path relative to configured remoteBasePath.
|
||||
* @param remoteFileName Remote file name relative to configured remoteBasePath.
|
||||
* @return true if upload succeeded (HTTP 2xx), false otherwise.
|
||||
*/
|
||||
suspend fun uploadFile(localFile: File, remoteRelativePath: String): Boolean = withContext(Dispatchers.IO) {
|
||||
suspend fun uploadFile(localFile: File, remoteFileName: String): Boolean = withContext(Dispatchers.IO) {
|
||||
val remote = buildRemoteUrl(remoteFileName)
|
||||
try {
|
||||
val cl = client ?: return@withContext false
|
||||
val remote = buildRemoteUrl(remoteRelativePath)
|
||||
|
||||
// Ensure parent directories exist
|
||||
val dirPath = remote.substringBeforeLast('/')
|
||||
@@ -67,14 +67,14 @@ object WebDavManager {
|
||||
cl.newCall(req).execute().use { resp ->
|
||||
val success = resp.isSuccessful
|
||||
if (success) {
|
||||
Log.i(AppConfig.TAG, "WebDAV upload success: $remoteRelativePath")
|
||||
Log.i(AppConfig.TAG, "WebDAV upload success: $remote")
|
||||
} else {
|
||||
Log.e(AppConfig.TAG, "WebDAV upload failed: $remoteRelativePath (HTTP ${resp.code})")
|
||||
Log.e(AppConfig.TAG, "WebDAV upload failed: $remote (HTTP ${resp.code})")
|
||||
}
|
||||
return@withContext success
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "WebDAV upload exception: $remoteRelativePath", e)
|
||||
Log.e(AppConfig.TAG, "WebDAV upload exception: $remote", e)
|
||||
return@withContext false
|
||||
}
|
||||
}
|
||||
@@ -82,18 +82,18 @@ object WebDavManager {
|
||||
/**
|
||||
* Download a remote file (relative to configured remoteBasePath) into a local file.
|
||||
*
|
||||
* @param remoteRelativePath Remote path relative to configured remoteBasePath.
|
||||
* @param remoteFileName Remote file name relative to configured remoteBasePath.
|
||||
* @param destFile Local destination file to write to.
|
||||
* @return true if download and write succeeded, false otherwise.
|
||||
*/
|
||||
suspend fun downloadFile(remoteRelativePath: String, destFile: File): Boolean = withContext(Dispatchers.IO) {
|
||||
suspend fun downloadFile(remoteFileName: String, destFile: File): Boolean = withContext(Dispatchers.IO) {
|
||||
val remote = buildRemoteUrl(remoteFileName)
|
||||
try {
|
||||
val cl = client ?: return@withContext false
|
||||
val remote = buildRemoteUrl(remoteRelativePath)
|
||||
val req = applyAuth(Request.Builder().url(remote).get()).build()
|
||||
cl.newCall(req).execute().use { resp ->
|
||||
if (!resp.isSuccessful) {
|
||||
Log.e(AppConfig.TAG, "WebDAV download failed: $remoteRelativePath (HTTP ${resp.code})")
|
||||
Log.e(AppConfig.TAG, "WebDAV download failed: $remote (HTTP ${resp.code})")
|
||||
return@withContext false
|
||||
}
|
||||
|
||||
@@ -104,29 +104,31 @@ object WebDavManager {
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(AppConfig.TAG, "WebDAV download success: $remoteRelativePath")
|
||||
Log.i(AppConfig.TAG, "WebDAV download success: $remote")
|
||||
return@withContext true
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "WebDAV download exception: $remoteRelativePath", e)
|
||||
Log.e(AppConfig.TAG, "WebDAV download exception: $remote", e)
|
||||
return@withContext false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a full remote URL by combining the configured base URL, the configured
|
||||
* remote base path and a relative path provided by the caller.
|
||||
* remote base path and a file name provided by the caller.
|
||||
*
|
||||
* Example: baseUrl="https://example.com/remote.php/dav", remoteBasePath="backups",
|
||||
* remoteRelativePath="backup_ng.zip" => "https://example.com/remote.php/dav/backups/backup_ng.zip"
|
||||
* remoteFileName="backup_ng.zip" => "https://example.com/remote.php/dav/backups/backup_ng.zip"
|
||||
*
|
||||
* @param remoteRelativePath A path relative to the configured remoteBasePath (no leading slash required).
|
||||
* @param remoteFileName A file name relative to the configured remoteBasePath (no leading slash required).
|
||||
* @return Full URL string used for HTTP operations.
|
||||
*/
|
||||
private fun buildRemoteUrl(remoteRelativePath: String): String {
|
||||
private fun buildRemoteUrl(remoteFileName: String): String {
|
||||
val base = cfg?.baseUrl?.trimEnd('/') ?: ""
|
||||
val basePath = cfg?.remoteBasePath?.trim('/') ?: ""
|
||||
val rel = remoteRelativePath.trimStart('/')
|
||||
// Use configured remoteBasePath when not empty; otherwise fallback to AppConfig.WEBDAV_BACKUP_DIR
|
||||
val basePathConfigured = cfg?.remoteBasePath?.trim('/')?.takeIf { it.isNotEmpty() }
|
||||
val basePath = basePathConfigured ?: AppConfig.WEBDAV_BACKUP_DIR
|
||||
val rel = remoteFileName.trimStart('/')
|
||||
return if (basePath.isEmpty()) "$base/$rel" else "$base/$basePath/$rel"
|
||||
}
|
||||
|
||||
@@ -170,7 +172,7 @@ object WebDavManager {
|
||||
Log.w(AppConfig.TAG, "WebDAV MKCOL $mkUrl returned ${resp.code}")
|
||||
}
|
||||
}
|
||||
} catch (ignored: Exception) {
|
||||
} catch (_: Exception) {
|
||||
// best-effort, continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.WEBDAV_BACKUP_FILE_NAME
|
||||
import com.v2ray.ang.BuildConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivityBackupBinding
|
||||
@@ -40,10 +41,6 @@ class BackupActivity : BaseActivity() {
|
||||
resources.getStringArray(R.array.config_backup_options)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val BACKUP_FILE_NAME = "backup_ng.zip"
|
||||
}
|
||||
|
||||
private val requestPermissionLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||
if (isGranted) {
|
||||
@@ -263,7 +260,7 @@ class BackupActivity : BaseActivity() {
|
||||
WebDavManager.init(saved)
|
||||
|
||||
val ok = try {
|
||||
WebDavManager.uploadFile(tempFile, BACKUP_FILE_NAME)
|
||||
WebDavManager.uploadFile(tempFile, WEBDAV_BACKUP_FILE_NAME)
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "WebDAV upload error", e)
|
||||
false
|
||||
@@ -303,7 +300,7 @@ class BackupActivity : BaseActivity() {
|
||||
try {
|
||||
target = File(cacheDir, "download_${System.currentTimeMillis()}.zip")
|
||||
WebDavManager.init(saved)
|
||||
val ok = WebDavManager.downloadFile(BACKUP_FILE_NAME, target)
|
||||
val ok = WebDavManager.downloadFile(WEBDAV_BACKUP_FILE_NAME, target)
|
||||
if (!ok) {
|
||||
withContext(Dispatchers.Main) {
|
||||
toastError(R.string.toast_failure)
|
||||
@@ -351,7 +348,7 @@ class BackupActivity : BaseActivity() {
|
||||
val url = dialogBinding.etWebdavUrl.text.toString().trim()
|
||||
val user = dialogBinding.etWebdavUser.text.toString().trim().ifEmpty { null }
|
||||
val pass = dialogBinding.etWebdavPass.text.toString()
|
||||
val remotePath = dialogBinding.etWebdavRemotePath.text.toString().trim().ifEmpty { "/" }
|
||||
val remotePath = dialogBinding.etWebdavRemotePath.text.toString().trim().ifEmpty { AppConfig.WEBDAV_BACKUP_DIR }
|
||||
val cfg = WebDavConfig(baseUrl = url, username = user, password = pass, remoteBasePath = remotePath)
|
||||
MmkvManager.encodeWebDavConfig(cfg)
|
||||
toastSuccess(R.string.toast_success)
|
||||
|
||||
@@ -375,24 +375,6 @@ object Utils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the backup directory.
|
||||
*
|
||||
* @param context The context to use.
|
||||
* @return The path to the backup directory.
|
||||
*/
|
||||
fun backupPath(context: Context?): String {
|
||||
if (context == null) return ""
|
||||
|
||||
return try {
|
||||
context.getExternalFilesDir(AppConfig.DIR_BACKUPS)?.absolutePath
|
||||
?: context.getDir(AppConfig.DIR_BACKUPS, 0).absolutePath
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "Failed to get backup path", e)
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the device ID for XUDP base key.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user