Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-10-04 00:41:13 +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
|
// Ensure we don't a. spam console, and b. spam download/check requests
|
||||||
if (!brokenResourcePacks.contains(packet.getPackId())) {
|
if (!brokenResourcePacks.contains(packet.getPackId())) {
|
||||||
brokenResourcePacks.add(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?");
|
"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
|
// 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() {
|
public ResourcePack create() {
|
||||||
if (this.fallback == null) {
|
if (this.fallback == null) {
|
||||||
try {
|
try {
|
||||||
final Path downloadedPack = ResourcePackLoader.downloadPack(url).whenComplete((pack, throwable) -> {
|
final Path downloadedPack = ResourcePackLoader.downloadPack(url, false).whenComplete((pack, throwable) -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Failed to download pack from " + url, throwable);
|
GeyserImpl.getInstance().getLogger().error("Failed to download pack from " + url, throwable);
|
||||||
if (GeyserImpl.getInstance().getConfig().isDebugMode()) {
|
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");
|
final Path cachedCdnPacksDirectory = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs");
|
||||||
|
|
||||||
// Download CDN packs to get the pack uuid's
|
// Download CDN packs to get the pack uuid's
|
||||||
@ -231,11 +231,8 @@ public class ResourcePackLoader implements RegistryLoader<Path, Map<String, Reso
|
|||||||
return packMap;
|
return packMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompletableFuture<@Nullable Path> downloadPack(String url) throws IllegalArgumentException {
|
public static CompletableFuture<@Nullable Path> downloadPack(String url, boolean force) throws IllegalArgumentException {
|
||||||
|
return WebUtils.checkUrlAndDownloadRemotePack(url, force).whenCompleteAsync((cachedPath, throwable) -> {
|
||||||
//TODO check if our cache pack is fine (size, url hash; head req)
|
|
||||||
|
|
||||||
return WebUtils.checkUrlAndDownloadRemotePack(url).whenCompleteAsync((cachedPath, throwable) -> {
|
|
||||||
if (cachedPath == null) {
|
if (cachedPath == null) {
|
||||||
// already warned about in WebUtils
|
// already warned about in WebUtils
|
||||||
return;
|
return;
|
||||||
|
@ -34,6 +34,7 @@ import javax.naming.directory.InitialDirContext;
|
|||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@ -41,11 +42,15 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public class WebUtils {
|
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
|
* 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
|
* If it is, it will download the pack file and return a path to it
|
||||||
*
|
*
|
||||||
* @param url The URL to check
|
* @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
|
* @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(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
try {
|
try {
|
||||||
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
|
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();
|
int size = con.getContentLength();
|
||||||
String type = con.getContentType();
|
String type = con.getContentType();
|
||||||
|
|
||||||
@ -123,21 +140,49 @@ public class WebUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream in = con.getInputStream();
|
Path packLocation = REMOTE_PACK_CACHE.resolve(url.hashCode() + ".zip");
|
||||||
Path fileLocation = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs").resolve(url.hashCode() + ".zip");
|
Path packMetadata = packLocation.resolveSibling(url.hashCode() + ".metadata");
|
||||||
Files.copy(in, fileLocation, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
|
|
||||||
if (Files.size(fileLocation) != size) {
|
if (Files.exists(packLocation) && Files.exists(packMetadata)) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Downloaded pack has " + Files.size(fileLocation) + " bytes, expected " + size + " bytes");
|
try {
|
||||||
Files.delete(fileLocation);
|
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 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) {
|
} catch (MalformedURLException e) {
|
||||||
throw new IllegalArgumentException("Malformed URL: " + url);
|
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) {
|
} 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