Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change attachment InputStream to ChannelProvider #682

Merged
merged 9 commits into from
Sep 10, 2022
10 changes: 6 additions & 4 deletions core/src/test/kotlin/rest/RestTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ import dev.kord.rest.Image
import dev.kord.rest.builder.interaction.group
import dev.kord.rest.builder.interaction.int
import dev.kord.rest.builder.interaction.subCommand
import io.ktor.util.cio.*
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.*
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue

Expand Down Expand Up @@ -151,7 +153,7 @@ class RestServiceTest {
val message = channel.createMessage {
content = "TEST"

addFile("test.txt", ClassLoader.getSystemResourceAsStream("images/kord.png")!!)
addFile("test.txt", File(ClassLoader.getSystemResource("images/kord.png").toURI()).readChannel())
}

channel.getMessage(message.id)
Expand Down Expand Up @@ -377,7 +379,7 @@ class RestServiceTest {
val message = channel.createMessage {
content = "TEST"

addFile("test.txt", ClassLoader.getSystemResourceAsStream("images/kord.png")!!)
addFile("test.txt", File(ClassLoader.getSystemResource("images/kord.png").toURI()).readChannel())
}

assertEquals("TEST", message.content)
Expand All @@ -389,7 +391,7 @@ class RestServiceTest {
@Order(23)
fun `message with only file correctly`(): Unit = runBlocking {
val message = channel.createMessage {
addFile("test.txt", ClassLoader.getSystemResourceAsStream("images/kord.png")!!)
addFile("test.txt", File(ClassLoader.getSystemResource("images/kord.png").toURI()).readChannel())
}

assertEquals(1, message.attachments.size)
Expand All @@ -402,7 +404,7 @@ class RestServiceTest {
val message = channel.createMessage {
content = "TEST"

addFile("test.txt", ClassLoader.getSystemResourceAsStream("images/kord.png")!!)
addFile("test.txt", File(ClassLoader.getSystemResource("images/kord.png").toURI()).readChannel())
}

assertEquals("TEST", message.content)
Expand Down
20 changes: 18 additions & 2 deletions rest/api/rest.api
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,15 @@ public final class dev/kord/rest/Image$Size : java/lang/Enum {
}

public final class dev/kord/rest/NamedFile {
public fun <init> (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)V
public fun <init> (Ljava/lang/String;Ljava/io/InputStream;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/io/InputStream;
public final fun component2 ()Lio/ktor/utils/io/ByteReadChannel;
public final synthetic fun component2 ()Ljava/io/InputStream;
public final fun component3 ()Ljava/lang/String;
public final fun getInputStream ()Ljava/io/InputStream;
public final fun getName ()Ljava/lang/String;
public final fun getReadChannel ()Lio/ktor/utils/io/ByteReadChannel;
public final fun getUrl ()Ljava/lang/String;
}

Expand Down Expand Up @@ -1703,6 +1706,7 @@ public final class dev/kord/rest/builder/message/EmbedBuilder$Thumbnail : dev/ko

public final class dev/kord/rest/builder/message/create/FollowupMessageCreateBuilder : dev/kord/rest/builder/RequestBuilder, dev/kord/rest/builder/message/create/MessageCreateBuilder {
public fun <init> (Z)V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1723,6 +1727,7 @@ public final class dev/kord/rest/builder/message/create/InteractionResponseCreat
public fun <init> ()V
public fun <init> (Z)V
public synthetic fun <init> (ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1740,6 +1745,7 @@ public final class dev/kord/rest/builder/message/create/InteractionResponseCreat
}

public abstract interface class dev/kord/rest/builder/message/create/MessageCreateBuilder {
public abstract fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public abstract fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public abstract fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1754,6 +1760,7 @@ public abstract interface class dev/kord/rest/builder/message/create/MessageCrea
}

public final class dev/kord/rest/builder/message/create/MessageCreateBuilder$DefaultImpls {
public static fun addFile (Ldev/kord/rest/builder/message/create/MessageCreateBuilder;Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public static fun addFile (Ldev/kord/rest/builder/message/create/MessageCreateBuilder;Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public static fun addFile (Ldev/kord/rest/builder/message/create/MessageCreateBuilder;Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
Expand All @@ -1767,6 +1774,7 @@ public final class dev/kord/rest/builder/message/create/MessageCreateBuilderKt {

public final class dev/kord/rest/builder/message/create/UpdateMessageInteractionResponseCreateBuilder : dev/kord/rest/builder/RequestBuilder, dev/kord/rest/builder/message/create/MessageCreateBuilder {
public fun <init> ()V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1787,6 +1795,7 @@ public final class dev/kord/rest/builder/message/create/UpdateMessageInteraction

public final class dev/kord/rest/builder/message/create/UserMessageCreateBuilder : dev/kord/rest/builder/RequestBuilder, dev/kord/rest/builder/message/create/MessageCreateBuilder {
public fun <init> ()V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1810,6 +1819,7 @@ public final class dev/kord/rest/builder/message/create/UserMessageCreateBuilder

public final class dev/kord/rest/builder/message/create/WebhookMessageCreateBuilder : dev/kord/rest/builder/RequestBuilder, dev/kord/rest/builder/message/create/MessageCreateBuilder {
public fun <init> ()V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1831,6 +1841,7 @@ public final class dev/kord/rest/builder/message/create/WebhookMessageCreateBuil

public final class dev/kord/rest/builder/message/modify/FollowupMessageModifyBuilder : dev/kord/rest/builder/RequestBuilder, dev/kord/rest/builder/message/modify/MessageModifyBuilder {
public fun <init> ()V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1851,6 +1862,7 @@ public final class dev/kord/rest/builder/message/modify/FollowupMessageModifyBui

public final class dev/kord/rest/builder/message/modify/InteractionResponseModifyBuilder : dev/kord/rest/builder/RequestBuilder, dev/kord/rest/builder/message/modify/MessageModifyBuilder {
public fun <init> ()V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1870,6 +1882,7 @@ public final class dev/kord/rest/builder/message/modify/InteractionResponseModif
}

public abstract interface class dev/kord/rest/builder/message/modify/MessageModifyBuilder {
public abstract fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public abstract fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public abstract fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1887,6 +1900,7 @@ public abstract interface class dev/kord/rest/builder/message/modify/MessageModi
}

public final class dev/kord/rest/builder/message/modify/MessageModifyBuilder$DefaultImpls {
public static fun addFile (Ldev/kord/rest/builder/message/modify/MessageModifyBuilder;Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public static fun addFile (Ldev/kord/rest/builder/message/modify/MessageModifyBuilder;Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public static fun addFile (Ldev/kord/rest/builder/message/modify/MessageModifyBuilder;Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
Expand All @@ -1900,6 +1914,7 @@ public final class dev/kord/rest/builder/message/modify/MessageModifyBuilderKt {

public final class dev/kord/rest/builder/message/modify/UserMessageModifyBuilder : dev/kord/rest/builder/RequestBuilder, dev/kord/rest/builder/message/modify/MessageModifyBuilder {
public fun <init> ()V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand All @@ -1922,6 +1937,7 @@ public final class dev/kord/rest/builder/message/modify/UserMessageModifyBuilder

public final class dev/kord/rest/builder/message/modify/WebhookMessageModifyBuilder : dev/kord/rest/builder/RequestBuilder, dev/kord/rest/builder/message/modify/MessageModifyBuilder {
public fun <init> ()V
public fun addFile (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/lang/String;Ljava/io/InputStream;)Ldev/kord/rest/NamedFile;
public fun addFile (Ljava/nio/file/Path;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun getAllowedMentions ()Ldev/kord/rest/builder/message/AllowedMentionsBuilder;
Expand Down Expand Up @@ -5758,7 +5774,7 @@ public final class dev/kord/rest/request/RequestBuilder {
public final fun body (Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
public final fun build ()Ldev/kord/rest/request/Request;
public final fun file (Ldev/kord/rest/NamedFile;)V
public final fun file (Ljava/lang/String;Ljava/io/InputStream;)V
public final fun file (Ljava/lang/String;Lio/ktor/utils/io/ByteReadChannel;)V
public final fun getBaseUrl ()Ljava/lang/String;
public final fun getKeys ()Ljava/util/Map;
public final fun getRoute ()Ldev/kord/rest/route/Route;
Expand Down
21 changes: 19 additions & 2 deletions rest/src/main/kotlin/NamedFile.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
package dev.kord.rest

import io.ktor.client.request.forms.*
import io.ktor.utils.io.*
import io.ktor.utils.io.jvm.javaio.*
import java.io.InputStream

public class NamedFile(public val name: String, public val inputStream: InputStream) {
public class NamedFile(public val name: String, public val channelProvider: ChannelProvider) {
public constructor(name: String, inputStream: InputStream) : this(name, ChannelProvider { inputStream.toByteReadChannel() })
public constructor(name: String, channel: ByteReadChannel) : this(name, ChannelProvider { channel })

public val url: String get() = "attachment://$name"

@Deprecated(
"Use ByteReadChannel instead of InputStream",
ReplaceWith("readChannel"),
DeprecationLevel.WARNING,
)
public val inputStream: InputStream get() = channelProvider.block().toInputStream()

public operator fun component1(): String = name
public operator fun component2(): InputStream = inputStream
public operator fun component2(): ChannelProvider = channelProvider
public operator fun component3(): String = url

@Deprecated("Binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("component2")
@Suppress("DEPRECATION")
public fun _component2(): InputStream = inputStream
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import dev.kord.rest.builder.component.ActionRowBuilder
import dev.kord.rest.builder.component.MessageComponentBuilder
import dev.kord.rest.builder.message.AllowedMentionsBuilder
import dev.kord.rest.builder.message.EmbedBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import io.ktor.util.cio.*
import io.ktor.utils.io.*
import io.ktor.utils.io.jvm.javaio.toByteReadChannel
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Path
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
Expand Down Expand Up @@ -53,7 +53,16 @@ public sealed interface MessageCreateBuilder {
/**
* Adds a file with the [name] and [content] to the attachments.
*/
public fun addFile(name: String, content: InputStream): NamedFile {
@Deprecated(
"Use ByteReadChannel instead of InputStream",
level = DeprecationLevel.WARNING
)
public fun addFile(name: String, content: InputStream): NamedFile = addFile(name, content.toByteReadChannel())

/**
* Adds a file with the [name] and [content] to the attachments.
*/
public fun addFile(name: String, content: ByteReadChannel): NamedFile {
val namedFile = NamedFile(name, content)
files += namedFile
return namedFile
Expand All @@ -62,9 +71,8 @@ public sealed interface MessageCreateBuilder {
/**
* Adds a file with the given [path] to the attachments.
*/
public suspend fun addFile(path: Path): NamedFile = withContext(Dispatchers.IO) {
addFile(path.fileName.toString(), Files.newInputStream(path))
}
public suspend fun addFile(path: Path): NamedFile =
addFile(path.fileName.toString(), path.readChannel())


}
Expand Down
46 changes: 34 additions & 12 deletions rest/src/main/kotlin/builder/message/modify/MessageModifyBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import dev.kord.rest.builder.component.ActionRowBuilder
import dev.kord.rest.builder.component.MessageComponentBuilder
import dev.kord.rest.builder.message.AllowedMentionsBuilder
import dev.kord.rest.builder.message.EmbedBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import io.ktor.client.request.forms.*
import io.ktor.util.cio.*
import io.ktor.utils.io.*
import io.ktor.utils.io.jvm.javaio.toByteReadChannel
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Path
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
Expand All @@ -32,20 +33,41 @@ public sealed interface MessageModifyBuilder {

public var attachments: MutableList<DiscordAttachment>?

public fun addFile(name: String, content: InputStream): NamedFile {
val namedFile = NamedFile(name, content)
/**
* Adds a file with the [name] and [content] to the attachments.
*/
@Deprecated(
"Use ByteReadChannel instead of InputStream",
level = DeprecationLevel.WARNING
)
public fun addFile(name: String, content: InputStream): NamedFile =
NamedFile(name, content).also {
addFile(it)
}

files = (files ?: mutableListOf()).also {
it.add(namedFile)
public fun addFile(name: String, content: ByteReadChannel): NamedFile =
NamedFile(name, content).also {
addFile(it)
}

return namedFile
}
/**
* Adds a file with the [name] and [contentProvider] to the attachments.
*/
public fun addFile(name: String, contentProvider: ChannelProvider): NamedFile =
NamedFile(name, contentProvider).also {
addFile(it)
}

public suspend fun addFile(path: Path): NamedFile = withContext(Dispatchers.IO) {
addFile(path.fileName.toString(), Files.newInputStream(path))
}
public suspend fun addFile(path: Path): NamedFile =
NamedFile(path.fileName.toString(), path.readChannel()).also {
addFile(it)
}

public fun addFile(file: NamedFile) {
files = (files ?: mutableListOf()).also {
it.add(file)
}
}
}

public inline fun MessageModifyBuilder.embed(block: EmbedBuilder.() -> Unit) {
Expand Down
20 changes: 7 additions & 13 deletions rest/src/main/kotlin/request/Request.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import io.ktor.client.request.forms.*
import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.util.*
import io.ktor.utils.io.*
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.json.Json

Expand Down Expand Up @@ -89,19 +90,12 @@ public class MultipartRequest<B : Any, R>(
body?.let {
append("payload_json", Json.encodeToString(it.strategy, it.body))
}
try {

files.forEachIndexed { index, pair ->

val (name, inputStream) = pair
append(
"file$index",
inputStream.readBytes(),
Headers.build { append(HttpHeaders.ContentDisposition, "filename=$name") }
)
}
} finally {
files.forEach { it.inputStream.close() }
files.forEachIndexed { index, (fileName, channelProvider) ->
append(
"file$index",
channelProvider,
headersOf(HttpHeaders.ContentDisposition, "filename=$fileName")
)
}
}
}
14 changes: 13 additions & 1 deletion rest/src/main/kotlin/request/RequestBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package dev.kord.rest.request
import dev.kord.common.entity.Snowflake
import dev.kord.rest.NamedFile
import dev.kord.rest.route.Route
import io.ktor.client.request.forms.*
import io.ktor.http.*
import io.ktor.utils.io.*
import kotlinx.serialization.SerializationStrategy
import java.io.InputStream
import kotlin.DeprecationLevel.HIDDEN

public class RequestBuilder<T>(public val route: Route<T>, keySize: Int = 2) {
Expand Down Expand Up @@ -55,10 +58,19 @@ public class RequestBuilder<T>(public val route: Route<T>, keySize: Int = 2) {
headers.append(key, value)
}

public fun file(name: String, input: java.io.InputStream) {
@Deprecated("Use ByteReadChannel instead of InputStream", level = DeprecationLevel.WARNING)
public fun file(name: String, input: InputStream) {
files.add(NamedFile(name, input))
}

public fun file(name: String, channel: ByteReadChannel) {
files.add(NamedFile(name, channel))
}

public fun file(name: String, channelProvider: ChannelProvider) {
files.add(NamedFile(name, channelProvider))
}

public fun file(file: NamedFile) {
files.add(file)
}
Expand Down
Loading