From d677ae842c3c6b44b734ea8d71a66052f8cf58d1 Mon Sep 17 00:00:00 2001
From: OpalSoPL <90208316+OpalSoPL@users.noreply.github.com>
Date: Fri, 25 Jul 2025 18:39:20 +0200
Subject: [PATCH 1/2] feat: terminate connection after exceeding set amount of
tries
---
DiscordRPC/DiscordRpcClient.cs | 38 +++++++-
DiscordRPC/Events.cs | 7 ++
DiscordRPC/Message/MessageType.cs | 8 +-
.../Message/TooManyConnectionTriesMessage.cs | 13 +++
DiscordRPC/RPC/RpcConnection.cs | 95 +++++++++++--------
5 files changed, 117 insertions(+), 44 deletions(-)
create mode 100644 DiscordRPC/Message/TooManyConnectionTriesMessage.cs
diff --git a/DiscordRPC/DiscordRpcClient.cs b/DiscordRPC/DiscordRpcClient.cs
index 1c58df9c..7ea0e3b6 100644
--- a/DiscordRPC/DiscordRpcClient.cs
+++ b/DiscordRPC/DiscordRpcClient.cs
@@ -18,6 +18,20 @@ public sealed class DiscordRpcClient : IDisposable
{
#region Properties
+ ///
+ /// Maximal amount of tries before aborting connection. If -1, then limit isn't present.
+ ///
+ /// 15 should be optimal value (~70s)
+ public int MaxConnectionTries
+ {
+ get { return _maxConnectionTries; }
+ set
+ {
+ _maxConnectionTries = value;
+ if (connection != null) connection.MaxConnectionTries = value;
+ }
+ }
+ private int _maxConnectionTries;
///
/// Gets a value indicating if the client has registered a URI Scheme. If this is false, Join / Spectate events will fail.
@@ -41,7 +55,7 @@ public sealed class DiscordRpcClient : IDisposable
public int ProcessID { get; private set; }
///
- /// The maximum size of the message queue received from Discord.
+ /// The maximum size of the message queue received from Discord.
///
public int MaxQueueSize { get; private set; }
@@ -196,6 +210,11 @@ public bool ShutdownOnly
/// The RPC Connection has sent a message. Called before any other event and executed from the RPC Thread.
///
public event OnRpcMessageEvent OnRpcMessage;
+
+ ///
+ /// Too many failed connection tries. You must reinitialize the client.
+ ///
+ public event OnTooMannyConnectionTriesEvent OnTooMannyConnectionTries;
#endregion
#region Initialization
@@ -214,7 +233,11 @@ public DiscordRpcClient(string applicationID) : this(applicationID, -1) { }
/// The logger used to report messages. If null, then a will be created and logs will be ignored.
/// Should events be automatically invoked from the RPC Thread as they arrive from discord?
/// The pipe client to use and communicate to discord through. If null, the default will be used.
- public DiscordRpcClient(string applicationID, int pipe = -1, ILogger logger = null, bool autoEvents = true, INamedPipeClient client = null)
+ ///
+ /// The maximum number of connection attempts before terminating.
+ /// Use -1 to disable the limit entirely. A value of 15 is typically optimal (~70 seconds).
+ ///
+ public DiscordRpcClient(string applicationID, int pipe = -1, ILogger logger = null, bool autoEvents = true, INamedPipeClient client = null, int maxConnectionTries = -1)
{
//Make sure appID is NOT null.
if (string.IsNullOrEmpty(applicationID))
@@ -227,6 +250,7 @@ public DiscordRpcClient(string applicationID, int pipe = -1, ILogger logger = nu
HasRegisteredUriScheme = false;
AutoEvents = autoEvents;
SkipIdenticalPresence = true;
+ _maxConnectionTries = maxConnectionTries;
//Prepare the logger
_logger = logger ?? new NullLogger();
@@ -235,7 +259,8 @@ public DiscordRpcClient(string applicationID, int pipe = -1, ILogger logger = nu
connection = new RpcConnection(ApplicationID, ProcessID, TargetPipe, client ?? new ManagedNamedPipeClient(), autoEvents ? 0 : 128U)
{
ShutdownOnly = _shutdownOnly,
- Logger = _logger
+ Logger = _logger,
+ MaxConnectionTries = _maxConnectionTries
};
//Subscribe to its event
@@ -404,6 +429,13 @@ private void ProcessMessage(IMessage message)
if (OnConnectionFailed != null)
OnConnectionFailed.Invoke(this, message as ConnectionFailedMessage);
break;
+
+ case MessageType.TooMannyConnectionTries:
+ if (OnTooMannyConnectionTries != null)
+ OnTooMannyConnectionTries.Invoke(this, message as TooManyConnectionTriesMessage);
+
+ Deinitialize();
+ break;
//We got a message we dont know what to do with.
default:
diff --git a/DiscordRPC/Events.cs b/DiscordRPC/Events.cs
index b28c7fec..3d98078d 100644
--- a/DiscordRPC/Events.cs
+++ b/DiscordRPC/Events.cs
@@ -84,6 +84,13 @@ namespace DiscordRPC.Events
/// The arguments supplied with the event
public delegate void OnConnectionFailedEvent(object sender, ConnectionFailedMessage args);
+ ///
+ /// Too many failed connection tries. You must reinitialize the client.
+ ///
+ /// The Discord client handler that sent this event
+ /// The arguments supplied with the event
+ public delegate void OnTooMannyConnectionTriesEvent(object sender, TooManyConnectionTriesMessage args);
+
///
/// A RPC Message is received.
diff --git a/DiscordRPC/Message/MessageType.cs b/DiscordRPC/Message/MessageType.cs
index 223291ee..42f2d146 100644
--- a/DiscordRPC/Message/MessageType.cs
+++ b/DiscordRPC/Message/MessageType.cs
@@ -35,7 +35,7 @@ public enum MessageType
/// The Discord Client has unsubscribed from an event.
///
Unsubscribe,
-
+
///
/// The Discord Client wishes for this process to join a game.
///
@@ -59,6 +59,10 @@ public enum MessageType
///
/// Failed to establish any connection with discord. Discord is potentially not running?
///
- ConnectionFailed
+ ConnectionFailed,
+ ///
+ /// Too many failed connection tries. You must reinitialize the client.
+ ///
+ TooMannyConnectionTries
}
}
diff --git a/DiscordRPC/Message/TooManyConnectionTriesMessage.cs b/DiscordRPC/Message/TooManyConnectionTriesMessage.cs
new file mode 100644
index 00000000..e9d6eb30
--- /dev/null
+++ b/DiscordRPC/Message/TooManyConnectionTriesMessage.cs
@@ -0,0 +1,13 @@
+namespace DiscordRPC.Message
+{
+ ///
+ /// Too many failed connection tries. You must reinitialize the client.
+ ///
+ public class TooManyConnectionTriesMessage : IMessage
+ {
+ ///
+ /// The type of message received from discord
+ ///
+ public override MessageType Type { get { return MessageType.TooMannyConnectionTries; } }
+ }
+}
diff --git a/DiscordRPC/RPC/RpcConnection.cs b/DiscordRPC/RPC/RpcConnection.cs
index fd8ea6a4..19ca9da2 100644
--- a/DiscordRPC/RPC/RpcConnection.cs
+++ b/DiscordRPC/RPC/RpcConnection.cs
@@ -52,10 +52,12 @@ public ILogger Logger
}
private ILogger _logger;
+ public int MaxConnectionTries { get; set; }
+
///
- /// Called when a message is received from the RPC and is about to be enqueued. This is cross-thread and will execute on the RPC thread.
- ///
- public event OnRpcMessageEvent OnRpcMessage;
+ /// Called when a message is received from the RPC and is about to be enqueued. This is cross-thread and will execute on the RPC thread.
+ ///
+ public event OnRpcMessageEvent OnRpcMessage;
#region States
@@ -118,6 +120,7 @@ public RpcState State
private AutoResetEvent queueUpdatedEvent = new AutoResetEvent(false);
private BackoffDelay delay; //The backoff delay before reconnecting.
+ private int tries; //number of unsuccessful connections in row
#endregion
///
@@ -127,26 +130,28 @@ public RpcState State
/// The ID of the currently running process
/// The target pipe to connect too
/// The pipe client we shall use.
- /// The maximum size of the out queue
- /// The maximum size of the in queue
- public RpcConnection(string applicationID, int processID, int targetPipe, INamedPipeClient client, uint maxRxQueueSize = 128, uint maxRtQueueSize = 512)
+ /// The maximum size of the out queue
+ /// The maximum size of the in queue
+ /// The maximum amount of tries taken before terminating
+ public RpcConnection(string applicationID, int processID, int targetPipe, INamedPipeClient client, uint maxRxQueueSize = 128, uint maxRtQueueSize = 512, int maxConnectionTries = -1)
{
this.applicationID = applicationID;
this.processID = processID;
this.targetPipe = targetPipe;
- this.namedPipe = client;
- this.ShutdownOnly = true;
+ namedPipe = client;
+ ShutdownOnly = true;
+ MaxConnectionTries = maxConnectionTries;
//Assign a default logger
Logger = new ConsoleLogger();
delay = new BackoffDelay(500, 60 * 1000);
- _maxRtQueueSize = maxRtQueueSize;
+ _maxRtQueueSize = maxRtQueueSize;
_rtqueue = new Queue((int)_maxRtQueueSize + 1);
- _maxRxQueueSize = maxRxQueueSize;
- _rxqueue = new Queue((int)_maxRxQueueSize + 1);
-
+ _maxRxQueueSize = maxRxQueueSize;
+ _rxqueue = new Queue((int)_maxRxQueueSize + 1);
+
nonce = 0;
}
@@ -263,31 +268,31 @@ internal IMessage[] DequeueMessages()
}
}
#endregion
-
+
///
/// Main thread loop
///
private void MainLoop()
{
- //initialize the pipe
- Logger.Info("RPC Connection Started");
- if (Logger.Level <= LogLevel.Trace)
- {
- Logger.Trace("============================");
- Logger.Trace("Assembly: " + System.Reflection.Assembly.GetAssembly(typeof(RichPresence)).FullName);
- Logger.Trace("Pipe: " + namedPipe.GetType().FullName);
- Logger.Trace("Platform: " + Environment.OSVersion.ToString());
- Logger.Trace("applicationID: " + applicationID);
- Logger.Trace("targetPipe: " + targetPipe);
- Logger.Trace("POLL_RATE: " + POLL_RATE);
- Logger.Trace("_maxRtQueueSize: " + _maxRtQueueSize);
- Logger.Trace("_maxRxQueueSize: " + _maxRxQueueSize);
- Logger.Trace("============================");
- }
+ //initialize the pipe
+ Logger.Info("RPC Connection Started");
+ if (Logger.Level <= LogLevel.Trace)
+ {
+ Logger.Trace("============================");
+ Logger.Trace("Assembly: " + System.Reflection.Assembly.GetAssembly(typeof(RichPresence)).FullName);
+ Logger.Trace("Pipe: " + namedPipe.GetType().FullName);
+ Logger.Trace("Platform: " + Environment.OSVersion.ToString());
+ Logger.Trace("applicationID: " + applicationID);
+ Logger.Trace("targetPipe: " + targetPipe);
+ Logger.Trace("POLL_RATE: " + POLL_RATE);
+ Logger.Trace("_maxRtQueueSize: " + _maxRtQueueSize);
+ Logger.Trace("_maxRxQueueSize: " + _maxRxQueueSize);
+ Logger.Trace("============================");
+ }
- //Forever trying to connect unless the abort signal is sent
- //Keep Alive Loop
- while (!aborting && !shutdown)
+ //Forever trying to connect unless the abort signal is sent
+ //Keep Alive Loop
+ while (!aborting && !shutdown)
{
try
{
@@ -312,6 +317,7 @@ private void MainLoop()
//Attempt to establish a handshake
EstablishHandshake();
Logger.Trace("Connection Established. Starting reading loop...");
+ tries = 0;
//Continously iterate, waiting for the frame
//We want to only stop reading if the inside tells us (mainloop), if we are aborting (abort) or the pipe disconnects
@@ -341,19 +347,19 @@ private void MainLoop()
break;
//We have pinged, so we will flip it and respond back with pong
- case Opcode.Ping:
+ case Opcode.Ping:
Logger.Trace("PING");
frame.Opcode = Opcode.Pong;
namedPipe.WriteFrame(frame);
break;
//We have ponged? I have no idea if Discord actually sends ping/pongs.
- case Opcode.Pong:
+ case Opcode.Pong:
Logger.Trace("PONG");
break;
//A frame has been sent, we should deal with that
- case Opcode.Frame:
+ case Opcode.Frame:
if (shutdown)
{
//We are shutting down, so skip it
@@ -370,21 +376,23 @@ private void MainLoop()
//We have a frame, so we are going to process the payload and add it to the stack
EventPayload response = null;
- try { response = frame.GetObject(); } catch (Exception e)
+ try { response = frame.GetObject(); }
+ catch (Exception e)
{
Logger.Error("Failed to parse event! {0}", e.Message);
Logger.Error("Data: {0}", frame.Message);
}
- try { if (response != null) ProcessFrame(response); } catch(Exception e)
- {
+ try { if (response != null) ProcessFrame(response); }
+ catch (Exception e)
+ {
Logger.Error("Failed to process event! {0}", e.Message);
Logger.Error("Data: {0}", frame.Message);
}
break;
-
+
default:
case Opcode.Handshake:
@@ -398,7 +406,7 @@ private void MainLoop()
}
if (!aborting && namedPipe.IsConnected)
- {
+ {
//Process the entire command queue we have left
ProcessCommandQueue();
@@ -425,9 +433,18 @@ private void MainLoop()
// so we are going to wait a bit before doing it again
long sleep = delay.NextDelay();
+ tries++;
+
Logger.Trace("Waiting {0}ms before attempting to connect again", sleep);
Thread.Sleep(delay.NextDelay());
}
+ if (tries >= MaxConnectionTries && MaxConnectionTries != -1)
+ {
+ Logger.Error("Terminating attempts to connect, exceeded amount of tries");
+
+ EnqueueMessage(new TooManyConnectionTriesMessage());
+ break;
+ }
}
//catch(InvalidPipeException e)
//{
From 5c792f3f1b50dbf33c2dfa5cd366c8dd78cb139e Mon Sep 17 00:00:00 2001
From: OpalSoPL <90208316+OpalSoPL@users.noreply.github.com>
Date: Fri, 25 Jul 2025 18:46:06 +0200
Subject: [PATCH 2/2] fix: typo in tooManyConnectionTries
---
DiscordRPC/DiscordRpcClient.cs | 8 ++++----
DiscordRPC/Events.cs | 2 +-
DiscordRPC/Message/MessageType.cs | 2 +-
DiscordRPC/Message/TooManyConnectionTriesMessage.cs | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/DiscordRPC/DiscordRpcClient.cs b/DiscordRPC/DiscordRpcClient.cs
index 7ea0e3b6..d7a0d200 100644
--- a/DiscordRPC/DiscordRpcClient.cs
+++ b/DiscordRPC/DiscordRpcClient.cs
@@ -214,7 +214,7 @@ public bool ShutdownOnly
///
/// Too many failed connection tries. You must reinitialize the client.
///
- public event OnTooMannyConnectionTriesEvent OnTooMannyConnectionTries;
+ public event OnTooManyConnectionTriesEvent OnTooManyConnectionTries;
#endregion
#region Initialization
@@ -430,9 +430,9 @@ private void ProcessMessage(IMessage message)
OnConnectionFailed.Invoke(this, message as ConnectionFailedMessage);
break;
- case MessageType.TooMannyConnectionTries:
- if (OnTooMannyConnectionTries != null)
- OnTooMannyConnectionTries.Invoke(this, message as TooManyConnectionTriesMessage);
+ case MessageType.TooManyConnectionTries:
+ if (OnTooManyConnectionTries != null)
+ OnTooManyConnectionTries.Invoke(this, message as TooManyConnectionTriesMessage);
Deinitialize();
break;
diff --git a/DiscordRPC/Events.cs b/DiscordRPC/Events.cs
index 3d98078d..7556d74d 100644
--- a/DiscordRPC/Events.cs
+++ b/DiscordRPC/Events.cs
@@ -89,7 +89,7 @@ namespace DiscordRPC.Events
///
/// The Discord client handler that sent this event
/// The arguments supplied with the event
- public delegate void OnTooMannyConnectionTriesEvent(object sender, TooManyConnectionTriesMessage args);
+ public delegate void OnTooManyConnectionTriesEvent(object sender, TooManyConnectionTriesMessage args);
///
diff --git a/DiscordRPC/Message/MessageType.cs b/DiscordRPC/Message/MessageType.cs
index 42f2d146..3e1f1f1e 100644
--- a/DiscordRPC/Message/MessageType.cs
+++ b/DiscordRPC/Message/MessageType.cs
@@ -63,6 +63,6 @@ public enum MessageType
///
/// Too many failed connection tries. You must reinitialize the client.
///
- TooMannyConnectionTries
+ TooManyConnectionTries
}
}
diff --git a/DiscordRPC/Message/TooManyConnectionTriesMessage.cs b/DiscordRPC/Message/TooManyConnectionTriesMessage.cs
index e9d6eb30..32a76d7b 100644
--- a/DiscordRPC/Message/TooManyConnectionTriesMessage.cs
+++ b/DiscordRPC/Message/TooManyConnectionTriesMessage.cs
@@ -8,6 +8,6 @@ public class TooManyConnectionTriesMessage : IMessage
///
/// The type of message received from discord
///
- public override MessageType Type { get { return MessageType.TooMannyConnectionTries; } }
+ public override MessageType Type { get { return MessageType.TooManyConnectionTries; } }
}
}