Dazai
04/14/2022, 10:36 AMjava.lang.NegativeArraySizeException: -1537060379
at <http://io.ktor.utils.io|io.ktor.utils.io>.core.StringsKt.readBytes(Strings.kt:165)
at <http://io.ktor.utils.io|io.ktor.utils.io>.core.StringsKt.readBytes$default(Strings.kt:162)
at io.ktor.client.call.SavedCallKt.save(SavedCall.kt:73)
at io.ktor.client.call.SavedCallKt$save$1.invokeSuspend(SavedCall.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:39)
at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Sam
04/14/2022, 10:42 AMNegativeArraySizeException
typically indicates an overflow, i.e. something tried to allocate an array which is bigger than Int.MAX_VALUE
Sam
04/14/2022, 10:43 AMSam
04/14/2022, 10:44 AMDazai
04/14/2022, 10:52 AMsuspend fun downloadFile(
saveLocation: File,
fileUrl: String,
retries: Int = 2,
delay: Long = Random().nextLong(2000, 5000),
overwrite: Boolean = false
): Boolean {
if (retries < 0) return false
if (saveLocation.exists() && !overwrite) return true
if (fileUrl == "null") return true
saveLocation.delete()
if (!saveLocation.createNewFile()) return false
try {
logger.info { "Attempting to download $fileUrl, $retries retries remaining" }
val response: HttpResponse = client.get(fileUrl)
val channel = response.bodyAsChannel()
val byteBufferSize = 128000
while (channel.availableForRead > 0 || !channel.isClosedForRead) {
if (channel.availableForRead < byteBufferSize) {
saveLocation.appendBytes(channel.readRemaining().readBytes())
} else {
saveLocation.appendBytes(channel.readPacket(byteBufferSize).readBytes())
}
}
return true
} catch (e: Exception) {
e.printStackTrace()
delay(delay)
return downloadFile(saveLocation, fileUrl, retries - 1)
}
}
Dazai
04/14/2022, 10:53 AMDazai
04/14/2022, 10:53 AMSam
04/14/2022, 12:28 PMSavedCall
, which indicates to me that ktor is downloading the entire response into memory, rather than streaming itSam
04/14/2022, 12:28 PMclient.get
Sam
04/14/2022, 12:28 PMSam
04/14/2022, 12:29 PMclient.prepareGet(...).execute { ... }
to stream the response instead (where the code to consume the response goes inside the execute
block)Sam
04/14/2022, 12:32 PMInt.MAX_VALUE
bytesSam
04/14/2022, 12:39 PMchristophsturm
04/14/2022, 12:51 PMhttpClient.get<HttpStatement>
Dazai
04/15/2022, 4:11 AM