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