mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-12-05 01:46:12 +00:00
Support library option via additionalProperties (#16242)
* set library option obtain from additionalProperties * test library * update samples * remove old files
This commit is contained in:
@@ -6,22 +6,22 @@ gradle/wrapper/gradle-wrapper.properties
|
||||
gradlew
|
||||
gradlew.bat
|
||||
settings.gradle.kts
|
||||
src/commonMain/kotlin/org/openapitools/client/apis/DefaultApi.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/auth/ApiKeyAuth.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/auth/Authentication.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/auth/HttpBasicAuth.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/auth/HttpBearerAuth.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/auth/OAuth.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/Base64ByteArray.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/Bytes.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/OctetByteArray.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
|
||||
src/commonMain/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
|
||||
src/commonTest/kotlin/util/Coroutine.kt
|
||||
src/iosTest/kotlin/util/Coroutine.kt
|
||||
src/jsTest/kotlin/util/Coroutine.kt
|
||||
src/jvmTest/kotlin/util/Coroutine.kt
|
||||
src/main/kotlin/org/openapitools/client/apis/DefaultApi.kt
|
||||
src/main/kotlin/org/openapitools/client/auth/ApiKeyAuth.kt
|
||||
src/main/kotlin/org/openapitools/client/auth/Authentication.kt
|
||||
src/main/kotlin/org/openapitools/client/auth/HttpBasicAuth.kt
|
||||
src/main/kotlin/org/openapitools/client/auth/HttpBearerAuth.kt
|
||||
src/main/kotlin/org/openapitools/client/auth/OAuth.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/ApiAbstractions.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/ApiClient.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/Base64ByteArray.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/Bytes.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/HttpResponse.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/OctetByteArray.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/PartConfig.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/RequestConfig.kt
|
||||
src/main/kotlin/org/openapitools/client/infrastructure/RequestMethod.kt
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
*
|
||||
* Please note:
|
||||
* This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* Do not edit this file manually.
|
||||
*
|
||||
*/
|
||||
|
||||
@file:Suppress(
|
||||
"ArrayInDataClass",
|
||||
"EnumEntryName",
|
||||
"RemoveRedundantQualifierName",
|
||||
"UnusedImport"
|
||||
)
|
||||
|
||||
package org.openapitools.client.apis
|
||||
|
||||
|
||||
import org.openapitools.client.infrastructure.*
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import kotlinx.serialization.json.Json
|
||||
import io.ktor.http.ParametersBuilder
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
import kotlinx.serialization.encoding.*
|
||||
|
||||
open class DefaultApi(
|
||||
baseUrl: String = ApiClient.BASE_URL,
|
||||
httpClientEngine: HttpClientEngine? = null,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
jsonSerializer: Json = ApiClient.JSON_DEFAULT
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonSerializer) {
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param ids
|
||||
* @return void
|
||||
*/
|
||||
open suspend fun idsGet(ids: kotlin.collections.List<kotlin.String>): HttpResponse<Unit> {
|
||||
|
||||
val localVariableAuthNames = listOf<String>()
|
||||
|
||||
val localVariableBody =
|
||||
io.ktor.client.utils.EmptyContent
|
||||
|
||||
val localVariableQuery = mutableMapOf<String, List<String>>()
|
||||
val localVariableHeaders = mutableMapOf<String, String>()
|
||||
|
||||
val localVariableConfig = RequestConfig<kotlin.Any?>(
|
||||
RequestMethod.GET,
|
||||
"/{ids}".replace("{" + "ids" + "}", ids.joinToString(",")),
|
||||
query = localVariableQuery,
|
||||
headers = localVariableHeaders,
|
||||
requiresAuthentication = false,
|
||||
)
|
||||
|
||||
return request(
|
||||
localVariableConfig,
|
||||
localVariableBody,
|
||||
localVariableAuthNames
|
||||
).wrap()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.openapitools.client.auth
|
||||
|
||||
class ApiKeyAuth(private val location: String, val paramName: String) : Authentication {
|
||||
var apiKey: String? = null
|
||||
var apiKeyPrefix: String? = null
|
||||
|
||||
override fun apply(query: MutableMap<String, List<String>>, headers: MutableMap<String, String>) {
|
||||
val key: String = apiKey ?: return
|
||||
val prefix: String? = apiKeyPrefix
|
||||
val value: String = if (prefix != null) "$prefix $key" else key
|
||||
when (location) {
|
||||
"query" -> query[paramName] = listOf(value)
|
||||
"header" -> headers[paramName] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.openapitools.client.auth
|
||||
|
||||
interface Authentication {
|
||||
|
||||
/**
|
||||
* Apply authentication settings to header and query params.
|
||||
*
|
||||
* @param query Query parameters.
|
||||
* @param headers Header parameters.
|
||||
*/
|
||||
fun apply(query: MutableMap<String, List<String>>, headers: MutableMap<String, String>)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.openapitools.client.auth
|
||||
|
||||
import io.ktor.util.InternalAPI
|
||||
import io.ktor.util.encodeBase64
|
||||
|
||||
class HttpBasicAuth : Authentication {
|
||||
var username: String? = null
|
||||
var password: String? = null
|
||||
|
||||
@OptIn(InternalAPI::class)
|
||||
override fun apply(query: MutableMap<String, List<String>>, headers: MutableMap<String, String>) {
|
||||
if (username == null && password == null) return
|
||||
val str = (username ?: "") + ":" + (password ?: "")
|
||||
val auth = str.encodeBase64()
|
||||
headers["Authorization"] = "Basic $auth"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.openapitools.client.auth
|
||||
|
||||
class HttpBearerAuth(private val scheme: String?) : Authentication {
|
||||
var bearerToken: String? = null
|
||||
|
||||
override fun apply(query: MutableMap<String, List<String>>, headers: MutableMap<String, String>) {
|
||||
val token: String = bearerToken ?: return
|
||||
headers["Authorization"] = (if (scheme != null) upperCaseBearer(scheme)!! + " " else "") + token
|
||||
}
|
||||
|
||||
private fun upperCaseBearer(scheme: String): String? {
|
||||
return if ("bearer".equals(scheme, ignoreCase = true)) "Bearer" else scheme
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.openapitools.client.auth
|
||||
|
||||
class OAuth : Authentication {
|
||||
var accessToken: String? = null
|
||||
|
||||
override fun apply(query: MutableMap<String, List<String>>, headers: MutableMap<String, String>) {
|
||||
val token: String = accessToken ?: return
|
||||
headers["Authorization"] = "Bearer $token"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
typealias MultiValueMap = MutableMap<String,List<String>>
|
||||
|
||||
fun collectionDelimiter(collectionFormat: String) = when(collectionFormat) {
|
||||
"csv" -> ","
|
||||
"tsv" -> "\t"
|
||||
"pipe" -> "|"
|
||||
"space" -> " "
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" }
|
||||
|
||||
fun <T : Any?> toMultiValue(items: Array<T>, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter)
|
||||
= toMultiValue(items.asIterable(), collectionFormat, map)
|
||||
|
||||
fun <T : Any?> toMultiValue(items: Iterable<T>, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List<String> {
|
||||
return when(collectionFormat) {
|
||||
"multi" -> items.map(map)
|
||||
else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.serialization.kotlinx.json.json
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
import org.openapitools.client.auth.*
|
||||
|
||||
open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
private val jsonBlock: Json
|
||||
) {
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
it.install(ContentNegotiation) { json(jsonBlock) }
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
|
||||
private val client: HttpClient by lazy {
|
||||
httpClientEngine?.let { HttpClient(it, clientConfig) } ?: HttpClient(clientConfig)
|
||||
}
|
||||
|
||||
private val authentications: kotlin.collections.Map<String, Authentication>? = null
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "http://localhost"
|
||||
val JSON_DEFAULT = Json {
|
||||
ignoreUnknownKeys = true
|
||||
prettyPrint = true
|
||||
isLenient = true
|
||||
}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the username for the first HTTP basic authentication.
|
||||
*
|
||||
* @param username Username
|
||||
*/
|
||||
fun setUsername(username: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
?: throw Exception("No HTTP basic authentication configured")
|
||||
auth.username = username
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the password for the first HTTP basic authentication.
|
||||
*
|
||||
* @param password Password
|
||||
*/
|
||||
fun setPassword(password: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
?: throw Exception("No HTTP basic authentication configured")
|
||||
auth.password = password
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the API key value for the first API key authentication.
|
||||
*
|
||||
* @param apiKey API key
|
||||
* @param paramName The name of the API key parameter, or null or set the first key.
|
||||
*/
|
||||
fun setApiKey(apiKey: String, paramName: String? = null) {
|
||||
val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
|
||||
?: throw Exception("No API key authentication configured")
|
||||
auth.apiKey = apiKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the API key prefix for the first API key authentication.
|
||||
*
|
||||
* @param apiKeyPrefix API key prefix
|
||||
* @param paramName The name of the API key parameter, or null or set the first key.
|
||||
*/
|
||||
fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) {
|
||||
val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
|
||||
?: throw Exception("No API key authentication configured")
|
||||
auth.apiKeyPrefix = apiKeyPrefix
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the access token for the first OAuth2 authentication.
|
||||
*
|
||||
* @param accessToken Access token
|
||||
*/
|
||||
fun setAccessToken(accessToken: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth?
|
||||
?: throw Exception("No OAuth2 authentication configured")
|
||||
auth.accessToken = accessToken
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the access token for the first Bearer authentication.
|
||||
*
|
||||
* @param bearerToken The bearer token.
|
||||
*/
|
||||
fun setBearerToken(bearerToken: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
|
||||
?: throw Exception("No Bearer authentication configured")
|
||||
auth.bearerToken = bearerToken
|
||||
}
|
||||
|
||||
protected suspend fun <T: Any?> multipartFormRequest(requestConfig: RequestConfig<T>, body: kotlin.collections.List<PartData>?, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
return request(requestConfig, MultiPartFormDataContent(body ?: listOf()), authNames)
|
||||
}
|
||||
|
||||
protected suspend fun <T: Any?> urlEncodedFormRequest(requestConfig: RequestConfig<T>, body: Parameters?, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames)
|
||||
}
|
||||
|
||||
protected suspend fun <T: Any?> jsonRequest(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse = request(requestConfig, body, authNames)
|
||||
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
requestConfig.query.forEach { query ->
|
||||
query.value.forEach { value ->
|
||||
parameter(query.key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH)) {
|
||||
this.setBody(body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T: Any?> RequestConfig<T>.updateForAuth(authNames: kotlin.collections.List<String>) {
|
||||
for (authName in authNames) {
|
||||
val auth = authentications?.get(authName) ?: throw Exception("Authentication undefined: $authName")
|
||||
auth.apply(query, headers)
|
||||
}
|
||||
}
|
||||
|
||||
private fun URLBuilder.appendPath(components: kotlin.collections.List<String>): URLBuilder = apply {
|
||||
encodedPath = encodedPath.trimEnd('/') + components.joinToString("/", prefix = "/") { it.encodeURLQueryComponent() }
|
||||
}
|
||||
|
||||
private val RequestMethod.httpMethod: HttpMethod
|
||||
get() = when (this) {
|
||||
RequestMethod.DELETE -> HttpMethod.Delete
|
||||
RequestMethod.GET -> HttpMethod.Get
|
||||
RequestMethod.HEAD -> HttpMethod.Head
|
||||
RequestMethod.PATCH -> HttpMethod.Patch
|
||||
RequestMethod.PUT -> HttpMethod.Put
|
||||
RequestMethod.POST -> HttpMethod.Post
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
import kotlinx.serialization.encoding.*
|
||||
|
||||
@Serializable
|
||||
class Base64ByteArray(val value: ByteArray) {
|
||||
@Serializer(Base64ByteArray::class)
|
||||
companion object : KSerializer<Base64ByteArray> {
|
||||
override val descriptor = PrimitiveSerialDescriptor("Base64ByteArray", PrimitiveKind.STRING)
|
||||
override fun serialize(encoder: Encoder, obj: Base64ByteArray) = encoder.encodeString(obj.value.encodeBase64())
|
||||
override fun deserialize(decoder: Decoder) = Base64ByteArray(decoder.decodeString().decodeBase64Bytes())
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
other as Base64ByteArray
|
||||
return value.contentEquals(other.value)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return value.contentHashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Base64ByteArray(${hex(value)})"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlin.experimental.and
|
||||
|
||||
private val digits = "0123456789abcdef".toCharArray()
|
||||
private const val BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
private const val BASE64_MASK: Byte = 0x3f
|
||||
private const val BASE64_PAD = '='
|
||||
private val BASE64_INVERSE_ALPHABET = IntArray(256) { BASE64_ALPHABET.indexOf(it.toChar()) }
|
||||
|
||||
private fun String.toCharArray(): CharArray = CharArray(length) { get(it) }
|
||||
private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it] = 0 }
|
||||
private fun Int.toBase64(): Char = BASE64_ALPHABET[this]
|
||||
private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK
|
||||
internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes()
|
||||
|
||||
/**
|
||||
* Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes.
|
||||
*
|
||||
* Taken from https://github.com/ktorio/ktor/blob/master/ktor-utils/common/src/io/ktor/util/Crypto.kt
|
||||
*/
|
||||
internal fun hex(bytes: ByteArray): String {
|
||||
val result = CharArray(bytes.size * 2)
|
||||
var resultIndex = 0
|
||||
val digits = digits
|
||||
|
||||
for (element in bytes) {
|
||||
val b = element.toInt() and 0xff
|
||||
result[resultIndex++] = digits[b shr 4]
|
||||
result[resultIndex++] = digits[b and 0x0f]
|
||||
}
|
||||
|
||||
return result.concatToString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode bytes from HEX string. It should be no spaces and `0x` prefixes.
|
||||
*
|
||||
* Taken from https://github.com/ktorio/ktor/blob/master/ktor-utils/common/src/io/ktor/util/Crypto.kt
|
||||
*/
|
||||
internal fun hex(s: String): ByteArray {
|
||||
val result = ByteArray(s.length / 2)
|
||||
for (idx in result.indices) {
|
||||
val srcIdx = idx * 2
|
||||
val high = s[srcIdx].toString().toInt(16) shl 4
|
||||
val low = s[srcIdx + 1].toString().toInt(16)
|
||||
result[idx] = (high or low).toByte()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode [ByteReadPacket] in base64 format.
|
||||
*
|
||||
* Taken from https://github.com/ktorio/ktor/blob/424d1d2cfaa3281302c60af9500f738c8c2fc846/ktor-utils/common/src/io/ktor/util/Base64.kt
|
||||
*/
|
||||
private fun ByteReadPacket.encodeBase64(): String = buildString {
|
||||
val data = ByteArray(3)
|
||||
while (remaining > 0) {
|
||||
val read = readAvailable(data)
|
||||
data.clearFrom(read)
|
||||
|
||||
val padSize = (data.size - read) * 8 / 6
|
||||
val chunk = ((data[0].toInt() and 0xFF) shl 16) or
|
||||
((data[1].toInt() and 0xFF) shl 8) or
|
||||
(data[2].toInt() and 0xFF)
|
||||
|
||||
for (index in data.size downTo padSize) {
|
||||
val char = (chunk shr (6 * index)) and BASE64_MASK.toInt()
|
||||
append(char.toBase64())
|
||||
}
|
||||
|
||||
repeat(padSize) { append(BASE64_PAD) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode [ByteReadPacket] from base64 format
|
||||
*
|
||||
* Taken from https://github.com/ktorio/ktor/blob/424d1d2cfaa3281302c60af9500f738c8c2fc846/ktor-utils/common/src/io/ktor/util/Base64.kt
|
||||
*/
|
||||
private fun ByteReadPacket.decodeBase64Bytes(): Input = buildPacket {
|
||||
val data = ByteArray(4)
|
||||
|
||||
while (remaining > 0) {
|
||||
val read = readAvailable(data)
|
||||
|
||||
val chunk = data.foldIndexed(0) { index, result, current ->
|
||||
result or (current.fromBase64().toInt() shl ((3 - index) * 6))
|
||||
}
|
||||
|
||||
for (index in data.size - 2 downTo (data.size - read)) {
|
||||
val origin = (chunk shr (8 * index)) and 0xff
|
||||
writeByte(origin.toByte())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
val success: Boolean = response.status.isSuccess()
|
||||
val headers: Map<String, List<String>> = response.headers.mapEntries()
|
||||
suspend fun body(): T = provider.body(response)
|
||||
suspend fun <V : Any> typedBody(type: TypeInfo): V = provider.typedBody(response, type)
|
||||
|
||||
companion object {
|
||||
private fun Headers.mapEntries(): Map<String, List<String>> {
|
||||
val result = mutableMapOf<String, List<String>>()
|
||||
entries().forEach { result[it.key] = it.value }
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface BodyProvider<T : Any> {
|
||||
suspend fun body(response: io.ktor.client.statement.HttpResponse): T
|
||||
suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V
|
||||
}
|
||||
|
||||
class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
block(provider.body(response))
|
||||
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
provider.typedBody(response, type)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> io.ktor.client.statement.HttpResponse.wrap(): HttpResponse<T> =
|
||||
HttpResponse(this, TypedBodyProvider(typeInfo<T>()))
|
||||
|
||||
fun <T : Any, V : Any> HttpResponse<T>.map(block: T.() -> V): HttpResponse<V> =
|
||||
HttpResponse(response, MappedBodyProvider(provider, block))
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.*
|
||||
import kotlinx.serialization.encoding.*
|
||||
|
||||
@Serializable
|
||||
class OctetByteArray(val value: ByteArray) {
|
||||
@Serializer(OctetByteArray::class)
|
||||
companion object : KSerializer<OctetByteArray> {
|
||||
override val descriptor = PrimitiveSerialDescriptor("OctetByteArray", PrimitiveKind.STRING)
|
||||
override fun serialize(encoder: Encoder, obj: OctetByteArray) = encoder.encodeString(hex(obj.value))
|
||||
override fun deserialize(decoder: Decoder) = OctetByteArray(hex(decoder.decodeString()))
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || this::class != other::class) return false
|
||||
other as OctetByteArray
|
||||
return value.contentEquals(other.value)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return value.contentHashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "OctetByteArray(${hex(value)})"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
/**
|
||||
* Defines a config object for a given part of a multi-part request.
|
||||
* NOTE: Headers is a Map<String,String> because rfc2616 defines
|
||||
* multi-valued headers as csv-only.
|
||||
*/
|
||||
data class PartConfig<T>(
|
||||
val headers: MutableMap<String, String> = mutableMapOf(),
|
||||
val body: T? = null
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
/**
|
||||
* Defines a config object for a given request.
|
||||
* NOTE: This object doesn't include 'body' because it
|
||||
* allows for caching of the constructed object
|
||||
* for many request definitions.
|
||||
* NOTE: Headers is a Map<String,String> because rfc2616 defines
|
||||
* multi-valued headers as csv-only.
|
||||
*/
|
||||
data class RequestConfig<T>(
|
||||
val method: RequestMethod,
|
||||
val path: String,
|
||||
val headers: MutableMap<String, String> = mutableMapOf(),
|
||||
val query: MutableMap<String, List<String>> = mutableMapOf(),
|
||||
val requiresAuthentication: Boolean,
|
||||
val body: T? = null
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
/**
|
||||
* Provides enumerated HTTP verbs
|
||||
*/
|
||||
enum class RequestMethod {
|
||||
GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT
|
||||
}
|
||||
Reference in New Issue
Block a user