Skip to content

Commit

Permalink
[Change] Implement re-connecting to IPC Pipe if disconnected
Browse files Browse the repository at this point in the history
- This change integrates the Backoff logic from the Official RPC SDK, so that in the event of a disconnection, the Client will attempt to reconnect in subsequent `connect` executions, with increasing delays between `0.5 seconds` and `one minute`
- This only changes the behavior for an unexpected disconnection (Such as sending a Presence update while not connected to the RPC), it does not impact  a manual close (`onClose`)
  • Loading branch information
CDAGaming committed Jun 18, 2023
1 parent 876308e commit f35ac44
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 7 deletions.
37 changes: 30 additions & 7 deletions src/main/java/com/jagrosh/discordipc/IPCClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.jagrosh.discordipc.entities.pipe.Pipe;
import com.jagrosh.discordipc.entities.pipe.PipeStatus;
import com.jagrosh.discordipc.exceptions.NoDiscordClientException;
import com.jagrosh.discordipc.impl.Backoff;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -56,15 +57,17 @@
*/
public final class IPCClient implements Closeable {
private static final Logger LOGGER = LoggerFactory.getLogger(IPCClient.class);
private Logger FORCED_LOGGER = null;
private final Backoff RECONNECT_TIME_MS = new Backoff(500, 60 * 1000);
private final long clientId;
private final boolean autoRegister;
private final HashMap<String, Callback> callbacks = new HashMap<>();
private final String applicationId, optionalSteamId;
private volatile Pipe pipe;
private Logger forcedLogger = null;
private IPCListener listener = null;
private Thread readThread = null;
private String encoding = "UTF-8";
private long nextDelay = 0L;
private boolean debugMode;
private boolean verboseLogging;

Expand Down Expand Up @@ -213,7 +216,7 @@ private static int getPID() {
* @return the current logger to use
*/
public Logger getCurrentLogger(final Logger instance) {
return FORCED_LOGGER != null ? FORCED_LOGGER : instance;
return forcedLogger != null ? forcedLogger : instance;
}

/**
Expand All @@ -222,7 +225,7 @@ public Logger getCurrentLogger(final Logger instance) {
* @param forcedLogger The logger instance to be used
*/
public void setForcedLogger(Logger forcedLogger) {
FORCED_LOGGER = forcedLogger;
this.forcedLogger = forcedLogger;
}

/**
Expand Down Expand Up @@ -356,12 +359,24 @@ public void setVerboseLogging(boolean verboseLogging) {
* @throws IllegalStateException There is an open connection on this IPCClient.
* @throws NoDiscordClientException No client of the provided {@link DiscordBuild build type}(s) was found.
*/
public void connect(DiscordBuild... preferredOrder) throws NoDiscordClientException {
public void connect(DiscordBuild... preferredOrder) throws NoDiscordClientException, InterruptedException {
checkConnected(false);
long timeToConnect;
while ((timeToConnect = nextDelay - System.currentTimeMillis()) > 0) {
if (debugMode) {
getCurrentLogger(LOGGER).info("[DEBUG] Attempting connection in: " + timeToConnect + "ms");
}
Thread.sleep(timeToConnect);
}
callbacks.clear();
pipe = null;

pipe = Pipe.openPipe(this, clientId, callbacks, preferredOrder);
try {
pipe = Pipe.openPipe(this, clientId, callbacks, preferredOrder);
} catch (Exception ex) {
updateReconnectTime();
throw ex;
}

if (isAutoRegister()) {
try {
Expand Down Expand Up @@ -743,12 +758,20 @@ private void readPipe(final IPCClient instance) {
getCurrentLogger(LOGGER).error(String.format("Reading thread encountered an Exception: %s", ex));

pipe.setStatus(PipeStatus.DISCONNECTED);
if (listener != null)
if (listener != null) {
RECONNECT_TIME_MS.reset();
updateReconnectTime();
listener.onDisconnect(instance, ex);
}
}
}

// Private static methods
/**
* Sets the next delay before re-attempting connection.
*/
private void updateReconnectTime() {
nextDelay = System.currentTimeMillis() + RECONNECT_TIME_MS.nextDelay();
}

/**
* Constants representing a Response to an Ask to Join or Spectate Request
Expand Down
36 changes: 36 additions & 0 deletions src/main/java/com/jagrosh/discordipc/impl/Backoff.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.jagrosh.discordipc.impl;

import java.util.Random;
import java.util.concurrent.TimeUnit;

public class Backoff {
private final long minAmount;
private final long maxAmount;
private long current;
private int fails;
private final Random randGenerator;

public Backoff(long min, long max) {
this.minAmount = min;
this.maxAmount = max;
this.current = min;
this.fails = 0;
this.randGenerator = new Random();
}

public void reset() {
fails = 0;
current = minAmount;
}

public long nextDelay() {
fails++;
double delay = current * 2.0 * rand01();
current = Math.min(current + (long) delay, maxAmount);
return current;
}

private double rand01() {
return randGenerator.nextDouble();
}
}

0 comments on commit f35ac44

Please sign in to comment.