diff --git a/CHANGELOG.md b/CHANGELOG.md index 994767b69b1..f3fa7da9067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 0.9.10 + +* `Versions`: + * `Klock`: `2.5.2` -> `2.6.1` +* Ktor: + * Client: + * New function `UnifiedRequester#createStandardWebsocketFlow` without `checkReconnection` arg + * Server: + * Now it is possible to filter data in `Route#includeWebsocketHandling` + * Callback in `Route#includeWebsocketHandling` and dependent methods is `suspend` since now + * Add `URLProtocol` support in `Route#includeWebsocketHandling` and dependent methods + ## 0.9.9 * `Versions`: diff --git a/gradle.properties b/gradle.properties index 5a55491619f..70dce9a6f40 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ kotlin_exposed_version=0.37.3 ktor_version=1.6.7 -klockVersion=2.5.2 +klockVersion=2.6.1 github_release_plugin_version=2.2.12 @@ -45,5 +45,5 @@ dokka_version=1.6.10 # Project data group=dev.inmo -version=0.9.9 -android_code_version=99 +version=0.9.10 +android_code_version=100 diff --git a/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/FlowsWebsockets.kt b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/FlowsWebsockets.kt index 567d87e5b01..048c92dae3d 100644 --- a/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/FlowsWebsockets.kt +++ b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/FlowsWebsockets.kt @@ -4,6 +4,7 @@ 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.client.request.HttpRequestBuilder import io.ktor.http.cio.websocket.Frame import io.ktor.http.cio.websocket.readBytes import kotlinx.coroutines.flow.Flow @@ -17,6 +18,7 @@ import kotlinx.serialization.DeserializationStrategy inline fun HttpClient.createStandardWebsocketFlow( url: String, crossinline checkReconnection: (Throwable?) -> Boolean = { true }, + noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}, crossinline conversation: suspend (StandardKtorSerialInputData) -> T ): Flow { val correctedUrl = url.asCorrectWebSocketUrl @@ -26,7 +28,7 @@ inline fun HttpClient.createStandardWebsocketFlow( do { val reconnect = try { safely { - ws(correctedUrl) { + ws(correctedUrl, requestBuilder) { for (received in incoming) { when (received) { is Frame.Binary -> producerScope.send(conversation(received.readBytes())) @@ -65,10 +67,12 @@ inline fun HttpClient.createStandardWebsocketFlow( url: String, crossinline checkReconnection: (Throwable?) -> Boolean = { true }, deserializer: DeserializationStrategy, - serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat + serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, + noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}, ) = createStandardWebsocketFlow( url, - checkReconnection + checkReconnection, + requestBuilder ) { serialFormat.decodeDefault(deserializer, it) } diff --git a/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/StandardHttpClientGetPost.kt b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/StandardHttpClientGetPost.kt index 0cc8af023aa..c7922e312ac 100644 --- a/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/StandardHttpClientGetPost.kt +++ b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/StandardHttpClientGetPost.kt @@ -85,9 +85,16 @@ class UnifiedRequester( fun createStandardWebsocketFlow( url: String, - checkReconnection: (Throwable?) -> Boolean = { true }, - deserializer: DeserializationStrategy - ) = client.createStandardWebsocketFlow(url, checkReconnection, deserializer, serialFormat) + checkReconnection: (Throwable?) -> Boolean, + deserializer: DeserializationStrategy, + requestBuilder: HttpRequestBuilder.() -> Unit = {}, + ) = client.createStandardWebsocketFlow(url, checkReconnection, deserializer, serialFormat, requestBuilder) + + fun createStandardWebsocketFlow( + url: String, + deserializer: DeserializationStrategy, + requestBuilder: HttpRequestBuilder.() -> Unit = {}, + ) = createStandardWebsocketFlow(url, { true }, deserializer, requestBuilder) } val defaultRequester = UnifiedRequester() diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FlowsWebsocket.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FlowsWebsocket.kt index d26cd03cb08..01aaaf2952f 100644 --- a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FlowsWebsocket.kt +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FlowsWebsocket.kt @@ -4,25 +4,29 @@ import dev.inmo.micro_utils.coroutines.safely import dev.inmo.micro_utils.ktor.common.* import io.ktor.application.featureOrNull import io.ktor.application.install +import io.ktor.http.URLProtocol import io.ktor.http.cio.websocket.* import io.ktor.routing.Route import io.ktor.routing.application -import io.ktor.websocket.webSocket +import io.ktor.websocket.* import kotlinx.coroutines.flow.Flow import kotlinx.serialization.SerializationStrategy fun Route.includeWebsocketHandling( suburl: String, flow: Flow, - converter: (T) -> StandardKtorSerialInputData + protocol: URLProtocol = URLProtocol.WS, + converter: suspend WebSocketServerSession.(T) -> StandardKtorSerialInputData? ) { application.apply { featureOrNull(io.ktor.websocket.WebSockets) ?: install(io.ktor.websocket.WebSockets) } - webSocket(suburl) { + webSocket(suburl, protocol.name) { safely { flow.collect { - send(converter(it)) + converter(it) ?.let { data -> + send(data) + } } } } @@ -32,10 +36,24 @@ fun Route.includeWebsocketHandling( suburl: String, flow: Flow, serializer: SerializationStrategy, - serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat + serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, + protocol: URLProtocol = URLProtocol.WS, + filter: (suspend WebSocketServerSession.(T) -> Boolean)? = null ) = includeWebsocketHandling( suburl, - flow -) { - serialFormat.encodeDefault(serializer, it) -} + flow, + protocol, + converter = if (filter == null) { + { + serialFormat.encodeDefault(serializer, it) + } + } else { + { + if (filter(it)) { + serialFormat.encodeDefault(serializer, it) + } else { + null + } + } + } +) diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ServerRoutingShortcuts.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ServerRoutingShortcuts.kt index fac6c49af08..f2c06bc5e52 100644 --- a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ServerRoutingShortcuts.kt +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ServerRoutingShortcuts.kt @@ -5,8 +5,7 @@ import dev.inmo.micro_utils.coroutines.safely import dev.inmo.micro_utils.ktor.common.* import io.ktor.application.ApplicationCall import io.ktor.application.call -import io.ktor.http.ContentType -import io.ktor.http.HttpStatusCode +import io.ktor.http.* import io.ktor.http.content.PartData import io.ktor.http.content.forEachPart import io.ktor.request.receive @@ -18,6 +17,7 @@ import io.ktor.util.asStream import io.ktor.util.cio.writeChannel import io.ktor.util.pipeline.PipelineContext import io.ktor.utils.io.core.* +import io.ktor.websocket.WebSocketServerSession import kotlinx.coroutines.flow.Flow import kotlinx.serialization.* import java.io.File @@ -30,8 +30,10 @@ class UnifiedRouter( fun Route.includeWebsocketHandling( suburl: String, flow: Flow, - serializer: SerializationStrategy - ) = includeWebsocketHandling(suburl, flow, serializer, serialFormat) + serializer: SerializationStrategy, + protocol: URLProtocol = URLProtocol.WS, + filter: (suspend WebSocketServerSession.(T) -> Boolean)? = null + ) = includeWebsocketHandling(suburl, flow, serializer, serialFormat, protocol, filter) suspend fun PipelineContext<*, ApplicationCall>.unianswer( answerSerializer: SerializationStrategy,