All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xyz.shoaky.sourcedownloader.sdk.api.ApiClient.kt Maven / Gradle / Ivy

The newest version!
package xyz.shoaky.sourcedownloader.sdk.api

import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
import com.google.common.net.HttpHeaders
import com.google.common.net.MediaType
import org.slf4j.LoggerFactory
import org.springframework.web.util.UriComponentsBuilder
import xyz.shoaky.sourcedownloader.sdk.api.BaseRequest.Companion.stringTypeReference
import xyz.shoaky.sourcedownloader.sdk.util.Http
import xyz.shoaky.sourcedownloader.sdk.util.Jackson
import java.net.CookieManager
import java.net.URI
import java.net.URLEncoder
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse

interface ApiClient {

    fun , T : Any> execute(endpoint: URI, request: R): HttpResponse

}

abstract class HookedApiClient : ApiClient {

    override fun , T : Any> execute(endpoint: URI, request: R): HttpResponse {
        val uriBuilder = UriComponentsBuilder.fromUri(endpoint).path(request.path)

        if (request.httpMethod === HttpMethod.GET) {
            Jackson.convertToMap(request)
                .forEach {
                    uriBuilder.queryParam(it.key, it.value)
                }
        } else {
            request.queryString.forEach { (k, v) ->
                uriBuilder.queryParam(k, v)
            }
        }

        val requestBuilder = HttpRequest.newBuilder(uriBuilder.build().toUri())
            .method(request.httpMethod.name, bodyPublisher(request))
        request.setHeader(HttpHeaders.CONTENT_TYPE, request.mediaType)
        request.httpHeaders().forEach { (name, value) -> requestBuilder.header(name, value) }

        beforeRequest(requestBuilder, request)
        val httpRequest = requestBuilder.build()
        val httpResponse = httpClient.send(httpRequest, bodyHandler(request))
        if (log.isDebugEnabled) {
            log.debug(
                """
                request:{}
                requestBody:{}
                responseCode:{}
                responseBody:{}
                """, httpRequest.uri(), Jackson.toJsonString(httpRequest),
                httpResponse.statusCode(), httpResponse.body())
        }
        afterRequest(httpResponse, request)
        return httpResponse as HttpResponse
    }

    abstract fun , T : Any> beforeRequest(requestBuilder: HttpRequest.Builder, request: R)

    abstract fun , T : Any> afterRequest(response: HttpResponse, request: R)

    private fun , T : Any> bodyHandler(request: BaseRequest): HttpResponse.BodyHandler {
        if (request.mediaType == MediaType.JSON_UTF_8) {
            return Http.JsonBodyHandler(request.responseBodyType)
        }
        if (request.responseBodyType == stringTypeReference) {
            @Suppress("UNCHECKED_CAST")
            return stringBodyHandler as HttpResponse.BodyHandler
        }
        return Http.JsonBodyHandler(request.responseBodyType)
    }

    private fun , T : Any> bodyPublisher(request: BaseRequest): HttpRequest.BodyPublisher {
        val mediaType = request.mediaType
        if (mediaType == MediaType.FORM_DATA || mediaType == MediaType.PLAIN_TEXT_UTF_8) {
            val data = Jackson.convert(request, jacksonTypeRef>())
            val query = data.entries.stream()
                .filter { (_, v) -> v != null }
                .map { (k, v) ->
                    "${URLEncoder.encode(k, Charsets.UTF_8)}=${URLEncoder.encode(v.toString(), Charsets.UTF_8)}"
                }
                .reduce { p1, p2 -> "$p1&$p2" }
                .orElse("")
            return HttpRequest.BodyPublishers.ofString(query)
        }
        if (mediaType == MediaType.JSON_UTF_8) {
            val json = Jackson.toJsonString(request)
            return HttpRequest.BodyPublishers.ofString(json)
        }
        throw RuntimeException("No publisher support, mediaType:$mediaType")
    }

    companion object {
        private val stringBodyHandler = HttpResponse.BodyHandlers.ofString(Charsets.UTF_8)
        val cookieManager = CookieManager()
        private val httpClient: HttpClient = HttpClient.newBuilder().cookieHandler(cookieManager).build()
        private val log = LoggerFactory.getLogger(BaseRequest::class.java)
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy