I have an issue using <kotlinx.io> in a kotlin mpp...
# io
m
I have an issue using kotlinx.io in a kotlin mpp. The situation is that I use FileKit (https://github.com/vinceglb/FileKit) to select files on the different platforms (android, ios, jvm, etc.). FileKit returns a PlatformFile which can return a PlatformInputStream. This stream has a
readInto
method which is a suspend method (which makes sense with io operations). I want convert this FileKit specific PlatformInputStream into a generic kotlinx.io (Raw)Source to further use in my application. However, the kotlinx.io RawSource has a method, override fun
readAtMostTo
, which I need to implement for this, but this method is not a suspend function. Because this is a MPP and both FileKit and kotlinx.io are also MPP I think I should be able to make this work in common code, but I fail because the readInto method is not a suspend function but I need a coroutine context to call the readAtMostTo and wait for the result to return. In jvm I would be able to use runBlocking to call and wait for the result, but this is not possible in MPP common code. I really thought about different solutions but I cannot find a good solution for this. Does anybody have an idea? For simplicity here is some pseudo code showing what I try to achieve:
Copy code
class PlatformInputStreamSource(
    private val platformInputStream: PlatformInputStream
) : RawSource {
    override fun readAtMostTo(sink: Buffer, byteCount: Long): Long {
        ...
        
        << Here i need to start a coroutine context and wait for the numberOfBytesCopied
        val numberOfBytesCopied = platformInputStream.readInto(buffer, byteCount, bufferSize))
        
        ...
        
        << This non suspend function needs to return the number of bytes copied and therefor has to wait for the result from the readInto function.
        return numberOfBytesCopied.toLong()
    }
}
f
Unfortunately, there's no easy and always correct way to emulate
runBlocking
for Web targets. There are some hacky approaches that might work (like scheduling
readInto
call via
setTimeout
and then polling the status in a loop inside the
readAtMostTo
implementation), but such approaches need to be considered twice before using them. There was an attempt to provide suspendable counterparts for
RawSink
and
RawSource
, but it is currently on pause (mainly, because there were not so many use cases to work with). However, there are some outcomes of the work we had done that you may find helpful. We concluded, that the best we can do in order to bridge blocking and suspendable IO APIs is abstain from reimplementing all the blocking functions with
suspend
keyword being added to declarations. Instead, only a few suspendable function responsible for filling a
kotlinx.io.Buffer
could be introduced. Once they filled a buffer, all the blocking API could be used without worrying about the
suspend
attribute. See https://github.com/Kotlin/kotlinx-io/issues/163#issuecomment-1669133140. Perhaps, that approach would make more sense for you compared to all the hacks required to emulate
runBlocking
across all KMP targets.
m
Hi Filipp Zhinkin, thank you for the reply. In a sense I am happy with your answer because I was really doubting myself if I overlooked something very obvious. Indeed doing some kind of polling on a call was one solution I found which is not preferred but maybe as a temporary solution could abstract away the problem in common code. I will look into the link you provided, but at least I now know it is really not something I overlooked 🙂.