Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-10-03 16:31:14 +02:00
More robust downloading/caching
- better exception catching - proper error handling - caching of packs if size, etag, and last modified are the same
Dieser Commit ist enthalten in:
Ursprung
626189fa25
Commit
f12129986e
@ -284,10 +284,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
// Ensure we don't a. spam console, and b. spam download/check requests
|
||||
if (!brokenResourcePacks.contains(packet.getPackId())) {
|
||||
brokenResourcePacks.add(packet.getPackId());
|
||||
GeyserImpl.getInstance().getLogger().warning("Received a request for a remote pack that the client should have already downloaded!" +
|
||||
GeyserImpl.getInstance().getLogger().warning("Received a request for a remote pack that the client should have already downloaded! " +
|
||||
"Is the pack at the URL " + urlPackCodec.url() + " still available?");
|
||||
// not actually interested in using the download, but this does all the checks we need
|
||||
ResourcePackLoader.downloadPack(urlPackCodec.url());
|
||||
ResourcePackLoader.downloadPack(urlPackCodec.url(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ public class GeyserUrlPackCodec extends UrlPackCodec {
|
||||
public ResourcePack create() {
|
||||
if (this.fallback == null) {
|
||||
try {
|
||||
final Path downloadedPack = ResourcePackLoader.downloadPack(url).whenComplete((pack, throwable) -> {
|
||||
final Path downloadedPack = ResourcePackLoader.downloadPack(url, false).whenComplete((pack, throwable) -> {
|
||||
if (throwable != null) {
|
||||
GeyserImpl.getInstance().getLogger().error("Failed to download pack from " + url, throwable);
|
||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
||||
|
@ -200,7 +200,7 @@ public class ResourcePackLoader implements RegistryLoader<Path, Map<String, Reso
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, ResourcePack> loadRemotePacks() {
|
||||
private Map<String, ResourcePack> loadRemotePacks() {
|
||||
final Path cachedCdnPacksDirectory = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs");
|
||||
|
||||
// Download CDN packs to get the pack uuid's
|
||||
@ -231,11 +231,8 @@ public class ResourcePackLoader implements RegistryLoader<Path, Map<String, Reso
|
||||
return packMap;
|
||||
}
|
||||
|
||||
public static CompletableFuture<@Nullable Path> downloadPack(String url) throws IllegalArgumentException {
|
||||
|
||||
//TODO check if our cache pack is fine (size, url hash; head req)
|
||||
|
||||
return WebUtils.checkUrlAndDownloadRemotePack(url).whenCompleteAsync((cachedPath, throwable) -> {
|
||||
public static CompletableFuture<@Nullable Path> downloadPack(String url, boolean force) throws IllegalArgumentException {
|
||||
return WebUtils.checkUrlAndDownloadRemotePack(url, force).whenCompleteAsync((cachedPath, throwable) -> {
|
||||
if (cachedPath == null) {
|
||||
// already warned about in WebUtils
|
||||
return;
|
||||
|
@ -34,6 +34,7 @@ import javax.naming.directory.InitialDirContext;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -41,11 +42,15 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class WebUtils {
|
||||
|
||||
private static final Path REMOTE_PACK_CACHE = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs");
|
||||
|
||||
/**
|
||||
* Makes a web request to the given URL and returns the body as a string
|
||||
*
|
||||
@ -103,13 +108,25 @@ public class WebUtils {
|
||||
* If it is, it will download the pack file and return a path to it
|
||||
*
|
||||
* @param url The URL to check
|
||||
* @param force If true, the pack will be downloaded even if it is cached
|
||||
* @return Path to the downloaded pack file
|
||||
*/
|
||||
public static CompletableFuture<@Nullable Path> checkUrlAndDownloadRemotePack(String url) {
|
||||
public static CompletableFuture<@Nullable Path> checkUrlAndDownloadRemotePack(String url, boolean force) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
|
||||
con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION);
|
||||
|
||||
con.setConnectTimeout(10000);
|
||||
con.setReadTimeout(10000);
|
||||
con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().platformName() + "/" + GeyserImpl.VERSION);
|
||||
con.setInstanceFollowRedirects(false); // TODO verify
|
||||
|
||||
int responseCode = con.getResponseCode();
|
||||
if (responseCode >= 400) {
|
||||
GeyserImpl.getInstance().getLogger().error(String.format("Invalid response code from remote pack URL: %s (code: %d)", url, responseCode));
|
||||
return null;
|
||||
}
|
||||
|
||||
int size = con.getContentLength();
|
||||
String type = con.getContentType();
|
||||
|
||||
@ -123,21 +140,49 @@ public class WebUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
InputStream in = con.getInputStream();
|
||||
Path fileLocation = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs").resolve(url.hashCode() + ".zip");
|
||||
Files.copy(in, fileLocation, StandardCopyOption.REPLACE_EXISTING);
|
||||
Path packLocation = REMOTE_PACK_CACHE.resolve(url.hashCode() + ".zip");
|
||||
Path packMetadata = packLocation.resolveSibling(url.hashCode() + ".metadata");
|
||||
|
||||
if (Files.size(fileLocation) != size) {
|
||||
GeyserImpl.getInstance().getLogger().error("Downloaded pack has " + Files.size(fileLocation) + " bytes, expected " + size + " bytes");
|
||||
Files.delete(fileLocation);
|
||||
if (Files.exists(packLocation) && Files.exists(packMetadata)) {
|
||||
try {
|
||||
List<String> metadataLines = Files.readAllLines(packMetadata, StandardCharsets.UTF_8);
|
||||
int cachedSize = Integer.parseInt(metadataLines.get(0));
|
||||
String cachedEtag = metadataLines.get(1);
|
||||
long cachedLastModified = Long.parseLong(metadataLines.get(2));
|
||||
|
||||
if (cachedSize == size && cachedEtag.equals(con.getHeaderField("ETag")) && cachedLastModified == con.getLastModified()) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Using cached pack for " + url);
|
||||
return packLocation;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
GeyserImpl.getInstance().getLogger().error("Failed to read cached pack metadata: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
InputStream in = con.getInputStream();
|
||||
Files.copy(in, packLocation, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
if (Files.size(packLocation) != size) {
|
||||
GeyserImpl.getInstance().getLogger().error("Downloaded pack has " + Files.size(packLocation) + " bytes, expected " + size + " bytes");
|
||||
Files.delete(packLocation);
|
||||
return null;
|
||||
}
|
||||
|
||||
return fileLocation;
|
||||
try {
|
||||
Files.write(packMetadata, Arrays.asList(String.valueOf(size), con.getHeaderField("ETag"), String.valueOf(con.getLastModified())));
|
||||
} catch (IOException e) {
|
||||
GeyserImpl.getInstance().getLogger().error("Failed to write cached pack metadata: " + e.getMessage());
|
||||
}
|
||||
|
||||
return packLocation;
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException("Malformed URL: " + url);
|
||||
} catch (SocketTimeoutException | ConnectException e) {
|
||||
GeyserImpl.getInstance().getLogger().error("Unable to reach URL: " + url + " (" + e.getMessage() + ")");
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Unable to download and save remote resource pack from: " + url + ")");
|
||||
e.printStackTrace(); // TODO yeeeeeeeet
|
||||
throw new RuntimeException("Unable to download and save remote resource pack from: " + url + " (" + e.getMessage() + ")");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren