From 22732fee6a32d3f51f3d6fdebdc284bf5968fe28 Mon Sep 17 00:00:00 2001 From: yushijinhun Date: Sat, 16 Jun 2018 19:15:16 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AD=98=E5=82=A8AuthlibInjectorServerInfo?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E8=80=8C=E4=B8=8D=E6=98=AFurl=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/jackhuang/hmcl/setting/Config.java | 7 +- .../org/jackhuang/hmcl/setting/Settings.java | 73 +++++++++++++------ .../org/jackhuang/hmcl/ui/AddAccountPane.java | 30 ++------ .../hmcl/ui/AuthlibInjectorServersPage.java | 36 ++++----- .../java/org/jackhuang/hmcl/ui/FXUtils.java | 5 ++ .../AuthlibInjectorServerInfo.java | 15 ++++ 6 files changed, 95 insertions(+), 71 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java index 744815f7a..3673fb9ea 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java @@ -17,11 +17,12 @@ */ package org.jackhuang.hmcl.setting; -import java.util.HashSet; import java.util.Map; import java.util.TreeMap; import org.jackhuang.hmcl.Launcher; +import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServerInfo; + import com.google.gson.annotations.SerializedName; import javafx.beans.property.BooleanProperty; @@ -35,7 +36,6 @@ import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; -import javafx.collections.ObservableSet; public final class Config implements Cloneable { @@ -99,8 +99,7 @@ public final class Config implements Cloneable { @SerializedName("logLines") public final IntegerProperty logLines = new SimpleIntegerProperty(100); - @SerializedName("authlibInjectorServerURLs") - public final ObservableSet authlibInjectorServerURLs = FXCollections.observableSet(new HashSet<>()); + public final ObservableList authlibInjectorServers = FXCollections.observableArrayList(); @Override public Config clone() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java index 0f666bcae..51fa60681 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.setting; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + import javafx.beans.property.ObjectProperty; import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; @@ -35,6 +36,7 @@ import org.jackhuang.hmcl.Launcher; import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.auth.AccountFactory; import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorAccount; +import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServerInfo; import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.event.*; import org.jackhuang.hmcl.task.Schedulers; @@ -51,6 +53,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.stream.Collectors; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; +import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating; import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.Logging.LOG; @@ -71,7 +76,8 @@ public class Settings { public static final Settings INSTANCE = new Settings(); - private final Config SETTINGS = initSettings(); + // TODO: another way to access this property aside from Settings.INSTANCE.SETTINGS + public final Config SETTINGS = initSettings(); private final Map accounts = new ConcurrentHashMap<>(); @@ -99,7 +105,10 @@ public class Settings { accounts.put(Accounts.getAccountId(account), account); } - checkAuthlibInjectorAccounts(); + migrateAuthlibInjectorServers(); + + SETTINGS.authlibInjectorServers.addListener(onInvalidating(this::removeDanglingAuthlibInjectorAccounts)); + checkProfileMap(); save(); @@ -303,30 +312,50 @@ public class Settings { * AUTHLIB INJECTORS * ****************************************/ - public Set getAuthlibInjectorServerURLs() { - return SETTINGS.authlibInjectorServerURLs; + private Set getAuthlibInjectorServerUrls() { + return SETTINGS.authlibInjectorServers.stream() + .map(AuthlibInjectorServerInfo::getServerIp) + .collect(toSet()); } - public void removeAuthlibInjectorServerURL(String serverURL) { - SETTINGS.authlibInjectorServerURLs.remove(serverURL); - - checkAuthlibInjectorAccounts(); - save(); + /** + * The {@code serverBaseURL} specified in {@link AuthlibInjectorAccount} may not have an associated + * {@link AuthlibInjectorServerInfo} in {@link Config#authlibInjectorServers}, + * which usually happens when migrating data from an older version. + * This method adds the missing servers to {@link Config#authlibInjectorServers}. + */ + private void migrateAuthlibInjectorServers() { + Set existentServerUrls = getAuthlibInjectorServerUrls(); + accounts.values().stream() + .filter(AuthlibInjectorAccount.class::isInstance) + .map(it -> ((AuthlibInjectorAccount) it).getServerBaseURL()) + .distinct() + .filter(it -> !existentServerUrls.contains(it)) + .forEach(url -> { + String serverName; + try { + serverName = Accounts.getAuthlibInjectorServerName(url); + Logging.LOG.info("Migrated authlib injector server [" + url + "], name=[" + serverName + "]"); + } catch (Exception e) { + serverName = url; + Logging.LOG.log(Level.WARNING, "Failed to migrate authlib injector server [" + url + "]", e); + } + SETTINGS.authlibInjectorServers.add(new AuthlibInjectorServerInfo(url, serverName)); + }); } - public void addAuthlibInjectorServerURL(String serverURL) { - SETTINGS.authlibInjectorServerURLs.add(serverURL); - save(); - } - - private void checkAuthlibInjectorAccounts() { - for (Account account : getAccounts()) { - if (account instanceof AuthlibInjectorAccount) { - AuthlibInjectorAccount injectorAccount = (AuthlibInjectorAccount) account; - if (!SETTINGS.authlibInjectorServerURLs.contains(injectorAccount.getServerBaseURL())) - deleteAccount(account); - } - } + /** + * After an {@link AuthlibInjectorServerInfo} is removed, the associated accounts should also be removed. + * This method performs a check and removes the dangling accounts. + * Don't call this before {@link #migrateAuthlibInjectorServers()} is called, otherwise old data would be lost. + */ + private void removeDanglingAuthlibInjectorAccounts() { + Set currentServerUrls = getAuthlibInjectorServerUrls(); + accounts.values().stream() + .filter(AuthlibInjectorAccount.class::isInstance) + .filter(it -> !currentServerUrls.contains(((AuthlibInjectorAccount) it).getServerBaseURL())) + .collect(toList()) + .forEach(this::deleteAccount); } /**************************************** diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAccountPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAccountPane.java index 49cbfb7d0..df51d7378 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAccountPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AddAccountPane.java @@ -49,14 +49,13 @@ import org.jackhuang.hmcl.ui.construct.Validator; import org.jackhuang.hmcl.util.Constants; import org.jackhuang.hmcl.util.Logging; -import java.util.Collection; +import static java.util.stream.Collectors.toList; + import java.util.List; import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; import java.util.logging.Level; -import java.util.stream.Collectors; -import java.util.stream.Stream; public class AddAccountPane extends StackPane { @@ -96,10 +95,6 @@ public class AddAccountPane extends StackPane { }); cboType.getSelectionModel().select(0); - // These two lines can eliminate black, don't know why. - cboServers.getItems().setAll(new TwoLineListItem("", "")); - cboServers.getSelectionModel().select(0); - txtPassword.setOnAction(e -> onCreationAccept()); txtUsername.setOnAction(e -> onCreationAccept()); txtUsername.getValidators().add(new Validator(Launcher.i18n("input.email"), str -> !txtPassword.isVisible() || str.contains("@"))); @@ -113,21 +108,12 @@ public class AddAccountPane extends StackPane { } private void loadServers() { - Task.ofResult("list", () -> Settings.INSTANCE.getAuthlibInjectorServerURLs().parallelStream() - .flatMap(serverURL -> { - try { - return Stream.of(new TwoLineListItem(Accounts.getAuthlibInjectorServerName(serverURL), serverURL)); - } catch (Exception e) { - Logging.LOG.log(Level.WARNING, "Authlib-injector server root " + serverURL + " cannot be recognized.", e); - return Stream.empty(); - } - }) - .collect(Collectors.toList())) - .subscribe(Task.of(Schedulers.javafx(), variables -> { - cboServers.getItems().setAll(variables.>get("list")); - if (!cboServers.getItems().isEmpty()) - cboServers.getSelectionModel().select(0); - })); + cboServers.getItems().setAll( + Settings.INSTANCE.SETTINGS.authlibInjectorServers.stream() + .map(server -> new TwoLineListItem(server.getServerName(), server.getServerIp())) + .collect(toList())); + if (!cboServers.getItems().isEmpty()) + cboServers.getSelectionModel().select(0); } private void showSpinner() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AuthlibInjectorServersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AuthlibInjectorServersPage.java index 259635755..efd058f27 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AuthlibInjectorServersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AuthlibInjectorServersPage.java @@ -4,7 +4,6 @@ import com.jfoenix.controls.*; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.fxml.FXML; -import javafx.scene.Node; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.layout.StackPane; @@ -18,13 +17,9 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.ui.animation.ContainerAnimations; import org.jackhuang.hmcl.ui.animation.TransitionHandler; import org.jackhuang.hmcl.ui.wizard.DecoratorPage; -import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.NetworkUtils; -import java.util.Collection; -import java.util.logging.Level; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import static java.util.stream.Collectors.toList; public class AuthlibInjectorServersPage extends StackPane implements DecoratorPage { private final StringProperty title = new SimpleStringProperty(this, "title", Launcher.i18n("account.injector.server")); @@ -64,7 +59,7 @@ public class AuthlibInjectorServersPage extends StackPane implements DecoratorPa } private void removeServer(AuthlibInjectorServerItem item) { - Settings.INSTANCE.removeAuthlibInjectorServerURL(item.getInfo().getServerIp()); + Settings.INSTANCE.SETTINGS.authlibInjectorServers.remove(item.getInfo()); loading(); } @@ -72,27 +67,20 @@ public class AuthlibInjectorServersPage extends StackPane implements DecoratorPa getChildren().remove(contentPane); spinner.setVisible(true); - Task.ofResult("list", () -> Settings.INSTANCE.getAuthlibInjectorServerURLs().parallelStream() - .flatMap(serverURL -> { - try { - return Stream.of(new AuthlibInjectorServerItem(new AuthlibInjectorServerInfo(serverURL, Accounts.getAuthlibInjectorServerName(serverURL)), this::removeServer)); - } catch (Exception e) { - Logging.LOG.log(Level.WARNING, "Authlib-injector server root " + serverURL + " cannot be recognized.", e); - return Stream.empty(); - } - }) - .collect(Collectors.toList())) - .subscribe(Task.of(Schedulers.javafx(), variables -> { - listPane.getChildren().setAll(variables.>get("list")); - loadingCompleted(); - })); + listPane.getChildren().setAll( + Settings.INSTANCE.SETTINGS.authlibInjectorServers.stream() + .map(server -> new AuthlibInjectorServerItem(server, this::removeServer)) + .collect(toList())); + + // TODO: remove spinner + loadingCompleted(); } private void loadingCompleted() { getChildren().add(contentPane); spinner.setVisible(false); - if (Settings.INSTANCE.getAuthlibInjectorServerURLs().isEmpty()) + if (Settings.INSTANCE.SETTINGS.authlibInjectorServers.isEmpty()) onAdd(); } @@ -144,7 +132,9 @@ public class AuthlibInjectorServersPage extends StackPane implements DecoratorPa @FXML private void onAddFinish() { - Settings.INSTANCE.addAuthlibInjectorServerURL(serverBeingAdded.getServerIp()); + if (!Settings.INSTANCE.SETTINGS.authlibInjectorServers.contains(serverBeingAdded)) { + Settings.INSTANCE.SETTINGS.authlibInjectorServers.add(serverBeingAdded); + } loading(); dialog.close(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index ef5b377af..c5acdeaaa 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -23,6 +23,7 @@ import javafx.animation.Interpolator; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.application.Platform; +import javafx.beans.InvalidationListener; import javafx.beans.property.Property; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; @@ -67,6 +68,10 @@ public final class FXUtils { } } + public static InvalidationListener onInvalidating(Runnable action) { + return arg -> action.run(); + } + public static void onChange(ObservableValue value, Consumer consumer) { value.addListener((a, b, c) -> consumer.accept(c)); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorServerInfo.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorServerInfo.java index 41b5f7dcb..369fc6f35 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorServerInfo.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorServerInfo.java @@ -33,4 +33,19 @@ public class AuthlibInjectorServerInfo { public String getServerName() { return serverName; } + + @Override + public int hashCode() { + return serverIp.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (!(obj instanceof AuthlibInjectorServerInfo)) + return false; + AuthlibInjectorServerInfo another = (AuthlibInjectorServerInfo) obj; + return this.serverIp.equals(another.serverIp); + } }