From db2d227c36f828c8bb0368dc672138e9c1d4965a Mon Sep 17 00:00:00 2001 From: 0utplay Date: Sun, 23 Nov 2025 10:28:55 +0100 Subject: [PATCH 1/6] feat: move smart config into separate files --- .../modules/smart/SmartServiceManagement.java | 69 +++++++ .../modules/smart/SmartServiceTaskConfig.java | 14 ++ modules/smart/impl/build.gradle.kts | 10 +- .../smart/impl/CloudNetSmartModule.java | 48 +++-- .../impl/NodeSmartServiceManagement.java | 136 ++++++++++++++ .../modules/smart/impl/SmartCommand.java | 169 +++++++++++------- .../CloudNetLocalServiceListener.java | 12 +- .../CloudNetLocalServiceTaskListener.java | 38 ---- .../impl/listener/CloudNetTickListener.java | 10 +- .../listener/SmartConfigMessageListener.java | 52 ++++++ 10 files changed, 426 insertions(+), 132 deletions(-) create mode 100644 modules/smart/api/src/main/java/eu/cloudnetservice/modules/smart/SmartServiceManagement.java create mode 100644 modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/NodeSmartServiceManagement.java delete mode 100644 modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetLocalServiceTaskListener.java create mode 100644 modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/SmartConfigMessageListener.java diff --git a/modules/smart/api/src/main/java/eu/cloudnetservice/modules/smart/SmartServiceManagement.java b/modules/smart/api/src/main/java/eu/cloudnetservice/modules/smart/SmartServiceManagement.java new file mode 100644 index 0000000000..e7dd449ab0 --- /dev/null +++ b/modules/smart/api/src/main/java/eu/cloudnetservice/modules/smart/SmartServiceManagement.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019-present CloudNetService team & contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.cloudnetservice.modules.smart; + +import java.util.Map; +import lombok.NonNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnmodifiableView; + +/** + * Represents the management interface for smart service task configurations. + * + * @since 4.0 + */ +public interface SmartServiceManagement { + + /** + * Gets an unmodifiable view of all smart service task configurations mapped by their target task name. + * + * @return an unmodifiable view of all smart service task configurations. + */ + @NonNull + @UnmodifiableView + Map configurations(); + + /** + * Gets the smart service task entry with the given task name as {@link SmartServiceTaskConfig#targetTask()}. + * + * @param taskName the targetTask name of the smart service task configuration to get. + * @return the smart service task configuration or null if not present. + * @throws NullPointerException if the given task name is null. + */ + @Nullable SmartServiceTaskConfig smartServiceTaskConfig(@NonNull String taskName); + + /** + * Adds or updates the given smart service task configuration. If there is already a configuration for the same task + * name, the old one is replaced. + *

+ * The configuration is synced to all other nodes in the cluster. + * + * @param config the smart service task configuration to add. + * @throws NullPointerException if the given configuration is null. + */ + void addSmartServiceTaskConfig(@NonNull SmartServiceTaskConfig config); + + /** + * Removes the smart service task configuration based on the given task name. + *

+ * The configuration is removed from all other nodes in the cluster. + * + * @param taskName the targetTask name of the smart service task configuration to remove. + * @throws NullPointerException if the given task name is null. + */ + void removeSmartServiceTaskConfig(@NonNull String taskName); +} diff --git a/modules/smart/api/src/main/java/eu/cloudnetservice/modules/smart/SmartServiceTaskConfig.java b/modules/smart/api/src/main/java/eu/cloudnetservice/modules/smart/SmartServiceTaskConfig.java index c89a6df135..d82648371f 100644 --- a/modules/smart/api/src/main/java/eu/cloudnetservice/modules/smart/SmartServiceTaskConfig.java +++ b/modules/smart/api/src/main/java/eu/cloudnetservice/modules/smart/SmartServiceTaskConfig.java @@ -16,9 +16,11 @@ package eu.cloudnetservice.modules.smart; +import java.util.Objects; import lombok.NonNull; public record SmartServiceTaskConfig( + @NonNull String targetTask, boolean enabled, int priority, int maxServices, @@ -39,6 +41,8 @@ public record SmartServiceTaskConfig( public static @NonNull Builder builder(@NonNull SmartServiceTaskConfig config) { return builder() + .targetTask(config.targetTask()) + .enabled(config.enabled()) .priority(config.priority()) @@ -72,6 +76,8 @@ public enum TemplateInstaller { public static class Builder { + private String targetTask; + private boolean enabled = false; private int priority = 10; @@ -89,6 +95,11 @@ public static class Builder { private int forAnewInstanceDelayTimeInSeconds = 300; private int percentOfPlayersForANewServiceByInstance = 100; + public @NonNull Builder targetTask(@NonNull String targetTask) { + this.targetTask = targetTask; + return this; + } + public @NonNull Builder enabled(boolean enabled) { this.enabled = enabled; return this; @@ -150,7 +161,10 @@ public static class Builder { } public @NonNull SmartServiceTaskConfig build() { + Objects.requireNonNull(this.targetTask, "targetTask must be set"); + return new SmartServiceTaskConfig( + this.targetTask, this.enabled, this.priority, this.maxServices, diff --git a/modules/smart/impl/build.gradle.kts b/modules/smart/impl/build.gradle.kts index 90e5dda9f4..ea367ee9de 100644 --- a/modules/smart/impl/build.gradle.kts +++ b/modules/smart/impl/build.gradle.kts @@ -25,8 +25,12 @@ plugins { dependencies { compileOnly(libs.guava) - compileOnlyApi(projects.node.nodeApi) + compileOnlyApi(projects.node.nodeImpl) + compileOnlyApi(projects.utils.utilsBase) compileOnlyApi(projects.modules.bridge.bridgeApi) + + annotationProcessor(libs.aerogelAuto) + api(projects.modules.smart.smartApi) } @@ -34,6 +38,10 @@ tasks.shadowJar.configure { archiveFileName = Files.smart } +tasks.withType().configureEach { + options.compilerArgs.add("-AaerogelAutoFileName=autoconfigure/smart.aero") +} + moduleJson { name = "CloudNet-Smart" author = "CloudNetService" diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java index 3b8df68c57..fcec018fb4 100644 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java @@ -17,6 +17,7 @@ package eu.cloudnetservice.modules.smart.impl; import eu.cloudnetservice.driver.event.EventManager; +import eu.cloudnetservice.driver.inject.InjectionLayer; import eu.cloudnetservice.driver.module.ModuleLifeCycle; import eu.cloudnetservice.driver.module.ModuleTask; import eu.cloudnetservice.driver.module.driver.DriverModule; @@ -24,16 +25,22 @@ import eu.cloudnetservice.driver.service.ServiceTask; import eu.cloudnetservice.modules.smart.SmartServiceTaskConfig; import eu.cloudnetservice.modules.smart.impl.listener.CloudNetLocalServiceListener; -import eu.cloudnetservice.modules.smart.impl.listener.CloudNetLocalServiceTaskListener; import eu.cloudnetservice.modules.smart.impl.listener.CloudNetTickListener; +import eu.cloudnetservice.modules.smart.impl.listener.SmartConfigMessageListener; import eu.cloudnetservice.node.command.CommandProvider; +import jakarta.inject.Inject; +import jakarta.inject.Named; import jakarta.inject.Singleton; import lombok.NonNull; -import org.jetbrains.annotations.Nullable; @Singleton public class CloudNetSmartModule extends DriverModule { + @Inject + public CloudNetSmartModule(@NonNull @Named("module") InjectionLayer layer) { + layer.installAutoConfigureBindings(this.getClass().getClassLoader(), "smart"); + } + @ModuleTask(lifecycle = ModuleLifeCycle.STARTED, order = Byte.MAX_VALUE) public void rewriteOldSmartTaskEntries(@NonNull ServiceTaskProvider taskProvider) { for (var task : taskProvider.serviceTasks()) { @@ -44,6 +51,7 @@ public void rewriteOldSmartTaskEntries(@NonNull ServiceTaskProvider taskProvider if (smartEntry.contains("dynamicMemoryAllocationRange")) { // rewrite the old config var config = SmartServiceTaskConfig.builder() + .targetTask(task.name()) .enabled(smartEntry.getBoolean("enabled")) .priority(smartEntry.getInt("priority")) @@ -68,20 +76,33 @@ public void rewriteOldSmartTaskEntries(@NonNull ServiceTaskProvider taskProvider .modifyProperties(properties -> properties.append("smartConfig", config)) .build(); taskProvider.addServiceTask(newTask); + } else if (!smartEntry.containsNonNull("targetTask")) { + var newEntry = smartEntry.mutableCopy().append("targetTask", task.name()); + var newTask = ServiceTask.builder(task) + .modifyProperties(properties -> properties.append("smartConfig", newEntry)) + .build(); + taskProvider.addServiceTask(newTask); } } } } @ModuleTask(lifecycle = ModuleLifeCycle.STARTED, order = 64) - public void addMissingSmartConfigurationEntries(@NonNull ServiceTaskProvider taskProvider) { - for (var task : taskProvider.serviceTasks()) { - // check if the service task needs a smart entry - if (!task.propertyHolder().contains("smartConfig")) { - var newTask = ServiceTask.builder(task) - .modifyProperties(properties -> properties.append("smartConfig", SmartServiceTaskConfig.builder().build())) + public void moveSmartConfig( + @NonNull ServiceTaskProvider taskProvider, + @NonNull NodeSmartServiceManagement management + ) { + for (var serviceTask : taskProvider.serviceTasks()) { + var config = serviceTask.propertyHolder().readObject("smartConfig", SmartServiceTaskConfig.class); + if (config != null) { + var updatedTask = ServiceTask.builder(serviceTask) + .modifyProperties(properties -> properties.remove("smartConfig")) .build(); - taskProvider.addServiceTask(newTask); + taskProvider.addServiceTask(updatedTask); + + if (config.enabled()) { + management.addSmartServiceTaskConfigSilently(config); + } } } } @@ -90,14 +111,9 @@ public void addMissingSmartConfigurationEntries(@NonNull ServiceTaskProvider tas public void start(@NonNull EventManager eventManager, @NonNull CommandProvider commandProvider) { eventManager .registerListener(CloudNetTickListener.class) - .registerListener(CloudNetLocalServiceListener.class) - .registerListener(CloudNetLocalServiceTaskListener.class); + .registerListener(SmartConfigMessageListener.class) + .registerListener(CloudNetLocalServiceListener.class); commandProvider.register(SmartCommand.class); } - - public @Nullable SmartServiceTaskConfig smartConfig(@NonNull ServiceTask task) { - // try to get the smart config entry - return task.propertyHolder().readObject("smartConfig", SmartServiceTaskConfig.class); - } } diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/NodeSmartServiceManagement.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/NodeSmartServiceManagement.java new file mode 100644 index 0000000000..0582328893 --- /dev/null +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/NodeSmartServiceManagement.java @@ -0,0 +1,136 @@ +/* + * Copyright 2019-present CloudNetService team & contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.cloudnetservice.modules.smart.impl; + +import dev.derklaro.aerogel.auto.annotation.Provides; +import eu.cloudnetservice.driver.channel.ChannelMessage; +import eu.cloudnetservice.driver.document.DocumentFactory; +import eu.cloudnetservice.modules.smart.SmartServiceManagement; +import eu.cloudnetservice.modules.smart.SmartServiceTaskConfig; +import eu.cloudnetservice.node.cluster.sync.DataSyncRegistry; +import eu.cloudnetservice.node.impl.cluster.sync.DefaultDataSyncHandler; +import eu.cloudnetservice.utils.base.io.FileUtil; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.inject.Singleton; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import lombok.NonNull; +import org.jetbrains.annotations.Nullable; + +@Singleton +@Provides(SmartServiceManagement.class) +public final class NodeSmartServiceManagement implements SmartServiceManagement { + + public static final String SMART_CONFIG_ADD = "add_smart_config"; + public static final String SMART_CONFIG_REMOVE = "remove_smart_config"; + public static final String SMART_CHANNEL_NAME = "internal_smart_channel"; + + private final Path dataDirectory; + private final Map smartConfigs = new ConcurrentHashMap<>(); + + @Inject + public NodeSmartServiceManagement( + @NonNull @Named("dataDirectory") Path dataDirectory, + @NonNull DataSyncRegistry syncRegistry + ) { + this.dataDirectory = dataDirectory; + + this.loadSmartConfigurations(); + syncRegistry.registerHandler(DefaultDataSyncHandler.builder() + .key("smart-configs") + .nameExtractor(SmartServiceTaskConfig::targetTask) + .dataCollector(this.smartConfigs::values) + .convertObject(SmartServiceTaskConfig.class) + .currentGetter(config -> this.smartServiceTaskConfig(config.targetTask())) + .writer(this::addSmartServiceTaskConfigSilently) + .build()); + } + + /** + * {@inheritDoc} + */ + @Override + public @NonNull Map configurations() { + return Collections.unmodifiableMap(this.smartConfigs); + } + + /** + * {@inheritDoc} + */ + @Override + public @Nullable SmartServiceTaskConfig smartServiceTaskConfig(@NonNull String taskName) { + return this.smartConfigs.get(taskName); + } + + /** + * {@inheritDoc} + */ + @Override + public void addSmartServiceTaskConfig(@NonNull SmartServiceTaskConfig config) { + ChannelMessage.builder() + .targetNodes() + .channel(SMART_CHANNEL_NAME) + .message(SMART_CONFIG_ADD) + .build(buffer -> buffer.writeObject(config)) + .send(); + this.addSmartServiceTaskConfigSilently(config); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeSmartServiceTaskConfig(@NonNull String taskName) { + ChannelMessage.builder() + .targetNodes() + .channel(SMART_CHANNEL_NAME) + .message(SMART_CONFIG_REMOVE) + .build(buffer -> buffer.writeString(taskName)) + .send(); + this.removeSmartServiceTaskConfigSilently(taskName); + } + + public void addSmartServiceTaskConfigSilently(@NonNull SmartServiceTaskConfig config) { + this.smartConfigs.put(config.targetTask(), config); + DocumentFactory.json().newDocument(config).writeTo(this.smartConfigFile(config.targetTask())); + } + + public void removeSmartServiceTaskConfigSilently(@NonNull String taskName) { + this.smartConfigs.remove(taskName); + FileUtil.delete(this.smartConfigFile(taskName)); + } + + void loadSmartConfigurations() { + FileUtil.walkFileTree(this.dataDirectory, (_, file) -> { + var config = DocumentFactory.json().parse(file).toInstanceOf(SmartServiceTaskConfig.class); + var taskName = file.getFileName().toString().replace(".json", ""); + if (!taskName.equals(config.targetTask())) { + FileUtil.move(file, this.smartConfigFile(config.targetTask()), StandardCopyOption.REPLACE_EXISTING); + } + + this.smartConfigs.put(config.targetTask(), config); + }, false, "*.json"); + } + + private @NonNull Path smartConfigFile(@NonNull String taskName) { + return this.dataDirectory.resolve(taskName + ".json"); + } +} diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/SmartCommand.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/SmartCommand.java index 1a2ffaa710..01893ed15a 100644 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/SmartCommand.java +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/SmartCommand.java @@ -20,7 +20,7 @@ import eu.cloudnetservice.driver.language.I18n; import eu.cloudnetservice.driver.provider.ServiceTaskProvider; import eu.cloudnetservice.driver.registry.Service; -import eu.cloudnetservice.driver.service.ServiceTask; +import eu.cloudnetservice.modules.smart.SmartServiceManagement; import eu.cloudnetservice.modules.smart.SmartServiceTaskConfig; import eu.cloudnetservice.node.command.annotation.Description; import eu.cloudnetservice.node.command.exception.ArgumentNotAvailableException; @@ -43,45 +43,91 @@ @Description("module-smart-command-description") public class SmartCommand { - private final ServiceTaskProvider taskProvider; + private final SmartServiceManagement smartManagement; + private final ServiceTaskProvider serviceTaskProvider; @Inject - public SmartCommand(@NonNull ServiceTaskProvider taskProvider) { - this.taskProvider = taskProvider; + public SmartCommand( + @NonNull SmartServiceManagement smartManagement, + @NonNull ServiceTaskProvider serviceTaskProvider + ) { + this.smartManagement = smartManagement; + this.serviceTaskProvider = serviceTaskProvider; } - @Parser(name = "smartTask", suggestions = "smartTask") - public @NonNull ServiceTask smartTaskParser(@NonNull @Service I18n i18n, @NonNull CommandInput input) { - var task = this.taskProvider.serviceTask(input.readString()); - if (task == null) { - throw new ArgumentNotAvailableException(i18n.translate("command-tasks-task-not-found")); - } - // only allow tasks with the smart config - if (!task.propertyHolder().contains("smartConfig")) { - throw new ArgumentNotAvailableException(i18n.translate("module-smart-command-task-no-entry", task.name())); + @Parser(suggestions = "smartConfig") + public @NonNull SmartServiceTaskConfig smartConfigParser(@NonNull @Service I18n i18n, @NonNull CommandInput input) { + var targetTask = input.readString(); + var config = this.smartManagement.smartServiceTaskConfig(targetTask); + if (config == null) { + throw new ArgumentNotAvailableException(i18n.translate("module-smart-command-task-no-entry", targetTask)); } - return task; + + return config; } - @Suggestions("smartTask") + @Suggestions("smartConfig") public @NonNull Stream suggestSmartTasks() { - return this.taskProvider.serviceTasks() + return this.smartManagement.configurations() + .values() .stream() - .filter(serviceTask -> serviceTask.propertyHolder().contains("smartConfig")) - .map(Named::name); + .map(SmartServiceTaskConfig::targetTask); + } + + @Parser(name = "newSmartConfigs", suggestions = "newSmartConfigs") + public @NonNull String newSmartConfigParser(@NonNull @Service I18n i18n, @NonNull CommandInput input) { + var taskName = input.readString(); + var task = this.serviceTaskProvider.serviceTask(taskName); + if (task == null) { + throw new ArgumentNotAvailableException(i18n.translate("command-tasks-task-not-found", taskName)); + } + + var config = this.smartManagement.smartServiceTaskConfig(taskName); + if (config != null) { + throw new ArgumentNotAvailableException(i18n.translate("module-smart-command-task-already-exists", taskName)); + } + + return taskName; + } + + @Suggestions("newSmartConfigs") + public @NonNull Stream suggestNewSmartConfigs() { + return this.serviceTaskProvider.serviceTasks().stream() + .map(Named::name) + .filter(taskName -> this.smartManagement.smartServiceTaskConfig(taskName) == null); + } + + @Command("smart create ") + public void createEntry( + @NonNull @Service I18n i18n, + @NonNull CommandSource source, + @NonNull @Argument(value = "task", parserName = "newSmartConfigs") String taskName + ) { + this.updateSmart(SmartServiceTaskConfig.builder().targetTask(taskName).build(), Function.identity()); + source.sendMessage(i18n.translate("module-smart-command-task-created", taskName)); + } + + @Command("smart delete ") + public void deleteEntry( + @NonNull @Service I18n i18n, + @NonNull CommandSource source, + @NonNull @Argument("task") SmartServiceTaskConfig config + ) { + this.smartManagement.removeSmartServiceTaskConfig(config.targetTask()); + source.sendMessage(i18n.translate("module-smart-command-task-deleted", config.targetTask())); } @Command("smart task enabled ") public void enable( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("enabled") boolean enabled ) { - this.updateSmart(task, config -> config.enabled(enabled)); + this.updateSmart(config, builder -> builder.enabled(enabled)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", - "enabled", task.name(), + "enabled", config.targetTask(), enabled)); } @@ -89,14 +135,14 @@ public void enable( public void priority( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("priority") int priority ) { - this.updateSmart(task, config -> config.priority(priority)); + this.updateSmart(config, builder -> builder.priority(priority)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "priority", - task.name(), + config.targetTask(), priority)); } @@ -104,14 +150,14 @@ public void priority( public void maxServices( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("amount") int maxServices ) { - this.updateSmart(task, config -> config.maxServices(maxServices)); + this.updateSmart(config, builder -> builder.maxServices(maxServices)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "maxServices", - task.name(), + config.targetTask(), maxServices)); } @@ -119,15 +165,15 @@ public void maxServices( public void preparedServices( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("amount") int preparedServices ) { - this.updateSmart(task, config -> config.preparedServices(preparedServices)); + this.updateSmart(config, builder -> builder.preparedServices(preparedServices)); source.sendMessage( i18n.translate( "command-tasks-set-property-success", "preparedServices", - task.name(), + config.targetTask(), preparedServices)); } @@ -135,15 +181,15 @@ public void preparedServices( public void smartMinServiceCount( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("amount") int smartMinServiceCount ) { - this.updateSmart(task, config -> config.smartMinServiceCount(smartMinServiceCount)); + this.updateSmart(config, builder -> builder.smartMinServiceCount(smartMinServiceCount)); source.sendMessage( i18n.translate( "command-tasks-set-property-success", "smartMinServiceCount", - task.name(), + config.targetTask(), smartMinServiceCount)); } @@ -151,15 +197,15 @@ public void smartMinServiceCount( public void splitLogicallyOverNodes( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("enabled") boolean enabled ) { - this.updateSmart(task, config -> config.splitLogicallyOverNodes(enabled)); + this.updateSmart(config, builder -> builder.splitLogicallyOverNodes(enabled)); source.sendMessage( i18n.translate( "command-tasks-set-property-success", "splitLogicallyOverNodes", - task.name(), + config.targetTask(), enabled)); } @@ -167,14 +213,14 @@ public void splitLogicallyOverNodes( public void directTemplatesAndInclusionsSetup( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("enabled") boolean enabled ) { - this.updateSmart(task, config -> config.directTemplatesAndInclusionsSetup(enabled)); + this.updateSmart(config, builder -> builder.directTemplatesAndInclusionsSetup(enabled)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "directTemplatesAndInclusionsSetup", - task.name(), + config.targetTask(), enabled)); } @@ -182,14 +228,14 @@ public void directTemplatesAndInclusionsSetup( public void templateInstaller( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @NonNull @Argument("installer") SmartServiceTaskConfig.TemplateInstaller installer ) { - this.updateSmart(task, config -> config.templateInstaller(installer)); + this.updateSmart(config, builder -> builder.templateInstaller(installer)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "templateInstaller", - task.name(), + config.targetTask(), installer)); } @@ -197,14 +243,14 @@ public void templateInstaller( public void autoStopTimeByUnusedServiceInSeconds( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("seconds") int seconds ) { - this.updateSmart(task, config -> config.autoStopTimeByUnusedServiceInSeconds(seconds)); + this.updateSmart(config, builder -> builder.autoStopTimeByUnusedServiceInSeconds(seconds)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "autoStopTimeByUnusedServiceInSeconds", - task.name(), + config.targetTask(), seconds)); } @@ -212,14 +258,14 @@ public void autoStopTimeByUnusedServiceInSeconds( public void percentOfPlayersToCheckShouldStopTheService( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("percent") @Range(min = "0", max = "100") int percent ) { - this.updateSmart(task, config -> config.percentOfPlayersToCheckShouldStop(percent)); + this.updateSmart(config, builder -> builder.percentOfPlayersToCheckShouldStop(percent)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "percentOfPlayersToCheckShouldStop", - task.name(), + config.targetTask(), percent)); } @@ -227,14 +273,14 @@ public void percentOfPlayersToCheckShouldStopTheService( public void forAnewInstanceDelayTimeInSeconds( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("seconds") int seconds ) { - this.updateSmart(task, config -> config.forAnewInstanceDelayTimeInSeconds(seconds)); + this.updateSmart(config, builder -> builder.forAnewInstanceDelayTimeInSeconds(seconds)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "forAnewInstanceDelayTimeInSeconds", - task.name(), + config.targetTask(), seconds)); } @@ -242,31 +288,22 @@ public void forAnewInstanceDelayTimeInSeconds( public void percentOfPlayersForANewServiceByInstance( @NonNull @Service I18n i18n, @NonNull CommandSource source, - @NonNull @Argument(value = "task", parserName = "smartTask") ServiceTask task, + @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("percent") @Range(min = "0", max = "100") int percent ) { - this.updateSmart(task, config -> config.percentOfPlayersForANewServiceByInstance(percent)); + this.updateSmart(config, builder -> builder.percentOfPlayersForANewServiceByInstance(percent)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "percentOfPlayersForANewServiceByInstance", - task.name(), + config.targetTask(), percent)); } private void updateSmart( - @NonNull ServiceTask serviceTask, + @NonNull SmartServiceTaskConfig config, @NonNull Function modifier ) { - // read the smart config from the task - var property = serviceTask.propertyHolder().readObject("smartConfig", SmartServiceTaskConfig.class); - - // rewrite the config and update it in the cluster - var task = ServiceTask.builder(serviceTask) - .modifyProperties(properties -> { - var newSmartConfigEntry = modifier.apply(SmartServiceTaskConfig.builder(property)).build(); - properties.append("smartConfig", newSmartConfigEntry); - }) - .build(); - this.taskProvider.addServiceTask(task); + var resultingConfig = modifier.apply(SmartServiceTaskConfig.builder(config)).build(); + this.smartManagement.addSmartServiceTaskConfig(resultingConfig); } } diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetLocalServiceListener.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetLocalServiceListener.java index 61752baf81..cefeaa78bf 100644 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetLocalServiceListener.java +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetLocalServiceListener.java @@ -23,8 +23,8 @@ import eu.cloudnetservice.driver.service.ServiceLifeCycle; import eu.cloudnetservice.driver.service.ServiceTask; import eu.cloudnetservice.driver.service.ServiceTemplate; +import eu.cloudnetservice.modules.smart.SmartServiceManagement; import eu.cloudnetservice.modules.smart.SmartServiceTaskConfig; -import eu.cloudnetservice.modules.smart.impl.CloudNetSmartModule; import eu.cloudnetservice.node.event.service.CloudServicePostLifecycleEvent; import eu.cloudnetservice.node.event.service.CloudServicePrePrepareEvent; import eu.cloudnetservice.node.service.CloudService; @@ -40,17 +40,17 @@ @Singleton public final class CloudNetLocalServiceListener { - private final CloudNetSmartModule module; private final ServiceTaskProvider taskProvider; + private final SmartServiceManagement management; private final CloudServiceProvider cloudServiceProvider; @Inject public CloudNetLocalServiceListener( - @NonNull CloudNetSmartModule module, @NonNull ServiceTaskProvider taskProvider, + @NonNull SmartServiceManagement management, @NonNull CloudServiceProvider cloudServiceProvider ) { - this.module = module; + this.management = management; this.taskProvider = taskProvider; this.cloudServiceProvider = cloudServiceProvider; } @@ -65,7 +65,7 @@ public void handle(@NonNull CloudServicePostLifecycleEvent event) { } // include templates and inclusions if configured - var config = this.module.smartConfig(task); + var config = this.management.smartServiceTaskConfig(task.name()); if (config != null && config.enabled() && config.directTemplatesAndInclusionsSetup()) { this.installTemplates(config, task, event.service()); @@ -90,7 +90,7 @@ public void handlePrePrepare(@NonNull CloudServicePrePrepareEvent event) { return; } - var config = this.module.smartConfig(task); + var config = this.management.smartServiceTaskConfig(task.name()); if (config != null && config.enabled()) { if (config.directTemplatesAndInclusionsSetup()) { // remove all initial templates & inclusions from the waiting templates, as they diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetLocalServiceTaskListener.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetLocalServiceTaskListener.java deleted file mode 100644 index 98e5b9cb29..0000000000 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetLocalServiceTaskListener.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2019-present CloudNetService team & contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package eu.cloudnetservice.modules.smart.impl.listener; - -import eu.cloudnetservice.driver.event.EventListener; -import eu.cloudnetservice.driver.service.ServiceTask; -import eu.cloudnetservice.modules.smart.SmartServiceTaskConfig; -import eu.cloudnetservice.node.event.task.LocalServiceTaskAddEvent; -import jakarta.inject.Singleton; -import lombok.NonNull; - -@Singleton -public final class CloudNetLocalServiceTaskListener { - - @EventListener - public void handle(@NonNull LocalServiceTaskAddEvent event) { - if (!event.task().propertyHolder().contains("smartConfig")) { - var newTask = ServiceTask.builder(event.task()) - .modifyProperties(properties -> properties.append("smartConfig", SmartServiceTaskConfig.builder().build())) - .build(); - event.task(newTask); - } - } -} diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetTickListener.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetTickListener.java index 39cc25037f..c8b5a534e0 100644 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetTickListener.java +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/CloudNetTickListener.java @@ -25,8 +25,8 @@ import eu.cloudnetservice.driver.service.ServiceLifeCycle; import eu.cloudnetservice.driver.service.ServiceTask; import eu.cloudnetservice.modules.bridge.BridgeDocProperties; +import eu.cloudnetservice.modules.smart.SmartServiceManagement; import eu.cloudnetservice.modules.smart.SmartServiceTaskConfig; -import eu.cloudnetservice.modules.smart.impl.CloudNetSmartModule; import eu.cloudnetservice.modules.smart.impl.util.SmartUtil; import eu.cloudnetservice.node.cluster.NodeServer; import eu.cloudnetservice.node.cluster.NodeServerProvider; @@ -50,8 +50,8 @@ @Singleton public final class CloudNetTickListener { - private final CloudNetSmartModule module; private final ServiceTaskProvider taskProvider; + private final SmartServiceManagement management; private final CloudServiceManager serviceManager; private final CloudServiceFactory serviceFactory; private final NodeServerProvider nodeServerProvider; @@ -61,14 +61,14 @@ public final class CloudNetTickListener { @Inject public CloudNetTickListener( - @NonNull CloudNetSmartModule module, @NonNull ServiceTaskProvider taskProvider, + @NonNull SmartServiceManagement management, @NonNull CloudServiceManager serviceManager, @NonNull CloudServiceFactory serviceFactory, @NonNull NodeServerProvider nodeServerProvider ) { - this.module = module; this.taskProvider = taskProvider; + this.management = management; this.serviceManager = serviceManager; this.serviceFactory = serviceFactory; this.nodeServerProvider = nodeServerProvider; @@ -81,7 +81,7 @@ public void handleTick(@NonNull CloudNetTickServiceStartEvent event) { private void handleSmartEntries() { this.taskProvider.serviceTasks().forEach(task -> { - var config = this.module.smartConfig(task); + var config = this.management.smartServiceTaskConfig(task.name()); if (config != null && config.enabled()) { // get all services of the task var services = this.serviceManager.servicesByTask(task.name()); diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/SmartConfigMessageListener.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/SmartConfigMessageListener.java new file mode 100644 index 0000000000..35ea0827ed --- /dev/null +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/listener/SmartConfigMessageListener.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019-present CloudNetService team & contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package eu.cloudnetservice.modules.smart.impl.listener; + +import eu.cloudnetservice.driver.event.EventListener; +import eu.cloudnetservice.driver.event.events.channel.ChannelMessageReceiveEvent; +import eu.cloudnetservice.modules.smart.SmartServiceTaskConfig; +import eu.cloudnetservice.modules.smart.impl.NodeSmartServiceManagement; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import lombok.NonNull; + +@Singleton +public final class SmartConfigMessageListener { + + private final NodeSmartServiceManagement nodeSmartServiceManagement; + + @Inject + public SmartConfigMessageListener(@NonNull NodeSmartServiceManagement nodeSmartServiceManagement) { + this.nodeSmartServiceManagement = nodeSmartServiceManagement; + } + + @EventListener + private void handleChannelMessage(@NonNull ChannelMessageReceiveEvent event) { + if (NodeSmartServiceManagement.SMART_CHANNEL_NAME.equals(event.channel())) { + switch (event.message()) { + case NodeSmartServiceManagement.SMART_CONFIG_ADD -> { + var config = event.content().readObject(SmartServiceTaskConfig.class); + this.nodeSmartServiceManagement.addSmartServiceTaskConfigSilently(config); + } + case NodeSmartServiceManagement.SMART_CONFIG_REMOVE -> { + var taskName = event.content().readString(); + this.nodeSmartServiceManagement.removeSmartServiceTaskConfigSilently(taskName); + } + } + } + } +} From 360e3becd5718598250bd57d494e108e778e3ff6 Mon Sep 17 00:00:00 2001 From: 0utplay Date: Sun, 23 Nov 2025 11:38:52 +0100 Subject: [PATCH 2/6] chore: lang files --- node/impl/src/main/resources/lang/de_DE.properties | 8 +++----- node/impl/src/main/resources/lang/en_US.properties | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/node/impl/src/main/resources/lang/de_DE.properties b/node/impl/src/main/resources/lang/de_DE.properties index 85e67ba1ef..b075ec3a71 100644 --- a/node/impl/src/main/resources/lang/de_DE.properties +++ b/node/impl/src/main/resources/lang/de_DE.properties @@ -51,7 +51,6 @@ server-network-connection-denied=Die Verbindungsanfrage von {0$clientAddress$} a network-listener-bound=Ein Netzwerk-Listener wurde erfolgreich an die Adresse "{0$address$}" gebunden... network-listener-bound-exceptionally=Ein Netzwerk Listener konnte nicht auf "{0$address$}" gebunden werden\: {1$reason$} network-selected-transport=Netzwerkkomponenten verwenden {0$transport$} Transport -network-selected-dispatch-thread-type=Netzwerk-Dispatcher verwenden {0$type$} Threads startup-failed-no-network-listener-bound=Cloudnet konnte nicht gestartet werden, da keine Netzwerk Listener gebunden wurden\! CloudNet stoppt in 5 Sekunden # # Application lifecycle @@ -194,10 +193,6 @@ command-create-by-task-starting={1$amount$} Services von {0$task$} werden erstel command-create-by-task-failed=Die Services konnten nicht erstellt werden command-create-by-task-success=Die Services wurden basierend auf dem Task erstellt. Sie können mit dem Befehl 'service' verwaltet werden # -# Command Debug -# -command-debug-description=Schaltet den globalen Debug-Modus um -# # Command exit # command-exit-description=Stoppt das Programm und alle verwalteten Prozesse @@ -382,6 +377,9 @@ module-syncproxy-command-set-maxplayers=Das Spielerlimit der Konfiguration {0$gr # module-smart-command-description=Administration der Smart-Config von jedem Tasks module-smart-command-task-no-entry=Der Task {0$task$} hat keinen konfigurierten Smart-Eintrag +module-smart-command-task-already-exists=Der Task {0$task$} hat bereits einen konfigurierten Smart-Eintrag +module-smart-command-task-created=Der Smart-Eintrag für den Task {0$task$} wurde erstellt +module-smart-command-task-deleted=Der Smart-Eintrag für den Task {0$task$} wurde gelöscht # # Module Docker Services # diff --git a/node/impl/src/main/resources/lang/en_US.properties b/node/impl/src/main/resources/lang/en_US.properties index f76744642b..f62e160f49 100644 --- a/node/impl/src/main/resources/lang/en_US.properties +++ b/node/impl/src/main/resources/lang/en_US.properties @@ -51,7 +51,6 @@ server-network-connection-denied=Connection request from {0$clientAddress$} to n network-listener-bound=Successfully bound a network listener to the address "{0$address$}"... network-listener-bound-exceptionally=Unable to bind network listener to "{0$address$}": {1$reason$} network-selected-transport=Network components are using {0$transport$} transport -network-selected-dispatch-thread-type=Network dispatchers are using {0$type$} threads startup-failed-no-network-listener-bound=Unable to complete startup, no network listener was bound successfully! CloudNet will stop in 5 seconds # # Application lifecycle @@ -194,10 +193,6 @@ command-create-by-task-starting=Starting to create {1$amount$} services for {0$t command-create-by-task-failed=The services couldn't be created command-create-by-task-success=The services were created based on the task. They can be managed with the 'service' command # -# Command Debug -# -command-debug-description=Toggle the global debug mode -# # Command exit # command-exit-description=Stops the program and all managed subprocesses @@ -382,6 +377,9 @@ module-syncproxy-command-set-maxplayers=The player limit of configuration {0$gro # module-smart-command-description=Administration for the smart config of each task module-smart-command-task-no-entry=The task {0$task$} has no configured smart entry +module-smart-command-task-already-exists=The task {0$task$} already has a smart entry +module-smart-command-task-created=The smart entry for task {0$task$} was created +module-smart-command-task-deleted=The smart entry for task {0$task$} was deleted # # Module Docker Services # From 15e9e9574a884c07d422989e6c157842d9e483ff Mon Sep 17 00:00:00 2001 From: 0utplay Date: Sun, 23 Nov 2025 16:15:59 +0100 Subject: [PATCH 3/6] chore: reloading --- .../modules/smart/impl/CloudNetSmartModule.java | 5 +++++ .../modules/smart/impl/NodeSmartServiceManagement.java | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java index fcec018fb4..ecf5f4d6fa 100644 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java @@ -116,4 +116,9 @@ public void start(@NonNull EventManager eventManager, @NonNull CommandProvider c commandProvider.register(SmartCommand.class); } + + @ModuleTask(lifecycle = ModuleLifeCycle.RELOADING) + public void reload(@NonNull NodeSmartServiceManagement management) { + management.loadSmartConfigurations(); + } } diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/NodeSmartServiceManagement.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/NodeSmartServiceManagement.java index 0582328893..058fcf5ac6 100644 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/NodeSmartServiceManagement.java +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/NodeSmartServiceManagement.java @@ -53,7 +53,6 @@ public NodeSmartServiceManagement( ) { this.dataDirectory = dataDirectory; - this.loadSmartConfigurations(); syncRegistry.registerHandler(DefaultDataSyncHandler.builder() .key("smart-configs") .nameExtractor(SmartServiceTaskConfig::targetTask) @@ -62,6 +61,7 @@ public NodeSmartServiceManagement( .currentGetter(config -> this.smartServiceTaskConfig(config.targetTask())) .writer(this::addSmartServiceTaskConfigSilently) .build()); + this.loadSmartConfigurations(); } /** @@ -119,6 +119,8 @@ public void removeSmartServiceTaskConfigSilently(@NonNull String taskName) { } void loadSmartConfigurations() { + this.smartConfigs.clear(); + FileUtil.walkFileTree(this.dataDirectory, (_, file) -> { var config = DocumentFactory.json().parse(file).toInstanceOf(SmartServiceTaskConfig.class); var taskName = file.getFileName().toString().replace(".json", ""); @@ -126,7 +128,7 @@ void loadSmartConfigurations() { FileUtil.move(file, this.smartConfigFile(config.targetTask()), StandardCopyOption.REPLACE_EXISTING); } - this.smartConfigs.put(config.targetTask(), config); + this.addSmartServiceTaskConfig(config); }, false, "*.json"); } From 998313d08db4d4e015026d6b9d3cb492b12f3248 Mon Sep 17 00:00:00 2001 From: 0utplay Date: Sun, 23 Nov 2025 16:16:51 +0100 Subject: [PATCH 4/6] chore: reloading --- modules/smart/impl/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/smart/impl/build.gradle.kts b/modules/smart/impl/build.gradle.kts index ea367ee9de..1503fb76cf 100644 --- a/modules/smart/impl/build.gradle.kts +++ b/modules/smart/impl/build.gradle.kts @@ -47,7 +47,6 @@ moduleJson { author = "CloudNetService" main = "eu.cloudnetservice.modules.smart.impl.CloudNetSmartModule" description = "CloudNet extension, which implement smart network handling and automatic services providing" - runtimeModule = true // depend on internal modules dependencies.add(ModuleConfiguration.Dependency("CloudNet-Bridge").apply { needsRepoResolve = false From 4ddb37058c820182921f488787e59a55f5e3fa34 Mon Sep 17 00:00:00 2001 From: 0utplay Date: Sun, 30 Nov 2025 17:44:30 +0100 Subject: [PATCH 5/6] chore: merge update, conversion & splitting into one step --- .../smart/impl/CloudNetSmartModule.java | 47 +++++++------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java index ecf5f4d6fa..9da7381814 100644 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/CloudNetSmartModule.java @@ -42,15 +42,20 @@ public CloudNetSmartModule(@NonNull @Named("module") InjectionLayer layer) { } @ModuleTask(lifecycle = ModuleLifeCycle.STARTED, order = Byte.MAX_VALUE) - public void rewriteOldSmartTaskEntries(@NonNull ServiceTaskProvider taskProvider) { + public void rewriteOldSmartTaskEntries( + @NonNull ServiceTaskProvider taskProvider, + @NonNull NodeSmartServiceManagement management + ) { for (var task : taskProvider.serviceTasks()) { // check if the task had a smart config entry previously if (task.propertyHolder().contains("smartConfig")) { + SmartServiceTaskConfig config = null; + // check if the task still uses the old format var smartEntry = task.propertyHolder().readDocument("smartConfig"); if (smartEntry.contains("dynamicMemoryAllocationRange")) { // rewrite the old config - var config = SmartServiceTaskConfig.builder() + config = SmartServiceTaskConfig.builder() .targetTask(task.name()) .enabled(smartEntry.getBoolean("enabled")) .priority(smartEntry.getInt("priority")) @@ -70,38 +75,20 @@ public void rewriteOldSmartTaskEntries(@NonNull ServiceTaskProvider taskProvider .percentOfPlayersForANewServiceByInstance(smartEntry.getInt("percentOfPlayersForANewServiceByInstance")) .build(); - - // append the new smart entry and update the service - var newTask = ServiceTask.builder(task) - .modifyProperties(properties -> properties.append("smartConfig", config)) - .build(); - taskProvider.addServiceTask(newTask); } else if (!smartEntry.containsNonNull("targetTask")) { var newEntry = smartEntry.mutableCopy().append("targetTask", task.name()); - var newTask = ServiceTask.builder(task) - .modifyProperties(properties -> properties.append("smartConfig", newEntry)) - .build(); - taskProvider.addServiceTask(newTask); + config = newEntry.toInstanceOf(SmartServiceTaskConfig.class); } - } - } - } - @ModuleTask(lifecycle = ModuleLifeCycle.STARTED, order = 64) - public void moveSmartConfig( - @NonNull ServiceTaskProvider taskProvider, - @NonNull NodeSmartServiceManagement management - ) { - for (var serviceTask : taskProvider.serviceTasks()) { - var config = serviceTask.propertyHolder().readObject("smartConfig", SmartServiceTaskConfig.class); - if (config != null) { - var updatedTask = ServiceTask.builder(serviceTask) - .modifyProperties(properties -> properties.remove("smartConfig")) - .build(); - taskProvider.addServiceTask(updatedTask); - - if (config.enabled()) { - management.addSmartServiceTaskConfigSilently(config); + if (config != null) { + var updatedTask = ServiceTask.builder(task) + .modifyProperties(properties -> properties.remove("smartConfig")) + .build(); + taskProvider.addServiceTask(updatedTask); + + if (config.enabled()) { + management.addSmartServiceTaskConfigSilently(config); + } } } } From 3d6d9caff6bdb8bea13459377295f3fc3e5b998c Mon Sep 17 00:00:00 2001 From: 0utplay Date: Mon, 15 Dec 2025 12:33:31 +0100 Subject: [PATCH 6/6] chore: rename config update method --- .../modules/smart/impl/SmartCommand.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/SmartCommand.java b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/SmartCommand.java index 01893ed15a..8665771b2f 100644 --- a/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/SmartCommand.java +++ b/modules/smart/impl/src/main/java/eu/cloudnetservice/modules/smart/impl/SmartCommand.java @@ -103,7 +103,7 @@ public void createEntry( @NonNull CommandSource source, @NonNull @Argument(value = "task", parserName = "newSmartConfigs") String taskName ) { - this.updateSmart(SmartServiceTaskConfig.builder().targetTask(taskName).build(), Function.identity()); + this.updateSmartConfig(SmartServiceTaskConfig.builder().targetTask(taskName).build(), Function.identity()); source.sendMessage(i18n.translate("module-smart-command-task-created", taskName)); } @@ -124,7 +124,7 @@ public void enable( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("enabled") boolean enabled ) { - this.updateSmart(config, builder -> builder.enabled(enabled)); + this.updateSmartConfig(config, builder -> builder.enabled(enabled)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "enabled", config.targetTask(), @@ -138,7 +138,7 @@ public void priority( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("priority") int priority ) { - this.updateSmart(config, builder -> builder.priority(priority)); + this.updateSmartConfig(config, builder -> builder.priority(priority)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "priority", @@ -153,7 +153,7 @@ public void maxServices( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("amount") int maxServices ) { - this.updateSmart(config, builder -> builder.maxServices(maxServices)); + this.updateSmartConfig(config, builder -> builder.maxServices(maxServices)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "maxServices", @@ -168,7 +168,7 @@ public void preparedServices( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("amount") int preparedServices ) { - this.updateSmart(config, builder -> builder.preparedServices(preparedServices)); + this.updateSmartConfig(config, builder -> builder.preparedServices(preparedServices)); source.sendMessage( i18n.translate( "command-tasks-set-property-success", @@ -184,7 +184,7 @@ public void smartMinServiceCount( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("amount") int smartMinServiceCount ) { - this.updateSmart(config, builder -> builder.smartMinServiceCount(smartMinServiceCount)); + this.updateSmartConfig(config, builder -> builder.smartMinServiceCount(smartMinServiceCount)); source.sendMessage( i18n.translate( "command-tasks-set-property-success", @@ -200,7 +200,7 @@ public void splitLogicallyOverNodes( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("enabled") boolean enabled ) { - this.updateSmart(config, builder -> builder.splitLogicallyOverNodes(enabled)); + this.updateSmartConfig(config, builder -> builder.splitLogicallyOverNodes(enabled)); source.sendMessage( i18n.translate( "command-tasks-set-property-success", @@ -216,7 +216,7 @@ public void directTemplatesAndInclusionsSetup( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("enabled") boolean enabled ) { - this.updateSmart(config, builder -> builder.directTemplatesAndInclusionsSetup(enabled)); + this.updateSmartConfig(config, builder -> builder.directTemplatesAndInclusionsSetup(enabled)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "directTemplatesAndInclusionsSetup", @@ -231,7 +231,7 @@ public void templateInstaller( @NonNull @Argument("task") SmartServiceTaskConfig config, @NonNull @Argument("installer") SmartServiceTaskConfig.TemplateInstaller installer ) { - this.updateSmart(config, builder -> builder.templateInstaller(installer)); + this.updateSmartConfig(config, builder -> builder.templateInstaller(installer)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "templateInstaller", @@ -246,7 +246,7 @@ public void autoStopTimeByUnusedServiceInSeconds( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("seconds") int seconds ) { - this.updateSmart(config, builder -> builder.autoStopTimeByUnusedServiceInSeconds(seconds)); + this.updateSmartConfig(config, builder -> builder.autoStopTimeByUnusedServiceInSeconds(seconds)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "autoStopTimeByUnusedServiceInSeconds", @@ -261,7 +261,7 @@ public void percentOfPlayersToCheckShouldStopTheService( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("percent") @Range(min = "0", max = "100") int percent ) { - this.updateSmart(config, builder -> builder.percentOfPlayersToCheckShouldStop(percent)); + this.updateSmartConfig(config, builder -> builder.percentOfPlayersToCheckShouldStop(percent)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "percentOfPlayersToCheckShouldStop", @@ -276,7 +276,7 @@ public void forAnewInstanceDelayTimeInSeconds( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("seconds") int seconds ) { - this.updateSmart(config, builder -> builder.forAnewInstanceDelayTimeInSeconds(seconds)); + this.updateSmartConfig(config, builder -> builder.forAnewInstanceDelayTimeInSeconds(seconds)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "forAnewInstanceDelayTimeInSeconds", @@ -291,7 +291,7 @@ public void percentOfPlayersForANewServiceByInstance( @NonNull @Argument("task") SmartServiceTaskConfig config, @Argument("percent") @Range(min = "0", max = "100") int percent ) { - this.updateSmart(config, builder -> builder.percentOfPlayersForANewServiceByInstance(percent)); + this.updateSmartConfig(config, builder -> builder.percentOfPlayersForANewServiceByInstance(percent)); source.sendMessage(i18n.translate( "command-tasks-set-property-success", "percentOfPlayersForANewServiceByInstance", @@ -299,7 +299,7 @@ public void percentOfPlayersForANewServiceByInstance( percent)); } - private void updateSmart( + private void updateSmartConfig( @NonNull SmartServiceTaskConfig config, @NonNull Function modifier ) {