CancellationToken.java
package com.shengzhiai.yugu;
import java.util.ArrayList;
import java.util.List;
/**
* Cancels a REST call from another thread: the running attempt is aborted, a pending retry wait
* ends, and the call throws {@code RequestCancelledException} (90003).
*
* <pre>{@code
* CancellationToken token = new CancellationToken();
* executor.submit(() -> client.evaluate(audio, config, RequestOptions.builder().cancellation(token).build()));
* token.cancel();
* }</pre>
*/
public final class CancellationToken {
private final List<Runnable> callbacks = new ArrayList<>();
private boolean cancelled;
/** Cancels; idempotent. */
public void cancel() {
List<Runnable> run;
synchronized (this) {
if (cancelled) {
return;
}
cancelled = true;
run = new ArrayList<>(callbacks);
callbacks.clear();
}
for (Runnable r : run) {
try {
r.run();
} catch (RuntimeException ignored) {
// a callback must not prevent the others from running
}
}
}
/** @return true after {@link #cancel()} */
public synchronized boolean isCancelled() {
return cancelled;
}
/**
* Registers a callback that runs on cancel, or immediately when already cancelled. SDK internal.
*
* @param r callback
* @return a handle that unregisters the callback
*/
public Runnable onCancel(Runnable r) {
boolean runNow;
synchronized (this) {
runNow = cancelled;
if (!runNow) {
callbacks.add(r);
}
}
if (runNow) {
r.run();
return () -> { };
}
return () -> {
synchronized (CancellationToken.this) {
callbacks.remove(r);
}
};
}
}