1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-02-08 02:54:24 +01:00

Reduce download method complexity of FileDownloader class.

This commit is contained in:
Mattia Bertorello 2019-07-11 16:00:54 +02:00
parent a8c7184c11
commit 1bfdf83db8
No known key found for this signature in database
GPG Key ID: CE1FB2BE91770F24
2 changed files with 95 additions and 79 deletions

View File

@ -126,7 +126,7 @@ public class DownloadableContributionsDownloader {
} }
public void download(URL url, File tmpFile, Progress progress, String statusText, ProgressListener progressListener, boolean noResume, boolean allowCache) throws Exception { public void download(URL url, File tmpFile, Progress progress, String statusText, ProgressListener progressListener, boolean noResume, boolean allowCache) throws Exception {
FileDownloader downloader = new FileDownloader(url, tmpFile); FileDownloader downloader = new FileDownloader(url, tmpFile, allowCache);
downloader.addObserver((o, arg) -> { downloader.addObserver((o, arg) -> {
FileDownloader me = (FileDownloader) o; FileDownloader me = (FileDownloader) o;
String msg = ""; String msg = "";
@ -139,7 +139,7 @@ public class DownloadableContributionsDownloader {
progress.setProgress(me.getProgress()); progress.setProgress(me.getProgress());
progressListener.onProgress(progress); progressListener.onProgress(progress);
}); });
downloader.download(noResume, allowCache); downloader.download(noResume);
if (!downloader.isCompleted()) { if (!downloader.isCompleted()) {
throw new Exception(format(tr("Error downloading {0}"), url), downloader.getError()); throw new Exception(format(tr("Error downloading {0}"), url), downloader.getError());
} }

View File

@ -65,14 +65,15 @@ public class FileDownloader extends Observable {
private final URL downloadUrl; private final URL downloadUrl;
private final File outputFile; private final File outputFile;
private InputStream stream = null; private final boolean allowCache;
private Exception error; private Exception error;
public FileDownloader(URL url, File file) { public FileDownloader(URL url, File file, boolean allowCache) {
downloadUrl = url; this.downloadUrl = url;
outputFile = file; this.outputFile = file;
downloaded = 0; this.allowCache = allowCache;
initialSize = 0; this.downloaded = 0;
this.initialSize = 0;
} }
public long getInitialSize() { public long getInitialSize() {
@ -118,11 +119,11 @@ public class FileDownloader extends Observable {
} }
public void download(boolean noResume, boolean allowCache) throws InterruptedException { public void download(boolean noResume) throws InterruptedException {
if ("file".equals(downloadUrl.getProtocol())) { if ("file".equals(downloadUrl.getProtocol())) {
saveLocalFile(); saveLocalFile();
} else { } else {
downloadFile(noResume, allowCache); downloadFile(noResume);
} }
} }
@ -136,56 +137,100 @@ public class FileDownloader extends Observable {
} }
} }
private void downloadFile(boolean noResume, boolean allowCache) throws InterruptedException { private void downloadFile(boolean noResume) throws InterruptedException {
RandomAccessFile randomAccessOutputFile = null;
try { try {
setStatus(Status.CONNECTING); setStatus(Status.CONNECTING);
final Optional<FileDownloaderCache.FileCached> fileCached = FileDownloaderCache.getFileCached(downloadUrl); final Optional<FileDownloaderCache.FileCached> fileCached = FileDownloaderCache.getFileCached(downloadUrl);
if (fileCached.isPresent() && fileCached.get().isNotChange()) { if (fileCached.isPresent() && fileCached.get().isNotChange()) {
final Optional<File> fileFromCache = getFileCached(fileCached.get());
if (fileFromCache.isPresent()) {
// Copy the cached file in the destination file
FileUtils.copyFile(fileFromCache.get(), outputFile);
} else {
openConnectionAndFillTheFile(noResume);
if (allowCache) {
fileCached.get().updateCacheFile(outputFile);
} else {
log.info("The file {} was not cached because allow cache is false", downloadUrl);
}
}
}
setStatus(Status.COMPLETE);
} catch (InterruptedException e) {
setStatus(Status.CANCELLED);
// lets InterruptedException go up to the caller
throw e;
} catch (SocketTimeoutException e) {
setStatus(Status.CONNECTION_TIMEOUT_ERROR);
setError(e);
log.error("The request went in socket timeout", e);
} catch (Exception e) {
setStatus(Status.ERROR);
setError(e);
log.error("The request stop", e);
}
}
private Optional<File> getFileCached(FileDownloaderCache.FileCached fileCached) {
try { try {
final Optional<File> fileFromCache = final Optional<File> fileFromCache =
fileCached.get().getFileFromCache(); fileCached.getFileFromCache();
if (fileFromCache.isPresent()) { if (fileFromCache.isPresent()) {
log.info("No need to download using cached file: {}", fileCached.get()); log.info("No need to download using cached file: {}", fileCached);
FileUtils.copyFile(fileFromCache.get(), outputFile); return fileFromCache;
setStatus(Status.COMPLETE);
return;
} else { } else {
log.info( log.info(
"The file in the cache is not in the path or the md5 validation failed: path={}, file exist={}, md5 validation={}", "The file in the cache is not in the path or the md5 validation failed: path={}, file exist={}, md5 validation={}",
fileCached.get().getLocalPath(), fileCached.get().exists(), fileCached.get().md5Check()); fileCached.getLocalPath(), fileCached.exists(), fileCached.md5Check());
} }
} catch (Exception e) { } catch (Exception e) {
log.warn( log.warn(
"Cannot get the file from the cache, will be downloaded a new one ", e); "Cannot get the file from the cache, will be downloaded a new one ", e);
} }
} else {
log.info("The file is change {}", fileCached); log.info("The file is change {}", fileCached);
return Optional.empty();
} }
private void openConnectionAndFillTheFile(boolean noResume) throws Exception {
initialSize = outputFile.length(); initialSize = outputFile.length();
if (noResume && initialSize > 0) { if (noResume && initialSize > 0) {
// delete file and restart downloading // delete file and restart downloading
Files.deleteIfExists(outputFile.toPath()); Files.deleteIfExists(outputFile.toPath());
initialSize = 0; initialSize = 0;
} }
// Open file and seek to the end of it
randomAccessOutputFile = new RandomAccessFile(outputFile, "rw");
randomAccessOutputFile.seek(initialSize);
final HttpURLConnection connection = new HttpConnectionManager(downloadUrl) final HttpURLConnection connection = new HttpConnectionManager(downloadUrl)
.makeConnection((c) -> setDownloaded(0)); .makeConnection((c) -> setDownloaded(0));
final int resp = connection.getResponseCode(); final int resp = connection.getResponseCode();
if (resp < 200 || resp >= 300) { if (resp < 200 || resp >= 300) {
IOUtils.closeQuietly(randomAccessOutputFile);
Files.deleteIfExists(outputFile.toPath()); Files.deleteIfExists(outputFile.toPath());
throw new IOException("Received invalid http status code from server: " + resp); throw new IOException("Received invalid http status code from server: " + resp);
} }
RandomAccessFile randomAccessOutputFile = null;
try {
// Open file and seek to the end of it
randomAccessOutputFile = new RandomAccessFile(outputFile, "rw");
randomAccessOutputFile.seek(initialSize);
readStreamCopyTo(randomAccessOutputFile, connection);
} finally {
IOUtils.closeQuietly(randomAccessOutputFile);
}
}
private void readStreamCopyTo(RandomAccessFile randomAccessOutputFile, HttpURLConnection connection) throws Exception {
InputStream stream = null;
try {
// Check for valid content length. // Check for valid content length.
long len = connection.getContentLength(); long len = connection.getContentLength();
if (len >= 0) { if (len >= 0) {
@ -193,9 +238,8 @@ public class FileDownloader extends Observable {
} }
setStatus(Status.DOWNLOADING); setStatus(Status.DOWNLOADING);
synchronized (this) {
stream = connection.getInputStream(); stream = connection.getInputStream();
}
byte[] buffer = new byte[10240]; byte[] buffer = new byte[10240];
while (status == Status.DOWNLOADING) { while (status == Status.DOWNLOADING) {
int read = stream.read(buffer); int read = stream.read(buffer);
@ -215,38 +259,10 @@ public class FileDownloader extends Observable {
if (getDownloaded() < getDownloadSize()) if (getDownloaded() < getDownloadSize())
throw new Exception("Incomplete download"); throw new Exception("Incomplete download");
} }
// Set the cache whe it finish to download the file
IOUtils.closeQuietly(randomAccessOutputFile);
if (fileCached.isPresent() && allowCache) {
fileCached.get().updateCacheFile(outputFile);
}
if (!allowCache) {
log.info("The file {} was not cached because allow cache is false", downloadUrl);
}
setStatus(Status.COMPLETE);
} catch (InterruptedException e) {
setStatus(Status.CANCELLED);
// lets InterruptedException go up to the caller
throw e;
} catch (SocketTimeoutException e) {
setStatus(Status.CONNECTION_TIMEOUT_ERROR);
setError(e);
log.error("The request went in socket timeout", e);
} catch (Exception e) {
setStatus(Status.ERROR);
setError(e);
log.error("The request stop", e);
} finally { } finally {
IOUtils.closeQuietly(randomAccessOutputFile);
synchronized (this) {
IOUtils.closeQuietly(stream); IOUtils.closeQuietly(stream);
} }
} }
}
private void setError(Exception e) { private void setError(Exception e) {
error = e; error = e;