DownloadWorker: more work

This commit is contained in:
Rahul Patel
2025-02-27 05:46:55 +05:30
parent 46d4322976
commit 330762d86d
2 changed files with 47 additions and 41 deletions

View File

@@ -14,8 +14,7 @@ fun InputStream.copyTo(out: OutputStream, streamSize: Long): Flow<DownloadInfo>
var bytesCopied: Long = 0 var bytesCopied: Long = 0
val buffer = ByteArray(DEFAULT_BUFFER_SIZE) val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
var bytes = read(buffer) var bytes = read(buffer)
var lastTotalBytesRead: Long = 0
var lastTotalBytesRead = 0L
var speed: Long = 0 var speed: Long = 0
@Suppress("KotlinConstantConditions") // False-positive for bytesCopied always being zero @Suppress("KotlinConstantConditions") // False-positive for bytesCopied always being zero
val timer = fixedRateTimer("timer", true, 0L, 1000) { val timer = fixedRateTimer("timer", true, 0L, 1000) {
@@ -26,6 +25,8 @@ fun InputStream.copyTo(out: OutputStream, streamSize: Long): Flow<DownloadInfo>
while (bytes >= 0) { while (bytes >= 0) {
out.write(buffer, 0, bytes) out.write(buffer, 0, bytes)
out.flush()
bytesCopied += bytes bytesCopied += bytes
// Emit stream progress in percentage // Emit stream progress in percentage
emit(DownloadInfo((bytesCopied * 100 / streamSize).toInt(), bytes.toLong(), speed)) emit(DownloadInfo((bytesCopied * 100 / streamSize).toInt(), bytes.toLong(), speed))

View File

@@ -188,7 +188,12 @@ class DownloadWorker @AssistedInject constructor(
): Boolean = withContext(Dispatchers.IO) { ): Boolean = withContext(Dispatchers.IO) {
for (file in files) { for (file in files) {
try { try {
downloadFile(file) val success = downloadFile(file)
if (!success) {
Log.w(TAG, "Download failed for $packageName")
return@withContext false
}
if (isStopped) { if (isStopped) {
Log.w(TAG, "Download cancelled for $packageName") Log.w(TAG, "Download cancelled for $packageName")
@@ -288,24 +293,24 @@ class DownloadWorker @AssistedInject constructor(
* Downloads the file from the given request. * Downloads the file from the given request.
* Failed downloads aren't removed and persists as long as [CacheWorker] doesn't cleans them. * Failed downloads aren't removed and persists as long as [CacheWorker] doesn't cleans them.
* @param gFile A [GPlayFile] to download * @param gFile A [GPlayFile] to download
* @return A [Result] indicating whether the file was downloaded or not. * @return A [Boolean] indicating whether the file was downloaded or not.
*/ */
private suspend fun downloadFile(gFile: GPlayFile): Result { private suspend fun downloadFile(gFile: GPlayFile): Boolean = withContext(Dispatchers.IO) {
Log.i(TAG, "Downloading ${gFile.name}") Log.i(TAG, "Downloading ${gFile.name}")
return withContext(Dispatchers.IO) {
val file = PathUtil.getLocalFile(appContext, gFile, download) val file = PathUtil.getLocalFile(appContext, gFile, download)
// If file exists and has integrity intact, no need to download again // If file exists and has integrity intact, no need to download again
if (file.exists() && verifyFile(gFile)) { if (file.exists() && verifyFile(gFile)) {
Log.i(TAG, "$file is already downloaded!") Log.i(TAG, "$file is already downloaded!")
downloadedBytes += file.length() downloadedBytes += file.length()
return@withContext Result.success() return@withContext true
} }
val tmpFileSuffix = ".tmp"
val tmpFile = File(file.absolutePath + tmpFileSuffix)
try { try {
// Download as a temporary file to avoid installing corrupted files // Download as a temporary file to avoid installing corrupted files
val tmpFileSuffix = ".tmp"
val tmpFile = File(file.absolutePath + tmpFileSuffix)
val isNewFile = tmpFile.createNewFile() val isNewFile = tmpFile.createNewFile()
val okHttpClient = httpClient as HttpClient val okHttpClient = httpClient as HttpClient
@@ -319,7 +324,7 @@ class DownloadWorker @AssistedInject constructor(
okHttpClient.call(gFile.url, headers).body?.byteStream()?.use { input -> okHttpClient.call(gFile.url, headers).body?.byteStream()?.use { input ->
FileOutputStream(tmpFile, !isNewFile).use { FileOutputStream(tmpFile, !isNewFile).use {
input.copyTo(it, gFile.size).collect { p -> onProgress(p) } input.copyTo(it, gFile.size).collect { info -> onProgress(info) }
} }
} }
@@ -327,12 +332,12 @@ class DownloadWorker @AssistedInject constructor(
throw Exception("Failed to remove .tmp extension from $tmpFile") throw Exception("Failed to remove .tmp extension from $tmpFile")
} }
return@withContext Result.success() return@withContext true
} catch (exception: Exception) { } catch (exception: Exception) {
Log.e(TAG, "Failed to download $file!", exception) Log.e(TAG, "Failed to download $file!", exception)
tmpFile.delete()
notifyStatus(DownloadStatus.FAILED) notifyStatus(DownloadStatus.FAILED)
return@withContext Result.failure() return@withContext true
}
} }
} }