mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2025-01-07 19:17:52 +01:00
Only save new config options with new reload flag, add initial v1 config migration
This commit is contained in:
parent
62fe2d36d0
commit
c54f677761
@ -30,9 +30,11 @@ import java.util.Collections;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public enum ReloadFlag {
|
public enum ReloadFlag {
|
||||||
CONFIG(false),
|
CONFIG(false),
|
||||||
|
CONFIG_UPGRADE(false),
|
||||||
LINKED_ACCOUNT_PROVIDER(false),
|
LINKED_ACCOUNT_PROVIDER(false),
|
||||||
STORAGE(true),
|
STORAGE(true),
|
||||||
DISCORD_CONNECTION(DiscordSRVApi::isReady),
|
DISCORD_CONNECTION(DiscordSRVApi::isReady),
|
||||||
@ -41,8 +43,8 @@ public enum ReloadFlag {
|
|||||||
// Bukkit only
|
// Bukkit only
|
||||||
TRANSLATIONS(false);
|
TRANSLATIONS(false);
|
||||||
|
|
||||||
public static final Set<ReloadFlag> ALL = Collections.unmodifiableSet(
|
public static final Set<ReloadFlag> LOAD = Collections.unmodifiableSet(
|
||||||
new LinkedHashSet<>(Arrays.asList(values())));
|
Arrays.stream(values()).filter(flag -> flag != ReloadFlag.CONFIG_UPGRADE).collect(Collectors.toSet()));
|
||||||
public static final Set<ReloadFlag> DEFAULT_FLAGS = Collections.unmodifiableSet(
|
public static final Set<ReloadFlag> DEFAULT_FLAGS = Collections.unmodifiableSet(
|
||||||
new LinkedHashSet<>(Collections.singletonList(CONFIG)));
|
new LinkedHashSet<>(Collections.singletonList(CONFIG)));
|
||||||
|
|
||||||
|
@ -94,13 +94,13 @@ public class BukkitDiscordSRV extends AbstractDiscordSRV<DiscordSRVBukkitBootstr
|
|||||||
this.playerProvider = new BukkitPlayerProvider(this);
|
this.playerProvider = new BukkitPlayerProvider(this);
|
||||||
this.pluginManager = new BukkitPluginManager(this);
|
this.pluginManager = new BukkitPluginManager(this);
|
||||||
|
|
||||||
|
load();
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
this.connectionConfigManager = new BukkitConnectionConfigManager(this);
|
this.connectionConfigManager = new BukkitConnectionConfigManager(this);
|
||||||
this.configManager = new BukkitConfigManager(this);
|
this.configManager = new BukkitConfigManager(this);
|
||||||
this.messagesConfigManager = new BukkitMessagesConfigManager(this);
|
this.messagesConfigManager = new BukkitMessagesConfigManager(this);
|
||||||
|
|
||||||
load();
|
|
||||||
|
|
||||||
this.autoCompleteHelper = new BukkitGameCommandExecutionHelper(this);
|
this.autoCompleteHelper = new BukkitGameCommandExecutionHelper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +112,7 @@ import java.util.*;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
@ -441,7 +442,8 @@ public abstract class AbstractDiscordSRV<
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CC connectionConfig() {
|
public CC connectionConfig() {
|
||||||
return connectionConfigManager().config();
|
ConnectionConfigManager<CC> configManager = connectionConfigManager();
|
||||||
|
return configManager != null ? configManager.config() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -449,7 +451,8 @@ public abstract class AbstractDiscordSRV<
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public C config() {
|
public C config() {
|
||||||
return configManager().config();
|
MainConfigManager<C> configManager = configManager();
|
||||||
|
return configManager != null ? configManager.config() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -457,12 +460,17 @@ public abstract class AbstractDiscordSRV<
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MC messagesConfig(@Nullable Locale locale) {
|
public MC messagesConfig(@Nullable Locale locale) {
|
||||||
MessagesConfigSingleManager<MC> manager = locale != null ? messagesConfigManager().getManager(locale) : null;
|
MessagesConfigManager<MC> configManager = messagesConfigManager();
|
||||||
|
if (configManager == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessagesConfigSingleManager<MC> manager = locale != null ? configManager.getManager(locale) : null;
|
||||||
if (manager == null) {
|
if (manager == null) {
|
||||||
manager = messagesConfigManager().getManager(defaultLocale());
|
manager = configManager.getManager(defaultLocale());
|
||||||
}
|
}
|
||||||
if (manager == null) {
|
if (manager == null) {
|
||||||
manager = messagesConfigManager().getManager(Locale.US);
|
manager = configManager.getManager(Locale.US);
|
||||||
}
|
}
|
||||||
return manager.config();
|
return manager.config();
|
||||||
}
|
}
|
||||||
@ -715,7 +723,7 @@ public abstract class AbstractDiscordSRV<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initial load
|
// Initial load
|
||||||
reload(ReloadFlag.ALL, true);
|
reload(ReloadFlag.LOAD, true);
|
||||||
|
|
||||||
if (serverType() == ServerType.PROXY) {
|
if (serverType() == ServerType.PROXY) {
|
||||||
runServerStarted().get();
|
runServerStarted().get();
|
||||||
@ -741,11 +749,17 @@ public abstract class AbstractDiscordSRV<
|
|||||||
logger().info("Reloading DiscordSRV...");
|
logger().info("Reloading DiscordSRV...");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags.contains(ReloadFlag.CONFIG)) {
|
boolean configUpgrade = flags.contains(ReloadFlag.CONFIG_UPGRADE);
|
||||||
|
if (flags.contains(ReloadFlag.CONFIG) || configUpgrade) {
|
||||||
try {
|
try {
|
||||||
connectionConfigManager().load();
|
AtomicBoolean anyMissingOptions = new AtomicBoolean(false);
|
||||||
configManager().load();
|
connectionConfigManager().reload(configUpgrade, anyMissingOptions);
|
||||||
messagesConfigManager().load();
|
configManager().reload(configUpgrade, anyMissingOptions);
|
||||||
|
messagesConfigManager().reload(configUpgrade, anyMissingOptions);
|
||||||
|
|
||||||
|
if (anyMissingOptions.get()) {
|
||||||
|
logger().info("Use \"/discordsrv reload config_upgrade\" to write the latest configuration");
|
||||||
|
}
|
||||||
|
|
||||||
channelConfig().reload();
|
channelConfig().reload();
|
||||||
createHttpClient();
|
createHttpClient();
|
||||||
|
@ -155,7 +155,7 @@ public class ReloadCommand implements GameCommandExecutor, GameCommandSuggester
|
|||||||
if (discordSRV.status().isStartupError()) {
|
if (discordSRV.status().isStartupError()) {
|
||||||
// If startup error, use all flags
|
// If startup error, use all flags
|
||||||
parts.clear();
|
parts.clear();
|
||||||
flags.addAll(ReloadFlag.ALL);
|
flags.addAll(ReloadFlag.LOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String part : parts) {
|
for (String part : parts) {
|
||||||
@ -190,7 +190,7 @@ public class ReloadCommand implements GameCommandExecutor, GameCommandSuggester
|
|||||||
String last = currentInput.substring(lastSpace);
|
String last = currentInput.substring(lastSpace);
|
||||||
String beforeLastSpace = currentInput.substring(0, lastSpace);
|
String beforeLastSpace = currentInput.substring(0, lastSpace);
|
||||||
|
|
||||||
List<String> options = ReloadFlag.ALL.stream()
|
List<String> options = Arrays.stream(ReloadFlag.values())
|
||||||
.map(flag -> flag.name().toLowerCase(Locale.ROOT))
|
.map(flag -> flag.name().toLowerCase(Locale.ROOT))
|
||||||
.filter(flag -> flag.startsWith(last))
|
.filter(flag -> flag.startsWith(last))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
@ -28,6 +28,7 @@ import com.discordsrv.common.exception.ConfigException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public abstract class MessagesConfigManager<C extends MessagesConfig> {
|
public abstract class MessagesConfigManager<C extends MessagesConfig> {
|
||||||
@ -57,7 +58,7 @@ public abstract class MessagesConfigManager<C extends MessagesConfig> {
|
|||||||
return discordSRV.dataDirectory().resolve("messages");
|
return discordSRV.dataDirectory().resolve("messages");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load() throws ConfigException {
|
public void reload(boolean forceSave, AtomicBoolean anyMissingOptions) throws ConfigException {
|
||||||
synchronized (configs) {
|
synchronized (configs) {
|
||||||
configs.clear();
|
configs.clear();
|
||||||
|
|
||||||
@ -106,7 +107,7 @@ public abstract class MessagesConfigManager<C extends MessagesConfig> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<Locale, MessagesConfigSingleManager<C>> entry : configs.entrySet()) {
|
for (Map.Entry<Locale, MessagesConfigSingleManager<C>> entry : configs.entrySet()) {
|
||||||
entry.getValue().load();
|
entry.getValue().reload(forceSave, anyMissingOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,13 @@ import com.discordsrv.common.exception.ConfigException;
|
|||||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||||
import org.spongepowered.configurate.loader.AbstractConfigurationLoader;
|
import org.spongepowered.configurate.loader.AbstractConfigurationLoader;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public interface ConfigManager<T> {
|
public interface ConfigManager<T> {
|
||||||
|
|
||||||
T createConfiguration();
|
T createConfiguration();
|
||||||
T config();
|
T config();
|
||||||
|
|
||||||
void load() throws ConfigException;
|
void reload(boolean forceSave, AtomicBoolean anyMissingOptions) throws ConfigException;
|
||||||
void reload() throws ConfigException;
|
|
||||||
void save(AbstractConfigurationLoader<CommentedConfigurationNode> loader) throws ConfigException;
|
void save(AbstractConfigurationLoader<CommentedConfigurationNode> loader) throws ConfigException;
|
||||||
void save() throws ConfigException;
|
|
||||||
}
|
}
|
||||||
|
@ -58,8 +58,10 @@ import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -385,56 +387,73 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
protected void translate(CommentedConfigurationNode node) throws ConfigurateException {}
|
||||||
protected ConfigurationNode getTranslation() throws ConfigurateException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") // Cast to generic
|
||||||
@Override
|
@Override
|
||||||
public void load() throws ConfigException {
|
public void reload(boolean forceSave, AtomicBoolean anyMissingOptions) throws ConfigException {
|
||||||
reload();
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public void reload() throws ConfigException {
|
|
||||||
T defaultConfig = createConfiguration();
|
T defaultConfig = createConfiguration();
|
||||||
try {
|
Class<T> defaultConfigClass = (Class<T>) defaultConfig.getClass();
|
||||||
CommentedConfigurationNode node;
|
|
||||||
if (filePath().toFile().exists()) {
|
|
||||||
// Config file exists, load from that
|
|
||||||
node = loader().load();
|
|
||||||
|
|
||||||
ConfigurationNode translation = getTranslation();
|
|
||||||
if (translation != null) {
|
|
||||||
// Merge translation
|
|
||||||
node.mergeFrom(translation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply defaults that may not be there
|
|
||||||
node.mergeFrom(getDefault(defaultConfig, true));
|
|
||||||
} else {
|
|
||||||
node = getDefault(defaultConfig, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SAVE_OR_LOAD.set(true);
|
SAVE_OR_LOAD.set(true);
|
||||||
this.configuration = objectMapper()
|
|
||||||
.get((Class<T>) defaultConfig.getClass())
|
if (!Files.exists(filePath)) {
|
||||||
.load(node);
|
CommentedConfigurationNode node = getDefault(defaultConfig, false);
|
||||||
} finally {
|
translate(node);
|
||||||
SAVE_OR_LOAD.set(false);
|
|
||||||
|
configuration = objectMapper().get(defaultConfigClass).load(node);
|
||||||
|
|
||||||
|
// TODO: v1 migration
|
||||||
|
|
||||||
|
save(loader());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load existing file & translate
|
||||||
|
CommentedConfigurationNode node = loader().load();
|
||||||
|
|
||||||
|
CommentedConfigurationNode defaultNode = getDefault(defaultConfig, true);
|
||||||
|
translate(defaultNode);
|
||||||
|
|
||||||
|
// Log missing options, apply (missing) defaults
|
||||||
|
if (!forceSave) {
|
||||||
|
// Only log if it's not being force saved
|
||||||
|
checkIfValuesMissing(node, defaultNode, anyMissingOptions);
|
||||||
|
}
|
||||||
|
node.mergeFrom(defaultNode);
|
||||||
|
|
||||||
|
configuration = objectMapper().get(defaultConfigClass).load(node);
|
||||||
|
if (forceSave) {
|
||||||
|
save(loader);
|
||||||
}
|
}
|
||||||
} catch (ConfigurateException e) {
|
} catch (ConfigurateException e) {
|
||||||
Class<?> configClass = defaultConfig.getClass();
|
Class<?> configClass = defaultConfig.getClass();
|
||||||
if (!configClass.isAnnotationPresent(ConfigSerializable.class)) {
|
if (!configClass.isAnnotationPresent(ConfigSerializable.class)) {
|
||||||
// Not very obvious and can easily happen
|
// Not very obvious and can easily happen
|
||||||
throw new ConfigException(configClass.getName()
|
throw new ConfigException(configClass.getName() + " is not annotated with @ConfigSerializable", e);
|
||||||
+ " is not annotated with @ConfigSerializable", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ConfigException("Failed to load configuration", e);
|
throw new ConfigException("Failed to load configuration", e);
|
||||||
|
} finally {
|
||||||
|
SAVE_OR_LOAD.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkIfValuesMissing(
|
||||||
|
CommentedConfigurationNode node,
|
||||||
|
CommentedConfigurationNode defaultNode,
|
||||||
|
AtomicBoolean anyMissingOptions
|
||||||
|
) throws ConfigurateException {
|
||||||
|
for (CommentedConfigurationNode child : defaultNode.childrenMap().values()) {
|
||||||
|
CommentedConfigurationNode value = node.node(child.key());
|
||||||
|
if (value.virtual()) {
|
||||||
|
logger.warning("Missing option \"" + child.key() + "\" in " + fileName());
|
||||||
|
anyMissingOptions.set(true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkIfValuesMissing(value, child, anyMissingOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,24 +461,16 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
|
|||||||
@Override
|
@Override
|
||||||
public void save(AbstractConfigurationLoader<CommentedConfigurationNode> loader) throws ConfigException {
|
public void save(AbstractConfigurationLoader<CommentedConfigurationNode> loader) throws ConfigException {
|
||||||
try {
|
try {
|
||||||
|
SAVE_OR_LOAD.set(true);
|
||||||
CommentedConfigurationNode node = loader.createNode();
|
CommentedConfigurationNode node = loader.createNode();
|
||||||
save(configuration, (Class<T>) configuration.getClass(), node);
|
|
||||||
|
// Save configuration to the node
|
||||||
|
objectMapper().get((Class<T>) configuration.getClass()).save(configuration, node);
|
||||||
|
|
||||||
|
// Save the node to the provided loader
|
||||||
loader.save(node);
|
loader.save(node);
|
||||||
} catch (ConfigurateException e) {
|
} catch (ConfigurateException e) {
|
||||||
throw new ConfigException("Failed to load configuration", e);
|
throw new ConfigException("Failed to load configuration", e);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save() throws ConfigException {
|
|
||||||
LT loader = loader();
|
|
||||||
save(loader);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void save(T config, Class<T> clazz, CommentedConfigurationNode node) throws SerializationException {
|
|
||||||
try {
|
|
||||||
SAVE_OR_LOAD.set(true);
|
|
||||||
objectMapper().get(clazz).save(config, node);
|
|
||||||
} finally {
|
} finally {
|
||||||
SAVE_OR_LOAD.set(false);
|
SAVE_OR_LOAD.set(false);
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,6 @@ package com.discordsrv.common.config.configurate.manager.abstraction;
|
|||||||
|
|
||||||
import com.discordsrv.common.DiscordSRV;
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import com.discordsrv.common.config.Config;
|
import com.discordsrv.common.config.Config;
|
||||||
import com.discordsrv.common.exception.ConfigException;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||||
import org.spongepowered.configurate.ConfigurateException;
|
import org.spongepowered.configurate.ConfigurateException;
|
||||||
import org.spongepowered.configurate.ConfigurationNode;
|
import org.spongepowered.configurate.ConfigurationNode;
|
||||||
@ -56,13 +54,6 @@ public abstract class TranslatedConfigManager<T extends Config, LT extends Abstr
|
|||||||
return discordSRV.defaultLocale();
|
return discordSRV.defaultLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void load() throws ConfigException {
|
|
||||||
super.reload();
|
|
||||||
translate();
|
|
||||||
super.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String header() {
|
protected String header() {
|
||||||
if (header != null) {
|
if (header != null) {
|
||||||
@ -72,41 +63,19 @@ public abstract class TranslatedConfigManager<T extends Config, LT extends Abstr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable ConfigurationNode getTranslation() throws ConfigurateException {
|
protected void translate(CommentedConfigurationNode node) throws ConfigurateException {
|
||||||
ConfigurationNode translation = getTranslationRoot();
|
String fileName = fileName();
|
||||||
if (translation == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
translation = translation.copy();
|
|
||||||
translation.node("_comments").set(null);
|
|
||||||
return translation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void translate() throws ConfigException {
|
|
||||||
T config = config();
|
|
||||||
if (config == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
ConfigurationNode translationRoot = getTranslationRoot();
|
ConfigurationNode translationRoot = getTranslationRoot();
|
||||||
if (translationRoot == null) {
|
if (translationRoot == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String fileIdentifier = config.getFileName();
|
ConfigurationNode translation = translationRoot.node(fileName);
|
||||||
ConfigurationNode translation = translationRoot.node(fileIdentifier);
|
ConfigurationNode comments = translationRoot.node(fileName + "_comments");
|
||||||
ConfigurationNode comments = translationRoot.node(fileIdentifier + "_comments");
|
|
||||||
|
|
||||||
CommentedConfigurationNode node = loader().createNode();
|
|
||||||
this.header = comments.node("$header").getString();
|
this.header = comments.node("$header").getString();
|
||||||
|
|
||||||
save(config, (Class<T>) config.getClass(), node);
|
|
||||||
translateNode(node, translation, comments);
|
translateNode(node, translation, comments);
|
||||||
} catch (ConfigurateException e) {
|
|
||||||
throw new ConfigException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConfigurationNode getTranslationRoot() throws ConfigurateException {
|
private ConfigurationNode getTranslationRoot() throws ConfigurateException {
|
||||||
|
@ -0,0 +1,154 @@
|
|||||||
|
package com.discordsrv.common.config.helper;
|
||||||
|
|
||||||
|
import com.discordsrv.common.DiscordSRV;
|
||||||
|
import com.discordsrv.common.abstraction.sync.enums.SyncDirection;
|
||||||
|
import com.discordsrv.common.config.connection.ConnectionConfig;
|
||||||
|
import com.discordsrv.common.config.main.ConsoleConfig;
|
||||||
|
import com.discordsrv.common.config.main.GroupSyncConfig;
|
||||||
|
import com.discordsrv.common.config.main.MainConfig;
|
||||||
|
import com.discordsrv.common.config.main.channels.DiscordToMinecraftChatConfig;
|
||||||
|
import com.discordsrv.common.config.main.channels.base.BaseChannelConfig;
|
||||||
|
import com.discordsrv.common.config.main.channels.base.ChannelConfig;
|
||||||
|
import org.spongepowered.configurate.ConfigurateException;
|
||||||
|
import org.spongepowered.configurate.ConfigurationNode;
|
||||||
|
import org.spongepowered.configurate.serialize.SerializationException;
|
||||||
|
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class V1ConfigMigration {
|
||||||
|
|
||||||
|
private final DiscordSRV discordSRV;
|
||||||
|
private final ConfigurationNode config;
|
||||||
|
private final ConfigurationNode messages;
|
||||||
|
private final ConfigurationNode linking;
|
||||||
|
private final ConfigurationNode synchronization;
|
||||||
|
|
||||||
|
public V1ConfigMigration(DiscordSRV discordSRV) {
|
||||||
|
this.discordSRV = discordSRV;
|
||||||
|
this.config = loadNode(discordSRV, "config.yml");
|
||||||
|
this.messages = loadNode(discordSRV, "messages.yml");
|
||||||
|
this.linking = loadNode(discordSRV, "linking.yml");
|
||||||
|
this.synchronization = loadNode(discordSRV, "synchronization.yml");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ConfigurationNode loadNode(DiscordSRV discordSRV, String fileName) {
|
||||||
|
try {
|
||||||
|
Path path = discordSRV.dataDirectory().resolve(fileName);
|
||||||
|
if (!Files.exists(path)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return YamlConfigurationLoader.builder().path(path).build().load();
|
||||||
|
} catch (ConfigurateException e) {
|
||||||
|
discordSRV.logger().warning("Failed to load v1 " + fileName + " for migration", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void migrate(MainConfig mainConfig) throws SerializationException {
|
||||||
|
mainConfig.channels.remove("global");
|
||||||
|
BaseChannelConfig defaultChannel = mainConfig.channels.get("default");
|
||||||
|
if (defaultChannel != null) {
|
||||||
|
defaultChannel.discordToMinecraft.enabled = config.node("DiscordChatChannelDiscordToMinecraft").getBoolean(true);
|
||||||
|
|
||||||
|
String emojiBehaviour = config.node("DiscordChatChannelEmojiBehavior").getString();
|
||||||
|
if ("show".equalsIgnoreCase(emojiBehaviour)) {
|
||||||
|
defaultChannel.discordToMinecraft.unicodeEmojiBehaviour = DiscordToMinecraftChatConfig.EmojiBehaviour.SHOW;
|
||||||
|
} else if ("hide".equalsIgnoreCase(emojiBehaviour)) {
|
||||||
|
defaultChannel.discordToMinecraft.unicodeEmojiBehaviour = DiscordToMinecraftChatConfig.EmojiBehaviour.HIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultChannel.discordToMinecraft.ignores.bots = config.node("DiscordChatChannelBlockBots").getBoolean(false);
|
||||||
|
defaultChannel.discordToMinecraft.ignores.webhooks = config.node("DiscordChatChannelWebhooks").getBoolean(true);
|
||||||
|
defaultChannel.discordToMinecraft.ignores.userBotAndWebhookIds.whitelist = false;
|
||||||
|
defaultChannel.discordToMinecraft.ignores.userBotAndWebhookIds.ids = config.node("DiscordChatChannelBlockedIds").getList(Long.class);
|
||||||
|
defaultChannel.discordToMinecraft.ignores.roleIds.whitelist = config.node("DiscordChatChannelBlockedRolesAsWhitelist").getBoolean(false);
|
||||||
|
defaultChannel.discordToMinecraft.ignores.roleIds.ids = config.node("DiscordChatChannelBlockedRolesIds").getList(Long.class);
|
||||||
|
|
||||||
|
defaultChannel.minecraftToDiscord.enabled = config.node("DiscordChatChannelMinecraftToDiscord").getBoolean(true);
|
||||||
|
List<String> allowedMentions = config.node("DiscordChatChannelAllowedMentions").getList(String.class, Collections.emptyList());
|
||||||
|
defaultChannel.minecraftToDiscord.mentions.channels = allowedMentions.contains("channel");
|
||||||
|
defaultChannel.minecraftToDiscord.mentions.everyone = allowedMentions.contains("everyone");
|
||||||
|
defaultChannel.minecraftToDiscord.mentions.roles = allowedMentions.contains("role");
|
||||||
|
defaultChannel.minecraftToDiscord.mentions.users = allowedMentions.contains("user");
|
||||||
|
}
|
||||||
|
|
||||||
|
config.node("Channels").childrenMap().forEach((key, value) -> {
|
||||||
|
String channelId = value.getString();
|
||||||
|
if (!(key instanceof String) || channelId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelConfig channelConfig = new ChannelConfig();
|
||||||
|
channelConfig.destination.channelIds = Collections.singletonList(Long.parseUnsignedLong(channelId));
|
||||||
|
channelConfig.destination.threads = Collections.emptyList();
|
||||||
|
mainConfig.channels.put((String) key, channelConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
String consoleChannelId = config.node("DiscordConsoleChannelId").getString("");
|
||||||
|
if (!consoleChannelId.replace("0", "").isEmpty()) {
|
||||||
|
ConsoleConfig consoleConfig = new ConsoleConfig();
|
||||||
|
consoleConfig.channel.channelId = Long.parseUnsignedLong(consoleChannelId);
|
||||||
|
consoleConfig.appender.outputMode = config.node("DiscordConsoleChannelUseCodeBlocks").getBoolean() ? ConsoleConfig.OutputMode.DIFF : ConsoleConfig.OutputMode.PLAIN_CONTENT;
|
||||||
|
consoleConfig.appender.levels.levels = config.node("DiscordConsoleChannelLevels").getList(String.class, Collections.emptyList())
|
||||||
|
.stream().map(level -> level.toUpperCase(Locale.ROOT)).collect(Collectors.toList());
|
||||||
|
consoleConfig.appender.levels.blacklist = false;
|
||||||
|
|
||||||
|
mainConfig.console.clear();
|
||||||
|
mainConfig.console.add(consoleConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean toMinecraft = synchronization.node("BanSynchronizationDiscordToMinecraft").getBoolean(true);
|
||||||
|
boolean toDiscord = synchronization.node("BanSynchronizationMinecraftToDiscord").getBoolean(true);
|
||||||
|
SyncDirection banSyncDirection = SyncDirection.BIDIRECTIONAL;
|
||||||
|
if (toMinecraft && !toDiscord) {
|
||||||
|
banSyncDirection = SyncDirection.DISCORD_TO_MINECRAFT;
|
||||||
|
} else if (!toMinecraft && toDiscord) {
|
||||||
|
banSyncDirection = SyncDirection.MINECRAFT_TO_DISCORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
mainConfig.banSync.direction = banSyncDirection;
|
||||||
|
|
||||||
|
|
||||||
|
boolean minecraftIsTieBreaker = synchronization.node("GroupRoleSynchronizationMinecraftIsAuthoritative").getBoolean(true);
|
||||||
|
boolean oneWay = synchronization.node("GroupRoleSynchronizationOneWay").getBoolean(false);
|
||||||
|
SyncDirection groupSyncDirection = oneWay
|
||||||
|
? (minecraftIsTieBreaker ? SyncDirection.MINECRAFT_TO_DISCORD : SyncDirection.DISCORD_TO_MINECRAFT)
|
||||||
|
: SyncDirection.BIDIRECTIONAL;
|
||||||
|
int groupSyncCycleTime = synchronization.node("GroupRoleSynchronizationCycleTime").getInt();
|
||||||
|
|
||||||
|
mainConfig.groupSync.pairs.clear();
|
||||||
|
synchronization.node("GroupRoleSynchronizationGroupsAndRolesToSync").childrenMap().forEach((key, value) -> {
|
||||||
|
String roleId = value.getString();
|
||||||
|
if (!(key instanceof String) || roleId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GroupSyncConfig.PairConfig pairConfig = new GroupSyncConfig.PairConfig();
|
||||||
|
pairConfig.roleId = Long.parseUnsignedLong(roleId);
|
||||||
|
pairConfig.groupName = (String) key;
|
||||||
|
pairConfig.direction = groupSyncDirection;
|
||||||
|
pairConfig.timer.cycleTime = groupSyncCycleTime;
|
||||||
|
|
||||||
|
mainConfig.groupSync.pairs.add(pairConfig);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void migrate(ConnectionConfig connectionConfig) {
|
||||||
|
connectionConfig.bot.token = config.node("BotToken").getString();
|
||||||
|
|
||||||
|
if (!config.node("ProxyHost").getString("").endsWith("example.com")) {
|
||||||
|
connectionConfig.httpProxy.enabled = true;
|
||||||
|
connectionConfig.httpProxy.host = config.node("ProxyHost").getString();
|
||||||
|
connectionConfig.httpProxy.port = config.node("ProxyPort").getInt();
|
||||||
|
connectionConfig.httpProxy.basicAuth.enabled = true;
|
||||||
|
connectionConfig.httpProxy.basicAuth.username = config.node("ProxyUser").getString();
|
||||||
|
connectionConfig.httpProxy.basicAuth.password = config.node("ProxyPassword").getString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -92,12 +92,15 @@ public class TemporaryLocalData {
|
|||||||
return new Model();
|
return new Model();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Model model;
|
||||||
try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(file))) {
|
try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(file))) {
|
||||||
return discordSRV.json().readValue(inputStream, Model.class);
|
model = discordSRV.json().readValue(inputStream, Model.class);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
discordSRV.logger().error("Failed to load temporary local data, resetting", e);
|
discordSRV.logger().error("Failed to load temporary local data, resetting", e);
|
||||||
return new Model();
|
return new Model();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return model != null ? model : new Model();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +114,5 @@ public class TemporaryLocalData {
|
|||||||
*/
|
*/
|
||||||
public Map<String, List<Long>> consoleThreadRotationIds = new HashMap<>();
|
public Map<String, List<Long>> consoleThreadRotationIds = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user