Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-12-24 23:30:26 +01:00
Improved Scheduler API (#696)
* Improved Scheduler API - Added `Scheduler#builder(plugin)` This method allows a more simplified builder while maintaining the main requirement of the executor plugin - Added `Scheduler#taskByPlugin(plugin)` Allows to obtain the tasks that a plugin has sent to execute and that are currently active - Added `TaskBuilder#task(Consumer<SchuledTask>)` Allows to specify a task with access to the task itself with the ability to cancel itself * Applied requested changes - Removed tasks builder method - Added `Scheduler#buildTask(plugin, Consumer<ScheduledTask>)` * Removed some unused imports * Applied suggested change * Fix possible test bug * Applied more suggested changes * Fixed tests inside tasks
Dieser Commit ist enthalten in:
Ursprung
f088bd4443
Commit
e45ca5f357
@ -7,11 +7,7 @@
|
|||||||
|
|
||||||
package com.velocitypowered.api.command;
|
package com.velocitypowered.api.command;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a command that can be executed by a {@link CommandSource}
|
* Represents a command that can be executed by a {@link CommandSource}
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
package com.velocitypowered.api.permission;
|
package com.velocitypowered.api.permission;
|
||||||
|
|
||||||
import net.kyori.adventure.permission.PermissionChecker;
|
import net.kyori.adventure.permission.PermissionChecker;
|
||||||
import net.kyori.adventure.util.TriState;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a object that has a set of queryable permissions.
|
* Represents a object that has a set of queryable permissions.
|
||||||
|
@ -23,7 +23,6 @@ import java.util.Collection;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.kyori.adventure.audience.Audience;
|
import net.kyori.adventure.audience.Audience;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an interface to a Minecraft server proxy.
|
* Provides an interface to a Minecraft server proxy.
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package com.velocitypowered.api.scheduler;
|
package com.velocitypowered.api.scheduler;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a task that is scheduled to run on the proxy.
|
* Represents a task that is scheduled to run on the proxy.
|
||||||
*/
|
*/
|
||||||
@ -17,7 +19,7 @@ public interface ScheduledTask {
|
|||||||
*
|
*
|
||||||
* @return the plugin that scheduled this task
|
* @return the plugin that scheduled this task
|
||||||
*/
|
*/
|
||||||
Object plugin();
|
@NotNull Object plugin();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current status of this task.
|
* Returns the current status of this task.
|
||||||
|
@ -8,8 +8,12 @@
|
|||||||
package com.velocitypowered.api.scheduler;
|
package com.velocitypowered.api.scheduler;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.checkerframework.common.value.qual.IntRange;
|
import org.checkerframework.common.value.qual.IntRange;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a scheduler to execute tasks on the proxy.
|
* Represents a scheduler to execute tasks on the proxy.
|
||||||
@ -23,7 +27,24 @@ public interface Scheduler {
|
|||||||
* @param runnable the task to run when scheduled
|
* @param runnable the task to run when scheduled
|
||||||
* @return the task builder
|
* @return the task builder
|
||||||
*/
|
*/
|
||||||
TaskBuilder buildTask(Object plugin, Runnable runnable);
|
TaskBuilder buildTask(@NotNull Object plugin, @NotNull Runnable runnable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new {@link TaskBuilder} for creating a task on the proxy.
|
||||||
|
*
|
||||||
|
* @param plugin the plugin to request the task for
|
||||||
|
* @param consumer the task to be run when scheduled with the capacity to cancel itself
|
||||||
|
* @return the task builder
|
||||||
|
*/
|
||||||
|
TaskBuilder buildTask(@NotNull Object plugin, @NotNull Consumer<ScheduledTask> consumer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link ScheduledTask} for a specific plugin.
|
||||||
|
*
|
||||||
|
* @param plugin the plugin object
|
||||||
|
* @return the list of {@link ScheduledTask} corresponding to a specific plugin
|
||||||
|
*/
|
||||||
|
@NotNull Collection<ScheduledTask> tasksByPlugin(@NotNull Object plugin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a fluent interface to schedule tasks on the proxy.
|
* Represents a fluent interface to schedule tasks on the proxy.
|
||||||
@ -37,7 +58,7 @@ public interface Scheduler {
|
|||||||
* @param unit the unit of time for {@code time}
|
* @param unit the unit of time for {@code time}
|
||||||
* @return this builder, for chaining
|
* @return this builder, for chaining
|
||||||
*/
|
*/
|
||||||
TaskBuilder delay(@IntRange(from = 0) long time, TimeUnit unit);
|
TaskBuilder delay(@IntRange(from = 0) long time, @NotNull TimeUnit unit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies that the task should delay its execution by the specified amount of time.
|
* Specifies that the task should delay its execution by the specified amount of time.
|
||||||
@ -45,7 +66,7 @@ public interface Scheduler {
|
|||||||
* @param duration the duration of the delay
|
* @param duration the duration of the delay
|
||||||
* @return this builder, for chaining
|
* @return this builder, for chaining
|
||||||
*/
|
*/
|
||||||
default TaskBuilder delay(Duration duration) {
|
default TaskBuilder delay(@NotNull Duration duration) {
|
||||||
return delay(duration.toMillis(), TimeUnit.MILLISECONDS);
|
return delay(duration.toMillis(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +78,7 @@ public interface Scheduler {
|
|||||||
* @param unit the unit of time for {@code time}
|
* @param unit the unit of time for {@code time}
|
||||||
* @return this builder, for chaining
|
* @return this builder, for chaining
|
||||||
*/
|
*/
|
||||||
TaskBuilder repeat(@IntRange(from = 0) long time, TimeUnit unit);
|
TaskBuilder repeat(@IntRange(from = 0) long time, @NotNull TimeUnit unit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies that the task should continue running after waiting for the specified amount, until
|
* Specifies that the task should continue running after waiting for the specified amount, until
|
||||||
@ -66,7 +87,7 @@ public interface Scheduler {
|
|||||||
* @param duration the duration of the delay
|
* @param duration the duration of the delay
|
||||||
* @return this builder, for chaining
|
* @return this builder, for chaining
|
||||||
*/
|
*/
|
||||||
default TaskBuilder repeat(Duration duration) {
|
default TaskBuilder repeat(@NotNull Duration duration) {
|
||||||
return repeat(duration.toMillis(), TimeUnit.MILLISECONDS);
|
return repeat(duration.toMillis(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ package com.velocitypowered.natives.compression;
|
|||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFER_SIZE;
|
import static com.velocitypowered.natives.compression.CompressorUtils.ZLIB_BUFFER_SIZE;
|
||||||
import static com.velocitypowered.natives.compression.CompressorUtils.ensureMaxSize;
|
|
||||||
|
|
||||||
import com.velocitypowered.natives.util.BufferPreference;
|
import com.velocitypowered.natives.util.BufferPreference;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
@ -34,9 +34,7 @@ import java.util.zip.DataFormatException;
|
|||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.condition.EnabledOnJre;
|
|
||||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||||
import org.junit.jupiter.api.condition.JRE;
|
|
||||||
|
|
||||||
class VelocityCompressorTest {
|
class VelocityCompressorTest {
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Multimaps;
|
import com.google.common.collect.Multimaps;
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import com.velocitypowered.api.plugin.PluginContainer;
|
|
||||||
import com.velocitypowered.api.plugin.PluginManager;
|
import com.velocitypowered.api.plugin.PluginManager;
|
||||||
import com.velocitypowered.api.scheduler.ScheduledTask;
|
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||||
import com.velocitypowered.api.scheduler.Scheduler;
|
import com.velocitypowered.api.scheduler.Scheduler;
|
||||||
@ -32,13 +31,17 @@ import com.velocitypowered.api.scheduler.TaskStatus;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class VelocityScheduler implements Scheduler {
|
public class VelocityScheduler implements Scheduler {
|
||||||
@ -68,7 +71,25 @@ public class VelocityScheduler implements Scheduler {
|
|||||||
checkNotNull(plugin, "plugin");
|
checkNotNull(plugin, "plugin");
|
||||||
checkNotNull(runnable, "runnable");
|
checkNotNull(runnable, "runnable");
|
||||||
checkArgument(pluginManager.fromInstance(plugin).isPresent(), "plugin is not registered");
|
checkArgument(pluginManager.fromInstance(plugin).isPresent(), "plugin is not registered");
|
||||||
return new TaskBuilderImpl(plugin, runnable);
|
return new TaskBuilderImpl(plugin, runnable, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskBuilder buildTask(Object plugin, Consumer<ScheduledTask> consumer) {
|
||||||
|
checkNotNull(plugin, "plugin");
|
||||||
|
checkNotNull(consumer, "consumer");
|
||||||
|
checkArgument(pluginManager.fromInstance(plugin).isPresent(), "plugin is not registered");
|
||||||
|
return new TaskBuilderImpl(plugin, null, consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull Collection<ScheduledTask> tasksByPlugin(@NonNull Object plugin) {
|
||||||
|
checkNotNull(plugin, "plugin");
|
||||||
|
checkArgument(pluginManager.fromInstance(plugin).isPresent(), "plugin is not registered");
|
||||||
|
final Collection<ScheduledTask> tasks = tasksByPlugin.get(plugin);
|
||||||
|
synchronized (tasksByPlugin) {
|
||||||
|
return Set.copyOf(tasks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,12 +114,14 @@ public class VelocityScheduler implements Scheduler {
|
|||||||
|
|
||||||
private final Object plugin;
|
private final Object plugin;
|
||||||
private final Runnable runnable;
|
private final Runnable runnable;
|
||||||
|
private final Consumer<ScheduledTask> consumer;
|
||||||
private long delay; // ms
|
private long delay; // ms
|
||||||
private long repeat; // ms
|
private long repeat; // ms
|
||||||
|
|
||||||
private TaskBuilderImpl(Object plugin, Runnable runnable) {
|
private TaskBuilderImpl(Object plugin, Runnable runnable, Consumer<ScheduledTask> consumer) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.runnable = runnable;
|
this.runnable = runnable;
|
||||||
|
this.consumer = consumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -127,7 +150,7 @@ public class VelocityScheduler implements Scheduler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ScheduledTask schedule() {
|
public ScheduledTask schedule() {
|
||||||
VelocityTask task = new VelocityTask(plugin, runnable, delay, repeat);
|
VelocityTask task = new VelocityTask(plugin, runnable, consumer, delay, repeat);
|
||||||
tasksByPlugin.put(plugin, task);
|
tasksByPlugin.put(plugin, task);
|
||||||
task.schedule();
|
task.schedule();
|
||||||
return task;
|
return task;
|
||||||
@ -138,14 +161,16 @@ public class VelocityScheduler implements Scheduler {
|
|||||||
|
|
||||||
private final Object plugin;
|
private final Object plugin;
|
||||||
private final Runnable runnable;
|
private final Runnable runnable;
|
||||||
|
private final Consumer<ScheduledTask> consumer;
|
||||||
private final long delay;
|
private final long delay;
|
||||||
private final long repeat;
|
private final long repeat;
|
||||||
private @Nullable ScheduledFuture<?> future;
|
private @Nullable ScheduledFuture<?> future;
|
||||||
private volatile @Nullable Thread currentTaskThread;
|
private volatile @Nullable Thread currentTaskThread;
|
||||||
|
|
||||||
private VelocityTask(Object plugin, Runnable runnable, long delay, long repeat) {
|
private VelocityTask(Object plugin, Runnable runnable, Consumer<ScheduledTask> consumer, long delay, long repeat) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.runnable = runnable;
|
this.runnable = runnable;
|
||||||
|
this.consumer = consumer;
|
||||||
this.delay = delay;
|
this.delay = delay;
|
||||||
this.repeat = repeat;
|
this.repeat = repeat;
|
||||||
}
|
}
|
||||||
@ -200,7 +225,11 @@ public class VelocityScheduler implements Scheduler {
|
|||||||
taskService.execute(() -> {
|
taskService.execute(() -> {
|
||||||
currentTaskThread = Thread.currentThread();
|
currentTaskThread = Thread.currentThread();
|
||||||
try {
|
try {
|
||||||
runnable.run();
|
if (runnable != null) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
consumer.accept(this);
|
||||||
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
if (e instanceof InterruptedException) {
|
if (e instanceof InterruptedException) {
|
||||||
|
@ -22,9 +22,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
import com.velocitypowered.api.scheduler.ScheduledTask;
|
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||||
import com.velocitypowered.api.scheduler.TaskStatus;
|
import com.velocitypowered.api.scheduler.TaskStatus;
|
||||||
import com.velocitypowered.proxy.testutil.FakePluginManager;
|
import com.velocitypowered.proxy.testutil.FakePluginManager;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
class VelocitySchedulerTest {
|
class VelocitySchedulerTest {
|
||||||
@ -65,4 +69,65 @@ class VelocitySchedulerTest {
|
|||||||
task.cancel();
|
task.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void obtainTasksFromPlugin() throws Exception {
|
||||||
|
VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager());
|
||||||
|
AtomicInteger i = new AtomicInteger(0);
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
scheduler.buildTask(FakePluginManager.PLUGIN_A, task -> {
|
||||||
|
if (i.getAndIncrement() >= 1) {
|
||||||
|
task.cancel();
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}).delay(50, TimeUnit.MILLISECONDS)
|
||||||
|
.repeat(Duration.ofMillis(5))
|
||||||
|
.schedule();
|
||||||
|
|
||||||
|
assertEquals(scheduler.tasksByPlugin(FakePluginManager.PLUGIN_A).size(), 1);
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
|
||||||
|
assertEquals(scheduler.tasksByPlugin(FakePluginManager.PLUGIN_A).size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConsumerCancel() throws Exception {
|
||||||
|
VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager());
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
ScheduledTask task = scheduler.buildTask(FakePluginManager.PLUGIN_B, actualTask -> {
|
||||||
|
actualTask.cancel();
|
||||||
|
latch.countDown();
|
||||||
|
})
|
||||||
|
.repeat(5, TimeUnit.MILLISECONDS)
|
||||||
|
.schedule();
|
||||||
|
|
||||||
|
assertEquals(TaskStatus.SCHEDULED, task.status());
|
||||||
|
|
||||||
|
latch.await();
|
||||||
|
|
||||||
|
assertEquals(TaskStatus.CANCELLED, task.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testConsumerEquality() throws Exception {
|
||||||
|
VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager());
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
AtomicReference<ScheduledTask> consumerTask = new AtomicReference<>();
|
||||||
|
AtomicReference<ScheduledTask> initialTask = new AtomicReference<>();
|
||||||
|
|
||||||
|
ScheduledTask task = scheduler.buildTask(FakePluginManager.PLUGIN_A, scheduledTask -> {
|
||||||
|
consumerTask.set(scheduledTask);
|
||||||
|
latch.countDown();
|
||||||
|
}).delay(60, TimeUnit.MILLISECONDS).schedule();
|
||||||
|
|
||||||
|
initialTask.set(task);
|
||||||
|
latch.await();
|
||||||
|
|
||||||
|
assertEquals(consumerTask.get(), initialTask.get());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren