feat: download specified jre from mojang
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 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.download.java;
|
||||
|
||||
import org.jackhuang.hmcl.download.ArtifactMalformedException;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.game.DownloadInfo;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.task.Task;
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.FileUtils;
|
||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.platform.Architecture;
|
||||
import org.jackhuang.hmcl.util.platform.OperatingSystem;
|
||||
import org.jackhuang.hmcl.util.versioning.VersionNumber;
|
||||
import org.tukaani.xz.LZMAInputStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JavaDownloadTask extends Task<Void> {
|
||||
private final String javaName;
|
||||
private final Path rootDir;
|
||||
private final String platform;
|
||||
private final Task<RemoteFiles> javaDownloadsTask;
|
||||
private JavaDownloads.JavaDownload download;
|
||||
private final List<Task<?>> dependencies = new ArrayList<>();
|
||||
|
||||
public JavaDownloadTask(String javaName, String javaVersion, Path rootDir, DownloadProvider downloadProvider) throws UnsupportedPlatformException {
|
||||
this.javaName = javaName;
|
||||
this.rootDir = rootDir;
|
||||
this.platform = getCurrentJavaPlatform().orElseThrow(UnsupportedPlatformException::new);
|
||||
this.javaDownloadsTask = new GetTask(NetworkUtils.toURL(downloadProvider.injectURL(
|
||||
"https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json")))
|
||||
.thenComposeAsync(javaDownloadsJson -> {
|
||||
JavaDownloads allDownloads = JsonUtils.fromNonNullJson(javaDownloadsJson, JavaDownloads.class);
|
||||
if (!allDownloads.getDownloads().containsKey(platform)) throw new UnsupportedPlatformException();
|
||||
Map<String, List<JavaDownloads.JavaDownload>> osDownloads = allDownloads.getDownloads().get(platform);
|
||||
if (!osDownloads.containsKey(javaName)) throw new UnsupportedPlatformException();
|
||||
List<JavaDownloads.JavaDownload> candidates = osDownloads.get(javaName);
|
||||
for (JavaDownloads.JavaDownload download : candidates) {
|
||||
if (VersionNumber.VERSION_COMPARATOR.compare(download.getVersion().getName(), javaVersion) >= 0) {
|
||||
this.download = download;
|
||||
return new GetTask(NetworkUtils.toURL(download.getManifest().getUrl()));
|
||||
}
|
||||
}
|
||||
throw new UnsupportedPlatformException();
|
||||
})
|
||||
.thenApplyAsync(javaDownloadJson -> JsonUtils.fromNonNullJson(javaDownloadJson, RemoteFiles.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Task<?>> getDependents() {
|
||||
return Collections.singleton(javaDownloadsTask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
Path jvmDir = rootDir.resolve(javaName).resolve(platform).resolve(javaName);
|
||||
for (Map.Entry<String, RemoteFiles.RemoteFile> file : javaDownloadsTask.getResult().getFiles().entrySet()) {
|
||||
Path dest = jvmDir.resolve(file.getKey());
|
||||
if (file.getValue().getDownloads().containsKey("lzma")) {
|
||||
DownloadInfo download = file.getValue().getDownloads().get("lzma");
|
||||
File tempFile = Files.createTempFile("hmcl", "tmp").toFile();
|
||||
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(download.getUrl()), tempFile, new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
|
||||
dependencies.add(task.thenRunAsync(() -> {
|
||||
try {
|
||||
Files.copy(new LZMAInputStream(new FileInputStream(tempFile)), dest);
|
||||
} catch (IOException e) {
|
||||
throw new ArtifactMalformedException("File " + file.getKey() + " is malformed");
|
||||
}
|
||||
}));
|
||||
} else if (file.getValue().getDownloads().containsKey("raw")) {
|
||||
DownloadInfo download = file.getValue().getDownloads().get("raw");
|
||||
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(download.getUrl()), dest.toFile(), new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
|
||||
dependencies.add(task);
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Task<?>> getDependencies() {
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doPostExecute() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postExecute() throws Exception {
|
||||
FileUtils.writeText(rootDir.resolve(javaName).resolve(platform).resolve(".version").toFile(), download.getVersion().getName());
|
||||
FileUtils.writeText(rootDir.resolve(javaName).resolve(platform).resolve(javaName + ".sha1").toFile(),
|
||||
javaDownloadsTask.getResult().getFiles().entrySet().stream()
|
||||
.map(entry -> entry.getKey() + " /#// " + entry.getValue().getDownloads().get("raw").getSha1() + " " + entry.getValue().getDownloads().get("raw").getSize())
|
||||
.collect(Collectors.joining(OperatingSystem.LINE_SEPARATOR)));
|
||||
}
|
||||
|
||||
public static Optional<String> getCurrentJavaPlatform() {
|
||||
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
|
||||
if (Architecture.CURRENT == Architecture.X86) {
|
||||
return Optional.of("linux-i386");
|
||||
} else if (Architecture.CURRENT == Architecture.X86_64) {
|
||||
return Optional.of("linux");
|
||||
}
|
||||
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX) {
|
||||
if (Architecture.CURRENT == Architecture.X86_64) {
|
||||
return Optional.of("mac-os");
|
||||
}
|
||||
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
|
||||
if (Architecture.CURRENT == Architecture.X86) {
|
||||
return Optional.of("windows-x86");
|
||||
} else if (Architecture.CURRENT == Architecture.X86_64) {
|
||||
return Optional.of("windows-x64");
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static class UnsupportedPlatformException extends Exception {}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 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.download.java;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.jackhuang.hmcl.game.DownloadInfo;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@JsonAdapter(JavaDownloads.Adapter.class)
|
||||
public class JavaDownloads {
|
||||
|
||||
private final Map<String, Map<String, List<JavaDownload>>> downloads;
|
||||
|
||||
public JavaDownloads(Map<String, Map<String, List<JavaDownload>>> downloads) {
|
||||
this.downloads = downloads;
|
||||
}
|
||||
|
||||
public Map<String, Map<String, List<JavaDownload>>> getDownloads() {
|
||||
return downloads;
|
||||
}
|
||||
|
||||
public static class Adapter implements JsonSerializer<JavaDownloads>, JsonDeserializer<JavaDownloads> {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(JavaDownloads src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return context.serialize(src.downloads);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaDownloads deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return new JavaDownloads(context.deserialize(json, new TypeToken<Map<String, Map<String, List<JavaDownload>>>>() {
|
||||
}.getType()));
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
public static class JavaDownload {
|
||||
private final Availability availability;
|
||||
private final DownloadInfo manifest;
|
||||
private final Version version;
|
||||
|
||||
public JavaDownload() {
|
||||
this(new Availability(), new DownloadInfo(), new Version());
|
||||
}
|
||||
|
||||
public JavaDownload(Availability availability, DownloadInfo manifest, Version version) {
|
||||
this.availability = availability;
|
||||
this.manifest = manifest;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Availability getAvailability() {
|
||||
return availability;
|
||||
}
|
||||
|
||||
public DownloadInfo getManifest() {
|
||||
return manifest;
|
||||
}
|
||||
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
public static class Availability {
|
||||
private final int group;
|
||||
private final int progress;
|
||||
|
||||
public Availability() {
|
||||
this(0, 0);
|
||||
}
|
||||
|
||||
public Availability(int group, int progress) {
|
||||
this.group = group;
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
public int getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public int getProgress() {
|
||||
return progress;
|
||||
}
|
||||
}
|
||||
|
||||
@Immutable
|
||||
public static class Version {
|
||||
private final String name;
|
||||
private final String released;
|
||||
|
||||
public Version() {
|
||||
this("", "");
|
||||
}
|
||||
|
||||
public Version(String name, String released) {
|
||||
this.name = name;
|
||||
this.released = released;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getReleased() {
|
||||
return released;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 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.download.java;
|
||||
|
||||
import org.jackhuang.hmcl.game.DownloadInfo;
|
||||
import org.jackhuang.hmcl.util.gson.JsonSubtype;
|
||||
import org.jackhuang.hmcl.util.gson.JsonType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class RemoteFiles {
|
||||
private final Map<String, RemoteFile> files;
|
||||
|
||||
public RemoteFiles(Map<String, RemoteFile> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public Map<String, RemoteFile> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
@JsonType(
|
||||
property = "type",
|
||||
subtypes = {
|
||||
@JsonSubtype(clazz = RemoteFile.class, name = "file"),
|
||||
@JsonSubtype(clazz = RemoteDirectory.class, name = "directory"),
|
||||
@JsonSubtype(clazz = RemoteLink.class, name = "link")
|
||||
}
|
||||
)
|
||||
public static class Remote {
|
||||
private final String type;
|
||||
|
||||
public Remote(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RemoteFile extends Remote {
|
||||
private final boolean executable;
|
||||
private final Map<String, DownloadInfo> downloads;
|
||||
|
||||
public RemoteFile(boolean executable, Map<String, DownloadInfo> downloads) {
|
||||
super("file");
|
||||
this.executable = executable;
|
||||
this.downloads = downloads;
|
||||
}
|
||||
|
||||
public boolean isExecutable() {
|
||||
return executable;
|
||||
}
|
||||
|
||||
public Map<String, DownloadInfo> getDownloads() {
|
||||
return downloads;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RemoteDirectory extends Remote {
|
||||
public RemoteDirectory() {
|
||||
super("directory");
|
||||
}
|
||||
}
|
||||
|
||||
public static class RemoteLink extends Remote {
|
||||
private final String target;
|
||||
|
||||
public RemoteLink(String target) {
|
||||
super("link");
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public String getTarget() {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user