mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 03:31:15 +03:00
[FEATURE] AsyncDownloader теперь стандарт
This commit is contained in:
parent
117b95d3fc
commit
0922c18b22
1 changed files with 132 additions and 0 deletions
|
@ -0,0 +1,132 @@
|
||||||
|
package pro.gravit.launcher;
|
||||||
|
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
public class AsyncDownloader {
|
||||||
|
public AsyncDownloader(Callback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncDownloader() {
|
||||||
|
callback = (ignored) -> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Callback
|
||||||
|
{
|
||||||
|
void update(long diff);
|
||||||
|
}
|
||||||
|
public final Callback callback;
|
||||||
|
public static class SizedFile
|
||||||
|
{
|
||||||
|
public final String path;
|
||||||
|
public final long size;
|
||||||
|
|
||||||
|
public SizedFile(String path, long size) {
|
||||||
|
this.path = path;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void downloadFile(URL url, Path target, long size) throws IOException
|
||||||
|
{
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
try(InputStream input = connection.getInputStream())
|
||||||
|
{
|
||||||
|
transfer(input, target, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void downloadFile(URL url, Path target) throws IOException
|
||||||
|
{
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
try(InputStream input = connection.getInputStream())
|
||||||
|
{
|
||||||
|
IOHelper.transfer(input, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void downloadListInOneThread(List<SizedFile> files, String baseURL, Path targetDir) throws URISyntaxException, IOException {
|
||||||
|
URI baseUri = new URI(baseURL);
|
||||||
|
String scheme = baseUri.getScheme();
|
||||||
|
String host = baseUri.getHost();
|
||||||
|
int port = baseUri.getPort();
|
||||||
|
if (port != -1)
|
||||||
|
host = host + ":" + port;
|
||||||
|
String path = baseUri.getPath();
|
||||||
|
for(AsyncDownloader.SizedFile currentFile : files)
|
||||||
|
{
|
||||||
|
URL url = new URI(scheme,host,path + currentFile.path, "", "").toURL();
|
||||||
|
downloadFile(url, targetDir.resolve(currentFile.path), currentFile.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public List<List<SizedFile>> sortFiles(List<SizedFile> files, int threads)
|
||||||
|
{
|
||||||
|
files.sort(Comparator.comparingLong((f) -> -f.size));
|
||||||
|
List<List<SizedFile>> result = new ArrayList<>();
|
||||||
|
for(int i=0;i<threads;++i) result.add(new LinkedList<>());
|
||||||
|
long[] sizes = new long[threads];
|
||||||
|
Arrays.fill(sizes, 0);
|
||||||
|
for(SizedFile file : files)
|
||||||
|
{
|
||||||
|
long min = Long.MAX_VALUE;
|
||||||
|
int minIndex = 0;
|
||||||
|
for(int i=0;i<threads;++i)
|
||||||
|
if(sizes[i] < min) { min = sizes[i]; minIndex = i;}
|
||||||
|
result.get(minIndex).add(file);
|
||||||
|
sizes[minIndex]+=file.size;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture[] runDownloadList(List<List<SizedFile>> files, String baseURL, Path targetDir, Executor executor) {
|
||||||
|
int threads = files.size();
|
||||||
|
CompletableFuture[] futures = new CompletableFuture[threads];
|
||||||
|
for(int i=0;i<threads;++i)
|
||||||
|
{
|
||||||
|
List<SizedFile> currentTasks = files.get(i);
|
||||||
|
futures[i] = CompletableFuture.runAsync(() -> {
|
||||||
|
try {
|
||||||
|
downloadListInOneThread(currentTasks, baseURL, targetDir);
|
||||||
|
} catch (URISyntaxException | IOException e) {
|
||||||
|
throw new CompletionException(e);
|
||||||
|
}
|
||||||
|
}, executor);
|
||||||
|
}
|
||||||
|
return futures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transfer(InputStream input, Path file, long size) throws IOException {
|
||||||
|
try (OutputStream fileOutput = IOHelper.newOutput(file)) {
|
||||||
|
long downloaded = 0L;
|
||||||
|
|
||||||
|
// Download with digest update
|
||||||
|
byte[] bytes = IOHelper.newBuffer();
|
||||||
|
while (downloaded < size) {
|
||||||
|
int remaining = (int) Math.min(size - downloaded, bytes.length);
|
||||||
|
int length = input.read(bytes, 0, remaining);
|
||||||
|
if (length < 0)
|
||||||
|
throw new EOFException(String.format("%d bytes remaining", size - downloaded));
|
||||||
|
|
||||||
|
// Update file
|
||||||
|
fileOutput.write(bytes, 0, length);
|
||||||
|
|
||||||
|
// Update state
|
||||||
|
downloaded += length;
|
||||||
|
//totalDownloaded += length;
|
||||||
|
callback.update(length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue