partially implemented ktor utils

This commit is contained in:
000Sanya
2020-09-22 12:20:22 +10:00
parent b84367f47c
commit 1dcf17a35d
38 changed files with 541 additions and 0 deletions

17
ktor/client/build.gradle Normal file
View File

@@ -0,0 +1,17 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
}
apply from: "$mppProjectWithSerializationPresetPath"
kotlin {
sourceSets {
commonMain {
dependencies {
api internalProject("micro_utils.ktor.common")
api "io.ktor:ktor-client:$ktor_version"
}
}
}
}

View File

@@ -0,0 +1,81 @@
package dev.inmo.micro_utils.ktor.client
import dev.inmo.micro_utils.ktor.common.asCorrectWebSocketUrl
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import io.ktor.client.HttpClient
import io.ktor.client.features.websocket.ws
import io.ktor.http.cio.websocket.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.serialization.DeserializationStrategy
/**
* @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish
* connection. Must return true in case if must be reconnected. By default always reconnecting
*/
inline fun <T> HttpClient.createStandardWebsocketFlow(
url: String,
crossinline checkReconnection: (Throwable?) -> Boolean = { true },
crossinline conversation: suspend (ByteArray) -> T
): Flow<T> {
val correctedUrl = url.asCorrectWebSocketUrl
return channelFlow {
val producerScope = this@channelFlow
do {
val reconnect = try {
safely(
{
throw it
}
) {
ws(
correctedUrl
) {
while (true) {
when (val received = incoming.receive()) {
is Frame.Binary -> producerScope.send(
conversation(received.readBytes())
)
else -> {
producerScope.close()
return@ws
}
}
}
}
}
checkReconnection(null)
} catch (e: Throwable) {
checkReconnection(e).also {
if (!it) {
producerScope.close(e)
}
}
}
} while (reconnect)
if (!producerScope.isClosedForSend) {
safely(
{ /* do nothing */ }
) {
producerScope.close()
}
}
}
}
/**
* @param checkReconnection This lambda will be called when it is required to reconnect to websocket to establish
* connection. Must return true in case if must be reconnected. By default always reconnecting
*/
inline fun <T> HttpClient.createStandardWebsocketFlow(
url: String,
crossinline checkReconnection: (Throwable?) -> Boolean = { true },
deserializer: DeserializationStrategy<T>
) = createStandardWebsocketFlow(
url,
checkReconnection
) {
standardKtorSerialFormat.decodeFromByteArray(deserializer, it)
}

View File

@@ -0,0 +1,33 @@
package dev.inmo.micro_utils.ktor.client
import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat
import io.ktor.client.HttpClient
import io.ktor.client.request.get
import io.ktor.client.request.post
import kotlinx.serialization.*
typealias BodyPair<T> = Pair<SerializationStrategy<T>, T>
suspend fun <ResultType> HttpClient.uniget(
url: String,
resultDeserializer: DeserializationStrategy<ResultType>
) = get<ByteArray>(
url
).let {
standardKtorSerialFormat.decodeFromByteArray(resultDeserializer, it)
}
fun <T> SerializationStrategy<T>.encodeUrlQueryValue(value: T) = standardKtorSerialFormat.encodeToHexString(
this,
value
)
suspend fun <BodyType, ResultType> HttpClient.unipost(
url: String,
bodyInfo: BodyPair<BodyType>,
resultDeserializer: DeserializationStrategy<ResultType>
) = post<ByteArray>(url) {
body = standardKtorSerialFormat.encodeToByteArray(bodyInfo.first, bodyInfo.second)
}.let {
standardKtorSerialFormat.decodeFromByteArray(resultDeserializer, it)
}