Remove UpdateChecker.updateChannel & Fix concurrent problems in update checking
This commit is contained in:
@@ -17,23 +17,19 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
|
||||
import com.jfoenix.concurrency.JFXUtilities;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import org.jackhuang.hmcl.setting.ConfigHolder;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.ui.Controllers;
|
||||
import org.jackhuang.hmcl.upgrade.UpdateChecker;
|
||||
import org.jackhuang.hmcl.util.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
@@ -42,7 +38,6 @@ import java.nio.file.Paths;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public final class Launcher extends Application {
|
||||
|
||||
@@ -58,24 +53,7 @@ public final class Launcher extends Application {
|
||||
primaryStage.setResizable(false);
|
||||
primaryStage.setScene(Controllers.getScene());
|
||||
|
||||
UpdateChecker.updateChannelProperty().addListener(observable -> {
|
||||
thread(() -> {
|
||||
try {
|
||||
UpdateChecker.checkUpdate();
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to check for update", e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
UpdateChecker.updateChannelProperty().bind(Bindings.createStringBinding(() -> {
|
||||
switch (ConfigHolder.config().getUpdateChannel()) {
|
||||
case DEVELOPMENT:
|
||||
return UpdateChecker.CHANNEL_DEV;
|
||||
default:
|
||||
return UpdateChecker.CHANNEL_STABLE;
|
||||
}
|
||||
}, ConfigHolder.config().updateChannelProperty()));
|
||||
UpdateChecker.init();
|
||||
|
||||
primaryStage.show();
|
||||
} catch (Throwable e) {
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.hildan.fxgson.creators.ObservableSetCreator;
|
||||
import org.hildan.fxgson.factories.JavaFxPropertyTypeAdapterFactory;
|
||||
import org.jackhuang.hmcl.Launcher;
|
||||
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
|
||||
import org.jackhuang.hmcl.upgrade.UpdateChannel;
|
||||
import org.jackhuang.hmcl.util.EnumOrdinalDeserializer;
|
||||
import org.jackhuang.hmcl.util.FileTypeAdapter;
|
||||
import org.jackhuang.hmcl.util.ObservableHelper;
|
||||
@@ -150,7 +151,7 @@ public final class Config implements Cloneable, Observable {
|
||||
private ObservableList<AuthlibInjectorServer> authlibInjectorServers = FXCollections.observableArrayList();
|
||||
|
||||
@SerializedName("updateChannel")
|
||||
private ObjectProperty<EnumUpdateChannel> updateChannel = new SimpleObjectProperty<>(EnumUpdateChannel.STABLE);
|
||||
private ObjectProperty<UpdateChannel> updateChannel = new SimpleObjectProperty<>(UpdateChannel.STABLE);
|
||||
|
||||
@SerializedName("_version")
|
||||
private IntegerProperty configVersion = new SimpleIntegerProperty(0);
|
||||
@@ -438,15 +439,15 @@ public final class Config implements Cloneable, Observable {
|
||||
return authlibInjectorServers;
|
||||
}
|
||||
|
||||
public EnumUpdateChannel getUpdateChannel() {
|
||||
public UpdateChannel getUpdateChannel() {
|
||||
return updateChannel.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<EnumUpdateChannel> updateChannelProperty() {
|
||||
public ObjectProperty<UpdateChannel> updateChannelProperty() {
|
||||
return updateChannel;
|
||||
}
|
||||
|
||||
public void setUpdateChannel(EnumUpdateChannel updateChannel) {
|
||||
public void setUpdateChannel(UpdateChannel updateChannel) {
|
||||
this.updateChannel.set(updateChannel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import org.jackhuang.hmcl.ui.construct.FontComboBox;
|
||||
import org.jackhuang.hmcl.ui.construct.MultiFileItem;
|
||||
import org.jackhuang.hmcl.ui.construct.Validator;
|
||||
import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
|
||||
import org.jackhuang.hmcl.upgrade.UpdateChannel;
|
||||
import org.jackhuang.hmcl.upgrade.RemoteVersion;
|
||||
import org.jackhuang.hmcl.upgrade.UpdateChecker;
|
||||
import org.jackhuang.hmcl.upgrade.UpdateHandler;
|
||||
@@ -242,24 +243,24 @@ public final class SettingsPage extends StackPane implements DecoratorPage {
|
||||
|
||||
lblUpdateNote.setWrappingWidth(470);
|
||||
|
||||
ObjectProperty<EnumUpdateChannel> updateChannel = new SimpleObjectProperty<EnumUpdateChannel>() {
|
||||
ObjectProperty<UpdateChannel> updateChannel = new SimpleObjectProperty<UpdateChannel>() {
|
||||
@Override
|
||||
protected void invalidated() {
|
||||
EnumUpdateChannel updateChannel = Objects.requireNonNull(get());
|
||||
chkUpdateDev.setSelected(updateChannel == EnumUpdateChannel.DEVELOPMENT);
|
||||
chkUpdateStable.setSelected(updateChannel == EnumUpdateChannel.STABLE);
|
||||
UpdateChannel updateChannel = Objects.requireNonNull(get());
|
||||
chkUpdateDev.setSelected(updateChannel == UpdateChannel.DEVELOPMENT);
|
||||
chkUpdateStable.setSelected(updateChannel == UpdateChannel.STABLE);
|
||||
}
|
||||
};
|
||||
|
||||
ToggleGroup updateChannelGroup = new ToggleGroup();
|
||||
chkUpdateDev.setToggleGroup(updateChannelGroup);
|
||||
chkUpdateDev.setUserData(EnumUpdateChannel.DEVELOPMENT);
|
||||
chkUpdateDev.setUserData(UpdateChannel.DEVELOPMENT);
|
||||
chkUpdateStable.setToggleGroup(updateChannelGroup);
|
||||
chkUpdateStable.setUserData(EnumUpdateChannel.STABLE);
|
||||
chkUpdateStable.setUserData(UpdateChannel.STABLE);
|
||||
updateChannelGroup.getToggles().forEach(
|
||||
toggle -> toggle.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
updateChannel.set((EnumUpdateChannel) toggle.getUserData());
|
||||
updateChannel.set((UpdateChannel) toggle.getUserData());
|
||||
}
|
||||
}));
|
||||
updateChannel.bindBidirectional(ConfigHolder.config().updateChannelProperty());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
* Copyright (C) 2018 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* 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
|
||||
@@ -15,9 +15,15 @@
|
||||
* 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.upgrade;
|
||||
|
||||
public enum EnumUpdateChannel {
|
||||
STABLE,
|
||||
DEVELOPMENT
|
||||
public enum UpdateChannel {
|
||||
STABLE("stable"),
|
||||
DEVELOPMENT("dev");
|
||||
|
||||
public final String channelName;
|
||||
|
||||
UpdateChannel(String channelName) {
|
||||
this.channelName = channelName;
|
||||
}
|
||||
}
|
||||
@@ -17,16 +17,20 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.upgrade;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
|
||||
import static org.jackhuang.hmcl.util.Lang.mapOf;
|
||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||
import static org.jackhuang.hmcl.util.VersionNumber.asVersion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.jfoenix.concurrency.JFXUtilities;
|
||||
import javafx.beans.property.*;
|
||||
import org.jackhuang.hmcl.Metadata;
|
||||
import org.jackhuang.hmcl.util.ImmediateStringProperty;
|
||||
import org.jackhuang.hmcl.setting.ConfigHolder;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
import javafx.application.Platform;
|
||||
@@ -37,11 +41,6 @@ import javafx.beans.value.ObservableBooleanValue;
|
||||
public final class UpdateChecker {
|
||||
private UpdateChecker() {}
|
||||
|
||||
public static final String CHANNEL_STABLE = "stable";
|
||||
public static final String CHANNEL_DEV = "dev";
|
||||
|
||||
private static StringProperty updateChannel = new ImmediateStringProperty(null, "updateChannel", CHANNEL_STABLE);
|
||||
|
||||
private static ObjectProperty<RemoteVersion> latestVersion = new SimpleObjectProperty<>();
|
||||
private static BooleanBinding outdated = Bindings.createBooleanBinding(
|
||||
() -> {
|
||||
@@ -55,16 +54,9 @@ public final class UpdateChecker {
|
||||
latestVersion);
|
||||
private static ReadOnlyBooleanWrapper checkingUpdate = new ReadOnlyBooleanWrapper(false);
|
||||
|
||||
public static String getUpdateChannel() {
|
||||
return updateChannel.get();
|
||||
}
|
||||
|
||||
public static void setUpdateChannel(String updateChannel) {
|
||||
UpdateChecker.updateChannel.set(updateChannel);
|
||||
}
|
||||
|
||||
public static StringProperty updateChannelProperty() {
|
||||
return updateChannel;
|
||||
public static void init() {
|
||||
ConfigHolder.config().updateChannelProperty().addListener(onInvalidating(UpdateChecker::requestCheckUpdate));
|
||||
requestCheckUpdate();
|
||||
}
|
||||
|
||||
public static RemoteVersion getLatestVersion() {
|
||||
@@ -91,35 +83,53 @@ public final class UpdateChecker {
|
||||
return checkingUpdate.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
public static void checkUpdate() throws IOException {
|
||||
private static RemoteVersion checkUpdate(UpdateChannel channel) throws IOException {
|
||||
if (!IntegrityChecker.isSelfVerified()) {
|
||||
return;
|
||||
throw new IOException("Self verification failed");
|
||||
}
|
||||
|
||||
JFXUtilities.runInFXAndWait(() -> {
|
||||
checkingUpdate.set(true);
|
||||
});
|
||||
String url = NetworkUtils.withQuery(Metadata.UPDATE_URL, mapOf(
|
||||
pair("version", Metadata.VERSION),
|
||||
pair("channel", channel.channelName)));
|
||||
|
||||
try {
|
||||
|
||||
String channel = getUpdateChannel();
|
||||
String url = NetworkUtils.withQuery(Metadata.UPDATE_URL, mapOf(
|
||||
pair("version", Metadata.VERSION),
|
||||
pair("channel", channel)));
|
||||
|
||||
RemoteVersion fetched = RemoteVersion.fetch(url);
|
||||
Platform.runLater(() -> {
|
||||
if (channel.equals(getUpdateChannel())) {
|
||||
latestVersion.set(fetched);
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
Platform.runLater(() -> checkingUpdate.set(false));
|
||||
}
|
||||
return RemoteVersion.fetch(url);
|
||||
}
|
||||
|
||||
private static boolean isDevelopmentVersion(String version) {
|
||||
return version.contains("@") || // eg. @develop@
|
||||
version.contains("SNAPSHOT"); // eg. 3.1.SNAPSHOT
|
||||
}
|
||||
|
||||
public static void requestCheckUpdate() {
|
||||
Platform.runLater(() -> {
|
||||
if (isCheckingUpdate())
|
||||
return;
|
||||
checkingUpdate.set(true);
|
||||
UpdateChannel channel = config().getUpdateChannel();
|
||||
|
||||
thread(() -> {
|
||||
RemoteVersion result = null;
|
||||
try {
|
||||
result = checkUpdate(channel);
|
||||
LOG.info("Latest version (" + channel + ") is " + result);
|
||||
} catch (IOException e) {
|
||||
LOG.log(Level.WARNING, "Failed to check for update", e);
|
||||
}
|
||||
|
||||
RemoteVersion finalResult = result;
|
||||
Platform.runLater(() -> {
|
||||
checkingUpdate.set(false);
|
||||
if (finalResult != null) {
|
||||
if (channel.equals(config().getUpdateChannel())) {
|
||||
latestVersion.set(finalResult);
|
||||
} else {
|
||||
// the channel has been changed during the period
|
||||
// check update again
|
||||
requestCheckUpdate();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user