java-commons/src/main/java/io/gitlab/jfronny/commons/concurrent/AsyncRequest.java

64 lines
1.8 KiB
Java

package io.gitlab.jfronny.commons.concurrent;
import io.gitlab.jfronny.commons.SamWithReceiver;
import io.gitlab.jfronny.commons.ref.R;
import java.util.Objects;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.function.Consumer;
public class AsyncRequest {
private final Action action;
private final Runnable finalize;
private final AsyncRequestState state = new AsyncRequestState();
private Future<Void> future = null;
public AsyncRequest(Action action, Runnable finalize) {
this.action = Objects.requireNonNull(action);
this.finalize = Objects.requireNonNull(finalize);
}
public AsyncRequest(Consumer<Context> runnable) {
this.action = (context, callback) -> new VoidFuture(ForkJoinPool.commonPool().submit(() -> {
runnable.accept(context);
callback.run();
}));
this.finalize = R::nop;
}
public void request() {
if (state.request().shouldStart()) start();
}
private void start() {
Future<Void>[] tasks = new Future[0];
future = tasks[0] = action.schedule(new Context() {
@Override
public boolean isCancelled() {
return tasks[0].isCancelled();
}
}, () -> {
if (!tasks[0].isCancelled()) {
finalize.run();
future = null;
}
if (state.emitFinished().shouldContinue()) start();
});
}
public void cancel() {
if (future != null) future.cancel(false);
state.cancel();
}
@SamWithReceiver
interface Action {
Future<Void> schedule(Context context, Runnable callback);
}
interface Context {
boolean isCancelled();
}
}