Build configuration DFU system. (#2589)

* Build configuration DFU system.

* Remove redundant object allocation.

* Fix

* Code cleanup

* Remove unnecessary GSON usage.

* Fix compiletime unchecked warning.
This commit is contained in:
Burning_TNT
2024-01-08 20:39:55 +08:00
committed by GitHub
parent 5d3660ffb8
commit 4e22585faf
2 changed files with 88 additions and 69 deletions

View File

@@ -17,7 +17,6 @@
*/ */
package org.jackhuang.hmcl.setting; package org.jackhuang.hmcl.setting;
import com.google.gson.Gson;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.util.InvocationDispatcher; import org.jackhuang.hmcl.util.InvocationDispatcher;
@@ -28,7 +27,6 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.IOException; import java.io.IOException;
import java.nio.file.*; import java.nio.file.*;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG; import static org.jackhuang.hmcl.util.Logging.LOG;
@@ -167,8 +165,7 @@ public final class ConfigHolder {
if (deserialized == null) { if (deserialized == null) {
LOG.info("Config is empty"); LOG.info("Config is empty");
} else { } else {
Map<?, ?> raw = new Gson().fromJson(content, Map.class); ConfigUpgrader.upgradeConfig(deserialized, content);
ConfigUpgrader.upgradeConfig(deserialized, raw);
return deserialized; return deserialized;
} }
} catch (JsonParseException e) { } catch (JsonParseException e) {

View File

@@ -17,49 +17,70 @@
*/ */
package org.jackhuang.hmcl.setting; package org.jackhuang.hmcl.setting;
import com.google.gson.Gson;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.BiConsumer;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.Logging.LOG;
final class ConfigUpgrader { final class ConfigUpgrader {
private static final int VERSION = 0;
private ConfigUpgrader() { private ConfigUpgrader() {
} }
private static final int CURRENT_VERSION = 1;
/** /**
* This method is for the compatibility with old HMCL 3.x as well as HMCL 2.x. * This method is for the compatibility with old HMCL versions.
* *
* @param deserialized deserialized config settings * @param deserialized deserialized config settings
* @param rawJson raw json structure of the config settings without modification * @param rawContent raw json content of the config settings without modification
* @return true if config version is upgraded
*/ */
static boolean upgradeConfig(Config deserialized, Map<?, ?> rawJson) { static void upgradeConfig(Config deserialized, String rawContent) {
boolean upgraded; if (deserialized.getConfigVersion() == CURRENT_VERSION) {
if (deserialized.getConfigVersion() < VERSION) { return;
deserialized.setConfigVersion(VERSION);
// TODO: Add upgrade code here.
upgraded = true;
} else {
upgraded = false;
} }
upgradeV2(deserialized, rawJson); int configVersion = deserialized.getConfigVersion();
upgradeV3(deserialized, rawJson); if (configVersion > CURRENT_VERSION) {
LOG.log(Level.WARNING, String.format("Current HMCL only support the configuration version up to %d. However, the version now is %d.", CURRENT_VERSION, configVersion));
return;
}
return upgraded; LOG.log(Level.INFO, String.format("Updating configuration from %d to %d.", configVersion, CURRENT_VERSION));
Map<?, ?> unmodifiableRawJson = Collections.unmodifiableMap(new Gson().<Map<?, ?>>fromJson(rawContent, Map.class));
for (Map.Entry<Integer, BiConsumer<Config, Map<?, ?>>> dfu : collectDFU()) {
if (configVersion < dfu.getKey()) {
dfu.getValue().accept(deserialized, unmodifiableRawJson);
configVersion = dfu.getKey();
}
}
deserialized.setConfigVersion(CURRENT_VERSION);
} }
/** /**
* Upgrade configuration of HMCL 2.x * <p>Initialize the dfu of HMCL. Feel free to use lambda as all the lambda here would not be initialized unless HMCL needs to update the configuration.
* For each item in this list, it should be a Map.Entry.</p>
* *
* @param deserialized deserialized config settings * <p>The key should be a version number. All the configuration with a version number which is less than the specific one will be applied to this upgrader.</p>
* @param rawJson raw json structure of the config settings without modification * <p>The value should be the upgrader. The configuration which is waited to being processed, and the raw unmodifiable value of the json from the configuration file.</p>
* <p>The return value should a target version number of this item.</p>
*
* <p>The last item must return CURRENT_VERSION, as the config file should always being updated to the latest version.</p>
*/ */
private static void upgradeV2(Config deserialized, Map<?, ?> rawJson) { private static List<Map.Entry<Integer, BiConsumer<Config, Map<?, ?>>>> collectDFU() {
// Convert OfflineAccounts whose stored uuid is important. List<Map.Entry<Integer, BiConsumer<Config, Map<?, ?>>>> dfu = Lang.immutableListOf(
Pair.pair(1, (deserialized, rawJson) -> {
// Upgrade configuration of HMCL 2.x: Convert OfflineAccounts whose stored uuid is important.
tryCast(rawJson.get("auth"), Map.class).ifPresent(auth -> { tryCast(rawJson.get("auth"), Map.class).ifPresent(auth -> {
tryCast(auth.get("offline"), Map.class).ifPresent(offline -> { tryCast(auth.get("offline"), Map.class).ifPresent(offline -> {
String selected = rawJson.containsKey("selectedAccount") ? null String selected = rawJson.containsKey("selectedAccount") ? null
@@ -79,15 +100,8 @@ final class ConfigUpgrader {
}); });
}); });
}); });
}
/** // Upgrade configuration of HMCL earlier than 3.1.70
* Upgrade configuration of HMCL earlier than 3.1.70
*
* @param deserialized deserialized config settings
* @param rawJson raw json structure of the config settings without modification
*/
private static void upgradeV3(Config deserialized, Map<?, ?> rawJson) {
if (!rawJson.containsKey("commonDirType")) if (!rawJson.containsKey("commonDirType"))
deserialized.setCommonDirType(deserialized.getCommonDirectory().equals(Settings.getDefaultCommonDirectory()) ? EnumCommonDirectory.DEFAULT : EnumCommonDirectory.CUSTOM); deserialized.setCommonDirType(deserialized.getCommonDirectory().equals(Settings.getDefaultCommonDirectory()) ? EnumCommonDirectory.DEFAULT : EnumCommonDirectory.CUSTOM);
if (!rawJson.containsKey("backgroundType")) if (!rawJson.containsKey("backgroundType"))
@@ -108,5 +122,13 @@ final class ConfigUpgrader {
} }
}); });
} }
})
);
if (dfu.get(dfu.size() - 1).getKey() != CURRENT_VERSION) {
throw new IllegalStateException("The last dfu must adapt all the config version below CURRENT_VERSION");
}
return dfu;
} }
} }