Skip to content

Commit 3dc8309

Browse files
committed
feat(core): promote AuthenticationFailureException + ConnectionAttemptFailedException to public top-level types
Both exceptions used to live as `internal sealed class` definitions nested at the bottom of ObsWebSocketClient.cs. The library already raises a public `AuthenticationFailure` event with a public AuthenticationFailureEventArgs, so the typed signal exists — but consumers that prefer a typed catch over an event subscription couldn't `catch (AuthenticationFailureException)` because the type wasn't visible. Promote both exceptions to public top-level types in their own files, documented inline. Internal call sites and the existing tests (which already referenced these by name through InternalsVisibleTo) compile unchanged. The public AuthenticationFailure event continues to fire for callers that prefer the event-driven path. Motivation: downstream consumers (StreamWeaver in particular) used to string-match exception messages — `Contains("auth")` / `Contains("credential")` on ObsWebSocketException — which is fragile to library wording changes. With the typed exception public, those callers can switch to a clean `catch (AuthenticationFailureException)` or subscribe to the existing AuthenticationFailure event.
1 parent 8bb8862 commit 3dc8309

3 files changed

Lines changed: 67 additions & 7 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
namespace ObsWebSocket.Core;
2+
3+
/// <summary>
4+
/// Thrown when authentication against the OBS WebSocket server fails — typically because the
5+
/// configured password is wrong, missing, or otherwise rejected by the server's challenge.
6+
/// </summary>
7+
/// <remarks>
8+
/// Consumers can catch this directly to distinguish auth failures from generic
9+
/// <see cref="ObsWebSocketException"/> connection issues without inspecting the message string.
10+
/// The same condition is also surfaced via the
11+
/// <see cref="ObsWebSocketClient.AuthenticationFailure"/> event for callers that prefer the
12+
/// event-driven path.
13+
/// </remarks>
14+
[Serializable]
15+
public sealed class AuthenticationFailureException : ObsWebSocketException
16+
{
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="AuthenticationFailureException"/> class.
19+
/// </summary>
20+
public AuthenticationFailureException() { }
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="AuthenticationFailureException"/> class with
24+
/// a specified error message.
25+
/// </summary>
26+
public AuthenticationFailureException(string message)
27+
: base(message) { }
28+
29+
/// <summary>
30+
/// Initializes a new instance of the <see cref="AuthenticationFailureException"/> class with
31+
/// a specified error message and a reference to the inner exception that caused this one.
32+
/// </summary>
33+
public AuthenticationFailureException(string message, Exception? innerException)
34+
: base(message, innerException ?? new InvalidOperationException("OBS authentication failed without a more specific cause.")) { }
35+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
namespace ObsWebSocket.Core;
2+
3+
/// <summary>
4+
/// Thrown when a single connection attempt to the OBS WebSocket server fails for a non-auth
5+
/// reason — protocol mismatch, transport error, handshake timeout, or a server-rejected
6+
/// configuration. Distinct from <see cref="AuthenticationFailureException"/> so consumers can
7+
/// decide whether to retry or stop.
8+
/// </summary>
9+
[Serializable]
10+
public sealed class ConnectionAttemptFailedException : ObsWebSocketException
11+
{
12+
/// <summary>
13+
/// Initializes a new instance of the <see cref="ConnectionAttemptFailedException"/> class.
14+
/// </summary>
15+
public ConnectionAttemptFailedException() { }
16+
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="ConnectionAttemptFailedException"/> class
19+
/// with a specified error message.
20+
/// </summary>
21+
public ConnectionAttemptFailedException(string message)
22+
: base(message) { }
23+
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="ConnectionAttemptFailedException"/> class
26+
/// with a specified error message and a reference to the inner exception that caused this one.
27+
/// </summary>
28+
public ConnectionAttemptFailedException(string message, Exception? innerException)
29+
: base(message, innerException ?? new InvalidOperationException("OBS connection attempt failed without a more specific cause.")) { }
30+
}

ObsWebSocket.Core/ObsWebSocketClient.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2549,11 +2549,6 @@ private void RaiseAuthenticationFailureEvent(Uri uri, int attempt, Exception err
25492549
}
25502550
#endregion
25512551

2552-
#region Internal Exception Types
2553-
internal sealed class ConnectionAttemptFailedException(string message, Exception? inner = null)
2554-
: ObsWebSocketException(message, inner);
2555-
2556-
internal sealed class AuthenticationFailureException(string message, Exception? inner = null)
2557-
: ObsWebSocketException(message, inner);
2558-
#endregion
2552+
// ConnectionAttemptFailedException and AuthenticationFailureException were promoted to
2553+
// public top-level types in v0.3.1-dev3; their definitions now live in their own files.
25592554
}

0 commit comments

Comments
 (0)