From 440e20f5eac8480b42f1cc00129ac9f190d83ce6 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Fri, 11 Mar 2022 23:35:59 +0100 Subject: [PATCH] Switched to ConfigUtils and prepared the addition of metrics --- build-logic/src/main/kotlin/Versions.kt | 2 + build-logic/src/main/kotlin/extensions.kt | 2 +- .../floodgate.database-conventions.gradle.kts | 2 +- .../floodgate.publish-conventions.gradle.kts | 31 +++ .../floodgate.shadow-conventions.gradle.kts | 28 --- build.gradle.kts | 2 +- core/build.gradle.kts | 5 + .../floodgate/config/FloodgateConfig.java | 43 ++++- .../config/loader/ConfigInitializer.java | 109 ----------- .../floodgate/config/loader/ConfigLoader.java | 90 ++++----- .../config/loader/DefaultConfigHandler.java | 159 --------------- .../config/updater/ConfigFileUpdater.java | 182 ------------------ .../config/updater/ConfigUpdater.java | 122 ------------ .../floodgate/module/CommonModule.java | 22 +-- core/src/main/resources/config.yml | 6 +- ruleset.xml | 4 - spigot/build.gradle.kts | 2 +- 17 files changed, 120 insertions(+), 691 deletions(-) create mode 100644 build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts delete mode 100644 core/src/main/java/org/geysermc/floodgate/config/loader/ConfigInitializer.java delete mode 100644 core/src/main/java/org/geysermc/floodgate/config/loader/DefaultConfigHandler.java delete mode 100644 core/src/main/java/org/geysermc/floodgate/config/updater/ConfigFileUpdater.java delete mode 100644 core/src/main/java/org/geysermc/floodgate/config/updater/ConfigUpdater.java diff --git a/build-logic/src/main/kotlin/Versions.kt b/build-logic/src/main/kotlin/Versions.kt index 1e5c883f..4251d3e8 100644 --- a/build-logic/src/main/kotlin/Versions.kt +++ b/build-logic/src/main/kotlin/Versions.kt @@ -26,6 +26,7 @@ object Versions { const val geyserVersion = "2.0.0-SNAPSHOT" const val cumulusVersion = "1.0-SNAPSHOT" + const val configUtilsVersion = "1.0-SNAPSHOT" const val spigotVersion = "1.13-R0.1-SNAPSHOT" const val fastutilVersion = "8.5.3" const val lombokVersion = "1.18.20" @@ -33,6 +34,7 @@ object Versions { const val nettyVersion = "4.1.49.Final" const val snakeyamlVersion = "1.28" const val cloudVersion = "1.5.0" + const val bstatsVersion = "3.0.0" const val javaWebsocketVersion = "1.5.2" diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index fa5eeb31..1b781cb2 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -36,7 +36,7 @@ fun Project.isSnapshot(): Boolean = fun Project.fullVersion(): String { var version = version.toString() if (version.endsWith("-SNAPSHOT")) { - version += " (b${buildNumberAsString()}-${lastCommitHash()}}" + version += " (b${buildNumberAsString()}-${lastCommitHash()})" } return version } diff --git a/build-logic/src/main/kotlin/floodgate.database-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.database-conventions.gradle.kts index 2012ba65..b41417e2 100644 --- a/build-logic/src/main/kotlin/floodgate.database-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.database-conventions.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("floodgate.shadow-conventions") + id("floodgate.publish-conventions") } tasks { diff --git a/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts new file mode 100644 index 00000000..37c815c2 --- /dev/null +++ b/build-logic/src/main/kotlin/floodgate.publish-conventions.gradle.kts @@ -0,0 +1,31 @@ +plugins { + id("floodgate.shadow-conventions") + id("com.jfrog.artifactory") + id("maven-publish") +} + +publishing { + publications.create("mavenJava") { + groupId = project.group as String + artifactId = "floodgate-" + project.name + version = project.version as String + + artifact(tasks["shadowJar"]) + artifact(tasks["sourcesJar"]) + } +} + +artifactory { + publish { + repository { + setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases") + setMavenCompatible(true) + } + defaults { + publishConfigs("archives") + setPublishArtifacts(true) + setPublishPom(true) + setPublishIvy(false) + } + } +} \ No newline at end of file diff --git a/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts index f85e3c98..5405f480 100644 --- a/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/floodgate.shadow-conventions.gradle.kts @@ -3,8 +3,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar plugins { id("floodgate.base-conventions") id("com.github.johnrengelman.shadow") - id("com.jfrog.artifactory") - id("maven-publish") } tasks { @@ -31,30 +29,4 @@ tasks { named("build") { dependsOn(shadowJar) } -} - -publishing { - publications.create("mavenJava") { - groupId = project.group as String - artifactId = "floodgate-" + project.name - version = project.version as String - - artifact(tasks["shadowJar"]) - artifact(tasks["sourcesJar"]) - } -} - -artifactory { - publish { - repository { - setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases") - setMavenCompatible(true) - } - defaults { - publishConfigs("archives") - setPublishArtifacts(true) - setPublishPom(true) - setPublishIvy(false) - } - } } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index e4a88f13..b24fcbfa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -44,7 +44,7 @@ subprojects { plugins.apply("floodgate.database-conventions") } else { when (this) { - in platforms -> plugins.apply("floodgate.shadow-conventions") + in platforms -> plugins.apply("floodgate.publish-conventions") else -> plugins.apply("floodgate.base-conventions") } } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index e96167ea..8a1d04e0 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -2,10 +2,12 @@ import net.kyori.blossom.BlossomExtension plugins { id("net.kyori.blossom") + id("floodgate.shadow-conventions") } dependencies { api(projects.api) + api("org.geysermc.configutils", "configutils", Versions.configUtilsVersion) api("com.google.inject", "guice", Versions.guiceVersion) api("com.nukkitx.fastutil", "fastutil-short-object-maps", Versions.fastutilVersion) @@ -13,12 +15,15 @@ dependencies { api("org.java-websocket", "Java-WebSocket", Versions.javaWebsocketVersion) api("cloud.commandframework", "cloud-core", Versions.cloudVersion) api("org.yaml", "snakeyaml", Versions.snakeyamlVersion) + api("org.bstats", "bstats-base", Versions.bstatsVersion) } // present on all platforms provided("io.netty", "netty-transport", Versions.nettyVersion) provided("io.netty", "netty-codec", Versions.nettyVersion) +relocate("org.bstats") + configure { val constantsFile = "src/main/java/org/geysermc/floodgate/util/Constants.java" replaceToken("\${branch}", branchName(), constantsFile) diff --git a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java b/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java index 2fa23c89..9fb105d8 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java +++ b/core/src/main/java/org/geysermc/floodgate/config/FloodgateConfig.java @@ -25,15 +25,22 @@ package org.geysermc.floodgate.config; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.Key; +import java.util.UUID; import lombok.Getter; +import org.geysermc.configutils.loader.callback.CallbackResult; +import org.geysermc.configutils.loader.callback.GenericPostInitializeCallback; +import org.geysermc.floodgate.config.loader.ConfigLoader; /** * The global Floodgate configuration file used in every platform. Some platforms have their own * addition to the global configuration like {@link ProxyFloodgateConfig} for the proxies. */ @Getter -public class FloodgateConfig { +public class FloodgateConfig implements GenericPostInitializeCallback { private String keyFileName; private String usernamePrefix; private boolean replaceSpaces; @@ -42,22 +49,36 @@ public class FloodgateConfig { private DisconnectMessages disconnect; private PlayerLinkConfig playerLink; + private MetricsConfig metrics; private boolean debug; private int configVersion; private Key key; - public void setKey(Key key) { - if (this.key == null) { - this.key = key; - } - } - public boolean isProxy() { return this instanceof ProxyFloodgateConfig; } + @Override + public CallbackResult postInitialize(ConfigLoader loader) { + Path keyPath = loader.getDataFolder().resolve(getKeyFileName()); + + // don't assume that the key always exists with the existence of a config + if (!Files.exists(keyPath)) { + loader.generateKey(keyPath); + } + + try { + Key floodgateKey = loader.getKeyProducer().produceFrom(keyPath); + loader.getCipher().init(floodgateKey); + key = floodgateKey; + } catch (IOException exception) { + return CallbackResult.failed(exception.getMessage()); + } + return CallbackResult.ok(); + } + @Getter public static class DisconnectMessages { private String invalidKey; @@ -68,10 +89,16 @@ public class FloodgateConfig { public static class PlayerLinkConfig { private boolean enabled; private boolean requireLink; - private boolean enableOwnLinking = false; + private boolean enableOwnLinking; private boolean allowed; private long linkCodeTimeout; private String type; private boolean enableGlobalLinking; } + + @Getter + public static class MetricsConfig { + private boolean enabled; + private UUID uuid; + } } diff --git a/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigInitializer.java b/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigInitializer.java deleted file mode 100644 index dfa49a3d..00000000 --- a/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigInitializer.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Floodgate - */ - -package org.geysermc.floodgate.config.loader; - -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.LinkedHashMap; -import java.util.Map; -import org.geysermc.floodgate.config.FloodgateConfig; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.Constructor; -import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor; -import org.yaml.snakeyaml.introspector.BeanAccess; -import org.yaml.snakeyaml.introspector.FieldProperty; -import org.yaml.snakeyaml.introspector.Property; -import org.yaml.snakeyaml.introspector.PropertyUtils; - -public class ConfigInitializer { - private static final Yaml YAML; - - static { - Constructor constructor = - new CustomClassLoaderConstructor(ConfigInitializer.class.getClassLoader()); - - constructor.setPropertyUtils(new PropertyUtils() { - @Override - protected Map getPropertiesMap(Class type, BeanAccess bAccess) { - Map properties = new LinkedHashMap<>(); - getPropertiesFromClass(type, FloodgateConfig.class, properties); - return properties; - } - - private void getPropertiesFromClass( - Class type, - Class stopAfter, - Map propertyMap) { - - Class current = type; - while (!Object.class.equals(current)) { - for (Field field : current.getDeclaredFields()) { - int modifiers = field.getModifiers(); - if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) { - String correctName = getCorrectName(field.getName()); - // children should override parents - propertyMap.putIfAbsent(correctName, new FieldProperty(field)); - } - - if (field.getClass().getSuperclass().equals(current)) { - getPropertiesFromClass(field.getClass(), field.getClass(), propertyMap); - } - } - - if (current.equals(stopAfter)) { - return; - } - - current = type.getSuperclass(); - } - } - - private String getCorrectName(String name) { - // convert sendFloodgateData to send-floodgate-data, - // which is the style of writing config fields - StringBuilder propertyBuilder = new StringBuilder(); - for (int i = 0; i < name.length(); i++) { - char current = name.charAt(i); - if (Character.isUpperCase(current)) { - propertyBuilder.append('-').append(Character.toLowerCase(current)); - } else { - propertyBuilder.append(current); - } - } - return propertyBuilder.toString(); - } - }); - constructor.getPropertyUtils().setSkipMissingProperties(true); - YAML = new Yaml(constructor); - } - - public static T initializeFrom( - InputStream dataStream, - Class configClass) { - return YAML.loadAs(dataStream, configClass); - } -} diff --git a/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigLoader.java b/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigLoader.java index d1e85689..b261e63f 100644 --- a/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigLoader.java +++ b/core/src/main/java/org/geysermc/floodgate/config/loader/ConfigLoader.java @@ -25,24 +25,27 @@ package org.geysermc.floodgate.config.loader; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.security.Key; +import java.util.UUID; +import lombok.Getter; import lombok.RequiredArgsConstructor; +import org.geysermc.configutils.ConfigUtilities; +import org.geysermc.configutils.file.codec.PathFileCodec; +import org.geysermc.configutils.file.template.ResourceTemplateReader; +import org.geysermc.configutils.updater.change.Changes; import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.ProxyFloodgateConfig; -import org.geysermc.floodgate.config.updater.ConfigUpdater; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.KeyProducer; +@Getter @RequiredArgsConstructor public final class ConfigLoader { private final Path dataFolder; private final Class configClass; - private final DefaultConfigHandler configCreator; - private final ConfigUpdater updater; private final KeyProducer keyProducer; private final FloodgateCipher cipher; @@ -51,61 +54,42 @@ public final class ConfigLoader { @SuppressWarnings("unchecked") public T load() { - Path configPath = dataFolder.resolve("config.yml"); - - String defaultConfigName = "config.yml"; - boolean proxy = ProxyFloodgateConfig.class.isAssignableFrom(configClass); - if (proxy) { - defaultConfigName = "proxy-" + defaultConfigName; + String templateFile = "config.yml"; + if (ProxyFloodgateConfig.class.isAssignableFrom(configClass)) { + templateFile = "proxy-" + templateFile; } - boolean newConfig = !Files.exists(configPath); - if (newConfig) { - try { - configCreator.createDefaultConfig(defaultConfigName, configPath); - } catch (Exception exception) { - logger.error("Error while creating config", exception); - } - } + //todo old Floodgate logged a message when version = 0 and it generated a new key. + // Might be nice to allow you to run a function for a specific version. + + // it would also be nice to have sections in versionBuilder so that you don't have to + // provide the path all the time + + ConfigUtilities utilities = + ConfigUtilities.builder() + .fileCodec(PathFileCodec.of(dataFolder)) + .configFile("config.yml") + .templateReader(ResourceTemplateReader.of(getClass())) + .template(templateFile) + .changes(Changes.builder() + .version(1, Changes.versionBuilder() + .keyRenamed("player-link.enable", "player-link.enabled") + .keyRenamed("player-link.allow-linking", "player-link.allowed")) + .version(2, Changes.versionBuilder() + .keyRenamed("player-link.use-global-linking", "player-link.enable-global-linking")) + .build()) + .definePlaceholder("metrics.uuid", UUID::randomUUID) + .postInitializeCallbackArgument(this) + .build(); - T configInstance; try { - // check and update if the config is outdated - if (!newConfig) { - updater.update(this, defaultConfigName); - } - - FloodgateConfig config = ConfigInitializer.initializeFrom( - Files.newInputStream(configPath), configClass); - - try { - configInstance = (T) config; - } catch (ClassCastException exception) { - logger.error("Failed to cast config file to required class.", exception); - throw new RuntimeException(exception); - } - } catch (Exception exception) { - logger.error("Error while loading config", exception); + return (T) utilities.executeOn(configClass); + } catch (Throwable throwable) { throw new RuntimeException( - "Failed to load the config! Try to delete the config file", exception); + "Failed to load the config! Try to delete the config file if this error persists", + throwable + ); } - - Path keyPath = dataFolder.resolve(configInstance.getKeyFileName()); - // don't assume that the key always exists with the existence of a config - if (!Files.exists(keyPath)) { - generateKey(keyPath); - } - - try { - Key key = keyProducer.produceFrom(keyPath); - cipher.init(key); - configInstance.setKey(key); - } catch (IOException exception) { - logger.error("Error while reading the key", exception); - throw new RuntimeException("Failed to read the key!", exception); - } - - return configInstance; } public void generateKey(Path keyPath) { diff --git a/core/src/main/java/org/geysermc/floodgate/config/loader/DefaultConfigHandler.java b/core/src/main/java/org/geysermc/floodgate/config/loader/DefaultConfigHandler.java deleted file mode 100644 index 4549237b..00000000 --- a/core/src/main/java/org/geysermc/floodgate/config/loader/DefaultConfigHandler.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Floodgate - */ - -package org.geysermc.floodgate.config.loader; - -import static org.geysermc.floodgate.util.MessageFormatter.format; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import org.geysermc.floodgate.util.Utils; - -public class DefaultConfigHandler { - public void createDefaultConfig(String defaultConfigLocation, Path configPath) throws IOException { - List configLines = loadDefaultConfig(defaultConfigLocation); - - // writing the new config file - Files.write(configPath, configLines); - } - - public List loadDefaultConfig(String defaultConfigLocation) - throws IOException { - List lines = Utils.readAllLines(defaultConfigLocation); - - List configLines = new ArrayList<>(); - String parentConfig = null; - List parentLines = null; - - int lastInsertLine = -1; - int tempAddAfter = -1; - - for (String line : lines) { - // >>(space) or >>| - if (line.startsWith(">>")) { - if (line.length() >= 3) { - - // define parent file - if (line.charAt(2) == ' ') { - if (tempAddAfter != -1) { - throw new IllegalStateException( - "Cannot define new parent without closing the current section"); - } - parentConfig = line.substring(3); - parentLines = null; - lastInsertLine = -1; - continue; - } - - // define start / end of insert section - if (line.charAt(2) == '|') { - // end section - if (line.length() == 3) { - if (tempAddAfter == -1) { - throw new IllegalStateException("Cannot close an unclosed section"); - } - lastInsertLine = tempAddAfter; - tempAddAfter = -1; - continue; - } - - // start insert section - if (parentConfig == null) { - throw new IllegalStateException( - "Cannot start insert section without providing a parent"); - } - - if (tempAddAfter != -1) { - throw new IllegalStateException( - "Cannot start section with an unclosed section"); - } - - // note that addAfter starts counting from 1 - int addAfter = Integer.parseInt(line.substring(4)) - 1; - if (lastInsertLine > -1 && addAfter < lastInsertLine) { - throw new IllegalStateException(format( - "Cannot add the same lines twice {} {}", - addAfter, lastInsertLine - )); - } - - // as you can see by this implementation - // we don't support parent files in parent files - - if (lastInsertLine == -1) { - parentLines = Utils.readAllLines(parentConfig); - - for (int i = 0; i <= addAfter; i++) { - configLines.add(parentLines.get(i)); - } - } else { - for (int i = lastInsertLine; i <= addAfter; i++) { - configLines.add(parentLines.get(i)); - } - } - - tempAddAfter = addAfter; - continue; - } - - if (line.charAt(2) == '*') { - if (parentConfig == null) { - throw new IllegalStateException( - "Cannot write rest of the parent without providing a parent"); - } - - if (tempAddAfter != -1) { - throw new IllegalStateException( - "Cannot write rest of the parent config while an insert section is still open"); - } - - if (lastInsertLine == -1) { - parentLines = Utils.readAllLines(parentConfig); - configLines.addAll(parentLines); - continue; - } - - // the lastInsertLine has already been printed, so we won't print it twice - for (int i = lastInsertLine + 1; i < parentLines.size(); i++) { - configLines.add(parentLines.get(i)); - } - continue; - } - - throw new IllegalStateException( - "The use of >>" + line.charAt(2) + " is unknown"); - } - throw new IllegalStateException("Unable do something with just >>"); - } - // everything else: comments and key/value lines will be added - configLines.add(line); - } - - return configLines; - } -} diff --git a/core/src/main/java/org/geysermc/floodgate/config/updater/ConfigFileUpdater.java b/core/src/main/java/org/geysermc/floodgate/config/updater/ConfigFileUpdater.java deleted file mode 100644 index f2877c85..00000000 --- a/core/src/main/java/org/geysermc/floodgate/config/updater/ConfigFileUpdater.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Floodgate - */ - -package org.geysermc.floodgate.config.updater; - -import com.google.common.base.Ascii; -import com.google.inject.Inject; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.config.loader.DefaultConfigHandler; - -public final class ConfigFileUpdater { - @Inject private FloodgateLogger logger; - @Inject private DefaultConfigHandler defaultConfigHandler; - - /** - * Simple config file updater. Please note that all the keys should be unique and that this - * system wasn't made for complex configurations. - * - * @param configLocation the location of the Floodgate config - * @param currentVersion the key value map of the current config - * @param renames name changes introduced in this version. new (key) to old - * (value) - * @param defaultConfigLocation the location of the default Floodgate config - * @throws IOException if an I/O error occurs - */ - public void update( - Path configLocation, - Map currentVersion, - Map renames, - String defaultConfigLocation) - throws IOException { - - List notFound = new ArrayList<>(); - List newConfig = defaultConfigHandler.loadDefaultConfig(defaultConfigLocation); - - String spaces = ""; - Map map = null; - - String line; - for (int i = 0; i < newConfig.size(); i++) { - line = newConfig.get(i); - // we don't have to check comments or empty lines - if (line.isEmpty() || line.charAt(0) == '#') { - continue; - } - - StringBuilder currentSpaces = new StringBuilder(); - while (line.charAt(currentSpaces.length()) == Ascii.SPACE) { - currentSpaces.append(Ascii.SPACE); - } - - // end of subcategory - if (!spaces.isEmpty() && currentSpaces.length() < spaces.length()) { - // we can assume this since we don't allow subcategories of subcategories - spaces = ""; - map = null; - } - - // ignore comments - if (line.charAt(currentSpaces.length()) == '#') { - continue; - } - - int splitIndex = line.indexOf(':'); - // if the line has a 'key: value' structure - if (splitIndex != -1) { - - // start of a subcategory - if (line.length() == splitIndex + 1) { - if (currentSpaces.length() > 0) { - throw new IllegalStateException( - "Config too complex! I can't understand subcategories of a subcategory"); - } - - spaces = " "; - //todo allow rename of subcategory? - //noinspection unchecked - map = (Map) currentVersion.get(line.substring(0, splitIndex)); - continue; - } - - String name = line.substring(spaces.length(), splitIndex); - - // don't change the config-version to the old value! - if (name.equals("config-version")) { - continue; - } - - // allow multiple renames - String tempName; - String oldName = name; - do { - tempName = oldName; - oldName = renames.getOrDefault(oldName, oldName); - } while (!oldName.equals(tempName)); - - Object value; - if (map != null) { - value = map.get(oldName); - } else { - value = currentVersion.get(spaces + oldName); - } - - // use default value if the key doesn't exist in the current version - if (value == null) { - notFound.add(name); - continue; - } - - if (value instanceof String) { - String v = (String) value; - if (!v.startsWith("\"") || !v.endsWith("\"")) { - value = "\"" + value + "\""; - } - //todo this doesn't update {0} {1} to {} {} e.g. - } - - logger.debug(name + " has been changed to " + value); - newConfig.set(i, spaces + name + ": " + value); - } - } - - Files.deleteIfExists(configLocation.getParent().resolve("config-old.yml")); - Files.copy(configLocation, configLocation.getParent().resolve("config-old.yml")); - Files.write(configLocation, newConfig); - - logger.info("Successfully updated the config file! " + - "Your old config has been moved to config-old.yml"); - - if (!notFound.isEmpty()) { - StringBuilder messageBuilder = new StringBuilder( - "Please note that the following keys we not found in the old config and " + - "are now using the default Floodgate config value. Missing/new keys: "); - - boolean first = true; - for (String value : notFound) { - if (!first) { - messageBuilder.append(", "); - } - - String renamed = renames.get(value); - if (renamed != null) { - messageBuilder.append(renamed).append(" to "); - } - - messageBuilder.append(value); - - first = false; - } - - logger.info(messageBuilder.toString()); - } - } -} diff --git a/core/src/main/java/org/geysermc/floodgate/config/updater/ConfigUpdater.java b/core/src/main/java/org/geysermc/floodgate/config/updater/ConfigUpdater.java deleted file mode 100644 index a75ab448..00000000 --- a/core/src/main/java/org/geysermc/floodgate/config/updater/ConfigUpdater.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Floodgate - */ - -package org.geysermc.floodgate.config.updater; - -import static com.google.common.base.Preconditions.checkArgument; -import static org.geysermc.floodgate.util.MessageFormatter.format; - -import java.io.BufferedReader; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import org.geysermc.floodgate.api.logger.FloodgateLogger; -import org.geysermc.floodgate.config.loader.ConfigLoader; -import org.yaml.snakeyaml.Yaml; - -@RequiredArgsConstructor -public final class ConfigUpdater { - private static final int CONFIG_VERSION = 2; - private final Path dataFolder; - private final ConfigFileUpdater fileUpdater; - private final FloodgateLogger logger; - - public void update(ConfigLoader loader, String defaultConfigLocation) { - Path configLocation = dataFolder.resolve("config.yml"); - - Map config; - - try (BufferedReader configReader = Files.newBufferedReader(configLocation)) { - config = new Yaml().load(configReader); - } catch (IOException exception) { - logger.error("Error while opening the config file", exception); - throw new RuntimeException("Failed to update config", exception); - } - - // new name -> old name - Map renames = new HashMap<>(); - - int version = 0; // pre-rewrite is the default config version - - Object versionElement = config.get("config-version"); - // only rewrite configs have a config-version - if (versionElement == null) { - logger.warn("We've detected a pre-rewrite config file, please note that Floodgate " + - "doesn't not work properly if you don't update your Floodgate key used on " + - "all your servers (including Geyser). We'll try to update your Floodgate " + - "config now and we'll also generate a new Floodgate key for you, but if " + - "you're running a network or if you're running a Spigot server with " + - "Geyser Standalone please update as you'll no longer be able to connect."); - renames.put("enabled", "enable"); - renames.put("allowed", "allow-linking"); - - // relocate the old key so that they can restore it if it was a new key - Path keyFilePath = dataFolder.resolve((String) config.get("key-file-name")); - if (Files.exists(keyFilePath)) { - try { - Files.copy(keyFilePath, dataFolder.resolve("old-key.pem")); - } catch (IOException exception) { - throw new RuntimeException( - "Failed to relocate the old key to make place for a new key", - exception); - } - } - loader.generateKey(keyFilePath); - } else { - // get (and verify) the config version - checkArgument( - versionElement instanceof Integer, - "Config version should be an integer. Did someone mess with the config?" - ); - - version = (int) versionElement; - checkArgument( - version > 0 && version <= CONFIG_VERSION, - format("Config is newer then possible on this version! Expected {}, got {}", - CONFIG_VERSION, version)); - } - - // config is already up-to-date - if (version == CONFIG_VERSION) { - return; - } - - if (version < 2) { - // renamed 'use-global-linking' to 'enable-global-linking' - // and added 'enable-own-linking' - renames.put("enable-global-linking", "use-global-linking"); - } - - try { - fileUpdater.update(configLocation, config, renames, defaultConfigLocation); - } catch (IOException exception) { - logger.error("Error while updating the config file", exception); - throw new RuntimeException("Failed to update config", exception); - } - } -} diff --git a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java index ad854b13..36e8140a 100644 --- a/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java +++ b/core/src/main/java/org/geysermc/floodgate/module/CommonModule.java @@ -43,9 +43,6 @@ import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfigHolder; import org.geysermc.floodgate.config.loader.ConfigLoader; -import org.geysermc.floodgate.config.loader.DefaultConfigHandler; -import org.geysermc.floodgate.config.updater.ConfigFileUpdater; -import org.geysermc.floodgate.config.updater.ConfigUpdater; import org.geysermc.floodgate.crypto.AesCipher; import org.geysermc.floodgate.crypto.AesKeyProducer; import org.geysermc.floodgate.crypto.Base64Topping; @@ -105,27 +102,10 @@ public class CommonModule extends AbstractModule { @Singleton public ConfigLoader configLoader( @Named("configClass") Class configClass, - DefaultConfigHandler defaultConfigHandler, - ConfigUpdater configUpdater, KeyProducer producer, FloodgateCipher cipher, FloodgateLogger logger) { - return new ConfigLoader(dataDirectory, configClass, defaultConfigHandler, configUpdater, - producer, cipher, logger); - } - - @Provides - @Singleton - public DefaultConfigHandler defaultConfigCreator() { - return new DefaultConfigHandler(); - } - - @Provides - @Singleton - public ConfigUpdater configUpdater( - ConfigFileUpdater configFileUpdater, - FloodgateLogger logger) { - return new ConfigUpdater(dataDirectory, configFileUpdater, logger); + return new ConfigLoader(dataDirectory, configClass, producer, cipher, logger); } @Provides diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index a1066356..27d23b77 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -58,5 +58,9 @@ player-link: # you have limited internet access. enable-global-linking: true +metrics: + enabled: true + uuid: ${metrics.uuid} + # Do not change this -config-version: 2 +config-version: 3 diff --git a/ruleset.xml b/ruleset.xml index ca7c5bae..a078f6db 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -10,10 +10,6 @@ .*/CommonPlayerLink.* - - .*/DefaultConfigHandler.* - - .*/ConfigFileUpdater.* .*/FloodgateConfig.* diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index 6f53213d..8bd8b9c0 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -5,9 +5,9 @@ var gsonVersion = "2.8.5" dependencies { api(projects.core) + implementation("cloud.commandframework", "cloud-bukkit", Versions.cloudVersion) // hack to make pre 1.12 work implementation("com.google.guava", "guava", guavaVersion) - implementation("cloud.commandframework", "cloud-bukkit", Versions.cloudVersion) } relocate("com.google.inject")