Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<String, SmartServiceTaskConfig> 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.
* <p>
* 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.
* <p>
* 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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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())

Expand Down Expand Up @@ -72,6 +76,8 @@ public enum TemplateInstaller {

public static class Builder {

private String targetTask;

private boolean enabled = false;
private int priority = 10;

Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
11 changes: 9 additions & 2 deletions modules/smart/impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,28 @@ 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)
}

tasks.shadowJar.configure {
archiveFileName = Files.smart
}

tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.add("-AaerogelAutoFileName=autoconfigure/smart.aero")
}

moduleJson {
name = "CloudNet-Smart"
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,46 @@
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;
import eu.cloudnetservice.driver.provider.ServiceTaskProvider;
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) {
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"))

Expand All @@ -62,26 +75,21 @@ public void rewriteOldSmartTaskEntries(@NonNull ServiceTaskProvider taskProvider
.percentOfPlayersForANewServiceByInstance(smartEntry.getInt("percentOfPlayersForANewServiceByInstance"))

.build();
} else if (!smartEntry.containsNonNull("targetTask")) {
var newEntry = smartEntry.mutableCopy().append("targetTask", task.name());
config = newEntry.toInstanceOf(SmartServiceTaskConfig.class);
}

// append the new smart entry and update the service
var newTask = ServiceTask.builder(task)
.modifyProperties(properties -> properties.append("smartConfig", config))
if (config != null) {
var updatedTask = ServiceTask.builder(task)
.modifyProperties(properties -> properties.remove("smartConfig"))
.build();
taskProvider.addServiceTask(newTask);
}
}
}
}
taskProvider.addServiceTask(updatedTask);

@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()))
.build();
taskProvider.addServiceTask(newTask);
if (config.enabled()) {
management.addSmartServiceTaskConfigSilently(config);
}
}
}
}
}
Expand All @@ -90,14 +98,14 @@ 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);
@ModuleTask(lifecycle = ModuleLifeCycle.RELOADING)
public void reload(@NonNull NodeSmartServiceManagement management) {
management.loadSmartConfigurations();
}
}
Loading
Loading