mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-06-01 23:45:28 +00:00
75 lines
2.6 KiB
Kotlin
75 lines
2.6 KiB
Kotlin
package dev.inmo.micro_utils.ktor.client
|
|
|
|
import dev.inmo.micro_utils.coroutines.safely
|
|
import dev.inmo.micro_utils.ktor.common.*
|
|
import io.ktor.client.HttpClient
|
|
import io.ktor.client.features.websocket.ws
|
|
import io.ktor.http.cio.websocket.Frame
|
|
import io.ktor.http.cio.websocket.readBytes
|
|
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 (StandardKtorSerialInputData) -> T
|
|
): Flow<T> {
|
|
val correctedUrl = url.asCorrectWebSocketUrl
|
|
|
|
return channelFlow {
|
|
val producerScope = this@channelFlow
|
|
do {
|
|
val reconnect = try {
|
|
safely ({ throw it }) {
|
|
ws(correctedUrl) {
|
|
for (received in incoming) {
|
|
when (received) {
|
|
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(
|
|
{ it.printStackTrace() }
|
|
) {
|
|
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>,
|
|
serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat
|
|
) = createStandardWebsocketFlow(
|
|
url,
|
|
checkReconnection
|
|
) {
|
|
serialFormat.decodeDefault(deserializer, it)
|
|
}
|