修复无法加载 WebP 图标的问题 (#4171)

This commit is contained in:
Glavo
2025-08-02 15:37:48 +08:00
committed by GitHub
parent e0425102c8
commit 2617dd3630
10 changed files with 230 additions and 109 deletions

View File

@@ -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);
}
}
}
};
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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 {