Skip to content

Commit

Permalink
Create SchedulerMainThreadBased to simplify implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
Rollczi committed Nov 15, 2024
1 parent 37f415c commit 56503a5
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package dev.rollczi.litecommands.bukkit;

import dev.rollczi.litecommands.scheduler.Scheduler;
import dev.rollczi.litecommands.scheduler.SchedulerPoll;
import dev.rollczi.litecommands.shared.ThrowingSupplier;
import dev.rollczi.litecommands.scheduler.SchedulerMainThreadBased;
import java.util.logging.Level;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitScheduler;

import java.time.Duration;
import java.util.concurrent.CompletableFuture;

class BukkitSchedulerImpl implements Scheduler {
class BukkitSchedulerImpl extends SchedulerMainThreadBased {

private final BukkitScheduler bukkitScheduler;
private final Plugin plugin;
Expand All @@ -21,64 +18,36 @@ class BukkitSchedulerImpl implements Scheduler {
this.plugin = plugin;
}

@Override
public <T> CompletableFuture<T> supplyLater(SchedulerPoll type, Duration delay, ThrowingSupplier<T, Throwable> supplier) {
SchedulerPoll resolved = type.resolve(SchedulerPoll.MAIN, SchedulerPoll.ASYNCHRONOUS);

if (resolved.equals(SchedulerPoll.MAIN)) {
return supplySync(type, supplier, delay);
}

if (resolved.equals(SchedulerPoll.ASYNCHRONOUS)) {
return supplyAsync(type, supplier, delay);
}

throw new IllegalArgumentException("Unknown scheduler poll type: " + type);
}

@Override
public void shutdown() {
}

private <T> CompletableFuture<T> supplySync(SchedulerPoll type, ThrowingSupplier<T, Throwable> supplier, Duration delay) {
CompletableFuture<T> future = new CompletableFuture<>();

@Override
protected void runSynchronous(Runnable task, Duration delay) {
if (Bukkit.isPrimaryThread() && delay.isZero()) {
return tryRun(type, future, supplier);
task.run();
return;
}

if (delay.isZero()) {
bukkitScheduler.runTask(plugin, () -> tryRun(type, future, supplier));
bukkitScheduler.runTask(plugin, task);
} else {
bukkitScheduler.runTaskLater(plugin, () -> tryRun(type, future, supplier), toTicks(delay));
bukkitScheduler.runTaskLater(plugin, task, toTicks(delay));
}

return future;
}

private <T> CompletableFuture<T> supplyAsync(SchedulerPoll type, ThrowingSupplier<T, Throwable> supplier, Duration delay) {
CompletableFuture<T> future = new CompletableFuture<>();

@Override
protected void runAsynchronous(Runnable task, Duration delay) {
if (delay.isZero()) {
bukkitScheduler.runTaskAsynchronously(plugin, () -> tryRun(type, future, supplier));
bukkitScheduler.runTaskAsynchronously(plugin, task);
} else {
bukkitScheduler.runTaskLaterAsynchronously(plugin, () -> tryRun(type, future, supplier), toTicks(delay));
bukkitScheduler.runTaskLaterAsynchronously(plugin, task, toTicks(delay));
}

return future;
}

private <T> CompletableFuture<T> tryRun(SchedulerPoll type, CompletableFuture<T> future, ThrowingSupplier<T, Throwable> supplier) {
try {
future.complete(supplier.get());
} catch (Throwable throwable) {
future.completeExceptionally(throwable);
if (type.isLogging()) {
plugin.getLogger().log(Level.SEVERE, "An error occurred while executing a task", throwable);
}
}

return future;
@Override
protected void log(Throwable throwable) {
this.plugin.getLogger().log(Level.SEVERE, "An error occurred while executing a task", throwable);
}

private long toTicks(Duration duration) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dev.rollczi.litecommands.scheduler;

import dev.rollczi.litecommands.shared.ThrowingSupplier;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;

public abstract class SchedulerMainThreadBased implements Scheduler {

@Override
public final <T> CompletableFuture<T> supplyLater(SchedulerPoll type, Duration delay, ThrowingSupplier<T, Throwable> supplier) {
SchedulerPoll resolved = type.resolve(SchedulerPoll.MAIN, SchedulerPoll.ASYNCHRONOUS);
CompletableFuture<T> future = new CompletableFuture<>();

if (resolved.equals(SchedulerPoll.MAIN)) {
runSynchronous(() -> tryRun(type, future, supplier), delay);
return future;
}

if (resolved.equals(SchedulerPoll.ASYNCHRONOUS)) {
runAsynchronous(() -> tryRun(type, future, supplier), delay);
return future;
}

throw new IllegalArgumentException("Unknown scheduler poll type: " + type);
}

abstract protected void runSynchronous(Runnable task, Duration delay);

protected abstract void runAsynchronous(Runnable task, Duration delay);

private <T> void tryRun(SchedulerPoll type, CompletableFuture<T> future, ThrowingSupplier<T, Throwable> supplier) {
try {
future.complete(supplier.get());
}
catch (Throwable throwable) {
future.completeExceptionally(throwable);

if (type.isLogging()) {
this.log(throwable);
}
}
}

protected void log(Throwable throwable) {}

}

0 comments on commit 56503a5

Please sign in to comment.