Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-platform InputStream Alternative in Kotlin?

I’m looking for a multi-platform alternative to input streams. My concrete task is to fetch an encrypted file from a remote server via https and decrypt it on demand.

In Java land I would an implement InputStream which proxies the reads to the input stream from the https library. How can I do the same in kotlin targeting multiple platforms.

I see ktor returns an ByteReadChannel, but I don’t know which functions.

I’m lost and don’t know where to start. Thanks for your help in advance.

like image 665
wollnyst Avatar asked Oct 26 '18 18:10

wollnyst


People also ask

Is kotlin multi platform?

With Kotlin Multiplatform, you can create different multiplatform projects for multiple platforms, including web, desktop, and other native platforms. Kotlin applications will work on different operating systems, such as macOS, Windows, Linux, Android, iOS, watchOS, and others.

Is kotlin Multiplatform the future?

We at Touchlab believe Kotlin Multiplatform is the tech stack of the future. For many platforms, but especially for native mobile.

What is input stream in Kotlin?

This class allows an application to create an input stream in which the bytes read are supplied by the contents of a string. Known Indirect Subclasses.


1 Answers

If the framework you are using does not provide you with a full-fledged InputStream implementation, the only chance left is to write your own. Much like what the ktor developers did: ByteReadChannel is just an abstraction of "reading bytes from a channel". This abstraction lives in the common part and allows to write application and business logic around it.

The key to make this work in the context of a Kotlin Multiplatform project is, the actual implementation needs to be provided in the platform specific parts. The JVM specific code of the ktor project actually has an implementation that uses InputStream: InputStream.toByteReadChannel.

You certainly don't have to do it like your example from the ktor project and model everything down from byte channels up to file representations. If you want to leverage Kotlin framework classes, Sequences might be handy. This could look something like this:

// in common
interface FileFetcher {
  fun fetch(): Sequence<Byte>
}

expect fun fileFetcher(source: String): FileFetcher

// in jvm
class JvmFileFetcher(val input: java.io.InputStream): FileFetcher {
  override fun fetch(): Sequence<Byte> = input.readBytes().asSequence()
}

actual fun fileFetcher(source: String): FileFetcher {
  val input = java.net.URL(source).openStream()
  return JvmFileFetcher(input)
}

You would define an interface FileFetcher along with a factory function fileFetcher in the common part. By using the expect keyword on the fileFetcher function you need to provide platform-specific implementations for all target platforms you define. Use the FileFetcher interface in the common part to implement your logic (decrypting file contents etc.). See the documentation for Sequence for how to work with it.

Then implement the factory function for all platforms and use the actual keyword on them. You will then need to write platform-specific implementations of FileFetcher. My example shows how a JVM version of the FileFetcher interface.

The example is of course very basic and you probably would not want to do it exactly like this (at least some buffering would be needed, I guess). Also, within the JVM part you could also leverage your favorite networking/HTTP library easily.

like image 81
Brian Avatar answered Oct 17 '22 01:10

Brian