Hello all, I’m trying to write a file download met...
# ktor
a
Hello all, I’m trying to write a file download method using Ktor on a native/mpp app. here’s my method so far:
Copy code
suspend fun HttpClient.downloadFile(
    output: File,
    downloadUrl: Url,
    md5Hash: String
): Flow<DownloadResult> {
    return flow {
        try {
            val response = get<HttpResponse> { url(downloadUrl) }
            val data = ByteArray(response.contentLength()?.toInt() ?: 0)
            var offset = 0
            do {
                val progress = (offset.toDouble() / data.size) * 100
                emit(DownloadResult.Progress(progress))
                val currentRead = response.content.readAvailable(data, offset, data.size)
                offset += currentRead
            } while (currentRead > 0)

            if (response.status.isSuccess()) {
                if (data.md5().hex == md5Hash) {
                    output.write(data)
                    emit(DownloadResult.Success)
                } else {
                    emit(DownloadResult.ErrorCorruptFile)
                }
            } else {
                emit(DownloadResult.ErrorBadResponseCode(response.status.value))
            }
        } catch (e: TimeoutCancellationException) {
            emit(DownloadResult.ErrorRequestTimeout("Connection timed out", e))
        } catch (t: Throwable) {
            emit(DownloadResult.Error("Failed to connect", t))
        }
    }
}
The problem is that the 
response.content.readAvailable()
 method always seems to read the whole file at once without chunking it up, which means my progress emission only gets outputted once. I’m wondering if there’s something I’m doing wrong here? or if that’s normal behaviour? Also as a side note the file I’m testing on is 25MB so it should emit a few times I’d think.
t
(A) "/ data.size" may throw zero divide. you can't believe content length always provided. Use ByteArrayOutputStream to generate an extensible byte array. (B) Don't use readAvailable() that block while stream.available() <= 0.
👍 1
j
a
@tateisu what should I use instead of stream.readavailable()
Also thank you guys for the assistance. I appreciate it.