update balanced download provider

This commit is contained in:
Tungstend 2024-02-07 14:48:24 +08:00
parent 8d19196a35
commit 8508e52241
3 changed files with 44 additions and 28 deletions

View File

@ -84,7 +84,7 @@ public final class DownloadProviders {
AdaptedDownloadProvider fileProvider = new AdaptedDownloadProvider();
fileProvider.setDownloadProviderCandidates(Arrays.asList(MCBBS, BMCLAPI, MOJANG));
BalancedDownloadProvider balanced = new BalancedDownloadProvider(Arrays.asList(MCBBS, BMCLAPI, MOJANG));
BalancedDownloadProvider balanced = new BalancedDownloadProvider(MOJANG, MCBBS, BMCLAPI);
providersById = mapOf(
pair("official", new AutoDownloadProvider(MOJANG, fileProvider)),

View File

@ -18,20 +18,17 @@
package com.tungsten.fclcore.download;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Official Download Provider fetches version list from Mojang and
* download files from mcbbs.
*/
public class BalancedDownloadProvider implements DownloadProvider {
List<DownloadProvider> candidates;
public final class BalancedDownloadProvider implements DownloadProvider {
private final DownloadProvider[] candidates;
private final Map<String, VersionList<?>> versionLists = new HashMap<>();
Map<String, VersionList<?>> versionLists = new HashMap<>();
public BalancedDownloadProvider(List<DownloadProvider> candidates) {
public BalancedDownloadProvider(DownloadProvider... candidates) {
this.candidates = candidates;
}
@ -52,13 +49,13 @@ public class BalancedDownloadProvider implements DownloadProvider {
@Override
public VersionList<?> getVersionListById(String id) {
if (!versionLists.containsKey(id)) {
versionLists.put(id, new MultipleSourceVersionList(
candidates.stream()
.map(downloadProvider -> downloadProvider.getVersionListById(id))
.collect(Collectors.toList())));
}
return versionLists.get(id);
return versionLists.computeIfAbsent(id, value -> {
VersionList<?>[] lists = new VersionList<?>[candidates.length];
for (int i = 0; i < candidates.length; i++) {
lists[i] = candidates[i].getVersionListById(value);
}
return new MultipleSourceVersionList(lists);
});
}
@Override

View File

@ -17,23 +17,26 @@
*/
package com.tungsten.fclcore.download;
import java.util.List;
import static com.tungsten.fclcore.util.Logging.LOG;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
public class MultipleSourceVersionList extends VersionList<RemoteVersion> {
private final List<VersionList<?>> backends;
private final VersionList<?>[] backends;
MultipleSourceVersionList(List<VersionList<?>> backends) {
MultipleSourceVersionList(VersionList<?>[] backends) {
this.backends = backends;
assert (backends.size() >= 1);
assert (backends.length >= 1);
}
@Override
public boolean hasType() {
boolean hasType = backends.get(0).hasType();
assert (backends.stream().allMatch(versionList -> versionList.hasType() == hasType));
boolean hasType = backends[0].hasType();
assert (Arrays.stream(backends).allMatch(versionList -> versionList.hasType() == hasType));
return hasType;
}
@ -47,11 +50,9 @@ public class MultipleSourceVersionList extends VersionList<RemoteVersion> {
throw new UnsupportedOperationException("MultipleSourceVersionList does not support loading the entire remote version list.");
}
@Override
public CompletableFuture<?> refreshAsync(String gameVersion) {
versions.clear(gameVersion);
return CompletableFuture.anyOf(backends.stream()
.map(versionList -> versionList.refreshAsync(gameVersion)
private CompletableFuture<?> refreshAsync(String gameVersion, int sourceIndex) {
VersionList<?> versionList = backends[sourceIndex];
CompletableFuture<Void> future = versionList.refreshAsync(gameVersion)
.thenRunAsync(() -> {
lock.writeLock().lock();
@ -60,7 +61,25 @@ public class MultipleSourceVersionList extends VersionList<RemoteVersion> {
} finally {
lock.writeLock().unlock();
}
}))
.toArray(CompletableFuture[]::new));
});
if (sourceIndex == backends.length - 1) {
return future;
} else {
return future.<CompletableFuture<?>>handle((ignore, e) -> {
if (e == null) {
return future;
}
LOG.log(Level.WARNING, "Failed to fetch versions list and try to fetch from other source", e);
return refreshAsync(gameVersion, sourceIndex + 1);
}).thenCompose(it -> it);
}
}
@Override
public CompletableFuture<?> refreshAsync(String gameVersion) {
versions.clear(gameVersion);
return refreshAsync(gameVersion, 0);
}
}