X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fxdcc%2Fcore%2FConnectionBackoff.java;fp=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fxdcc%2Fcore%2FConnectionBackoff.java;h=5ba44a6281b1e71f9182a4fec0b44dcb8295d99d;hb=9ec3cf37feeaa7a3daa8e21df2c7580597aacf0b;hp=0000000000000000000000000000000000000000;hpb=60eeb8cc8d2ccd56dfae68cea32012443bbe50a8;p=xudocci.git diff --git a/src/main/java/net/pterodactylus/xdcc/core/ConnectionBackoff.java b/src/main/java/net/pterodactylus/xdcc/core/ConnectionBackoff.java new file mode 100644 index 0000000..5ba44a6 --- /dev/null +++ b/src/main/java/net/pterodactylus/xdcc/core/ConnectionBackoff.java @@ -0,0 +1,105 @@ +package net.pterodactylus.xdcc.core; + +import java.time.Clock; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import net.pterodactylus.xdcc.data.Network; + +/** + * Manages backoff times for connections. + * + * @author David ‘Bombe’ Roden + */ +public class ConnectionBackoff { + + private static final long MILLIS_PER_SECOND = TimeUnit.MINUTES.toMillis(1); + private static final long MILLIS_PER_HOUR = TimeUnit.HOURS.toMillis(1); + + private final Clock clock; + private final Map connectionFailures = new HashMap<>(); + + public ConnectionBackoff() { + this(Clock.systemDefaultZone()); + } + + public ConnectionBackoff(Clock clock) { + this.clock = clock; + } + + public void connectionFailed(Network network) { + ConnectionFailureCounter connectionFailureCounter = getConnectionFailureCounter(network); + connectionFailureCounter.countFailure(); + } + + public void connectionSuccessful(Network network) { + ConnectionFailureCounter connectionFailureCounter = getConnectionFailureCounter(network); + connectionFailureCounter.reset(); + } + + public long getBackoff(Network network) { + ConnectionFailureCounter connectionFailureCounter = getConnectionFailureCounter(network); + if (!connectionFailureCounter.hasFailure()) { + return 0; + } + long delay = (long) (MILLIS_PER_SECOND * + Math.pow(1.2, connectionFailureCounter.getFailureCount() - 1)); + return Math.min(MILLIS_PER_HOUR, Math.max(0, + (connectionFailureCounter.getLastFailureTime() + delay) - Instant.now(clock) + .toEpochMilli())); + } + + private ConnectionFailureCounter getConnectionFailureCounter(Network network) { + ConnectionFailureCounter connectionFailureCounter; + synchronized (connectionFailures) { + if (!connectionFailures.containsKey(network)) { + connectionFailures.put(network, new ConnectionFailureCounter()); + } + connectionFailureCounter = connectionFailures.get(network); + } + return connectionFailureCounter; + } + + private class ConnectionFailureCounter { + + private final Object lock = new Object(); + private int count; + private long lastFailureTime; + + public void reset() { + synchronized (lock) { + count = 0; + lastFailureTime = 0; + } + } + + public void countFailure() { + synchronized (lock) { + count++; + lastFailureTime = Instant.now(clock).toEpochMilli(); + } + } + + public boolean hasFailure() { + synchronized (lock) { + return (count > 0); + } + } + + public int getFailureCount() { + synchronized (lock) { + return count; + } + } + + public long getLastFailureTime() { + synchronized (lock) { + return lastFailureTime; + } + } + + } + +}