From 8e6b56b2d613db73866872c0d40fb4e10f046d56 Mon Sep 17 00:00:00 2001 From: huangyuhui Date: Tue, 9 Jan 2018 17:14:50 +0800 Subject: [PATCH] upgrader --- .../jackhuang/hmcl/event/OutOfDateEvent.java} | 34 ++- .../game/HMCLMultiCharacterSelector.java} | 24 +- .../hmcl/setting/EnumGameDirectory.java} | 18 +- .../hmcl/setting/LauncherVisibility.java} | 6 +- .../hmcl/ui/animation/AnimationHandler.java} | 18 +- .../hmcl/ui/construct/MessageBox.java | 162 ++++++++++++ .../hmcl/ui/construct/UTF8Control.java | 62 +++++ .../hmcl/ui/construct/Validator.java | 42 +++ .../jackhuang/hmcl/ui/wizard/Navigation.java} | 37 ++- .../hmcl/ui/wizard/Refreshable.java} | 8 +- .../hmcl/upgrade/AppDataUpgrader.java | 246 ++++++++++++++++++ .../jackhuang/hmcl/upgrade/IUpgrader.java} | 20 +- .../hmcl/upgrade/NewFileUpgrader.java | 83 ++++++ .../jackhuang/hmcl/upgrade/UpdateChecker.java | 139 ++++++++++ .../main/kotlin/org/jackhuang/hmcl/Main.kt | 2 + .../hmcl/ui/construct/UTF8Control.kt | 55 ---- .../jackhuang/hmcl/upgrade/AppDataUpgrader.kt | 227 ---------------- .../jackhuang/hmcl/upgrade/UpdateChecker.kt | 112 -------- .../java/org/jackhuang/hmcl/task/Task.java | 6 +- 19 files changed, 842 insertions(+), 459 deletions(-) rename HMCL/src/main/{kotlin/org/jackhuang/hmcl/ui/construct/Validator.kt => java/org/jackhuang/hmcl/event/OutOfDateEvent.java} (59%) rename HMCL/src/main/{kotlin/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.kt => java/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.java} (55%) rename HMCL/src/main/{kotlin/org/jackhuang/hmcl/setting/EnumGameDirectory.kt => java/org/jackhuang/hmcl/setting/EnumGameDirectory.java} (71%) rename HMCL/src/main/{kotlin/org/jackhuang/hmcl/setting/LauncherVisibility.kt => java/org/jackhuang/hmcl/setting/LauncherVisibility.java} (94%) rename HMCL/src/main/{kotlin/org/jackhuang/hmcl/ui/animation/AnimationHandler.kt => java/org/jackhuang/hmcl/ui/animation/AnimationHandler.java} (75%) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageBox.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/UTF8Control.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Validator.java rename HMCL/src/main/{kotlin/org/jackhuang/hmcl/ui/wizard/Navigation.kt => java/org/jackhuang/hmcl/ui/wizard/Navigation.java} (61%) rename HMCL/src/main/{kotlin/org/jackhuang/hmcl/ui/wizard/Refreshable.kt => java/org/jackhuang/hmcl/ui/wizard/Refreshable.java} (89%) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java rename HMCL/src/main/{kotlin/org/jackhuang/hmcl/upgrade/IUpgrader.kt => java/org/jackhuang/hmcl/upgrade/IUpgrader.java} (72%) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java delete mode 100644 HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/UTF8Control.kt delete mode 100644 HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/AppDataUpgrader.kt delete mode 100644 HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/UpdateChecker.kt diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/Validator.kt b/HMCL/src/main/java/org/jackhuang/hmcl/event/OutOfDateEvent.java similarity index 59% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/Validator.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/event/OutOfDateEvent.java index 358758963..60b209253 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/Validator.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/event/OutOfDateEvent.java @@ -15,19 +15,31 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.ui.construct +package org.jackhuang.hmcl.event; -import com.jfoenix.validation.base.ValidatorBase -import javafx.scene.control.TextInputControl +import org.jackhuang.hmcl.util.VersionNumber; /** - * @param validator return true if the input string is valid. + * + * Result: Deny if do not upgrade HMCL. + * + * @author huangyuhui */ -class Validator(val validator: (String) -> Boolean) : ValidatorBase() { - override fun eval() { - if (this.srcControl.get() is TextInputControl) { - val text = (srcControl.get() as TextInputControl).text - hasErrors.set(!validator(text)) - } +public final class OutOfDateEvent extends Event { + private final VersionNumber version; + + public OutOfDateEvent(Object source, VersionNumber version) { + super(source); + this.version = version; } -} \ No newline at end of file + + public VersionNumber getVersion() { + return version; + } + + @Override + public boolean hasResult() { + return true; + } + +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.kt b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.java similarity index 55% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.java index c2d6e4909..cbe667531 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLMultiCharacterSelector.java @@ -15,15 +15,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.game +package org.jackhuang.hmcl.game; -import org.jackhuang.hmcl.auth.Account -import org.jackhuang.hmcl.auth.MultiCharacterSelector -import org.jackhuang.hmcl.auth.NoSelectedCharacterException -import org.jackhuang.hmcl.auth.yggdrasil.GameProfile +import org.jackhuang.hmcl.auth.Account; +import org.jackhuang.hmcl.auth.MultiCharacterSelector; +import org.jackhuang.hmcl.auth.NoSelectedCharacterException; +import org.jackhuang.hmcl.auth.yggdrasil.GameProfile; -object HMCLMultiCharacterSelector : MultiCharacterSelector { - override fun select(account: Account, names: MutableList): GameProfile { - return names.firstOrNull() ?: throw NoSelectedCharacterException(account) +import java.util.List; + +/** + * @author huangyuhui + */ +public final class HMCLMultiCharacterSelector implements MultiCharacterSelector { + @Override + public GameProfile select(Account account, List names) throws NoSelectedCharacterException { + return names.stream().findFirst().orElseThrow(() -> new NoSelectedCharacterException(account)); } -} \ No newline at end of file +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/EnumGameDirectory.kt b/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumGameDirectory.java similarity index 71% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/EnumGameDirectory.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumGameDirectory.java index fc2447500..94d79016b 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/EnumGameDirectory.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumGameDirectory.java @@ -15,10 +15,24 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.setting +package org.jackhuang.hmcl.setting; -enum class EnumGameDirectory { +/** + * Determines where game runs in and game files such as mods. + * + * @author huangyuhui + */ +public enum EnumGameDirectory { + /** + * .minecraft + */ ROOT_FOLDER, + /** + * .minecraft/versions/<version name> + */ VERSION_FOLDER, + /** + * user customized directory. + */ CUSTOM } \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/LauncherVisibility.kt b/HMCL/src/main/java/org/jackhuang/hmcl/setting/LauncherVisibility.java similarity index 94% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/LauncherVisibility.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/setting/LauncherVisibility.java index 0d3cce324..d58f65f34 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/setting/LauncherVisibility.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/LauncherVisibility.java @@ -15,13 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.setting +package org.jackhuang.hmcl.setting; /** * The visibility of launcher. * @author huangyuhui */ -enum class LauncherVisibility { +public enum LauncherVisibility { /** * Close the launcher anyway when the game process created even if failed to @@ -44,4 +44,4 @@ enum class LauncherVisibility { * Hide the launcher and reopen it when game closes. */ HIDE_AND_REOPEN -} \ No newline at end of file +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/AnimationHandler.kt b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/AnimationHandler.java similarity index 75% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/AnimationHandler.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/AnimationHandler.java index ba2ebac73..6b567af6e 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/animation/AnimationHandler.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/AnimationHandler.java @@ -15,14 +15,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.ui.animation +package org.jackhuang.hmcl.ui.animation; -import javafx.scene.Node -import javafx.scene.layout.Pane -import javafx.util.Duration +import javafx.scene.Node; +import javafx.scene.layout.Pane; +import javafx.util.Duration; -interface AnimationHandler { - val snapshot: Node - val duration: Duration - val view: Pane -} \ No newline at end of file +public interface AnimationHandler { + Node getSnapshot(); + Duration getDuration(); + Pane getView(); +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageBox.java new file mode 100644 index 000000000..062aa0608 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MessageBox.java @@ -0,0 +1,162 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui.construct; + +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonType; +import javafx.scene.control.TextInputDialog; +import org.jackhuang.hmcl.MainKt; +import javax.swing.UIManager; + +import java.util.Optional; + +public final class MessageBox { + private MessageBox() { + } + + private static final String TITLE = MainKt.i18n("message.info"); + + /** + * User Operation: Yes + */ + public static final int YES_OPTION = 0; + + /** + * User Operation: No + */ + public static final int NO_OPTION = 1; + + /** + * User Operation: Cancel + */ + public static final int CANCEL_OPTION = 2; + + /** + * User Operation: OK + */ + public static final int OK_OPTION = 0; + + /** + * User Operation: Closed Message Box + */ + public static final int CLOSED_OPTION = -1; + + /** + * Buttons: Yes No + */ + public static final int YES_NO_OPTION = 10; + /** + * Buttons: Yes No Cancel + */ + public static final int YES_NO_CANCEL_OPTION = 11; + /** + * Buttons: OK Cancel + */ + public static final int OK_CANCEL_OPTION = 12; + + /** + * Message Box Type: Error + */ + public static final int ERROR_MESSAGE = 0; + /** + * Message Box Type: Info + */ + public static final int INFORMATION_MESSAGE = 1; + /** + * Message Box Type: Warning + */ + public static final int WARNING_MESSAGE = 2; + /** + * Message Box Type: Question + */ + public static final int QUESTION_MESSAGE = 3; + /** + * Message Box Type: Plain + */ + public static final int PLAIN_MESSAGE = -1; + + + public static void show(String message) { + show(message, TITLE); + } + + /** + * Show MsgBox with title and options + * + * @param message The Message + * @param title The title of MsgBox. + * @return user operation. + */ + public static void show(String message, String title) { + Alert alert = new Alert(Alert.AlertType.INFORMATION); + alert.setTitle(title); + alert.setHeaderText(title); + alert.setContentText(message); + alert.showAndWait(); + } + + public static int confirm(String message, String title) { + return confirm(message, title, -1); + } + + public static int confirm(String message, int option) { + return confirm(message, TITLE, option); + } + + public static int confirm(String message, String title, int option) { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setTitle(title); + alert.setHeaderText(title); + alert.setContentText(message); + switch (option) { + case YES_NO_OPTION: + alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO); + break; + case YES_NO_CANCEL_OPTION: + alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO, ButtonType.CANCEL); + break; + case OK_CANCEL_OPTION: + alert.getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); + break; + } + Optional buttonType = alert.showAndWait(); + if (!buttonType.isPresent()) return CLOSED_OPTION; + else if (buttonType.get() == ButtonType.OK) return OK_OPTION; + else if (buttonType.get() == ButtonType.YES) return YES_OPTION; + else if (buttonType.get() == ButtonType.NO) return NO_OPTION; + else if (buttonType.get() == ButtonType.CANCEL) return CANCEL_OPTION; + else throw new IllegalStateException("Unrecognized button type:" + buttonType.get()); + } + + public static Optional input(String message) { + return input(message, UIManager.getString("OptionPane.inputDialogTitle")); + } + + public static Optional input(String message, String title) { + return input(message, title, ""); + } + + public static Optional input(String message, String title, String initialValue) { + TextInputDialog dialog = new TextInputDialog(initialValue); + dialog.setTitle(title); + dialog.setHeaderText(message); + dialog.setContentText(message); + + return dialog.showAndWait(); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/UTF8Control.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/UTF8Control.java new file mode 100644 index 000000000..682350e3c --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/UTF8Control.java @@ -0,0 +1,62 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui.construct; + +import kotlin.jvm.Throws; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.Locale; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +public class UTF8Control extends ResourceBundle.Control { + @Override + public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) + throws IllegalAccessException, InstantiationException, IOException { + // The below is a copy of the default implementation. + String bundleName = toBundleName(baseName, locale); + String resourceName = toResourceName(bundleName, "properties"); + ResourceBundle bundle = null; + InputStream stream = null; + if (reload) { + URL url = loader.getResource(resourceName); + if (url != null) { + URLConnection connection = url.openConnection(); + if (connection != null) { + connection.setUseCaches(false); + stream = connection.getInputStream(); + } + } + } else { + stream = loader.getResourceAsStream(resourceName); + } + if (stream != null) { + try { + // Only this line is changed to make it to read properties files as UTF-8. + bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8")); + } finally { + stream.close(); + } + } + return bundle; + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Validator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Validator.java new file mode 100644 index 000000000..d667d5ed2 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Validator.java @@ -0,0 +1,42 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui.construct; + +import com.jfoenix.validation.base.ValidatorBase; +import javafx.scene.control.TextInputControl; + +import java.util.function.Predicate; + +public final class Validator extends ValidatorBase { + private final Predicate validator; + + /** + * @param validator return true if the input string is valid. + */ + public Validator(Predicate validator) { + this.validator = validator; + } + + @Override + protected void eval() { + if (this.srcControl.get() instanceof TextInputControl) { + String text = ((TextInputControl) srcControl.get()).getText(); + hasErrors.set(!validator.test(text)); + } + } +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Navigation.kt b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Navigation.java similarity index 61% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Navigation.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Navigation.java index 3cdb53778..d60af667b 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Navigation.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Navigation.java @@ -15,25 +15,36 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.ui.wizard +package org.jackhuang.hmcl.ui.wizard; -import org.jackhuang.hmcl.ui.animation.ContainerAnimations +import org.jackhuang.hmcl.ui.animation.ContainerAnimations; -interface Navigation { - fun onStart() - fun onNext() - fun onPrev(cleanUp: Boolean) - fun canPrev(): Boolean - fun onFinish() - fun onEnd() - fun onCancel() +public interface Navigation { - enum class NavigationDirection(val animation: ContainerAnimations) { + void onStart(); + void onNext(); + void onPrev(boolean cleanUp); + boolean canPrev(); + void onFinish(); + void onEnd(); + void onCancel(); + + enum NavigationDirection { START(ContainerAnimations.NONE), PREVIOUS(ContainerAnimations.SWIPE_RIGHT), NEXT(ContainerAnimations.SWIPE_LEFT), FINISH(ContainerAnimations.SWIPE_LEFT), IN(ContainerAnimations.ZOOM_IN), - OUT(ContainerAnimations.ZOOM_OUT) + OUT(ContainerAnimations.ZOOM_OUT); + + private final ContainerAnimations animation; + + NavigationDirection(ContainerAnimations animation) { + this.animation = animation; + } + + public ContainerAnimations getAnimation() { + return animation; + } } -} \ No newline at end of file +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Refreshable.kt b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Refreshable.java similarity index 89% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Refreshable.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Refreshable.java index ffc6dff6e..d8d27a6d7 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/wizard/Refreshable.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/wizard/Refreshable.java @@ -15,8 +15,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.ui.wizard +package org.jackhuang.hmcl.ui.wizard; -interface Refreshable { - fun refresh() -} \ No newline at end of file +public interface Refreshable { + void refresh(); +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java new file mode 100644 index 000000000..66d6248dc --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/AppDataUpgrader.java @@ -0,0 +1,246 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.upgrade; + +import com.google.gson.JsonSyntaxException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.Proxy; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.*; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Pack200; +import java.util.logging.Level; +import java.util.zip.GZIPInputStream; + +import com.google.gson.reflect.TypeToken; +import org.jackhuang.hmcl.Main; +import org.jackhuang.hmcl.MainKt; +import org.jackhuang.hmcl.task.FileDownloadTask; +import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.ui.construct.MessageBox; +import org.jackhuang.hmcl.util.*; + +/** + * + * @author huangyuhui + */ +public class AppDataUpgrader extends IUpgrader { + + private boolean launchNewerVersion(List args, File jar) throws IOException, PrivilegedActionException { + try (JarFile jarFile = new JarFile(jar)) { + String mainClass = jarFile.getManifest().getMainAttributes().getValue("Main-Class"); + if (mainClass != null) { + ArrayList al = new ArrayList<>(args); + al.add("--noupdate"); + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + new URLClassLoader(new URL[]{jar.toURI().toURL()}, + URLClassLoader.getSystemClassLoader().getParent()).loadClass(mainClass) + .getMethod("main", String[].class).invoke(null, new Object[]{al.toArray(new String[0])}); + return null; + }); + return true; + } + } + return false; + } + + @Override + public void parseArguments(VersionNumber nowVersion, List args) { + File f = AppDataUpgraderPackGzTask.HMCL_VER_FILE; + if (!args.contains("--noupdate")) + try { + if (f.exists()) { + Map m = Constants.GSON.fromJson(FileUtils.readText(f), new TypeToken>() { + }.getType()); + String s = m.get("ver"); + if (s != null && VersionNumber.asVersion(s).compareTo(nowVersion) > 0) { + String j = m.get("loc"); + if (j != null) { + File jar = new File(j); + if (jar.exists() && launchNewerVersion(args, jar)) + System.exit(0); + } + } + } + } catch (JsonSyntaxException ex) { + f.delete(); + } catch (IOException | PrivilegedActionException t) { + Logging.LOG.log(Level.SEVERE, "Failed to execute newer version application", t); + } + } + + @Override + public void download(UpdateChecker checker, VersionNumber ver) { + if (!(ver instanceof IntVersionNumber)) + return; + IntVersionNumber version = (IntVersionNumber) ver; + checker.requestDownloadLink().then(Task.of(v -> { + Map map = v.get(UpdateChecker.REQUEST_DOWNLOAD_LINK_ID); + + if (MessageBox.confirm(MainKt.i18n("update.newest_version") + version.get(0) + "." + version.get(1) + "." + version.get(2) + "\n" + + MainKt.i18n("update.should_open_link"), + MessageBox.YES_NO_OPTION) == MessageBox.YES_OPTION) + if (map != null && map.containsKey("jar") && !StringUtils.isBlank(map.get("jar"))) + try { + String hash = null; + if (map.containsKey("jarsha1")) + hash = map.get("jarsha1"); + if (TaskWindow.factory().append(new AppDataUpgraderJarTask(NetworkUtils.toURL(map.get("jar")), version.toString(), hash)).execute()) { + new ProcessBuilder(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath(), "-jar", AppDataUpgraderJarTask.getSelf(version.toString()).getAbsolutePath()) + .directory(new File("").getAbsoluteFile()).start(); + System.exit(0); + } + } catch (IOException ex) { + Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex); + } + else if (map != null && map.containsKey("pack") && !StringUtils.isBlank(map.get("pack"))) + try { + String hash = null; + if (map.containsKey("packsha1")) + hash = map.get("packsha1"); + if (TaskWindow.factory().append(new AppDataUpgraderPackGzTask(NetworkUtils.toURL(map.get("pack")), version.toString(), hash)).execute()) { + new ProcessBuilder(JavaVersion.fromCurrentEnvironment().getBinary().getAbsolutePath(), "-jar", AppDataUpgraderPackGzTask.getSelf(version.toString()).getAbsolutePath()) + .directory(new File("").getAbsoluteFile()).start(); + System.exit(0); + } + } catch (IOException ex) { + Logging.LOG.log(Level.SEVERE, "Failed to create upgrader", ex); + } + else { + String url = URL_PUBLISH; + if (map != null) + if (map.containsKey(OperatingSystem.CURRENT_OS.getCheckedName())) + url = map.get(OperatingSystem.CURRENT_OS.getCheckedName()); + else if (map.containsKey(OperatingSystem.UNKNOWN.getCheckedName())) + url = map.get(OperatingSystem.UNKNOWN.getCheckedName()); + if (url == null) + url = URL_PUBLISH; + try { + java.awt.Desktop.getDesktop().browse(new URI(url)); + } catch (URISyntaxException | IOException e) { + Logging.LOG.log(Level.SEVERE, "Failed to browse uri: " + url, e); + OperatingSystem.setClipboard(url); + MessageBox.show(MainKt.i18n("update.no_browser")); + } + } + })).start(); + } + + public static class AppDataUpgraderPackGzTask extends Task { + + public static final File BASE_FOLDER = Main.getWorkingDirectory("hmcl"); + public static final File HMCL_VER_FILE = new File(BASE_FOLDER, "hmclver.json"); + + public static File getSelf(String ver) { + return new File(BASE_FOLDER, "HMCL-" + ver + ".jar"); + } + + private final URL downloadLink; + private final String newestVersion, hash; + File tempFile; + + public AppDataUpgraderPackGzTask(URL downloadLink, String newestVersion, String hash) throws IOException { + this.downloadLink = downloadLink; + this.newestVersion = newestVersion; + this.hash = hash; + tempFile = File.createTempFile("hmcl", ".pack.gz"); + + setName("Upgrade"); + } + + @Override + public Collection getDependents() { + return Arrays.asList(new FileDownloadTask(downloadLink, tempFile, Proxy.NO_PROXY, hash)); + } + + @Override + public void execute() throws Exception { + HashMap json = new HashMap<>(); + File f = getSelf(newestVersion); + if (!FileUtils.makeDirectory(f.getParentFile())) + throw new IOException("Failed to make directories: " + f.getParent()); + + for (int i = 0; f.exists(); i++) + f = new File(BASE_FOLDER, "HMCL-" + newestVersion + (i > 0 ? "-" + i : "") + ".jar"); + if (!f.createNewFile()) + throw new IOException("Failed to create new file: " + f); + + try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(f))) { + Pack200.newUnpacker().unpack(new GZIPInputStream(new FileInputStream(tempFile)), jos); + } + json.put("ver", newestVersion); + json.put("loc", f.getAbsolutePath()); + String result = Constants.GSON.toJson(json); + FileUtils.writeText(HMCL_VER_FILE, result); + } + + } + + public static class AppDataUpgraderJarTask extends Task { + + public static final File BASE_FOLDER = Main.getWorkingDirectory("hmcl"); + public static final File HMCL_VER_FILE = new File(BASE_FOLDER, "hmclver.json"); + + public static File getSelf(String ver) { + return new File(BASE_FOLDER, "HMCL-" + ver + ".jar"); + } + + private final URL downloadLink; + private final String newestVersion, hash; + File tempFile; + + public AppDataUpgraderJarTask(URL downloadLink, String newestVersion, String hash) throws IOException { + this.downloadLink = downloadLink; + this.newestVersion = newestVersion; + this.hash = hash; + tempFile = File.createTempFile("hmcl", ".jar"); + + setName("Upgrade"); + } + + @Override + public Collection getDependents() { + return Collections.singleton(new FileDownloadTask(downloadLink, tempFile, Proxy.NO_PROXY, hash)); + } + + @Override + public void execute() throws Exception { + HashMap json = new HashMap<>(); + File f = getSelf(newestVersion); + FileUtils.copyFile(tempFile, f); + json.put("ver", newestVersion); + json.put("loc", f.getAbsolutePath()); + String result = Constants.GSON.toJson(json); + FileUtils.writeText(HMCL_VER_FILE, result); + } + + } + + public static final String URL_PUBLISH = "http://www.mcbbs.net/thread-142335-1-1.html"; + public static final String URL_CONTACT = "http://huangyuhui.duapp.com/hmcl.php"; +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/IUpgrader.kt b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IUpgrader.java similarity index 72% rename from HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/IUpgrader.kt rename to HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IUpgrader.java index a112e0faf..e3cc37df8 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/IUpgrader.kt +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/IUpgrader.java @@ -15,15 +15,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see {http://www.gnu.org/licenses/}. */ -package org.jackhuang.hmcl.upgrade +package org.jackhuang.hmcl.upgrade; -import org.jackhuang.hmcl.util.VersionNumber +import org.jackhuang.hmcl.util.VersionNumber; + +import java.util.List; /** * * @author huangyuhui */ -interface IUpgrader { +public abstract class IUpgrader { + + public static final IUpgrader NOW_UPGRADER = new AppDataUpgrader(); /** * Paring arguments to decide on whether the upgrade is needed. @@ -31,19 +35,15 @@ interface IUpgrader { * @param nowVersion now launcher version * @param args Application CommandLine Arguments */ - fun parseArguments(nowVersion: VersionNumber, args: Array) + public abstract void parseArguments(VersionNumber nowVersion, List args); /** * Just download the new app. * * @param checker Should be VersionChecker - * @param versionNumber the newest version + * @param version the newest version * * @return should return true */ - fun download(checker: UpdateChecker, versionNumber: VersionNumber) - - companion object { - val NOW_UPGRADER: IUpgrader = AppDataUpgrader() - } + public abstract void download(UpdateChecker checker, VersionNumber version); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java new file mode 100644 index 000000000..88afe69be --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/NewFileUpgrader.java @@ -0,0 +1,83 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.upgrade; + +import org.jackhuang.hmcl.task.FileDownloadTask; +import org.jackhuang.hmcl.util.Charsets; +import org.jackhuang.hmcl.util.FileUtils; +import org.jackhuang.hmcl.util.Logging; +import org.jackhuang.hmcl.util.VersionNumber; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; + +/** + * + * @author huangyuhui + */ +public class NewFileUpgrader extends IUpgrader { + + @Override + public void parseArguments(VersionNumber nowVersion, List args) { + int i = args.indexOf("--removeOldLauncher"); + if (i != -1 && i < args.size() - 1) { + File f = new File(args.get(i + 1)); + if (f.exists()) + f.deleteOnExit(); + } + } + + @Override + public void download(UpdateChecker checker, VersionNumber version) { + URL url = requestDownloadLink(); + if (url == null) return; + File newf = new File(url.getFile()); + if (TaskWindow.factory().append(new FileDownloadTask(url, newf)).execute()) { + try { + new ProcessBuilder(newf.getCanonicalPath(), "--removeOldLauncher", getRealPath()) + .directory(new File("").getAbsoluteFile()) + .start(); + } catch (IOException ex) { + Logging.LOG.log(Level.SEVERE, "Failed to start new app", ex); + } + System.exit(0); + } + } + + private static String getRealPath() { + String realPath = NewFileUpgrader.class.getClassLoader().getResource("").getFile(); + File file = new File(realPath); + realPath = file.getAbsolutePath(); + try { + realPath = java.net.URLDecoder.decode(realPath, Charsets.DEFAULT_CHARSET.name()); + } catch (Exception e) { + e.printStackTrace(); + } + return realPath; + } + + private URL requestDownloadLink() { + return null; + } + +} + diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java new file mode 100644 index 000000000..1da3d391a --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/UpdateChecker.java @@ -0,0 +1,139 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.upgrade; + +import com.google.gson.JsonSyntaxException; +import org.jackhuang.hmcl.MainKt; +import org.jackhuang.hmcl.event.Event; +import org.jackhuang.hmcl.event.EventBus; +import org.jackhuang.hmcl.event.OutOfDateEvent; +import org.jackhuang.hmcl.task.TaskResult; +import org.jackhuang.hmcl.ui.construct.MessageBox; +import org.jackhuang.hmcl.util.Constants; +import org.jackhuang.hmcl.util.Logging; +import org.jackhuang.hmcl.util.NetworkUtils; +import org.jackhuang.hmcl.util.VersionNumber; + +import java.io.IOException; +import java.util.Map; +import java.util.logging.Level; + +/** + * + * @author huangyuhui + */ +public final class UpdateChecker { + + private volatile boolean outOfDate = false; + private VersionNumber base; + private String versionString; + public String type; + private Map download_link = null; + + public UpdateChecker(VersionNumber base, String type) { + this.base = base; + this.type = type; + } + + private VersionNumber value; + + public boolean isOutOfDate() { + return outOfDate; + } + + /** + * Download the version number synchronously. When you execute this method + * first, should leave "showMessage" false. + * + * @param showMessage If it is requested to warn the user that there is a + * new version. + * + * @return the process observable. + */ + public TaskResult process(final boolean showMessage) { + return new TaskResult() { + @Override + public void execute() throws Exception { + if (value == null) { + versionString = NetworkUtils.doGet(NetworkUtils.toURL("http://huangyuhui.duapp.com/info.php?type=" + type)); + value = VersionNumber.asVersion(versionString); + } + + if (value == null) { + Logging.LOG.warning("Failed to check update..."); + if (showMessage) + MessageBox.show(MainKt.i18n("update.failed")); + } else if (base.compareTo(value) < 0) + outOfDate = true; + if (outOfDate) + setResult(value); + } + + @Override + public String getId() { + return "update_checker.process"; + } + }; + } + + /** + * Get the cached newest version number, use "process" method to + * download! + * + * @return the newest version number + * + * @see #process(boolean) + */ + public VersionNumber getNewVersion() { + return value; + } + + /** + * Get the download links. + * + * @return a JSON, which contains the server response. + */ + public synchronized TaskResult> requestDownloadLink() { + return new TaskResult>() { + @Override + public void execute() throws Exception { + if (download_link == null) + try { + download_link = Constants.GSON.>fromJson(NetworkUtils.doGet(NetworkUtils.toURL("http://huangyuhui.duapp.com/update_link.php?type=" + type)), Map.class); + } catch (JsonSyntaxException | IOException e) { + Logging.LOG.log(Level.SEVERE, "Failed to get update link.", e); + } + setResult(download_link); + } + + @Override + public String getId() { + return "update_checker.request_download_link"; + } + }; + } + + public static final String REQUEST_DOWNLOAD_LINK_ID = "update_checker.request_download_link"; + + public void checkOutdate() { + if (outOfDate) + if (EventBus.EVENT_BUS.fireEvent(new OutOfDateEvent(this, getNewVersion())) != Event.Result.DENY) { + IUpgrader.NOW_UPGRADER.download(this, getNewVersion()); + } + } +} diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt index 04dc952bd..ce7e97713 100644 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt +++ b/HMCL/src/main/kotlin/org/jackhuang/hmcl/Main.kt @@ -70,6 +70,7 @@ class Main : Application() { launch(Main::class.java, *args) } + @JvmStatic fun getWorkingDirectory(folder: String): File { val userhome = System.getProperty("user.home", ".") return when (OperatingSystem.CURRENT_OS) { @@ -83,6 +84,7 @@ class Main : Application() { } } + @JvmStatic fun getMinecraftDirectory(): File = getWorkingDirectory("minecraft") fun stop() = runOnUiThread { diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/UTF8Control.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/UTF8Control.kt deleted file mode 100644 index 2a47804fa..000000000 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/ui/construct/UTF8Control.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2017 huangyuhui - * - * 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 {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hmcl.ui.construct - -import java.io.IOException -import java.io.InputStream -import java.io.InputStreamReader -import java.util.* - -object UTF8Control : ResourceBundle.Control() { - @Throws(IllegalAccessException::class, InstantiationException::class, IOException::class) - override fun newBundle(baseName: String, locale: Locale, format: String, loader: ClassLoader, reload: Boolean): ResourceBundle? { - // The below is a copy of the default implementation. - val bundleName = toBundleName(baseName, locale) - val resourceName = toResourceName(bundleName, "properties") - var bundle: ResourceBundle? = null - var stream: InputStream? = null - if (reload) { - val url = loader.getResource(resourceName) - if (url != null) { - val connection = url.openConnection() - if (connection != null) { - connection.useCaches = false - stream = connection.getInputStream() - } - } - } else { - stream = loader.getResourceAsStream(resourceName) - } - if (stream != null) { - try { - // Only this line is changed to make it to read properties files as UTF-8. - bundle = PropertyResourceBundle(InputStreamReader(stream, "UTF-8")) - } finally { - stream.close() - } - } - return bundle - } -} \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/AppDataUpgrader.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/AppDataUpgrader.kt deleted file mode 100644 index 2df501053..000000000 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/AppDataUpgrader.kt +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2017 huangyuhui - * - * 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 {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hmcl.upgrade - -import java.security.PrivilegedActionException -import java.io.IOException -import com.google.gson.JsonSyntaxException -import javafx.scene.control.Alert -import java.io.File -import java.net.URLClassLoader -import java.security.PrivilegedExceptionAction -import java.security.AccessController -import java.util.Arrays -import java.util.ArrayList -import java.util.jar.JarFile -import org.jackhuang.hmcl.Main -import java.util.HashMap -import org.jackhuang.hmcl.task.* -import java.util.logging.Level -import java.util.zip.GZIPInputStream -import java.util.jar.Pack200 -import java.util.jar.JarOutputStream -import org.jackhuang.hmcl.util.* -import java.net.URISyntaxException -import org.jackhuang.hmcl.i18n -import org.jackhuang.hmcl.ui.alert -import org.jackhuang.hmcl.util.Constants.GSON -import org.jackhuang.hmcl.util.Logging.LOG -import org.jackhuang.hmcl.util.VersionNumber -import java.net.Proxy -import java.net.URI - -class AppDataUpgrader : IUpgrader { - - @Throws(IOException::class, PrivilegedActionException::class) - private fun launchNewerVersion(args: Array, jar: File): Boolean { - JarFile(jar).use { jarFile -> - val mainClass = jarFile.manifest.mainAttributes.getValue("Main-Class") - if (mainClass != null) { - val al = ArrayList(Arrays.asList(*args)) - al.add("--noupdate") - AccessController.doPrivileged(PrivilegedExceptionAction { - URLClassLoader(arrayOf(jar.toURI().toURL()), - URLClassLoader.getSystemClassLoader().parent).loadClass(mainClass) - .getMethod("main", Array::class.java).invoke(null, *arrayOf(al.toTypedArray())) - null - }) - return true - } - } - return false - } - - override fun parseArguments(nowVersion: VersionNumber, args: Array) { - val f = AppDataUpgraderPackGzTask.HMCL_VER_FILE - if (!args.contains("--noupdate")) - try { - if (f.exists()) { - val m = GSON.fromJson(f.readText(), Map::class.java) - val s = m["ver"] as? String? - if (s != null && VersionNumber.asVersion(s.toString()) > nowVersion) { - val j = m["loc"] as? String? - if (j != null) { - val jar = File(j) - if (jar.exists() && launchNewerVersion(args, jar)) - System.exit(0) - } - } - } - } catch (ex: JsonSyntaxException) { - f.delete() - } catch (t: IOException) { - LOG.log(Level.SEVERE, "Failed to execute newer version application", t) - } catch (t: PrivilegedActionException) { - LOG.log(Level.SEVERE, "Failed to execute newer version application", t) - } - - } - - override fun download(checker: UpdateChecker, versionNumber: VersionNumber) { - val version = versionNumber as IntVersionNumber - checker.requestDownloadLink().then { - val map: Map? = it["update_checker.request_download_link"] - if (alert(Alert.AlertType.CONFIRMATION, "Alert", i18n("update.newest_version") + version[0] + "." + version[1] + "." + version[2] + "\n" - + i18n("update.should_open_link"))) - if (map != null && map.containsKey("jar") && map["jar"]!!.isNotBlank()) - try { - var hash: String? = null - if (map.containsKey("jarsha1")) - hash = map.get("jarsha1") - if (AppDataUpgraderJarTask(map["jar"]!!, version.toString(), hash!!).test()) { - ProcessBuilder(JavaVersion.fromCurrentEnvironment().binary.absolutePath, "-jar", AppDataUpgraderJarTask.getSelf(version.toString()).absolutePath).directory(File("").absoluteFile).start() - System.exit(0) - } - } catch (ex: IOException) { - LOG.log(Level.SEVERE, "Failed to create upgrader", ex) - } - else if (map != null && map.containsKey("pack") && map["pack"]!!.isNotBlank()) - try { - var hash: String? = null - if (map.containsKey("packsha1")) - hash = map["packsha1"] - if (AppDataUpgraderPackGzTask(map["pack"]!!, version.toString(), hash!!).test()) { - ProcessBuilder(JavaVersion.fromCurrentEnvironment().binary.absolutePath, "-jar", AppDataUpgraderPackGzTask.getSelf(version.toString()).absolutePath).directory(File("").absoluteFile).start() - System.exit(0) - } - } catch (ex: IOException) { - LOG.log(Level.SEVERE, "Failed to create upgrader", ex) - } - else { - var url = URL_PUBLISH - if (map != null) - if (map.containsKey(OperatingSystem.CURRENT_OS.checkedName)) - url = map.get(OperatingSystem.CURRENT_OS.checkedName)!! - else if (map.containsKey(OperatingSystem.UNKNOWN.checkedName)) - url = map.get(OperatingSystem.UNKNOWN.checkedName)!! - try { - java.awt.Desktop.getDesktop().browse(URI(url)) - } catch (e: URISyntaxException) { - LOG.log(Level.SEVERE, "Failed to browse uri: " + url, e) - OperatingSystem.setClipboard(url) - } catch (e: IOException) { - LOG.log(Level.SEVERE, "Failed to browse uri: " + url, e) - OperatingSystem.setClipboard(url) - } - - } - null - }.execute() - } - - class AppDataUpgraderPackGzTask(downloadLink: String, private val newestVersion: String, private val expectedHash: String) : Task() { - private val tempFile: File = File.createTempFile("hmcl", ".pack.gz") - private val dependents = listOf(FileDownloadTask(downloadLink.toURL(), tempFile, Proxy.NO_PROXY, expectedHash)) - override fun getDependents() = dependents - - init { - onDone() += { event -> if (event.isFailed) tempFile.delete() } - } - - override fun execute() { - val json = HashMap() - var f = getSelf(newestVersion) - if (!FileUtils.makeDirectory(f.parentFile)) - throw IOException("Failed to make directories: " + f.parent) - - var i = 0 - while (f.exists()) { - f = File(BASE_FOLDER, "HMCL-" + newestVersion + (if (i > 0) "-" + i else "") + ".jar") - i++ - } - if (!f.createNewFile()) - throw IOException("Failed to create new file: " + f) - - JarOutputStream(f.outputStream()).use { jos -> Pack200.newUnpacker().unpack(GZIPInputStream(tempFile.inputStream()), jos) } - json.put("ver", newestVersion) - json.put("loc", f.absolutePath) - val result = GSON.toJson(json) - HMCL_VER_FILE.writeText(result) - } - - val info: String - get() = "Upgrade" - - companion object { - - val BASE_FOLDER = Main.getWorkingDirectory("hmcl") - val HMCL_VER_FILE = File(BASE_FOLDER, "hmclver.json") - - fun getSelf(ver: String): File { - return File(BASE_FOLDER, "HMCL-$ver.jar") - } - } - - } - - class AppDataUpgraderJarTask(downloadLink: String, private val newestVersion: String, expectedHash: String) : Task() { - private val tempFile = File.createTempFile("hmcl", ".jar") - - init { - name = "Upgrade" - onDone() += { event -> if (event.isFailed) tempFile.delete() } - } - - private val dependents = listOf(FileDownloadTask(downloadLink.toURL(), tempFile, Proxy.NO_PROXY, expectedHash)) - override fun getDependents() = dependents - - override fun execute() { - val json = HashMap() - val f = getSelf(newestVersion) - tempFile.copyTo(f) - json.put("ver", newestVersion) - json.put("loc", f.absolutePath) - val result = GSON.toJson(json) - HMCL_VER_FILE.writeText(result) - } - - companion object { - val BASE_FOLDER = Main.getWorkingDirectory("hmcl") - val HMCL_VER_FILE = File(BASE_FOLDER, "hmclver.json") - - fun getSelf(ver: String): File { - return File(BASE_FOLDER, "HMCL-$ver.jar") - } - } - - } - - companion object { - const val URL_PUBLISH = "http://www.mcbbs.net/thread-142335-1-1.html" - } -} \ No newline at end of file diff --git a/HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/UpdateChecker.kt b/HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/UpdateChecker.kt deleted file mode 100644 index 961bd1092..000000000 --- a/HMCL/src/main/kotlin/org/jackhuang/hmcl/upgrade/UpdateChecker.kt +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2017 huangyuhui - * - * 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 {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hmcl.upgrade - -import java.io.IOException -import com.google.gson.JsonSyntaxException -import org.jackhuang.hmcl.task.TaskResult -import org.jackhuang.hmcl.util.* -import org.jackhuang.hmcl.util.Constants.GSON -import org.jackhuang.hmcl.util.Logging.LOG -import java.util.logging.Level - - -/** - * - * @author huangyuhui - */ -class UpdateChecker(var base: VersionNumber, var type: String) { - - @Volatile - var isOutOfDate = false - private set - var versionString: String? = null - private var download_link: Map? = null - - /** - * Get the cached newest version number, use "process" method to - * download! - * - * @return the newest version number - * - * @see process - */ - var newVersion: VersionNumber? = null - internal set - - /** - * Download the version number synchronously. When you execute this method - * first, should leave "showMessage" false. - * - * @param showMessage If it is requested to warn the user that there is a - * new version. - * - * @return the process observable. - */ - fun process(showMessage: Boolean): TaskResult { - return object : TaskResult() { - override fun getId() = "update_checker.process" - override fun execute() { - if (newVersion == null) { - versionString = NetworkUtils.doGet("http://huangyuhui.duapp.com/info.php?type=$type".toURL()) - newVersion = VersionNumber.asVersion(versionString!!) - } - - if (newVersion == null) { - LOG.warning("Failed to check update...") - } else if (base < newVersion!!) - isOutOfDate = true - if (isOutOfDate) - result = newVersion - } - } - } - - /** - * Get the download links. - * - * @return a JSON, which contains the server response. - */ - @Synchronized - fun requestDownloadLink(): TaskResult> { - return object : TaskResult>() { - override fun getId() = "update_checker.request_download_link" - override fun execute() { - @Suppress("UNCHECKED_CAST") - if (download_link == null) - try { - download_link = GSON.fromJson(NetworkUtils.doGet("http://huangyuhui.duapp.com/update_link.php?type=$type".toURL()), Map::class.java) as Map - } catch (e: JsonSyntaxException) { - LOG.log(Level.WARNING, "Failed to get update link.", e) - } catch (e: IOException) { - LOG.log(Level.WARNING, "Failed to get update link.", e) - } - - result = download_link - } - } - } -/* - val upgrade: EventHandler> = EventHandler() - - fun checkOutdate() { - if (isOutOfDate) - if (EVENT_BUS.fireChannelResulted(OutOfDateEvent(this, newVersion))) - upgrade.fire(SimpleEvent(this, newVersion)) - }*/ -} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java index 257912949..1b875c661 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/Task.java @@ -108,14 +108,14 @@ public abstract class Task { * The collection of sub-tasks that should execute **before** this task running. */ public Collection getDependents() { - return Collections.EMPTY_SET; + return Collections.emptySet(); } /** * The collection of sub-tasks that should execute **after** this task running. */ public Collection getDependencies() { - return Collections.EMPTY_SET; + return Collections.emptySet(); } public EventManager onDone() { @@ -180,8 +180,6 @@ public abstract class Task { progressProperty.unbind(); } - ; - public final TaskExecutor executor() { return new TaskExecutor(this); }