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

commonMain.request.Request.kt Maven / Gradle / Ivy

package dev.kord.rest.request

import dev.kord.rest.NamedFile
import dev.kord.rest.route.Route
import io.ktor.client.request.forms.*
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.util.*
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.json.Json

public sealed class Request(
    public val baseUrl: String = Route.baseUrl
) {
    public abstract val route: Route
    public abstract val routeParams: Map
    public abstract val headers: StringValues
    public abstract val parameters: StringValues
    public abstract val body: RequestBody?
    public abstract val files: List?

    public val path: String
        get() {
            var path = route.path
            routeParams.forEach { (k, v) -> path = path.replaceFirst(k.identifier, v.encodeURLQueryComponent()) }
            return path
        }
}

public val Request<*, *>.identifier: RequestIdentifier
    get() = when { //The major identifier is always the 'biggest' entity.
        Route.GuildId in routeParams -> RequestIdentifier.MajorParamIdentifier(
            route,
            routeParams.getValue(Route.GuildId)
        )

        Route.ChannelId in routeParams -> RequestIdentifier.MajorParamIdentifier(
            route,
            routeParams.getValue(Route.ChannelId)
        )

        Route.WebhookId in routeParams -> RequestIdentifier.MajorParamIdentifier(
            route,
            routeParams.getValue(Route.WebhookId)
        )

        else -> RequestIdentifier.RouteIdentifier(route)
    }

/**
 * A ['per-route'](https://discord.com/developers/docs/topics/rate-limits) identifier for rate limiting purposes.
 */
public sealed class RequestIdentifier {
    /**
     * An identifier that does not contain any major parameters.
     */
    public data class RouteIdentifier(val route: Route<*>) : RequestIdentifier()

    /**
     * An identifier with a major parameter.
     */
    public data class MajorParamIdentifier(val route: Route<*>, val param: String) : RequestIdentifier()
}

public data class RequestBody(val strategy: SerializationStrategy, val body: T) where T : Any

public class JsonRequest(
    override val route: Route,
    override val routeParams: Map,
    override val parameters: StringValues,
    override val headers: StringValues,
    override val body: RequestBody?,
    baseUrl: String = Route.baseUrl
) : Request(baseUrl) {
    override val files: List? = null
}

public class MultipartRequest(
    override val route: Route,
    override val routeParams: Map,
    override val parameters: StringValues,
    override val headers: StringValues,
    override val body: RequestBody?,
    override val files: List = emptyList(),
    baseUrl: String = Route.baseUrl
) : Request(baseUrl) {

    public val data: List = formData {
        body?.let {
            append(
                key = "payload_json",
                value = Json.encodeToString(it.strategy, it.body),
                headersOf(HttpHeaders.ContentType, ContentType.Application.Json.toString()),
            )
        }
        files.forEachIndexed { index, (filename, contentProvider) ->
            append(
                key = "files[$index]",
                value = contentProvider,
                headersOf(HttpHeaders.ContentDisposition, "filename=${filename.escapeIfNeeded()}"),
            )
        }
    }
}