mirror of
https://github.com/amir1376/ab-download-manager.git
synced 2025-02-20 11:43:24 +08:00
handle a situation when some webservers does not respect range header at first place
This commit is contained in:
parent
c06da4aaa7
commit
5f4ab5889c
@ -356,9 +356,14 @@ class DownloadJob(
|
||||
}
|
||||
|
||||
private fun onPartHaveToManyError(throwable: Throwable) {
|
||||
var paused = false
|
||||
if (throwable is DownloadValidationException) {
|
||||
scope.launch {
|
||||
pause(throwable)
|
||||
if (throwable.isCritical()){
|
||||
//stop the whole job! as we have big problem here
|
||||
paused = true
|
||||
scope.launch {
|
||||
pause(throwable)
|
||||
}
|
||||
}
|
||||
}
|
||||
val allHaveError = partDownloaderList.values
|
||||
@ -366,11 +371,11 @@ class DownloadJob(
|
||||
.all {
|
||||
it.injured()
|
||||
}
|
||||
if (allHaveError) {
|
||||
if (allHaveError && !paused) {
|
||||
// println("all have error!")
|
||||
scope.launch {
|
||||
// println("request pause send")
|
||||
pause(TooManyErrorException())
|
||||
pause(TooManyErrorException(throwable))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
package ir.amirab.downloader.exception
|
||||
|
||||
abstract class DownloadValidationException(msg:String):Exception(msg)
|
||||
abstract class DownloadValidationException(msg:String):Exception(msg){
|
||||
abstract fun isCritical():Boolean
|
||||
}
|
@ -2,16 +2,20 @@ package ir.amirab.downloader.exception
|
||||
|
||||
|
||||
sealed class FileChangedException(msg:String, ):DownloadValidationException(msg){
|
||||
override fun isCritical(): Boolean{
|
||||
// download must stop immediately
|
||||
return true
|
||||
}
|
||||
class LengthChangedException(
|
||||
val lastContentLength: Long,
|
||||
val newContentLength: Long
|
||||
) : DownloadValidationException(
|
||||
) : FileChangedException(
|
||||
"File size changed since last download! last time was $lastContentLength now it's $newContentLength"
|
||||
)
|
||||
class ETagChangedException(
|
||||
val oldETag: String,
|
||||
val newETag: String
|
||||
) : DownloadValidationException(
|
||||
) : FileChangedException(
|
||||
"File content changed since last download! last time was $oldETag now it's $newETag"
|
||||
)
|
||||
}
|
@ -5,4 +5,9 @@ class NoSpaceInStorageException(
|
||||
val required: Long
|
||||
) : DownloadValidationException(
|
||||
"No space available required=$required , available=$available"
|
||||
)
|
||||
) {
|
||||
override fun isCritical(): Boolean {
|
||||
// there is no space in users file system so we should stop
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,21 @@
|
||||
package ir.amirab.downloader.exception
|
||||
|
||||
//it should not happened unless web server is not respect our header
|
||||
class ServerPartIsNotTheSameAsWeExpectException(msg: String) : DownloadValidationException(msg)
|
||||
//it should not happen unless web server is not respect our header
|
||||
class ServerPartIsNotTheSameAsWeExpectException(
|
||||
start:Long,
|
||||
end:Long?,
|
||||
expectedLength:Long?,
|
||||
actualLength:Long?,
|
||||
) : DownloadValidationException (
|
||||
"Response Length not match.expecting '${expectedLength}',but we got '$actualLength',requested range is range is ${start}-${end}"
|
||||
// + "\n request headers ${conn.responseInfo.requestHeaders}"
|
||||
// + "\n response headers ${conn.responseInfo.responseHeaders}"
|
||||
){
|
||||
override fun isCritical(): Boolean {
|
||||
// some webservers somehow does not return the expected size at the first place
|
||||
// but after some try... they do!!!
|
||||
// because of them, I have to make this error non-critical
|
||||
// I have to investigate why!
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package ir.amirab.downloader.exception
|
||||
|
||||
class TooManyErrorException : Exception(
|
||||
"Download is stopped because all parts exceeds max retries"
|
||||
class TooManyErrorException(
|
||||
lastException: Throwable,
|
||||
) : Exception(
|
||||
"Download is stopped because all parts exceeds max retries",
|
||||
lastException,
|
||||
)
|
||||
|
@ -121,14 +121,12 @@ class PartDownloader(
|
||||
} catch (e: Exception) {
|
||||
tries++
|
||||
onCanceled(e)
|
||||
if (!canRetry(e)) {
|
||||
if (e is DownloadValidationException) {
|
||||
iCantRetryAnymore(e)
|
||||
}
|
||||
break
|
||||
} else {
|
||||
continue
|
||||
when(canRetry(e)){
|
||||
CanRetryResult.Yes -> continue
|
||||
CanRetryResult.No -> {}
|
||||
CanRetryResult.NoAndStopDownloadJob -> iCantRetryAnymore(e)
|
||||
}
|
||||
break
|
||||
}
|
||||
//download progress started, but maybe we have errors
|
||||
//wait for a finish/error event...
|
||||
@ -138,16 +136,13 @@ class PartDownloader(
|
||||
}
|
||||
when (status) {
|
||||
is PartDownloadStatus.Canceled -> {
|
||||
|
||||
if (!canRetry(status.e)) {
|
||||
if (status.e is DownloadValidationException) {
|
||||
iCantRetryAnymore(status.e)
|
||||
}
|
||||
break
|
||||
} else {
|
||||
tries++
|
||||
continue
|
||||
tries++
|
||||
when(canRetry(status.e)){
|
||||
CanRetryResult.Yes -> continue
|
||||
CanRetryResult.No -> {}
|
||||
CanRetryResult.NoAndStopDownloadJob -> iCantRetryAnymore(status.e)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
PartDownloadStatus.Completed -> break
|
||||
@ -169,15 +164,26 @@ class PartDownloader(
|
||||
}
|
||||
}
|
||||
|
||||
private fun canRetry(e: Throwable): Boolean {
|
||||
private sealed interface CanRetryResult{
|
||||
data object Yes:CanRetryResult
|
||||
data object No:CanRetryResult
|
||||
data object NoAndStopDownloadJob:CanRetryResult
|
||||
}
|
||||
|
||||
private fun canRetry(e: Throwable): CanRetryResult {
|
||||
return when {
|
||||
ExceptionUtils.isNormalCancellation(e) -> {
|
||||
false
|
||||
CanRetryResult.No
|
||||
}
|
||||
e is DownloadValidationException -> if (e.isCritical()){
|
||||
//download validation occurs, and also it is critical,
|
||||
//so we can't proceed any further
|
||||
CanRetryResult.NoAndStopDownloadJob
|
||||
}else{
|
||||
CanRetryResult.Yes
|
||||
}
|
||||
|
||||
e is DownloadValidationException -> false
|
||||
else -> {
|
||||
true
|
||||
CanRetryResult.Yes
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,9 +231,10 @@ class PartDownloader(
|
||||
if (contentLength != partCopy.remainingLength) {
|
||||
conn.closeable.close()
|
||||
throw ServerPartIsNotTheSameAsWeExpectException(
|
||||
"part remaining length: ${part.remainingLength} and response length: ${conn.contentLength} not match"
|
||||
+ "\n request headers ${conn.responseInfo.requestHeaders}"
|
||||
+ "\n response headers ${conn.responseInfo.responseHeaders}"
|
||||
start = partCopy.current,
|
||||
end = partCopy.to,
|
||||
expectedLength = partCopy.remainingLength,
|
||||
actualLength = contentLength
|
||||
)
|
||||
}
|
||||
thread = thread {
|
||||
|
Loading…
x
Reference in New Issue
Block a user