DownloadWorker: Extract and simplify GPlayFile -> File logic
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
package com.aurora.store.data.model
|
||||
|
||||
import java.io.File
|
||||
|
||||
data class Request(
|
||||
val url: String,
|
||||
val file: File,
|
||||
val size: Long,
|
||||
val sha1: String,
|
||||
val sha256: String
|
||||
)
|
||||
@@ -27,7 +27,6 @@ import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.model.Algorithm
|
||||
import com.aurora.store.data.model.DownloadInfo
|
||||
import com.aurora.store.data.model.DownloadStatus
|
||||
import com.aurora.store.data.model.Request
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.data.room.download.Download
|
||||
@@ -125,7 +124,7 @@ class DownloadWorker @AssistedInject constructor(
|
||||
}
|
||||
|
||||
// Purchase the app (free apps needs to be purchased too)
|
||||
val requestList = mutableListOf<Request>()
|
||||
val requestList = mutableListOf<GPlayFile>()
|
||||
if (download.sharedLibs.isNotEmpty()) {
|
||||
download.sharedLibs.forEach {
|
||||
PathUtil.getLibDownloadDir(
|
||||
@@ -135,10 +134,10 @@ class DownloadWorker @AssistedInject constructor(
|
||||
it.packageName
|
||||
).mkdirs()
|
||||
it.fileList = it.fileList.ifEmpty { purchase(it.packageName, it.versionCode, 0) }
|
||||
requestList.addAll(getDownloadRequest(it.fileList, it.packageName))
|
||||
requestList.addAll(it.fileList)
|
||||
}
|
||||
}
|
||||
requestList.addAll(getDownloadRequest(download.fileList, null))
|
||||
requestList.addAll(download.fileList)
|
||||
|
||||
// Update data for notification
|
||||
download.totalFiles = requestList.size
|
||||
@@ -169,12 +168,6 @@ class DownloadWorker @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
if (!requestList.all { it.file.exists() }) {
|
||||
Log.e(TAG, "Downloaded files are missing")
|
||||
onFailure()
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
// Mark download as completed
|
||||
onSuccess()
|
||||
return Result.success()
|
||||
@@ -237,47 +230,29 @@ class DownloadWorker @AssistedInject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDownloadRequest(files: List<GPlayFile>, libPackageName: String?): List<Request> {
|
||||
val downloadList = mutableListOf<Request>()
|
||||
files.filter { it.url.isNotBlank() }.forEach {
|
||||
val file = when (it.type) {
|
||||
GPlayFile.FileType.BASE, GPlayFile.FileType.SPLIT -> {
|
||||
PathUtil.getApkDownloadFile(
|
||||
appContext, download.packageName, download.versionCode, it, libPackageName
|
||||
)
|
||||
}
|
||||
|
||||
GPlayFile.FileType.OBB, GPlayFile.FileType.PATCH -> {
|
||||
PathUtil.getObbDownloadFile(download.packageName, it)
|
||||
}
|
||||
}
|
||||
downloadList.add(Request(it.url, file, it.size, it.sha1, it.sha256))
|
||||
}
|
||||
return downloadList
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the file from the given request.
|
||||
* Failed downloads aren't removed and persists as long as [CacheWorker] doesn't cleans them.
|
||||
* @param request A [Request] to download
|
||||
* @param gFile A [GPlayFile] to download
|
||||
* @return A [Result] indicating whether the file was downloaded or not.
|
||||
*/
|
||||
private suspend fun downloadFile(request: Request): Result {
|
||||
private suspend fun downloadFile(gFile: GPlayFile): Result {
|
||||
return withContext(Dispatchers.IO) {
|
||||
val algorithm = if (request.sha256.isBlank()) Algorithm.SHA1 else Algorithm.SHA256
|
||||
val expectedSha = if (algorithm == Algorithm.SHA1) request.sha1 else request.sha256
|
||||
val file = PathUtil.getLocalFile(appContext, gFile, download)
|
||||
val algorithm = if (gFile.sha256.isBlank()) Algorithm.SHA1 else Algorithm.SHA256
|
||||
val expectedSha = if (algorithm == Algorithm.SHA1) gFile.sha1 else gFile.sha256
|
||||
|
||||
// If file exists and sha matches the request, no need to download again
|
||||
if (request.file.exists() && validSha(request.file, expectedSha, algorithm)) {
|
||||
Log.i(TAG, "${request.file} is already downloaded!")
|
||||
downloadedBytes += request.file.length()
|
||||
if (file.exists() && validSha(file, expectedSha, algorithm)) {
|
||||
Log.i(TAG, "$file is already downloaded!")
|
||||
downloadedBytes += file.length()
|
||||
return@withContext Result.success()
|
||||
}
|
||||
|
||||
try {
|
||||
// Download as a temporary file to avoid installing corrupted files
|
||||
val tmpFileSuffix = ".tmp"
|
||||
val tmpFile = File(request.file.absolutePath + tmpFileSuffix)
|
||||
val tmpFile = File(file.absolutePath + tmpFileSuffix)
|
||||
val isNewFile = tmpFile.createNewFile()
|
||||
|
||||
val okHttpClient = httpClient as HttpClient
|
||||
@@ -289,9 +264,9 @@ class DownloadWorker @AssistedInject constructor(
|
||||
headers["Range"] = "bytes=${tmpFile.length()}-"
|
||||
}
|
||||
|
||||
okHttpClient.call(request.url, headers).body?.byteStream()?.use { input ->
|
||||
okHttpClient.call(gFile.url, headers).body?.byteStream()?.use { input ->
|
||||
FileOutputStream(tmpFile, !isNewFile).use {
|
||||
input.copyTo(it, request.size).collect { p -> onProgress(p) }
|
||||
input.copyTo(it, gFile.size).collect { p -> onProgress(p) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,13 +275,13 @@ class DownloadWorker @AssistedInject constructor(
|
||||
throw Exception("Incorrect hash for $tmpFile")
|
||||
}
|
||||
|
||||
if (!tmpFile.renameTo(request.file)) {
|
||||
if (!tmpFile.renameTo(file)) {
|
||||
throw Exception("Failed to remove .tmp extension from $tmpFile")
|
||||
}
|
||||
|
||||
return@withContext Result.success()
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to download ${request.file}!", exception)
|
||||
Log.e(TAG, "Failed to download $file!", exception)
|
||||
notifyStatus(DownloadStatus.FAILED)
|
||||
return@withContext Result.failure()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package com.aurora.store.util
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import com.aurora.store.data.room.download.Download
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import com.aurora.gplayapi.data.models.File as GPlayFile
|
||||
@@ -62,19 +63,33 @@ object PathUtil {
|
||||
)
|
||||
}
|
||||
|
||||
fun getApkDownloadFile(
|
||||
context: Context,
|
||||
packageName: String,
|
||||
versionCode: Int,
|
||||
file: GPlayFile,
|
||||
sharedLibPackageName: String? = null
|
||||
): File {
|
||||
val downloadDir = if (!sharedLibPackageName.isNullOrBlank()) {
|
||||
getLibDownloadDir(context, packageName, versionCode, sharedLibPackageName)
|
||||
} else {
|
||||
getAppDownloadDir(context, packageName, versionCode)
|
||||
/**
|
||||
* Returns an instance of java's [File] class for the given [GPlayFile]
|
||||
* @param context [Context]
|
||||
* @param gFile [GPlayFile] to download
|
||||
* @param download An instance of [Download]
|
||||
*/
|
||||
fun getLocalFile(context: Context, gFile: GPlayFile, download: Download): File {
|
||||
val isSharedLib = download.sharedLibs.any { it.fileList.contains(gFile) }
|
||||
return when (gFile.type) {
|
||||
GPlayFile.FileType.BASE, GPlayFile.FileType.SPLIT -> {
|
||||
val downloadDir = if (isSharedLib) {
|
||||
getLibDownloadDir(
|
||||
context,
|
||||
download.packageName,
|
||||
download.versionCode,
|
||||
download.packageName
|
||||
)
|
||||
} else {
|
||||
getAppDownloadDir(context, download.packageName, download.versionCode)
|
||||
}
|
||||
return File(downloadDir, gFile.name)
|
||||
}
|
||||
|
||||
GPlayFile.FileType.OBB, GPlayFile.FileType.PATCH -> {
|
||||
File(getObbDownloadDir(download.packageName), gFile.name)
|
||||
}
|
||||
}
|
||||
return File(downloadDir, file.name)
|
||||
}
|
||||
|
||||
fun getZipFile(context: Context, packageName: String, versionCode: Int): File {
|
||||
@@ -91,10 +106,6 @@ object PathUtil {
|
||||
return File(Environment.getExternalStorageDirectory(), "/Android/obb/$packageName")
|
||||
}
|
||||
|
||||
fun getObbDownloadFile(packageName: String, file: GPlayFile): File {
|
||||
return File(getObbDownloadDir(packageName), file.name)
|
||||
}
|
||||
|
||||
fun getSpoofDirectory(context: Context): File {
|
||||
return File(context.filesDir, SPOOF)
|
||||
}
|
||||
@@ -105,15 +116,5 @@ object PathUtil {
|
||||
file.createNewFile()
|
||||
return file
|
||||
}
|
||||
|
||||
fun canReadWriteOBB(context: Context): Boolean {
|
||||
val obbDir = context.obbDir.parentFile
|
||||
|
||||
if (obbDir != null) {
|
||||
return obbDir.exists() && obbDir.canRead() && obbDir.canWrite()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user