MicroUtils/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/FlowsWebsockets.kt

74 lines
2.5 KiB
Kotlin
Raw Normal View History

2020-09-22 02:20:22 +00:00
package dev.inmo.micro_utils.ktor.client
import dev.inmo.micro_utils.coroutines.safely
2020-09-26 15:42:05 +00:00
import dev.inmo.micro_utils.ktor.common.*
2020-09-22 02:20:22 +00:00
import io.ktor.client.HttpClient
import io.ktor.client.features.websocket.ws
2020-11-02 15:34:49 +00:00
import io.ktor.http.cio.websocket.Frame
import io.ktor.http.cio.websocket.readBytes
2020-09-22 02:20:22 +00:00
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 },
2020-09-26 15:42:05 +00:00
crossinline conversation: suspend (StandardKtorSerialInputData) -> T
2020-09-22 02:20:22 +00:00
): Flow<T> {
val correctedUrl = url.asCorrectWebSocketUrl
return channelFlow {
val producerScope = this@channelFlow
do {
val reconnect = try {
2020-09-26 15:42:05 +00:00
safely ({ throw it }) {
ws(correctedUrl) {
for (received in incoming) {
when (received) {
is Frame.Binary -> producerScope.send(conversation(received.readBytes()))
2020-09-22 02:20:22 +00:00
else -> {
producerScope.close()
return@ws
}
}
}
}
}
checkReconnection(null)
} catch (e: Throwable) {
checkReconnection(e).also {
if (!it) {
producerScope.close(e)
}
}
}
} while (reconnect)
if (!producerScope.isClosedForSend) {
safely(
2020-09-26 15:42:05 +00:00
{ it.printStackTrace() }
2020-09-22 02:20:22 +00:00
) {
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
) {
2020-09-26 15:42:05 +00:00
standardKtorSerialFormat.decodeDefault(deserializer, it)
2020-09-22 02:20:22 +00:00
}