Avoid incomplete downloads in cache
Previously, when a download was aborted (e.g. due to a bad internet connection), a partly downloaded file was remaining in cache, which would then be delivered upon later requests. This can lead e.g. to chats where images aren't loading. To avoid this, first download files to a temporary file that is not the final cache file, and only rename/move it on finish. Note that if you already have broken downloads, you still need to clear cache once to get rid of them after this commit, but it should not occur anymore afterwards.
This commit is contained in:
parent
910c0ff326
commit
4ef1f5c90f
@ -131,8 +131,14 @@ internal class DefaultFileService @Inject constructor(
|
||||
Timber.v("Response size ${response.body?.contentLength()} - Stream available: ${!source.exhausted()}")
|
||||
|
||||
// Write the file to cache (encrypted version if the file is encrypted)
|
||||
writeToFile(source.inputStream(), cachedFiles.file)
|
||||
// Write to a tmp file first, so if we abort before done, we don't have a broken cached file
|
||||
val tmpFile = File(cachedFiles.file.parentFile, "${cachedFiles.file.name}.tmp")
|
||||
if (tmpFile.exists()) {
|
||||
Timber.v("## FileService: discard aborted tmp file ${tmpFile.path}")
|
||||
}
|
||||
writeToFile(source.inputStream(), tmpFile)
|
||||
response.close()
|
||||
tmpFile.renameTo(cachedFiles.file)
|
||||
} else {
|
||||
Timber.v("## FileService: cache hit for $url")
|
||||
}
|
||||
@ -145,8 +151,13 @@ internal class DefaultFileService @Inject constructor(
|
||||
Timber.v("## FileService: decrypt file")
|
||||
// Ensure the parent folder exists
|
||||
cachedFiles.decryptedFile.parentFile?.mkdirs()
|
||||
// Write to a tmp file first, so if we abort before done, we don't have a broken cached file
|
||||
val tmpFile = File(cachedFiles.decryptedFile.parentFile, "${cachedFiles.decryptedFile.name}.tmp")
|
||||
if (tmpFile.exists()) {
|
||||
Timber.v("## FileService: discard aborted tmp file ${tmpFile.path}")
|
||||
}
|
||||
val decryptSuccess = cachedFiles.file.inputStream().use { inputStream ->
|
||||
cachedFiles.decryptedFile.outputStream().buffered().use { outputStream ->
|
||||
tmpFile.outputStream().buffered().use { outputStream ->
|
||||
MXEncryptedAttachments.decryptAttachment(
|
||||
inputStream,
|
||||
elementToDecrypt,
|
||||
@ -154,6 +165,7 @@ internal class DefaultFileService @Inject constructor(
|
||||
)
|
||||
}
|
||||
}
|
||||
tmpFile.renameTo(cachedFiles.decryptedFile)
|
||||
if (!decryptSuccess) {
|
||||
throw IllegalStateException("Decryption error")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user