Stefan Oltmann
08/10/2023, 1:01 PMStefan Oltmann
08/10/2023, 1:02 PMoverride suspend fun getPhotoMetadataBytes(
uri: String
): ImageMetadata? = withContext(dispatcher) {
runCatchingNetworkException("OneDrive metadata") {
val url = "$MICROSOFT_API_URL/me/drive/items/$uri/content"
httpClient.prepareGet(url).execute { httpResponse ->
val channel: ByteReadChannel = httpResponse.body()
val length = httpResponse.contentLength()
if (length == null) {
Log.debug("No content length for request $uri")
return@execute null
}
return@execute Kim.readMetadata(
byteReader = KtorByteReadChannelByteReader(channel),
length = length
)
}
}
}
class KtorByteReadChannelByteReader(
private val channel: ByteReadChannel,
private val bufferSize: Long = DEFAULT_BUFFER_SIZE
) : ByteReader {
private var buffer: ByteArray = byteArrayOf()
private var bufferOffset = 0
private var bufferLimit = 0
override fun readByte(): Byte? {
if (bufferOffset >= bufferLimit) {
if (channel.isClosedForRead)
return null
// Buffer is empty, read more data from the channel
buffer = runBlocking {
channel.readRemaining(limit = bufferSize).readBytes()
}
bufferLimit = buffer.size
bufferOffset = 0
}
return buffer[bufferOffset++]
}
override fun readBytes(count: Int): ByteArray {
val result = ByteArray(count)
var remaining = count
var offset = 0
while (remaining > 0) {
if (bufferOffset >= bufferLimit) {
if (channel.isClosedForRead)
break
// Buffer is empty, read more data from the channel
buffer = runBlocking {
channel.readRemaining(limit = bufferSize).readBytes()
}
bufferLimit = buffer.size
bufferOffset = 0
}
val bytesToCopy = minOf(remaining, bufferLimit - bufferOffset)
buffer.copyInto(result, offset, bufferOffset, bufferOffset + bytesToCopy)
offset += bytesToCopy
bufferOffset += bytesToCopy
remaining -= bytesToCopy
}
return result
}
override fun close() {
runBlocking {
channel.cancel()
}
}
companion object {
private const val DEFAULT_BUFFER_SIZE: Long = 32 * 1024
}
}
Stefan Oltmann
08/10/2023, 3:31 PMval url = "$MICROSOFT_API_URL/me/drive/items/$uri/content"
val input: ByteReadPacket = httpClient.get(url).body()
Kim.readMetadata(input)
Stefan Oltmann
08/10/2023, 5:34 PMAleksei Tirman [JB]
08/11/2023, 8:07 AMByteReadChannel.readFully
method and then using the resulted ByteArray
or ByteBuffer
?Stefan Oltmann
08/11/2023, 8:15 AMAleksei Tirman [JB]
08/11/2023, 8:25 AMreadMetadata
method which accepts a ByteReadChannel
?Aleksei Tirman [JB]
08/11/2023, 8:26 AMInput
which you already accept but asynchronous.Stefan Oltmann
08/11/2023, 11:48 AMKtorByteReadChannelByteReader
above.
My problem is, that I'm not sure if this is the right implementation to use ByteReadChannel
in a performant way.Aleksei Tirman [JB]
08/11/2023, 12:01 PMByteReader
and why do you have to implement it?Stefan Oltmann
08/11/2023, 4:11 PM