From 1dcf17a35d2e8e82b6bb0b8aaf63b4db63d63605 Mon Sep 17 00:00:00 2001 From: 000Sanya <000sanya.000sanya@gmail.com> Date: Tue, 22 Sep 2020 12:20:22 +1000 Subject: [PATCH] partially implemented ktor utils --- gradle.properties | 2 + ktor/client/build.gradle | 17 ++++ .../ktor/client/FlowsWebsockets.kt | 81 +++++++++++++++++++ .../ktor/client/StandardHttpClientGetPost.kt | 33 ++++++++ ktor/common/build.gradle | 16 ++++ .../ktor/common/BuildStandardUrl.kt | 23 ++++++ .../ktor/common/CollectionsSerializers.kt | 6 ++ .../ktor/common/CorrectCloseException.kt | 3 + .../ktor/common/CorrectWebsocketUrl.kt | 14 ++++ .../ktor/common/FromToDateTimeUrl.kt | 17 ++++ .../ktor/common/QueryParamsBuilder.kt | 25 ++++++ .../ktor/common/StandardSerializer.kt | 5 ++ .../micro_utils/ktor/common/WebSockets.kt | 7 ++ ktor/server/build.gradle | 24 ++++++ .../micro_utils/ktor/server/FlowsWebsocket.kt | 43 ++++++++++ .../ktor/server/FromToDateTimeInUrl.kt | 11 +++ .../ktor/server/ServerRoutingShortcuts.kt | 65 +++++++++++++++ .../ApplicationCachingHeadersConfigurator.kt | 21 +++++ .../ApplicationRoutingConfigurator.kt | 27 +++++++ .../ApplicationSessionsConfigurator.kt | 20 +++++ .../KtorApplicationConfigurator.kt | 7 ++ .../configurators/StatusPagesConfigurator.kt | 21 +++++ .../standardKtorSerialFormatContentType.kt | 5 ++ repos/ktor/client/build.gradle | 2 + .../client/crud/KtorReadStandardCrudRepo.kt | 4 + .../client/crud/KtorWriteStandardCrudRepo.kt | 4 + .../key_value/KtorStandartReadKeyValueRepo.kt | 4 + .../KtorStandartWriteKeyValueRepo.kt | 4 + .../KtorOneToManyReadKeyValueRepo.kt | 4 + .../KtorOneToManyWriteKeyValueRepo.kt | 3 + repos/ktor/server/build.gradle | 2 + .../server/crud/KtorReadStandardCrudRepo.kt | 3 + .../server/crud/KtorWriteStandardCrudRepo.kt | 3 + .../key_value/KtorStandartReadKeyValueRepo.kt | 4 + .../KtorStandartWriteKeyValueRepo.kt | 2 + ...onfigureOneToManyReadKeyValueRepoRoutes.kt | 4 + ...nfigureOneToManyWriteKeyValueRepoRoutes.kt | 2 + settings.gradle | 3 + 38 files changed, 541 insertions(+) create mode 100644 ktor/client/build.gradle create mode 100644 ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/FlowsWebsockets.kt create mode 100644 ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/StandardHttpClientGetPost.kt create mode 100644 ktor/common/build.gradle create mode 100644 ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/BuildStandardUrl.kt create mode 100644 ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CollectionsSerializers.kt create mode 100644 ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CorrectCloseException.kt create mode 100644 ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CorrectWebsocketUrl.kt create mode 100644 ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/FromToDateTimeUrl.kt create mode 100644 ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/QueryParamsBuilder.kt create mode 100644 ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/StandardSerializer.kt create mode 100644 ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/WebSockets.kt create mode 100644 ktor/server/build.gradle create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FlowsWebsocket.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FromToDateTimeInUrl.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ServerRoutingShortcuts.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationCachingHeadersConfigurator.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationRoutingConfigurator.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationSessionsConfigurator.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/KtorApplicationConfigurator.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/StatusPagesConfigurator.kt create mode 100644 ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/standardKtorSerialFormatContentType.kt diff --git a/gradle.properties b/gradle.properties index 5648e605a1a..c6694e53af0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,6 +7,8 @@ kotlin_exposed_version=0.27.1 ktor_version=1.4.0 +klockVersion=1.7.3 + gradle_bintray_plugin_version=1.8.5 uuidVersion=0.2.2 diff --git a/ktor/client/build.gradle b/ktor/client/build.gradle new file mode 100644 index 00000000000..bcdcdfd4e4c --- /dev/null +++ b/ktor/client/build.gradle @@ -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" + } + } + } +} 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 new file mode 100644 index 00000000000..b9000c27e07 --- /dev/null +++ b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/FlowsWebsockets.kt @@ -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 HttpClient.createStandardWebsocketFlow( + url: String, + crossinline checkReconnection: (Throwable?) -> Boolean = { true }, + crossinline conversation: suspend (ByteArray) -> T +): Flow { + 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 HttpClient.createStandardWebsocketFlow( + url: String, + crossinline checkReconnection: (Throwable?) -> Boolean = { true }, + deserializer: DeserializationStrategy +) = createStandardWebsocketFlow( + url, + checkReconnection +) { + standardKtorSerialFormat.decodeFromByteArray(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 new file mode 100644 index 00000000000..82a8876a90a --- /dev/null +++ b/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/client/StandardHttpClientGetPost.kt @@ -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 = Pair, T> + +suspend fun HttpClient.uniget( + url: String, + resultDeserializer: DeserializationStrategy +) = get( + url +).let { + standardKtorSerialFormat.decodeFromByteArray(resultDeserializer, it) +} + +fun SerializationStrategy.encodeUrlQueryValue(value: T) = standardKtorSerialFormat.encodeToHexString( + this, + value +) + +suspend fun HttpClient.unipost( + url: String, + bodyInfo: BodyPair, + resultDeserializer: DeserializationStrategy +) = post(url) { + body = standardKtorSerialFormat.encodeToByteArray(bodyInfo.first, bodyInfo.second) +}.let { + standardKtorSerialFormat.decodeFromByteArray(resultDeserializer, it) +} diff --git a/ktor/common/build.gradle b/ktor/common/build.gradle new file mode 100644 index 00000000000..f8c12008e68 --- /dev/null +++ b/ktor/common/build.gradle @@ -0,0 +1,16 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" +} + +apply from: "$mppProjectWithSerializationPresetPath" + +kotlin { + sourceSets { + commonMain { + dependencies { + api "com.soywiz.korlibs.klock:klock:$klockVersion" + } + } + } +} diff --git a/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/BuildStandardUrl.kt b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/BuildStandardUrl.kt new file mode 100644 index 00000000000..1c70bcd5358 --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/BuildStandardUrl.kt @@ -0,0 +1,23 @@ +package dev.inmo.micro_utils.ktor.common + +fun buildStandardUrl( + basePart: String, + subpart: String, + parameters: QueryParams = emptyMap() +) = "$basePart/$subpart".includeQueryParams( + parameters +) + +fun buildStandardUrl( + basePart: String, + subpart: String, + parameters: List +) = "$basePart/$subpart".includeQueryParams( + parameters +) + +fun buildStandardUrl( + basePart: String, + subpart: String, + vararg parameters: QueryParam +) = buildStandardUrl(basePart, subpart, parameters.toList()) diff --git a/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CollectionsSerializers.kt b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CollectionsSerializers.kt new file mode 100644 index 00000000000..54923c9d9d0 --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CollectionsSerializers.kt @@ -0,0 +1,6 @@ +package dev.inmo.micro_utils.ktor.common + +import kotlinx.serialization.builtins.SetSerializer +import kotlinx.serialization.builtins.serializer + +val setIdsSerializer = SetSerializer(String.serializer()) diff --git a/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CorrectCloseException.kt b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CorrectCloseException.kt new file mode 100644 index 00000000000..2189e312777 --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CorrectCloseException.kt @@ -0,0 +1,3 @@ +package dev.inmo.micro_utils.ktor.common + +object CorrectCloseException : Exception() diff --git a/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CorrectWebsocketUrl.kt b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CorrectWebsocketUrl.kt new file mode 100644 index 00000000000..887c15b5b0b --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/CorrectWebsocketUrl.kt @@ -0,0 +1,14 @@ +package dev.inmo.micro_utils.ktor.common + +private val schemaRegex = Regex("[^:]*//") + +val String.asCorrectWebSocketUrl: String + get() = if (startsWith("ws")) { + this + } else { + if (contains("://")) { + replace(schemaRegex, "ws://") + } else { + "ws://$this" + } + } diff --git a/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/FromToDateTimeUrl.kt b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/FromToDateTimeUrl.kt new file mode 100644 index 00000000000..ff015524268 --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/FromToDateTimeUrl.kt @@ -0,0 +1,17 @@ +package dev.inmo.micro_utils.ktor.common + +import com.soywiz.klock.DateTime + +typealias FromToDateTime = Pair + +val FromToDateTime.asFromToUrlPart: QueryParams + get() = mapOf( + "from" to first ?.unixMillis ?.toString(), + "to" to second ?.unixMillis ?.toString() + ) + +val QueryParams.extractFromToDateTime: FromToDateTime + get() = FromToDateTime( + get("from") ?.toDoubleOrNull() ?.let { DateTime(it) }, + get("to") ?.toDoubleOrNull() ?.let { DateTime(it) } + ) diff --git a/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/QueryParamsBuilder.kt b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/QueryParamsBuilder.kt new file mode 100644 index 00000000000..6205052b6d1 --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/QueryParamsBuilder.kt @@ -0,0 +1,25 @@ +package dev.inmo.micro_utils.ktor.common + +typealias QueryParam = Pair +typealias QueryParams = Map + +val QueryParams.asUrlQuery: String + get() = keys.joinToString("&") { "${it}${get(it) ?.let { value -> "=$value" }}" } + +val List.asUrlQuery: String + get() = joinToString("&") { (key, value) -> "${key}${value ?.let { _ -> "=$value" }}" } + +fun String.includeQueryParams( + queryParams: QueryParams +): String = "$this${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}" + +fun String.includeQueryParams( + queryParams: List +): String = "$this${if (contains("?")) "&" else "?"}${queryParams.asUrlQuery}" + +val String.parseUrlQuery: QueryParams + get() = split("&").map { + it.split("=").let { pair -> + pair.first() to pair.getOrNull(1) + } + }.toMap() diff --git a/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/StandardSerializer.kt b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/StandardSerializer.kt new file mode 100644 index 00000000000..6bef2004ea6 --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/StandardSerializer.kt @@ -0,0 +1,5 @@ +package dev.inmo.micro_utils.ktor.common + +import kotlinx.serialization.cbor.Cbor + +val standardKtorSerialFormat = Cbor diff --git a/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/WebSockets.kt b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/WebSockets.kt new file mode 100644 index 00000000000..1fdfb5c3421 --- /dev/null +++ b/ktor/common/src/commonMain/kotlin/dev/inmo/micro_utils/ktor/common/WebSockets.kt @@ -0,0 +1,7 @@ +package dev.inmo.micro_utils.ktor.common + +const val clientWebsocketHelloMessage = "Start getting of updates" +const val serverWebsocketHelloMessage = "Accepted" + +const val serverWebsocketNewMessageMessage = "NewMessage" +const val websocketFinalizationMessage = "Final" diff --git a/ktor/server/build.gradle b/ktor/server/build.gradle new file mode 100644 index 00000000000..f21e34a994b --- /dev/null +++ b/ktor/server/build.gradle @@ -0,0 +1,24 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" +} + +apply from: "$mppJavaProjectPresetPath" + +kotlin { + sourceSets { + commonMain { + dependencies { + api internalProject("micro_utils.ktor.common") + } + } + + jvmMain { + dependencies { + api "io.ktor:ktor-server:$ktor_version" + api "io.ktor:ktor-server-host-common:$ktor_version" + api "io.ktor:ktor-websockets:$ktor_version" + } + } + } +} 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 new file mode 100644 index 00000000000..7ae3de5d4ad --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FlowsWebsocket.kt @@ -0,0 +1,43 @@ +package dev.inmo.micro_utils.ktor.server + +import dev.inmo.micro_utils.ktor.common.CorrectCloseException +import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat +import io.ktor.http.cio.websocket.* +import io.ktor.routing.Route +import io.ktor.websocket.webSocket +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect +import kotlinx.serialization.SerializationStrategy + +private suspend fun DefaultWebSocketSession.checkReceivedAndCloseIfExists() { + if (incoming.poll() != null) { + close() + throw CorrectCloseException + } +} + +fun Route.includeWebsocketHandling( + suburl: String, + flow: Flow, + converter: (T) -> ByteArray +) { + webSocket(suburl) { + safely { + flow.collect { + checkReceivedAndCloseIfExists() + send(converter(it)) + } + } + } +} + +fun Route.includeWebsocketHandling( + suburl: String, + flow: Flow, + serializer: SerializationStrategy +) = includeWebsocketHandling( + suburl, + flow +) { + standardKtorSerialFormat.encodeToByteArray(serializer, it) +} diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FromToDateTimeInUrl.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FromToDateTimeInUrl.kt new file mode 100644 index 00000000000..c7e850a9bfd --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/FromToDateTimeInUrl.kt @@ -0,0 +1,11 @@ +package dev.inmo.micro_utils.ktor.server + +import com.soywiz.klock.DateTime +import dev.inmo.micro_utils.ktor.common.FromToDateTime +import io.ktor.http.Parameters + +val Parameters.extractFromToDateTime: FromToDateTime + get() = FromToDateTime( + get("from") ?.toDoubleOrNull() ?.let { DateTime(it) }, + get("to") ?.toDoubleOrNull() ?.let { DateTime(it) } + ) 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 new file mode 100644 index 00000000000..1c92ce90538 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/ServerRoutingShortcuts.kt @@ -0,0 +1,65 @@ +package dev.inmo.micro_utils.ktor.server + +import dev.inmo.micro_utils.ktor.common.standardKtorSerialFormat +import io.ktor.application.ApplicationCall +import io.ktor.http.HttpStatusCode +import io.ktor.response.respond +import io.ktor.response.respondBytes +import io.ktor.util.toByteArray +import kotlinx.serialization.* + +suspend fun ApplicationCall.unianswer( + answerSerializer: SerializationStrategy, + answer: T +) { + respondBytes( + standardKtorSerialFormat.encodeToByteArray(answerSerializer, answer), + standardKtorSerialFormatContentType + ) +} + +suspend fun ApplicationCall.uniload( + deserializer: DeserializationStrategy +) = standardKtorSerialFormat.decodeFromByteArray( + deserializer, + request.receiveChannel().toByteArray() +) + +suspend fun ApplicationCall.getParameterOrSendError( + field: String +) = parameters[field].also { + if (it == null) { + respond(HttpStatusCode.BadRequest, "Request must contains $field") + } +} + +fun ApplicationCall.getQueryParameter( + field: String +) = request.queryParameters[field] + +suspend fun ApplicationCall.getQueryParameterOrSendError( + field: String +) = getQueryParameter(field).also { + if (it == null) { + respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field") + } +} + +fun ApplicationCall.decodeUrlQueryValue( + field: String, + deserializer: DeserializationStrategy +) = getQueryParameter(field) ?.let { + standardKtorSerialFormat.decodeFromHexString( + deserializer, + it + ) +} + +suspend fun ApplicationCall.decodeUrlQueryValueOrSendError( + field: String, + deserializer: DeserializationStrategy +) = decodeUrlQueryValue(field, deserializer).also { + if (it == null) { + respond(HttpStatusCode.BadRequest, "Request query parameters must contains $field") + } +} diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationCachingHeadersConfigurator.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationCachingHeadersConfigurator.kt new file mode 100644 index 00000000000..9b04dcd3910 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationCachingHeadersConfigurator.kt @@ -0,0 +1,21 @@ +package dev.inmo.micro_utils.ktor.server.configurators + +import io.ktor.application.Application +import io.ktor.application.install +import io.ktor.features.CachingHeaders +import kotlinx.serialization.Contextual + +data class ApplicationCachingHeadersConfigurator( + private val elements: List<@Contextual Element> +) : KtorApplicationConfigurator { + interface Element { operator fun CachingHeaders.Configuration.invoke() } + + override fun Application.configure() { + install(CachingHeaders) { + elements.forEach { + it.apply { invoke() } + } + } + } +} + diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationRoutingConfigurator.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationRoutingConfigurator.kt new file mode 100644 index 00000000000..8bb687a7744 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationRoutingConfigurator.kt @@ -0,0 +1,27 @@ +package dev.inmo.micro_utils.ktor.server.configurators + +import io.ktor.application.* +import io.ktor.routing.Route +import io.ktor.routing.Routing +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable +class ApplicationRoutingConfigurator( + private val elements: List<@Contextual Element> +) : KtorApplicationConfigurator { + interface Element { operator fun Route.invoke() } + + override fun Application.configure() { + try { + feature(Routing) + } catch (e: IllegalStateException) { + install(Routing) { + elements.forEach { + it.apply { invoke() } + } + } + } + } +} + diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationSessionsConfigurator.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationSessionsConfigurator.kt new file mode 100644 index 00000000000..60513e24702 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/ApplicationSessionsConfigurator.kt @@ -0,0 +1,20 @@ +package dev.inmo.micro_utils.ktor.server.configurators + +import io.ktor.application.Application +import io.ktor.application.install +import io.ktor.sessions.Sessions +import kotlinx.serialization.Contextual + +class ApplicationSessionsConfigurator( + private val elements: List<@Contextual Element> +) : KtorApplicationConfigurator { + interface Element { operator fun Sessions.Configuration.invoke() } + + override fun Application.configure() { + install(Sessions) { + elements.forEach { + it.apply { invoke() } + } + } + } +} diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/KtorApplicationConfigurator.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/KtorApplicationConfigurator.kt new file mode 100644 index 00000000000..dcc877c8fa8 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/KtorApplicationConfigurator.kt @@ -0,0 +1,7 @@ +package dev.inmo.micro_utils.ktor.server.configurators + +import io.ktor.application.Application + +interface KtorApplicationConfigurator { + fun Application.configure() +} diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/StatusPagesConfigurator.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/StatusPagesConfigurator.kt new file mode 100644 index 00000000000..7bb090df3c1 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/configurators/StatusPagesConfigurator.kt @@ -0,0 +1,21 @@ +package dev.inmo.micro_utils.ktor.server.configurators + +import io.ktor.application.Application +import io.ktor.application.install +import io.ktor.features.StatusPages +import kotlinx.serialization.Contextual + +class StatusPagesConfigurator( + private val elements: List<@Contextual Element> +) : KtorApplicationConfigurator { + interface Element { operator fun StatusPages.Configuration.invoke() } + + override fun Application.configure() { + install(StatusPages) { + elements.forEach { + it.apply { invoke() } + } + } + } +} + diff --git a/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/standardKtorSerialFormatContentType.kt b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/standardKtorSerialFormatContentType.kt new file mode 100644 index 00000000000..cf132500cd8 --- /dev/null +++ b/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/ktor/server/standardKtorSerialFormatContentType.kt @@ -0,0 +1,5 @@ +package dev.inmo.micro_utils.ktor.server + +import io.ktor.http.ContentType + +val standardKtorSerialFormatContentType = ContentType.Application.Cbor diff --git a/repos/ktor/client/build.gradle b/repos/ktor/client/build.gradle index b96eda83744..3af78fdcda7 100644 --- a/repos/ktor/client/build.gradle +++ b/repos/ktor/client/build.gradle @@ -10,6 +10,8 @@ kotlin { commonMain { dependencies { api internalProject("micro_utils.repos.ktor.common") + api internalProject("micro_utils.pagination.ktor.common") + api internalProject("micro_utils.ktor.client") api "io.ktor:ktor-client:$ktor_version" } } diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt index b36e4424fba..082e72a83fb 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorReadStandardCrudRepo.kt @@ -1,7 +1,11 @@ package dev.inmo.micro_utils.repos.ktor.client.crud +import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue +import dev.inmo.micro_utils.ktor.client.uniget +import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.pagination.Pagination import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.pagination.asUrlQueryParts import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo import dev.inmo.micro_utils.repos.ktor.common.crud.* import io.ktor.client.HttpClient diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepo.kt index be78bd22db2..960ad239ad1 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/crud/KtorWriteStandardCrudRepo.kt @@ -1,5 +1,9 @@ package dev.inmo.micro_utils.repos.ktor.client.crud +import dev.inmo.micro_utils.ktor.client.BodyPair +import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow +import dev.inmo.micro_utils.ktor.client.unipost +import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.repos.UpdatedValuePair import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo import dev.inmo.micro_utils.repos.ktor.common.crud.* diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorStandartReadKeyValueRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorStandartReadKeyValueRepo.kt index bf7c32759bf..588768223d3 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorStandartReadKeyValueRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorStandartReadKeyValueRepo.kt @@ -1,7 +1,11 @@ package dev.inmo.micro_utils.repos.ktor.client.key_value +import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue +import dev.inmo.micro_utils.ktor.client.uniget +import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.pagination.Pagination import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.pagination.asUrlQueryParts import dev.inmo.micro_utils.repos.StandardReadKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.key_value.* import io.ktor.client.* diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorStandartWriteKeyValueRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorStandartWriteKeyValueRepo.kt index b7ad3c114c0..e8f11ecebc7 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorStandartWriteKeyValueRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/key_value/KtorStandartWriteKeyValueRepo.kt @@ -1,5 +1,9 @@ package dev.inmo.micro_utils.repos.ktor.client.key_value +import dev.inmo.micro_utils.ktor.client.BodyPair +import dev.inmo.micro_utils.ktor.client.createStandardWebsocketFlow +import dev.inmo.micro_utils.ktor.client.unipost +import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.repos.StandardWriteKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.key_value.* import io.ktor.client.* diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorOneToManyReadKeyValueRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorOneToManyReadKeyValueRepo.kt index 33e5cf05ee5..0df6f253bf8 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorOneToManyReadKeyValueRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorOneToManyReadKeyValueRepo.kt @@ -1,7 +1,11 @@ package dev.inmo.micro_utils.repos.ktor.client.one_to_many +import dev.inmo.micro_utils.ktor.client.encodeUrlQueryValue +import dev.inmo.micro_utils.ktor.client.uniget +import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.pagination.Pagination import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.pagination.asUrlQueryParts import dev.inmo.micro_utils.repos.OneToManyReadKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* import io.ktor.client.HttpClient diff --git a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorOneToManyWriteKeyValueRepo.kt b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorOneToManyWriteKeyValueRepo.kt index 7d6b8b69fc4..d714855ae25 100644 --- a/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorOneToManyWriteKeyValueRepo.kt +++ b/repos/ktor/client/src/commonMain/kotlin/dev/inmo/micro_utils/repos/ktor/client/one_to_many/KtorOneToManyWriteKeyValueRepo.kt @@ -1,5 +1,8 @@ package dev.inmo.micro_utils.repos.ktor.client.one_to_many +import dev.inmo.micro_utils.ktor.client.BodyPair +import dev.inmo.micro_utils.ktor.client.unipost +import dev.inmo.micro_utils.ktor.common.buildStandardUrl import dev.inmo.micro_utils.repos.OneToManyWriteKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* import io.ktor.client.HttpClient diff --git a/repos/ktor/server/build.gradle b/repos/ktor/server/build.gradle index ebcb40ce03d..ad744041182 100644 --- a/repos/ktor/server/build.gradle +++ b/repos/ktor/server/build.gradle @@ -15,6 +15,8 @@ kotlin { jvmMain { dependencies { + api internalProject("micro_utils.pagination.ktor.server") + api internalProject("micro_utils.ktor.server") api "io.ktor:ktor-server:$ktor_version" api "io.ktor:ktor-server-host-common:$ktor_version" } diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt index 0c74ddd8e23..d876840b033 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorReadStandardCrudRepo.kt @@ -1,9 +1,12 @@ package dev.inmo.micro_utils.repos.ktor.server.crud +import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValueOrSendError +import dev.inmo.micro_utils.ktor.server.unianswer import dev.inmo.micro_utils.repos.ktor.common.crud.containsRouting import dev.inmo.micro_utils.repos.ktor.common.crud.getByIdRouting import dev.inmo.micro_utils.repos.ktor.common.crud.getByPaginationRouting import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.repos.ReadStandardCRUDRepo import io.ktor.application.call import io.ktor.routing.Route diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorWriteStandardCrudRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorWriteStandardCrudRepo.kt index 4b393163609..968cec36eb5 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorWriteStandardCrudRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/crud/KtorWriteStandardCrudRepo.kt @@ -1,5 +1,8 @@ package dev.inmo.micro_utils.repos.ktor.server.crud +import dev.inmo.micro_utils.ktor.server.includeWebsocketHandling +import dev.inmo.micro_utils.ktor.server.unianswer +import dev.inmo.micro_utils.ktor.server.uniload import dev.inmo.micro_utils.repos.WriteStandardCRUDRepo import dev.inmo.micro_utils.repos.ktor.common.crud.* import io.ktor.application.call diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt index a0d66c1a967..d55d3a57b63 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartReadKeyValueRepo.kt @@ -1,5 +1,9 @@ package dev.inmo.micro_utils.repos.ktor.server.key_value +import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValueOrSendError +import dev.inmo.micro_utils.ktor.server.unianswer +import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.repos.StandardReadKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.key_value.* import io.ktor.application.* diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartWriteKeyValueRepo.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartWriteKeyValueRepo.kt index ff043aaaa24..e075249b1bc 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartWriteKeyValueRepo.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/key_value/KtorStandartWriteKeyValueRepo.kt @@ -1,5 +1,7 @@ package dev.inmo.micro_utils.repos.ktor.server.key_value +import dev.inmo.micro_utils.ktor.server.includeWebsocketHandling +import dev.inmo.micro_utils.ktor.server.uniload import dev.inmo.micro_utils.repos.StandardWriteKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.key_value.* import io.ktor.application.* diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/ConfigureOneToManyReadKeyValueRepoRoutes.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/ConfigureOneToManyReadKeyValueRepoRoutes.kt index 4a5a40075ea..0ef8beaeca0 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/ConfigureOneToManyReadKeyValueRepoRoutes.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/ConfigureOneToManyReadKeyValueRepoRoutes.kt @@ -1,6 +1,10 @@ package dev.inmo.micro_utils.repos.ktor.server.one_to_many +import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValue +import dev.inmo.micro_utils.ktor.server.decodeUrlQueryValueOrSendError +import dev.inmo.micro_utils.ktor.server.unianswer import dev.inmo.micro_utils.pagination.PaginationResult +import dev.inmo.micro_utils.pagination.extractPagination import dev.inmo.micro_utils.repos.OneToManyReadKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* import io.ktor.application.call diff --git a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/ConfigureOneToManyWriteKeyValueRepoRoutes.kt b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/ConfigureOneToManyWriteKeyValueRepoRoutes.kt index 9ef1ada0a3b..f39e0ee3b48 100644 --- a/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/ConfigureOneToManyWriteKeyValueRepoRoutes.kt +++ b/repos/ktor/server/src/jvmMain/kotlin/dev/inmo/micro_utils/repos/ktor/server/one_to_many/ConfigureOneToManyWriteKeyValueRepoRoutes.kt @@ -1,5 +1,7 @@ package dev.inmo.micro_utils.repos.ktor.server.one_to_many +import dev.inmo.micro_utils.ktor.server.unianswer +import dev.inmo.micro_utils.ktor.server.uniload import dev.inmo.micro_utils.repos.OneToManyWriteKeyValueRepo import dev.inmo.micro_utils.repos.ktor.common.one_to_many.* import io.ktor.application.call diff --git a/settings.gradle b/settings.gradle index a114ba3ac77..1c87c1f50d7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,9 @@ String[] includes = [ ":repos:ktor:client", ":repos:ktor:common", ":repos:ktor:server", + ":ktor:server", + ":ktor:common", + ":ktor:client", ]