Merge branch 'Feature/Refactor-file-download' of https://github.com/Chase22/TelegramBots into Chase22-Feature/Refactor-file-download
This commit is contained in:
commit
e551c64eea
@ -2,7 +2,6 @@ package org.telegram.telegrambots.bots;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
@ -14,6 +13,7 @@ import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.telegram.telegrambots.facilities.TelegramHttpClientBuilder;
|
||||
import org.telegram.telegrambots.facilities.filedownloader.TelegramFileDownloader;
|
||||
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
|
||||
import org.telegram.telegrambots.meta.api.methods.groupadministration.SetChatPhoto;
|
||||
import org.telegram.telegrambots.meta.api.methods.send.*;
|
||||
@ -36,10 +36,9 @@ import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback;
|
||||
import org.telegram.telegrambots.meta.updateshandlers.SentCallback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@ -61,6 +60,7 @@ public abstract class DefaultAbsSender extends AbsSender {
|
||||
private final DefaultBotOptions options;
|
||||
private volatile CloseableHttpClient httpClient;
|
||||
private volatile RequestConfig requestConfig;
|
||||
private final TelegramFileDownloader telegramFileDownloader = new TelegramFileDownloader(this::getBotToken);
|
||||
|
||||
protected DefaultAbsSender(DefaultBotOptions options) {
|
||||
super();
|
||||
@ -109,37 +109,35 @@ public abstract class DefaultAbsSender extends AbsSender {
|
||||
// Send Requests
|
||||
|
||||
public final java.io.File downloadFile(String filePath) throws TelegramApiException {
|
||||
if(filePath == null || filePath.isEmpty()){
|
||||
throw new TelegramApiException("Parameter file can not be null");
|
||||
}
|
||||
String url = File.getFileUrl(getBotToken(), filePath);
|
||||
String tempFileName = Long.toString(System.currentTimeMillis());
|
||||
return downloadToTemporaryFileWrappingExceptions(url, tempFileName);
|
||||
return telegramFileDownloader.downloadFile(filePath);
|
||||
}
|
||||
|
||||
public final java.io.File downloadFile(File file) throws TelegramApiException {
|
||||
assertParamNotNull(file, "file");
|
||||
String url = file.getFileUrl(getBotToken());
|
||||
String tempFileName = file.getFileId();
|
||||
return downloadToTemporaryFileWrappingExceptions(url, tempFileName);
|
||||
return telegramFileDownloader.downloadFile(file);
|
||||
}
|
||||
|
||||
public final java.io.File downloadFile(File file, java.io.File outputFile) throws TelegramApiException {
|
||||
return telegramFileDownloader.downloadFile(file, outputFile);
|
||||
}
|
||||
|
||||
public final java.io.File downloadFile(String filePath, java.io.File outputFile) throws TelegramApiException {
|
||||
return telegramFileDownloader.downloadFile(filePath, outputFile);
|
||||
}
|
||||
|
||||
public final void downloadFileAsync(String filePath, DownloadFileCallback<String> callback) throws TelegramApiException {
|
||||
if(filePath == null || filePath.isEmpty()){
|
||||
throw new TelegramApiException("Parameter filePath can not be null");
|
||||
}
|
||||
assertParamNotNull(callback, "callback");
|
||||
String url = File.getFileUrl(getBotToken(), filePath);
|
||||
String tempFileName = Long.toString(System.currentTimeMillis());
|
||||
exe.submit(getDownloadFileAsyncJob(filePath, callback, url, tempFileName));
|
||||
telegramFileDownloader.downloadFileAsync(filePath, callback);
|
||||
}
|
||||
|
||||
public final void downloadFileAsync(File file, DownloadFileCallback<File> callback) throws TelegramApiException {
|
||||
assertParamNotNull(file, "file");
|
||||
assertParamNotNull(callback, "callback");
|
||||
String url = file.getFileUrl(getBotToken());
|
||||
String tempFileName = file.getFileId();
|
||||
exe.submit(getDownloadFileAsyncJob(file, callback, url, tempFileName));
|
||||
telegramFileDownloader.downloadFileAsync(file, callback);
|
||||
}
|
||||
|
||||
public final InputStream downloadFileAsStream(String filePath) throws TelegramApiException {
|
||||
return telegramFileDownloader.downloadFileAsStream(filePath);
|
||||
}
|
||||
|
||||
public final InputStream downloadFileAsStream(File file) throws TelegramApiException {
|
||||
return telegramFileDownloader.downloadFileAsStream(file);
|
||||
}
|
||||
|
||||
// Specific Send Requests
|
||||
@ -720,38 +718,6 @@ public abstract class DefaultAbsSender extends AbsSender {
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Runnable getDownloadFileAsyncJob(T fileIdentifier, DownloadFileCallback<T> callback, String url, String tempFileName) {
|
||||
//noinspection Convert2Lambda
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
callback.onResult(fileIdentifier, downloadToTemporaryFile(url, tempFileName));
|
||||
} catch (MalformedURLException e) {
|
||||
callback.onException(fileIdentifier, new TelegramApiException("Wrong url for file: " + url));
|
||||
} catch (IOException e) {
|
||||
callback.onException(fileIdentifier, new TelegramApiRequestException("Error downloading the file", e));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private java.io.File downloadToTemporaryFileWrappingExceptions(String url, String tempFileName) throws TelegramApiException {
|
||||
try {
|
||||
return downloadToTemporaryFile(url, tempFileName);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new TelegramApiException("Wrong url for file: " + url);
|
||||
} catch (IOException e) {
|
||||
throw new TelegramApiRequestException("Error downloading the file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private java.io.File downloadToTemporaryFile(String url, String tempFileName) throws IOException {
|
||||
java.io.File output = java.io.File.createTempFile(tempFileName, ".tmp");
|
||||
FileUtils.copyURLToFile(new URL(url), output);
|
||||
return output;
|
||||
}
|
||||
|
||||
private <T extends Serializable, Method extends BotApiMethod<T>> String sendMethodRequest(Method method) throws TelegramApiValidationException, IOException {
|
||||
method.validate();
|
||||
String url = getBaseUrl() + method.getMethod();
|
||||
|
@ -0,0 +1,10 @@
|
||||
package org.telegram.telegrambots.facilities.filedownloader;
|
||||
|
||||
/**
|
||||
* Runtime Exception to wrap Exceptions thrown during file download
|
||||
*/
|
||||
public class DownloadFileException extends RuntimeException {
|
||||
public DownloadFileException(final String message, final Throwable e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
package org.telegram.telegrambots.facilities.filedownloader;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.telegram.telegrambots.meta.api.objects.File;
|
||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||
import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.apache.commons.io.FileUtils.copyInputStreamToFile;
|
||||
import static org.apache.http.HttpStatus.SC_OK;
|
||||
|
||||
/**
|
||||
* Wraps the file downloading code into one class.
|
||||
* @author Chase22
|
||||
* @version 1.0
|
||||
*/
|
||||
public class TelegramFileDownloader {
|
||||
private final HttpClient httpClient;
|
||||
private final Supplier<String> botTokenSupplier;
|
||||
|
||||
public TelegramFileDownloader(final Supplier<String> botTokenSupplier) {
|
||||
this.botTokenSupplier = botTokenSupplier;
|
||||
httpClient = HttpClients.createDefault();
|
||||
}
|
||||
|
||||
public TelegramFileDownloader(final HttpClient httpClient, final Supplier<String> botTokenSupplier) {
|
||||
this.httpClient = httpClient;
|
||||
this.botTokenSupplier = botTokenSupplier;
|
||||
}
|
||||
|
||||
public final java.io.File downloadFile(String filePath) throws TelegramApiException {
|
||||
String tempFileName = Long.toString(System.currentTimeMillis());
|
||||
return downloadFile(filePath, getTempFile(tempFileName));
|
||||
}
|
||||
|
||||
public final java.io.File downloadFile(File file) throws TelegramApiException {
|
||||
return downloadFile(file, getTempFile(file.getFileId()));
|
||||
}
|
||||
|
||||
public final java.io.File downloadFile(File file, java.io.File outputFile) throws TelegramApiException {
|
||||
if (file == null) {
|
||||
throw new TelegramApiException("Parameter file can not be null");
|
||||
}
|
||||
String url = file.getFileUrl(botTokenSupplier.get());
|
||||
return downloadToFile(url, outputFile);
|
||||
}
|
||||
|
||||
public final java.io.File downloadFile(String filePath, java.io.File outputFile) throws TelegramApiException {
|
||||
if (filePath == null || filePath.isEmpty()) {
|
||||
throw new TelegramApiException("Parameter file can not be null");
|
||||
}
|
||||
String url = File.getFileUrl(botTokenSupplier.get(), filePath);
|
||||
return downloadToFile(url, outputFile);
|
||||
}
|
||||
|
||||
public final InputStream downloadFileAsStream(String filePath) throws TelegramApiException {
|
||||
try {
|
||||
return getFileDownloadStreamFuture(File.getFileUrl(botTokenSupplier.get(), filePath)).get();
|
||||
} catch (InterruptedException e) {
|
||||
throw new TelegramApiException("Error downloading file", e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new TelegramApiException("Error downloading file", e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
public final InputStream downloadFileAsStream(File file) throws TelegramApiException {
|
||||
try {
|
||||
return getFileDownloadStreamFuture(file.getFileUrl(botTokenSupplier.get())).get();
|
||||
} catch (InterruptedException e) {
|
||||
throw new TelegramApiException("Error downloading file", e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new TelegramApiException("Error downloading file", e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
public final void downloadFileAsync(String filePath, DownloadFileCallback<String> callback) throws TelegramApiException {
|
||||
if (filePath == null || filePath.isEmpty()) {
|
||||
throw new TelegramApiException("Parameter filePath can not be null");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new TelegramApiException("Parameter callback can not be null");
|
||||
}
|
||||
String url = File.getFileUrl(botTokenSupplier.get(), filePath);
|
||||
String tempFileName = Long.toString(System.currentTimeMillis());
|
||||
|
||||
getFileDownloadFuture(url, getTempFile(tempFileName))
|
||||
.thenAccept(output -> callback.onResult(filePath, output))
|
||||
.exceptionally(throwable -> {
|
||||
// Unwrap java.util.concurrent.CompletionException
|
||||
if (throwable instanceof CompletionException) {
|
||||
callback.onException(filePath, new TelegramApiException("Error downloading file", throwable.getCause()));
|
||||
} else {
|
||||
callback.onException(filePath, new TelegramApiException("Error downloading file", throwable));
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public final void downloadFileAsync(File file, DownloadFileCallback<File> callback) throws TelegramApiException {
|
||||
if (file == null) {
|
||||
throw new TelegramApiException("Parameter file can not be null");
|
||||
}
|
||||
if (callback == null) {
|
||||
throw new TelegramApiException("Parameter callback can not be null");
|
||||
}
|
||||
String url = file.getFileUrl(botTokenSupplier.get());
|
||||
String tempFileName = file.getFileId();
|
||||
|
||||
getFileDownloadFuture(url, getTempFile(tempFileName))
|
||||
.thenAccept(output -> callback.onResult(file, output))
|
||||
.exceptionally(throwable -> {
|
||||
callback.onException(file, new TelegramApiException("Error downloading file", throwable));
|
||||
return null;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private java.io.File getTempFile(String tempFileName) throws TelegramApiException {
|
||||
try {
|
||||
return java.io.File.createTempFile(tempFileName, ".tmp");
|
||||
} catch (IOException e) {
|
||||
throw new TelegramApiException("Error downloading file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private java.io.File downloadToFile(String url, java.io.File output) throws TelegramApiException {
|
||||
try {
|
||||
return getFileDownloadFuture(url, output).get();
|
||||
} catch (InterruptedException e) {
|
||||
throw new TelegramApiException("File Download got interrupted", e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new TelegramApiException("Error downloading file", e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<java.io.File> getFileDownloadFuture(String url, java.io.File output) {
|
||||
return getFileDownloadStreamFuture(url).thenApply(stream -> {
|
||||
try {
|
||||
copyInputStreamToFile(stream, output);
|
||||
return output;
|
||||
} catch (IOException e) {
|
||||
throw new DownloadFileException("Error writing downloaded file", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<InputStream> getFileDownloadStreamFuture(final String url) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
HttpResponse response = httpClient.execute(new HttpGet(url));
|
||||
final int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == SC_OK) {
|
||||
return response.getEntity().getContent();
|
||||
} else {
|
||||
throw new TelegramApiException("Unexpected Status code while downloading file. Expected 200 got " + statusCode);
|
||||
}
|
||||
} catch (IOException | TelegramApiException e) {
|
||||
throw new DownloadFileException("Error downloading file", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package org.telegram.telegrambots.test;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.telegram.telegrambots.facilities.filedownloader.TelegramFileDownloader;
|
||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||
import org.telegram.telegrambots.meta.updateshandlers.DownloadFileCallback;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static java.nio.charset.Charset.defaultCharset;
|
||||
import static org.apache.commons.io.FileUtils.readFileToString;
|
||||
import static org.apache.commons.io.IOUtils.toInputStream;
|
||||
import static org.apache.http.HttpVersion.HTTP_1_1;
|
||||
import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TelegramFileDownloaderTest {
|
||||
|
||||
private TelegramFileDownloader telegramFileDownloader;
|
||||
|
||||
@Mock
|
||||
private DownloadFileCallback<String> downloadFileCallbackMock;
|
||||
|
||||
@Mock
|
||||
private HttpClient httpClientMock;
|
||||
|
||||
@Mock
|
||||
private HttpResponse httpResponseMock;
|
||||
|
||||
@Mock
|
||||
private HttpEntity httpEntityMock;
|
||||
|
||||
private Supplier<String> tokenSupplierMock = () -> "someToken";
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws IOException {
|
||||
|
||||
|
||||
when(httpResponseMock.getStatusLine()).thenReturn(new BasicStatusLine(HTTP_1_1, 200, "emptyString"));
|
||||
when(httpResponseMock.getEntity()).thenReturn(httpEntityMock);
|
||||
|
||||
when(httpEntityMock.getContent()).thenReturn(toInputStream("Some File Content", defaultCharset()));
|
||||
|
||||
when(httpClientMock.execute(any(HttpUriRequest.class))).thenReturn(httpResponseMock);
|
||||
|
||||
telegramFileDownloader = new TelegramFileDownloader(httpClientMock, tokenSupplierMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFileDownload() throws TelegramApiException, IOException {
|
||||
File returnFile = telegramFileDownloader.downloadFile("someFilePath");
|
||||
String content = readFileToString(returnFile, defaultCharset());
|
||||
|
||||
assertEquals("Some File Content", content);
|
||||
}
|
||||
|
||||
@Test(expected = TelegramApiException.class)
|
||||
public void testDownloadException() throws TelegramApiException {
|
||||
when(httpResponseMock.getStatusLine()).thenReturn(new BasicStatusLine(HTTP_1_1, 500, "emptyString"));
|
||||
|
||||
telegramFileDownloader.downloadFile("someFilePath");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAsyncDownload() throws TelegramApiException, IOException {
|
||||
final ArgumentCaptor<File> fileArgumentCaptor = ArgumentCaptor.forClass(File.class);
|
||||
|
||||
telegramFileDownloader.downloadFileAsync("someFilePath", downloadFileCallbackMock);
|
||||
|
||||
verify(downloadFileCallbackMock, timeout(100)
|
||||
.times(1))
|
||||
.onResult(any(), fileArgumentCaptor.capture());
|
||||
|
||||
String content = readFileToString(fileArgumentCaptor.getValue(), defaultCharset());
|
||||
assertEquals("Some File Content", content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAsyncException() throws TelegramApiException {
|
||||
final ArgumentCaptor<Exception> exceptionArgumentCaptor = ArgumentCaptor.forClass(Exception.class);
|
||||
|
||||
when(httpResponseMock.getStatusLine()).thenReturn(new BasicStatusLine(HTTP_1_1, 500, "emptyString"));
|
||||
|
||||
telegramFileDownloader.downloadFileAsync("someFilePath", downloadFileCallbackMock);
|
||||
|
||||
verify(downloadFileCallbackMock, timeout(100)
|
||||
.times(1))
|
||||
.onException(any(), exceptionArgumentCaptor.capture());
|
||||
|
||||
Exception e = exceptionArgumentCaptor.getValue();
|
||||
assertThat(e, instanceOf(TelegramApiException.class));
|
||||
assertEquals(e.getCause().getCause().getMessage(), "Unexpected Status code while downloading file. Expected 200 got 500");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user