diff --git a/src/main/java/net/dv8tion/jda/api/utils/FileUpload.java b/src/main/java/net/dv8tion/jda/api/utils/FileUpload.java
index e5ee426d30..6126253b85 100644
--- a/src/main/java/net/dv8tion/jda/api/utils/FileUpload.java
+++ b/src/main/java/net/dv8tion/jda/api/utils/FileUpload.java
@@ -18,13 +18,16 @@
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.requests.Requester;
-import net.dv8tion.jda.internal.utils.BufferedRequestBody;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.EntityString;
import net.dv8tion.jda.internal.utils.IOUtil;
+import net.dv8tion.jda.internal.utils.requestbody.DataSupplierBody;
+import net.dv8tion.jda.internal.utils.requestbody.TypedBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
+import okio.Okio;
+import okio.Source;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -32,6 +35,7 @@
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
+import java.util.function.Supplier;
/**
* Represents a file that is intended to be uploaded to Discord for arbitrary requests.
@@ -43,16 +47,80 @@
public class FileUpload implements Closeable, AttachedFile
{
private final InputStream resource;
+ private final Supplier extends Source> resourceSupplier;
private String name;
- private BufferedRequestBody body;
+ private TypedBody> body;
private String description;
protected FileUpload(InputStream resource, String name)
{
this.resource = resource;
+ this.resourceSupplier = null;
this.name = name;
}
+ protected FileUpload(Supplier extends Source> resourceSupplier, String name)
+ {
+ this.resourceSupplier = resourceSupplier;
+ this.resource = null;
+ this.name = name;
+ }
+
+ /**
+ * Creates a FileUpload that sources its data from the supplier.
+ *
The supplier must return a new stream on every call.
+ *
+ *
The streams are expected to always be at the beginning, when they are taken from the supplier. + * If the supplier returned the same stream instance, the reader would start at the wrong position when re-attempting a request. + * + *
When this supplier factory is used, {@link #getData()} will return a new instance on each call.
+ * It is the responsibility of the caller to close that stream.
+ *
+ * @param name
+ * The file name
+ * @param supplier
+ * The resource supplier, which returns a new stream on each call
+ *
+ * @throws IllegalArgumentException
+ * If null is provided or the name is blank
+ *
+ * @return {@link FileUpload}
+ */
+ @Nonnull
+ public static FileUpload fromStreamSupplier(@Nonnull String name, @Nonnull Supplier extends InputStream> supplier)
+ {
+ Checks.notNull(supplier, "Supplier");
+ return fromSourceSupplier(name, () -> Okio.source(supplier.get()));
+ }
+
+ /**
+ * Creates a FileUpload that sources its data from the supplier.
+ *
The supplier must return a new stream on every call.
+ *
+ *
The streams are expected to always be at the beginning, when they are taken from the supplier. + * If the supplier returned the same stream instance, the reader would start at the wrong position when re-attempting a request. + * + *
When this supplier factory is used, {@link #getData()} will return a new instance on each call.
+ * It is the responsibility of the caller to close that stream.
+ *
+ * @param name
+ * The file name
+ * @param supplier
+ * The resource supplier, which returns a new {@link Source} on each call
+ *
+ * @throws IllegalArgumentException
+ * If null is provided or the name is blank
+ *
+ * @return {@link FileUpload}
+ */
+ @Nonnull
+ public static FileUpload fromSourceSupplier(@Nonnull String name, @Nonnull Supplier extends Source> supplier)
+ {
+ Checks.notNull(supplier, "Supplier");
+ Checks.notBlank(name, "Name");
+ return new FileUpload(supplier, name);
+ }
+
/**
* Create a new {@link FileUpload} for an input stream.
*
This is used to upload data to discord for various purposes.
@@ -320,7 +388,10 @@ public String getDescription()
@Nonnull
public InputStream getData()
{
- return resource;
+ if (resource != null)
+ return resource;
+ else
+ return Okio.buffer(resourceSupplier.get()).inputStream();
}
/**
@@ -343,7 +414,11 @@ public synchronized RequestBody getRequestBody(@Nonnull MediaType type)
Checks.notNull(type, "Type");
if (body != null) // This allows FileUpload to be used more than once!
return body.withType(type);
- return body = IOUtil.createRequestBody(type, resource);
+
+ if (resource == null)
+ return body = new DataSupplierBody(type, resourceSupplier);
+ else
+ return body = IOUtil.createRequestBody(type, resource);
}
@Override
@@ -381,7 +456,7 @@ public void forceClose() throws IOException
@SuppressWarnings("deprecation")
protected void finalize()
{
- if (body == null) // Only close if the resource was never used
+ if (body == null && resource != null) // Only close if the resource was never used
IOUtil.silentClose(resource);
}
diff --git a/src/main/java/net/dv8tion/jda/internal/utils/IOUtil.java b/src/main/java/net/dv8tion/jda/internal/utils/IOUtil.java
index 555fd86e5d..9f27ea9dbd 100644
--- a/src/main/java/net/dv8tion/jda/internal/utils/IOUtil.java
+++ b/src/main/java/net/dv8tion/jda/internal/utils/IOUtil.java
@@ -17,6 +17,7 @@
package net.dv8tion.jda.internal.utils;
import com.neovisionaries.ws.client.WebSocketFactory;
+import net.dv8tion.jda.internal.utils.requestbody.BufferedRequestBody;
import okhttp3.ConnectionPool;
import okhttp3.Dispatcher;
import okhttp3.MediaType;
diff --git a/src/main/java/net/dv8tion/jda/internal/utils/BufferedRequestBody.java b/src/main/java/net/dv8tion/jda/internal/utils/requestbody/BufferedRequestBody.java
similarity index 85%
rename from src/main/java/net/dv8tion/jda/internal/utils/BufferedRequestBody.java
rename to src/main/java/net/dv8tion/jda/internal/utils/requestbody/BufferedRequestBody.java
index b6397cd127..1e6f134f36 100644
--- a/src/main/java/net/dv8tion/jda/internal/utils/BufferedRequestBody.java
+++ b/src/main/java/net/dv8tion/jda/internal/utils/requestbody/BufferedRequestBody.java
@@ -14,29 +14,27 @@
* limitations under the License.
*/
-package net.dv8tion.jda.internal.utils;
+package net.dv8tion.jda.internal.utils.requestbody;
+import net.dv8tion.jda.internal.utils.IOUtil;
import okhttp3.MediaType;
-import okhttp3.RequestBody;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;
import okio.Source;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import java.io.IOException;
-public class BufferedRequestBody extends RequestBody
+public class BufferedRequestBody extends TypedBody