diff --git a/src/TwitchLib.Communication.Tests/Clients/ClientTestsBase.cs b/src/TwitchLib.Communication.Tests/Clients/ClientTestsBase.cs
index 1fd81de..b0bacec 100644
--- a/src/TwitchLib.Communication.Tests/Clients/ClientTestsBase.cs
+++ b/src/TwitchLib.Communication.Tests/Clients/ClientTestsBase.cs
@@ -9,6 +9,7 @@
using TwitchLib.Communication.Tests.Helpers;
using Xunit;
+[assembly: CollectionBehavior(DisableTestParallelization = true)]
namespace TwitchLib.Communication.Tests.Clients
{
///
@@ -24,33 +25,33 @@ namespace TwitchLib.Communication.Tests.Clients
///
public abstract class ClientTestsBase where T : IClient
{
- private static uint WaitAfterDispose => 3;
private static TimeSpan WaitOneDuration => TimeSpan.FromSeconds(5);
- private static IClientOptions Options;
+ private readonly IClientOptions? _options;
- public ClientTestsBase(IClientOptions options = null)
+ protected ClientTestsBase(IClientOptions? options = null)
{
- Options = options;
+ _options = options;
}
[Fact]
- public void Client_Raises_OnConnected_EventArgs()
+ public async Task Client_Raises_OnConnected_EventArgs()
{
// create one logger per test-method! - cause one file per test-method is generated
- ILogger logger = TestLogHelper.GetLogger();
- T? client = GetClient(logger, Options);
+ var logger = TestLogHelper.GetLogger();
+ var client = GetClient(logger, _options);
Assert.NotNull(client);
try
{
- ManualResetEvent pauseConnected = new ManualResetEvent(false);
+ var pauseConnected = new ManualResetEvent(false);
- Assert.Raises(
+ await Assert.RaisesAsync(
h => client.OnConnected += h,
h => client.OnConnected -= h,
- () =>
+ async () =>
{
client.OnConnected += (sender, e) => pauseConnected.Set();
- client.Open();
+ await client.OpenAsync();
+
Assert.True(pauseConnected.WaitOne(WaitOneDuration));
});
}
@@ -61,33 +62,34 @@ public void Client_Raises_OnConnected_EventArgs()
}
finally
{
- Cleanup(client);
+ client.Dispose();
}
}
[Fact]
- public void Client_Raises_OnDisconnected_EventArgs()
+ public async Task Client_Raises_OnDisconnected_EventArgs()
{
// create one logger per test-method! - cause one file per test-method is generated
- ILogger logger = TestLogHelper.GetLogger();
- T? client = GetClient(logger, Options);
+ var logger = TestLogHelper.GetLogger();
+ var client = GetClient(logger, _options);
Assert.NotNull(client);
try
{
- ManualResetEvent pauseDisconnected = new ManualResetEvent(false);
+ var pauseDisconnected = new ManualResetEvent(false);
- Assert.Raises(
+ await Assert.RaisesAsync(
h => client.OnDisconnected += h,
h => client.OnDisconnected -= h,
- () =>
+ async () =>
{
- client.OnConnected += (sender, e) =>
+ client.OnConnected += async (sender, e) =>
{
- Task.Delay(WaitOneDuration).GetAwaiter().GetResult();
- client.Close();
+ await client.CloseAsync();
};
+
client.OnDisconnected += (sender, e) => pauseDisconnected.Set();
- client.Open();
+ await client.OpenAsync();
+
Assert.True(pauseDisconnected.WaitOne(WaitOneDuration));
});
}
@@ -98,30 +100,30 @@ public void Client_Raises_OnDisconnected_EventArgs()
}
finally
{
- Cleanup(client);
+ client.Dispose();
}
}
[Fact]
- public void Client_Raises_OnReconnected_EventArgs()
+ public async Task Client_Raises_OnReconnected_EventArgs()
{
// create one logger per test-method! - cause one file per test-method is generated
- ILogger logger = TestLogHelper.GetLogger();
- T? client = GetClient(logger, Options);
+ var logger = TestLogHelper.GetLogger();
+ var client = GetClient(logger, _options);
Assert.NotNull(client);
try
{
- ManualResetEvent pauseReconnected = new ManualResetEvent(false);
+ var pauseReconnected = new ManualResetEvent(false);
- Assert.Raises(
+ await Assert.RaisesAsync(
h => client.OnReconnected += h,
h => client.OnReconnected -= h,
- () =>
+ async () =>
{
- client.OnConnected += (s, e) => client.Reconnect();
+ client.OnConnected += async (s, e) => await client.ReconnectAsync();
client.OnReconnected += (s, e) => pauseReconnected.Set();
- client.Open();
+ await client.OpenAsync();
Assert.True(pauseReconnected.WaitOne(WaitOneDuration));
});
@@ -133,7 +135,7 @@ public void Client_Raises_OnReconnected_EventArgs()
}
finally
{
- Cleanup(client);
+ client.Dispose();
}
}
@@ -141,11 +143,11 @@ public void Client_Raises_OnReconnected_EventArgs()
public void Dispose_Client_Before_Connecting_IsOK()
{
// create one logger per test-method! - cause one file per test-method is generated
- ILogger logger = TestLogHelper.GetLogger();
+ var logger = TestLogHelper.GetLogger();
IClient? client = null;
try
{
- client = GetClient(logger, Options);
+ client = GetClient(logger, _options);
Assert.NotNull(client);
client.Dispose();
}
@@ -156,29 +158,25 @@ public void Dispose_Client_Before_Connecting_IsOK()
}
finally
{
- Cleanup((T?)client);
+ client?.Dispose();
}
}
- private static void Cleanup(T? client)
- {
- client?.Dispose();
- Task.Delay(TimeSpan.FromSeconds(WaitAfterDispose)).GetAwaiter().GetResult();
- }
-
private static TClient? GetClient(ILogger logger, IClientOptions? options = null)
{
- Type[] constructorParameterTypes = new Type[]
+ var constructorParameterTypes = new Type[]
{
typeof(IClientOptions),
typeof(ILogger)
};
- ConstructorInfo? constructor = typeof(TClient).GetConstructor(constructorParameterTypes);
- object[] constructorParameters = new object[]
+
+ var constructor = typeof(TClient).GetConstructor(constructorParameterTypes);
+ var constructorParameters = new object[]
{
options ?? new ClientOptions(),
logger
};
+
return (TClient?)constructor?.Invoke(constructorParameters);
}
}
diff --git a/src/TwitchLib.Communication/Clients/ClientBase.cs b/src/TwitchLib.Communication/Clients/ClientBase.cs
index 6b75074..578b1a1 100644
--- a/src/TwitchLib.Communication/Clients/ClientBase.cs
+++ b/src/TwitchLib.Communication/Clients/ClientBase.cs
@@ -22,9 +22,10 @@ namespace TwitchLib.Communication.Clients
///
///
///
- public abstract class ClientBase : IClient where T : IDisposable
+ public abstract class ClientBase : IClient
+ where T : IDisposable
{
- private static readonly object Lock = new object();
+ private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
private readonly NetworkServices _networkServices;
private CancellationTokenSource _cancellationTokenSource;
@@ -126,7 +127,7 @@ internal void RaiseMessage(OnMessageEventArgs eventArgs)
///
/// Wont raise the given if .IsCancellationRequested
///
- internal void RaiseFatal(Exception e = null)
+ internal void RaiseFatal(Exception ex = null)
{
Logger?.TraceMethodCall(GetType());
if (Token.IsCancellationRequested)
@@ -135,9 +136,9 @@ internal void RaiseFatal(Exception e = null)
}
var onFatalErrorEventArgs = new OnFatalErrorEventArgs("Fatal network error.");
- if (e != null)
+ if (ex != null)
{
- onFatalErrorEventArgs = new OnFatalErrorEventArgs(e);
+ onFatalErrorEventArgs = new OnFatalErrorEventArgs(ex);
}
OnFatality?.Invoke(this, onFatalErrorEventArgs);
@@ -155,67 +156,68 @@ private void RaiseConnected()
OnConnected?.Invoke(this, new OnConnectedEventArgs());
}
- public bool Send(string message)
+ public async Task SendAsync(string message)
{
Logger?.TraceMethodCall(GetType());
+
+ await _semaphore.WaitAsync(Token);
try
{
- lock (Lock)
- {
- ClientSend(message);
- return true;
- }
+ await ClientSendAsync(message);
+ return true;
}
catch (Exception e)
{
- RaiseSendFailed(new OnSendFailedEventArgs() { Exception = e, Data = message });
+ RaiseSendFailed(new OnSendFailedEventArgs { Exception = e, Data = message });
return false;
}
+ finally
+ {
+ _semaphore.Release();
+ }
}
- public bool Open()
+ public Task OpenAsync()
{
Logger?.TraceMethodCall(GetType());
- return OpenPrivate(false);
+ return OpenPrivateAsync(false);
}
- public void Close()
+ public async Task CloseAsync()
{
Logger?.TraceMethodCall(GetType());
// Network services has to be stopped first so that it wont reconnect
- _networkServices.Stop();
+ await _networkServices.StopAsync();
// ClosePrivate() also handles IClientOptions.DisconnectWait
- ClosePrivate();
+ await ClosePrivateAsync();
}
///
- ///
+ ///
///
public void Dispose()
{
Logger?.TraceMethodCall(GetType());
- Close();
+ CloseAsync().GetAwaiter().GetResult();
GC.SuppressFinalize(this);
}
- public bool Reconnect()
+ public async Task ReconnectAsync()
{
Logger?.TraceMethodCall(GetType());
// Stops everything (including NetworkServices)
if (IsConnected)
{
- Close();
+ await CloseAsync();
}
- // interface IClient doesnt declare a return value for Reconnect()
- // so we can suppress IDE0058 of ReconnectInternal()
- return ReconnectInternal();
+ return await ReconnectInternalAsync();
}
- private bool OpenPrivate(bool isReconnect)
+ private async Task OpenPrivateAsync(bool isReconnect)
{
Logger?.TraceMethodCall(GetType());
try
@@ -235,17 +237,17 @@ private bool OpenPrivate(bool isReconnect)
var first = true;
Options.ReconnectionPolicy.Reset(isReconnect);
- while (!IsConnected
- && !Options.ReconnectionPolicy.AreAttemptsComplete())
+
+ while (!IsConnected &&
+ !Options.ReconnectionPolicy.AreAttemptsComplete())
{
Logger?.TraceAction(GetType(), "try to connect");
if (!first)
{
- Task.Delay(Options.ReconnectionPolicy.GetReconnectInterval(), CancellationToken.None)
- .GetAwaiter().GetResult();
+ await Task.Delay(Options.ReconnectionPolicy.GetReconnectInterval(), CancellationToken.None);
}
- ConnectClient();
+ await ConnectClientAsync();
Options.ReconnectionPolicy.ProcessValues();
first = false;
}
@@ -259,6 +261,7 @@ private bool OpenPrivate(bool isReconnect)
Logger?.TraceAction(GetType(), "Client established a connection");
_networkServices.Start();
+
if (!isReconnect)
{
RaiseConnected();
@@ -276,7 +279,7 @@ private bool OpenPrivate(bool isReconnect)
}
///
- /// Stops
+ /// Stops
/// by calling
///
/// and enforces the
@@ -285,9 +288,9 @@ private bool OpenPrivate(bool isReconnect)
///
///
/// will keep running,
- /// because itself issued this call by calling
+ /// because itself issued this call by calling
///
- private void ClosePrivate()
+ private async Task ClosePrivateAsync()
{
Logger?.TraceMethodCall(GetType());
@@ -299,9 +302,8 @@ private void ClosePrivate()
CloseClient();
RaiseDisconnected();
_cancellationTokenSource = new CancellationTokenSource();
-
- Task.Delay(TimeSpan.FromMilliseconds(Options.DisconnectWait), CancellationToken.None)
- .GetAwaiter().GetResult();
+
+ await Task.Delay(TimeSpan.FromMilliseconds(Options.DisconnectWait), CancellationToken.None);
}
///
@@ -310,7 +312,7 @@ private void ClosePrivate()
///
/// Message to be send
///
- protected abstract void ClientSend(string message);
+ protected abstract Task ClientSendAsync(string message);
///
/// Instantiate the underlying client.
@@ -336,7 +338,7 @@ private void ClosePrivate()
///
/// Connect the client.
///
- protected abstract void ConnectClient();
+ protected abstract Task ConnectClientAsync();
///
/// To issue a reconnect
@@ -353,11 +355,11 @@ private void ClosePrivate()
///
/// if a connection could be established, otherwise
///
- internal bool ReconnectInternal()
+ internal async Task ReconnectInternalAsync()
{
Logger?.TraceMethodCall(GetType());
- ClosePrivate();
- var reconnected = OpenPrivate(true);
+ await ClosePrivateAsync();
+ var reconnected = await OpenPrivateAsync(true);
if (reconnected)
{
RaiseReconnected();
@@ -370,6 +372,6 @@ internal bool ReconnectInternal()
/// just the Action that listens for new Messages
/// the corresponding is held by
///
- internal abstract void ListenTaskAction();
+ internal abstract Task ListenTaskActionAsync();
}
}
\ No newline at end of file
diff --git a/src/TwitchLib.Communication/Clients/TcpClient.cs b/src/TwitchLib.Communication/Clients/TcpClient.cs
index 7467280..be18a5e 100644
--- a/src/TwitchLib.Communication/Clients/TcpClient.cs
+++ b/src/TwitchLib.Communication/Clients/TcpClient.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Net.Security;
+using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using TwitchLib.Communication.Events;
@@ -11,11 +12,12 @@ namespace TwitchLib.Communication.Clients
{
public class TcpClient : ClientBase
{
+ private StreamReader _reader;
+ private StreamWriter _writer;
+
protected override string Url => "irc.chat.twitch.tv";
private int Port => Options.UseSsl ? 6697 : 6667;
- private StreamReader Reader { get; set; }
- private StreamWriter Writer { get; set; }
public override bool IsConnected => Client?.Connected ?? false;
@@ -26,12 +28,12 @@ public TcpClient(
{
}
- internal override void ListenTaskAction()
+ internal override async Task ListenTaskActionAsync()
{
Logger?.TraceMethodCall(GetType());
- if (Reader == null)
+ if (_reader == null)
{
- Exception ex = new InvalidOperationException($"{nameof(Reader)} was null!");
+ var ex = new InvalidOperationException($"{nameof(_reader)} was null!");
Logger?.LogExceptionAsError(GetType(), ex);
RaiseFatal(ex);
throw ex;
@@ -41,7 +43,7 @@ internal override void ListenTaskAction()
{
try
{
- var input = Reader.ReadLine();
+ var input = await _reader.ReadLineAsync();
if (input is null)
{
continue;
@@ -64,7 +66,7 @@ internal override void ListenTaskAction()
}
}
- protected override void ClientSend(string message)
+ protected override async Task ClientSendAsync(string message)
{
Logger?.TraceMethodCall(GetType());
@@ -72,19 +74,19 @@ protected override void ClientSend(string message)
// this method should only be called from 'ClientBase.Send()'
// where its call gets synchronized/locked
// https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.networkstream?view=netstandard-2.0#remarks
- if (Writer == null)
+ if (_writer == null)
{
- Exception ex = new InvalidOperationException($"{nameof(Writer)} was null!");
+ var ex = new InvalidOperationException($"{nameof(_writer)} was null!");
Logger?.LogExceptionAsError(GetType(), ex);
RaiseFatal(ex);
throw ex;
}
- Writer.WriteLine(message);
- Writer.Flush();
+ await _writer.WriteLineAsync(message);
+ await _writer.FlushAsync();
}
- protected override void ConnectClient()
+ protected override async Task ConnectClientAsync()
{
Logger?.TraceMethodCall(GetType());
if (Client == null)
@@ -103,11 +105,9 @@ protected override void ConnectClient()
// the following answer
// NET6_0_OR_GREATER: https://stackoverflow.com/a/68998339
- var connectTask = Client.ConnectAsync(Url,
- Port);
- var waitTask = connectTask.WaitAsync(TimeOutEstablishConnection,
- Token);
- Task.WhenAny(connectTask, waitTask).GetAwaiter().GetResult();
+ var connectTask = Client.ConnectAsync(Url, Port);
+ var waitTask = connectTask.WaitAsync(TimeOutEstablishConnection, Token);
+ await Task.WhenAny(connectTask, waitTask);
#else
// within the following thread:
// https://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout
@@ -115,14 +115,15 @@ protected override void ConnectClient()
// https://stackoverflow.com/a/11191070
// https://stackoverflow.com/a/22078975
- using (var delayTaskCancellationTokenSource = new System.Threading.CancellationTokenSource())
+ using (var delayTaskCancellationTokenSource = new CancellationTokenSource())
{
var connectTask = Client.ConnectAsync(Url, Port);
- var delayTask = Task.Delay((int)TimeOutEstablishConnection.TotalMilliseconds,
+ var delayTask = Task.Delay(
+ (int)TimeOutEstablishConnection.TotalMilliseconds,
delayTaskCancellationTokenSource.Token);
- Task.WhenAny(connectTask, delayTask).GetAwaiter().GetResult();
- delayTaskCancellationTokenSource?.Cancel();
+ await Task.WhenAny(connectTask, delayTask);
+ delayTaskCancellationTokenSource.Cancel();
}
#endif
if (!Client.Connected)
@@ -134,15 +135,15 @@ protected override void ConnectClient()
Logger?.TraceAction(GetType(), "Client established connection successfully");
if (Options.UseSsl)
{
- SslStream ssl = new SslStream(Client.GetStream(), false);
- ssl.AuthenticateAsClient(Url);
- Reader = new StreamReader(ssl);
- Writer = new StreamWriter(ssl);
+ var ssl = new SslStream(Client.GetStream(), false);
+ await ssl.AuthenticateAsClientAsync(Url);
+ _reader = new StreamReader(ssl);
+ _writer = new StreamWriter(ssl);
}
else
{
- Reader = new StreamReader(Client.GetStream());
- Writer = new StreamWriter(Client.GetStream());
+ _reader = new StreamReader(Client.GetStream());
+ _writer = new StreamWriter(Client.GetStream());
}
}
catch (Exception ex) when (ex.GetType() == typeof(TaskCanceledException) ||
@@ -171,8 +172,8 @@ protected override System.Net.Sockets.TcpClient CreateClient()
protected override void CloseClient()
{
Logger?.TraceMethodCall(GetType());
- Reader?.Dispose();
- Writer?.Dispose();
+ _reader?.Dispose();
+ _writer?.Dispose();
Client?.Dispose();
}
}
diff --git a/src/TwitchLib.Communication/Clients/WebsocketClient.cs b/src/TwitchLib.Communication/Clients/WebsocketClient.cs
index d88dd90..a3d9c40 100644
--- a/src/TwitchLib.Communication/Clients/WebsocketClient.cs
+++ b/src/TwitchLib.Communication/Clients/WebsocketClient.cs
@@ -31,31 +31,31 @@ public WebSocketClient(
Url = Options.UseSsl ? "wss://pubsub-edge.twitch.tv:443" : "ws://pubsub-edge.twitch.tv:80";
break;
default:
- Exception ex = new ArgumentOutOfRangeException(nameof(Options.ClientType));
+ var ex = new ArgumentOutOfRangeException(nameof(Options.ClientType));
Logger?.LogExceptionAsError(GetType(), ex);
throw ex;
}
}
- internal override void ListenTaskAction()
+ internal override async Task ListenTaskActionAsync()
{
Logger?.TraceMethodCall(GetType());
if (Client == null)
{
- Exception ex = new InvalidOperationException($"{nameof(Client)} was null!");
+ var ex = new InvalidOperationException($"{nameof(Client)} was null!");
Logger?.LogExceptionAsError(GetType(), ex);
RaiseFatal(ex);
throw ex;
}
- var message = "";
+ var message = string.Empty;
while (IsConnected)
{
WebSocketReceiveResult result;
var buffer = new byte[1024];
try
{
- result = Client.ReceiveAsync(new ArraySegment(buffer), Token).GetAwaiter().GetResult();
+ result = await Client.ReceiveAsync(new ArraySegment(buffer), Token);
if (result == null)
{
continue;
@@ -78,7 +78,7 @@ internal override void ListenTaskAction()
switch (result.MessageType)
{
case WebSocketMessageType.Close:
- Close();
+ await CloseAsync();
break;
case WebSocketMessageType.Text when !result.EndOfMessage:
message += Encoding.UTF8.GetString(buffer).TrimEnd('\0');
@@ -99,11 +99,11 @@ internal override void ListenTaskAction()
}
// clear/reset message
- message = "";
+ message = string.Empty;
}
}
- protected override void ClientSend(string message)
+ protected override async Task ClientSendAsync(string message)
{
Logger?.TraceMethodCall(GetType());
@@ -118,26 +118,25 @@ protected override void ClientSend(string message)
// https://github.com/dotnet/corefx/blob/d6b11250b5113664dd3701c25bdf9addfacae9cc/src/Common/src/System/Net/WebSockets/ManagedWebSocket.cs#L22-L28
if (Client == null)
{
- Exception ex = new InvalidOperationException($"{nameof(Client)} was null!");
+ var ex = new InvalidOperationException($"{nameof(Client)} was null!");
Logger?.LogExceptionAsError(GetType(), ex);
RaiseFatal(ex);
throw ex;
}
var bytes = Encoding.UTF8.GetBytes(message);
- var sendTask = Client.SendAsync(new ArraySegment(bytes),
+ await Client.SendAsync(new ArraySegment(bytes),
WebSocketMessageType.Text,
true,
Token);
- sendTask.GetAwaiter().GetResult();
}
- protected override void ConnectClient()
+ protected override async Task ConnectClientAsync()
{
Logger?.TraceMethodCall(GetType());
if (Client == null)
{
- Exception ex = new InvalidOperationException($"{nameof(Client)} was null!");
+ var ex = new InvalidOperationException($"{nameof(Client)} was null!");
Logger?.LogExceptionAsError(GetType(), ex);
RaiseFatal(ex);
throw ex;
@@ -153,8 +152,7 @@ protected override void ConnectClient()
// NET6_0_OR_GREATER: https://stackoverflow.com/a/68998339
var connectTask = Client.ConnectAsync(new Uri(Url), Token);
var waitTask = connectTask.WaitAsync(TimeOutEstablishConnection, Token);
- // GetAwaiter().GetResult() to avoid async in method-signature 'protected override void SpecificClientConnect()';
- Task.WhenAny(connectTask, waitTask).GetAwaiter().GetResult();
+ await Task.WhenAny(connectTask, waitTask);
#else
// within the following thread:
// https://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout
@@ -164,12 +162,12 @@ protected override void ConnectClient()
using (var delayTaskCancellationTokenSource = new CancellationTokenSource())
{
- var connectTask = Client.ConnectAsync(new Uri(Url),
- Token);
- var delayTask = Task.Delay((int)TimeOutEstablishConnection.TotalMilliseconds,
+ var connectTask = Client.ConnectAsync(new Uri(Url), Token);
+ var delayTask = Task.Delay(
+ (int)TimeOutEstablishConnection.TotalMilliseconds,
delayTaskCancellationTokenSource.Token);
-
- Task.WhenAny(connectTask, delayTask).GetAwaiter().GetResult();
+
+ await Task.WhenAny(connectTask, delayTask);
delayTaskCancellationTokenSource.Cancel();
}
#endif
diff --git a/src/TwitchLib.Communication/Interfaces/IClient.cs b/src/TwitchLib.Communication/Interfaces/IClient.cs
index da77570..dff63fb 100644
--- a/src/TwitchLib.Communication/Interfaces/IClient.cs
+++ b/src/TwitchLib.Communication/Interfaces/IClient.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading.Tasks;
using TwitchLib.Communication.Events;
namespace TwitchLib.Communication.Interfaces
@@ -56,14 +57,14 @@ public interface IClient : IDisposable
///
/// if a connection could be established, otherwise
///
- bool Open();
+ Task OpenAsync();
///
/// if the underlying Client is connected,
///
- /// is invoked
+ /// is invoked
///
- /// before it makes a call to and
+ /// before it makes a call to and
///
///
/// this Method is also used by 'TwitchLib.Client.TwitchClient'
@@ -81,25 +82,25 @@ public interface IClient : IDisposable
///
/// , if the client reconnected; otherwise
///
- bool Reconnect();
+ Task ReconnectAsync();
///
/// stops everything
/// and waits for the via given amount of milliseconds
///
- void Close();
+ Task CloseAsync();
///
- /// sends the given irc-
+ /// Sends the given irc-
///
///
/// irc-message to send
///
///
- /// , if the message should be sent
+ /// , if the message was sent
///
/// otherwise
///
- bool Send(string message);
+ Task SendAsync(string message);
}
}
\ No newline at end of file
diff --git a/src/TwitchLib.Communication/Services/ConnectionWatchDog.cs b/src/TwitchLib.Communication/Services/ConnectionWatchDog.cs
index c2b8a9e..6bf4034 100644
--- a/src/TwitchLib.Communication/Services/ConnectionWatchDog.cs
+++ b/src/TwitchLib.Communication/Services/ConnectionWatchDog.cs
@@ -22,7 +22,7 @@ internal class ConnectionWatchDog where T : IDisposable
/// should only be set to a new instance in
///
/// -
- /// should only be set to in
+ /// should only be set to in
///
///
///
@@ -38,7 +38,7 @@ internal ConnectionWatchDog(
_client = client;
}
- internal Task StartMonitorTask()
+ internal Task StartMonitorTaskAsync()
{
_logger?.TraceMethodCall(GetType());
// We dont want to start more than one WatchDog
@@ -52,27 +52,28 @@ internal Task StartMonitorTask()
// This should be the only place where a new instance of CancellationTokenSource is set
_cancellationTokenSource = new CancellationTokenSource();
- return Task.Run(MonitorTaskAction, _cancellationTokenSource.Token);
+ return Task.Run(MonitorTaskActionAsync, _cancellationTokenSource.Token);
}
- internal void Stop()
+ internal async Task StopAsync()
{
_logger?.TraceMethodCall(GetType());
_cancellationTokenSource?.Cancel();
// give MonitorTaskAction a chance to catch cancellation
// otherwise it may result in an Exception
- Task.Delay(MonitorTaskDelayInMilliseconds * 2).GetAwaiter().GetResult();
+ await Task.Delay(MonitorTaskDelayInMilliseconds * 2);
_cancellationTokenSource?.Dispose();
// set it to null for the check within this.StartMonitorTask()
_cancellationTokenSource = null;
}
- private void MonitorTaskAction()
+ private async Task MonitorTaskActionAsync()
{
_logger?.TraceMethodCall(GetType());
try
{
- while (_cancellationTokenSource != null && !_cancellationTokenSource.Token.IsCancellationRequested)
+ while (_cancellationTokenSource != null &&
+ !_cancellationTokenSource.Token.IsCancellationRequested)
{
// we expect the client is connected,
// when this monitor task starts
@@ -84,7 +85,8 @@ private void MonitorTaskAction()
// ReconnectInternal() calls the correct Close-Method within the Client
// ReconnectInternal() makes attempts to reconnect according to the ReconnectionPolicy within the IClientOptions
_logger?.TraceAction(GetType(), "Try to reconnect");
- var connected = _client.ReconnectInternal();
+
+ var connected = await _client.ReconnectInternalAsync();
if (!connected)
{
_logger?.TraceAction(GetType(), "Client couldn't reconnect");
@@ -92,14 +94,14 @@ private void MonitorTaskAction()
// and no connection could be established
// a call to Client.Close() is made
// that public Close() also shuts down this ConnectionWatchDog
- _client.Close();
+ await _client.CloseAsync();
break;
}
_logger?.TraceAction(GetType(), "Client reconnected");
}
- Task.Delay(MonitorTaskDelayInMilliseconds).GetAwaiter().GetResult();
+ await Task.Delay(MonitorTaskDelayInMilliseconds);
}
}
catch (Exception ex) when (ex.GetType() == typeof(TaskCanceledException) ||
@@ -115,7 +117,7 @@ private void MonitorTaskAction()
_client.RaiseFatal();
// To ensure CancellationTokenSource is set to null again call Stop();
- Stop();
+ await StopAsync();
}
}
}
diff --git a/src/TwitchLib.Communication/Services/NetworkServices.cs b/src/TwitchLib.Communication/Services/NetworkServices.cs
index db27298..590e0ae 100644
--- a/src/TwitchLib.Communication/Services/NetworkServices.cs
+++ b/src/TwitchLib.Communication/Services/NetworkServices.cs
@@ -38,17 +38,19 @@ internal void Start()
// this task is probably still running
// may be in case of a network connection loss
// all other Tasks haven't been started or have been canceled!
- // ConnectionWatchDog is the only one, that has a seperate CancellationTokenSource!
- _monitorTask = _connectionWatchDog.StartMonitorTask();
+ // ConnectionWatchDog is the only one, that has a separate CancellationTokenSource!
+
+ // Let those tasks run in the background, do not await them
+ _monitorTask = _connectionWatchDog.StartMonitorTaskAsync();
}
- _listenTask = Task.Run(_client.ListenTaskAction, Token);
+ _listenTask = Task.Run(_client.ListenTaskActionAsync, Token);
}
- internal void Stop()
+ internal async Task StopAsync()
{
_logger?.TraceMethodCall(GetType());
- _connectionWatchDog.Stop();
+ await _connectionWatchDog.StopAsync();
}
}
}
\ No newline at end of file