refactor(downloaders): improve file system code (#1379)

This commit is contained in:
Ax333l 2023-10-14 17:42:10 +02:00 committed by GitHub
parent 56a4a7043d
commit 8f6d720454
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 50 deletions

View File

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "5515d164bc8f713201506d42a02d337f",
"identityHash": "371c7a84b122a2de8b660b35e6e9ce14",
"entities": [
{
"tableName": "patch_bundles",
@ -160,7 +160,7 @@
},
{
"tableName": "downloaded_app",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `version` TEXT NOT NULL, `file` TEXT NOT NULL, PRIMARY KEY(`package_name`, `version`))",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `version` TEXT NOT NULL, `directory` TEXT NOT NULL, PRIMARY KEY(`package_name`, `version`))",
"fields": [
{
"fieldPath": "packageName",
@ -175,8 +175,8 @@
"notNull": true
},
{
"fieldPath": "file",
"columnName": "file",
"fieldPath": "directory",
"columnName": "directory",
"affinity": "TEXT",
"notNull": true
}
@ -300,7 +300,7 @@
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '5515d164bc8f713201506d42a02d337f')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '371c7a84b122a2de8b660b35e6e9ce14')"
]
}
}

View File

@ -16,5 +16,5 @@ class Converters {
fun fileFromString(value: String) = File(value)
@TypeConverter
fun fileToString(file: File): String = file.absolutePath
fun fileToString(file: File): String = file.path
}

View File

@ -11,5 +11,5 @@ import java.io.File
data class DownloadedApp(
@ColumnInfo(name = "package_name") val packageName: String,
@ColumnInfo(name = "version") val version: String,
@ColumnInfo(name = "file") val file: File,
@ColumnInfo(name = "directory") val directory: File,
)

View File

@ -1,34 +1,61 @@
package app.revanced.manager.domain.repository
import android.app.Application
import android.content.Context
import app.revanced.manager.data.room.AppDatabase
import app.revanced.manager.data.room.AppDatabase.Companion.generateUid
import app.revanced.manager.data.room.apps.downloaded.DownloadedApp
import app.revanced.manager.network.downloader.AppDownloader
import kotlinx.coroutines.flow.distinctUntilChanged
import java.io.File
class DownloadedAppRepository(
app: Application,
db: AppDatabase
) {
private val dir = app.getDir("downloaded-apps", Context.MODE_PRIVATE)
private val dao = db.downloadedAppDao()
fun getAll() = dao.getAllApps().distinctUntilChanged()
suspend fun get(packageName: String, version: String) = dao.get(packageName, version)
fun getApkFileForApp(app: DownloadedApp): File = getApkFileForDir(dir.resolve(app.directory))
private fun getApkFileForDir(directory: File) = directory.listFiles()!!.first()
suspend fun add(
packageName: String,
version: String,
file: File
) = dao.insert(
DownloadedApp(
packageName = packageName,
version = version,
file = file
)
)
suspend fun download(
app: AppDownloader.App,
preferSplits: Boolean,
onDownload: suspend (downloadProgress: Pair<Float, Float>?) -> Unit = {},
): File {
this.get(app.packageName, app.version)?.let { downloaded ->
return getApkFileForApp(downloaded)
}
// Converted integers cannot contain / or .. unlike the package name or version, so they are safer to use here.
val relativePath = File(generateUid().toString())
val savePath = dir.resolve(relativePath).also { it.mkdirs() }
try {
app.download(savePath, preferSplits, onDownload)
dao.insert(DownloadedApp(
packageName = app.packageName,
version = app.version,
directory = relativePath,
))
} catch (e: Exception) {
savePath.deleteRecursively()
throw e
}
// Return the Apk file.
return getApkFileForDir(savePath)
}
suspend fun get(packageName: String, version: String) = dao.get(packageName, version)
suspend fun delete(downloadedApps: Collection<DownloadedApp>) {
downloadedApps.forEach {
it.file.deleteRecursively()
dir.resolve(it.directory).deleteRecursively()
}
dao.delete(downloadedApps)

View File

@ -171,7 +171,7 @@ class APKMirror : AppDownloader, KoinComponent {
saveDirectory: File,
preferSplit: Boolean,
onDownload: suspend (downloadProgress: Pair<Float, Float>?) -> Unit
): File {
) {
val variants = httpClient.getHtml { url(apkMirror + downloadLink) }
.div {
withClass = "variants-table"
@ -246,18 +246,10 @@ class APKMirror : AppDownloader, KoinComponent {
}
}
val saveLocation = if (variant.apkType == APKType.BUNDLE)
saveDirectory.resolve(version).also { it.mkdirs() }
else
saveDirectory.resolve("$version.apk")
val targetFile = saveDirectory.resolve("base.apk")
try {
val downloadLocation = if (variant.apkType == APKType.BUNDLE)
saveLocation.resolve("temp.zip")
else
saveLocation
httpClient.download(downloadLocation) {
httpClient.download(targetFile) {
url(apkMirror + downloadLink)
onDownload { bytesSentTotal, contentLength ->
onDownload(bytesSentTotal.div(100000).toFloat().div(10) to contentLength.div(100000).toFloat().div(10))
@ -267,16 +259,11 @@ class APKMirror : AppDownloader, KoinComponent {
if (variant.apkType == APKType.BUNDLE) {
// TODO: Extract temp.zip
downloadLocation.delete()
targetFile.delete()
}
} catch (e: Exception) {
saveLocation.deleteRecursively()
throw e
} finally {
onDownload(null)
}
return saveLocation
}
}

View File

@ -22,7 +22,6 @@ interface AppDownloader {
saveDirectory: File,
preferSplit: Boolean,
onDownload: suspend (downloadProgress: Pair<Float, Float>?) -> Unit = {}
): File
)
}
}

View File

@ -190,19 +190,11 @@ class PatcherWorker(
val inputFile = when (val selectedApp = args.input) {
is SelectedApp.Download -> {
val savePath = applicationContext.filesDir.resolve("downloaded-apps")
.resolve(args.input.packageName).also { it.mkdirs() }
selectedApp.app.download(
savePath,
downloadedAppRepository.download(
selectedApp.app,
prefs.preferSplits.get(),
onDownload = { downloadProgress.emit(it) }
).also {
downloadedAppRepository.add(
args.input.packageName,
args.input.version,
it
)
args.setInputFile(it)
updateProgress() // Downloading
}

View File

@ -68,7 +68,7 @@ class VersionSelectorViewModel(
}
val downloadedVersions = downloadedAppRepository.getAll().map { downloadedApps ->
downloadedApps.filter { it.packageName == packageName }.map { SelectedApp.Local(it.packageName, it.version, it.file, false) }
downloadedApps.filter { it.packageName == packageName }.map { SelectedApp.Local(it.packageName, it.version, downloadedAppRepository.getApkFileForApp(it), false) }
}
init {