修复无法加载 WebP 图标的问题 (#4171)
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.jackhuang.hmcl.task;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
/**
|
||||
* Download a file to cache repository.
|
||||
*
|
||||
* @author Glavo
|
||||
*/
|
||||
public final class CacheFileTask extends FetchTask<Path> {
|
||||
|
||||
public CacheFileTask(@NotNull URI uri) {
|
||||
super(List.of(uri), DEFAULT_RETRY);
|
||||
}
|
||||
|
||||
public CacheFileTask(@NotNull URI uri, int retry) {
|
||||
super(List.of(uri), retry);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EnumCheckETag shouldCheckETag() {
|
||||
// Check cache
|
||||
for (URI uri : uris) {
|
||||
try {
|
||||
setResult(repository.getCachedRemoteFile(uri));
|
||||
return EnumCheckETag.CACHED;
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
return EnumCheckETag.CHECK_E_TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void useCachedResult(Path cache) {
|
||||
setResult(cache);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Context getContext(URLConnection connection, boolean checkETag) throws IOException {
|
||||
assert checkETag;
|
||||
|
||||
Path temp = Files.createTempFile("hmcl-download-", null);
|
||||
OutputStream fileOutput = Files.newOutputStream(temp);
|
||||
|
||||
return new Context() {
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int len) throws IOException {
|
||||
fileOutput.write(buffer, offset, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
fileOutput.close();
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to close file: " + temp, e);
|
||||
}
|
||||
|
||||
if (!isSuccess()) {
|
||||
try {
|
||||
Files.deleteIfExists(temp);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to delete file: " + temp, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setResult(repository.cacheRemoteFile(connection, temp));
|
||||
} finally {
|
||||
try {
|
||||
Files.deleteIfExists(temp);
|
||||
} catch (IOException e) {
|
||||
LOG.warning("Failed to delete file: " + temp, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -44,9 +44,10 @@ import static org.jackhuang.hmcl.util.Lang.threadPool;
|
||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||
|
||||
public abstract class FetchTask<T> extends Task<T> {
|
||||
protected static final int DEFAULT_RETRY = 3;
|
||||
|
||||
protected final List<URI> uris;
|
||||
protected final int retry;
|
||||
protected boolean caching;
|
||||
protected CacheRepository repository = CacheRepository.getInstance();
|
||||
|
||||
public FetchTask(@NotNull List<@NotNull URI> uris, int retry) {
|
||||
@@ -61,10 +62,6 @@ public abstract class FetchTask<T> extends Task<T> {
|
||||
setExecutor(download());
|
||||
}
|
||||
|
||||
public void setCaching(boolean caching) {
|
||||
this.caching = caching;
|
||||
}
|
||||
|
||||
public void setCacheRepository(CacheRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ public class FileDownloadTask extends FetchTask<Void> {
|
||||
|
||||
private final Path file;
|
||||
private final IntegrityCheck integrityCheck;
|
||||
private boolean caching;
|
||||
private Path candidate;
|
||||
private final ArrayList<IntegrityCheckHandler> integrityCheckHandlers = new ArrayList<>();
|
||||
|
||||
@@ -132,7 +133,7 @@ public class FileDownloadTask extends FetchTask<Void> {
|
||||
* @param integrityCheck the integrity check to perform, null if no integrity check is to be performed
|
||||
*/
|
||||
public FileDownloadTask(List<URI> uris, Path path, IntegrityCheck integrityCheck) {
|
||||
this(uris, path, integrityCheck, 3);
|
||||
this(uris, path, integrityCheck, DEFAULT_RETRY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,6 +156,10 @@ public class FileDownloadTask extends FetchTask<Void> {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void setCaching(boolean caching) {
|
||||
this.caching = caching;
|
||||
}
|
||||
|
||||
public FileDownloadTask setCandidate(Path candidate) {
|
||||
this.candidate = candidate;
|
||||
return this;
|
||||
|
||||
@@ -36,8 +36,6 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
*/
|
||||
public final class GetTask extends FetchTask<String> {
|
||||
|
||||
private static final int DEFAULT_RETRY = 3;
|
||||
|
||||
private final Charset charset;
|
||||
|
||||
public GetTask(URI url) {
|
||||
|
||||
@@ -200,20 +200,20 @@ public class CacheRepository {
|
||||
// conn.setRequestProperty("If-Modified-Since", eTagItem.getRemoteLastModified());
|
||||
}
|
||||
|
||||
public void cacheRemoteFile(URLConnection connection, Path downloaded) throws IOException {
|
||||
cacheData(connection, () -> {
|
||||
public Path cacheRemoteFile(URLConnection connection, Path downloaded) throws IOException {
|
||||
return cacheData(connection, () -> {
|
||||
String hash = DigestUtils.digestToString(SHA1, downloaded);
|
||||
Path cached = cacheFile(downloaded, SHA1, hash);
|
||||
return new CacheResult(hash, cached);
|
||||
});
|
||||
}
|
||||
|
||||
public void cacheText(URLConnection connection, String text) throws IOException {
|
||||
cacheBytes(connection, text.getBytes(UTF_8));
|
||||
public Path cacheText(URLConnection connection, String text) throws IOException {
|
||||
return cacheBytes(connection, text.getBytes(UTF_8));
|
||||
}
|
||||
|
||||
public void cacheBytes(URLConnection connection, byte[] bytes) throws IOException {
|
||||
cacheData(connection, () -> {
|
||||
public Path cacheBytes(URLConnection connection, byte[] bytes) throws IOException {
|
||||
return cacheData(connection, () -> {
|
||||
String hash = DigestUtils.digestToString(SHA1, bytes);
|
||||
Path cached = getFile(SHA1, hash);
|
||||
FileUtils.writeBytes(cached, bytes);
|
||||
@@ -221,9 +221,9 @@ public class CacheRepository {
|
||||
});
|
||||
}
|
||||
|
||||
private void cacheData(URLConnection connection, ExceptionalSupplier<CacheResult, IOException> cacheSupplier) throws IOException {
|
||||
private Path cacheData(URLConnection connection, ExceptionalSupplier<CacheResult, IOException> cacheSupplier) throws IOException {
|
||||
String eTag = connection.getHeaderField("ETag");
|
||||
if (StringUtils.isBlank(eTag)) return;
|
||||
if (StringUtils.isBlank(eTag)) return null;
|
||||
URI uri;
|
||||
try {
|
||||
uri = NetworkUtils.dropQuery(connection.getURL().toURI());
|
||||
@@ -240,6 +240,7 @@ public class CacheRepository {
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
return cacheResult.cachedFile;
|
||||
}
|
||||
|
||||
private static final class CacheResult {
|
||||
|
||||
Reference in New Issue
Block a user