SafeDispatch/SafeMobileLIB_DLL/WebsocketClient/WebsocketClient.Reconnecting.cs
2024-02-22 18:43:59 +02:00

130 lines
4.2 KiB
C#

using SafeMobileLib.WebsocketClient.Models;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace SafeMobileLib.WebsocketClient
{
public partial class WebsocketClient
{
public Task _ { get; private set; }
/// <summary>
/// Force reconnection.
/// Closes current websocket stream and perform a new connection to the server.
/// In case of connection error it doesn't throw an exception, but tries to reconnect indefinitely.
/// </summary>
public Task Reconnect()
{
return ReconnectInternal(false);
}
/// <summary>
/// Force reconnection.
/// Closes current websocket stream and perform a new connection to the server.
/// In case of connection error it throws an exception and doesn't perform any other reconnection try.
/// </summary>
public Task ReconnectOrFail()
{
return ReconnectInternal(true);
}
private async Task ReconnectInternal(bool failFast)
{
if (!IsStarted)
{
Utils.WriteLine("Client not started, ignoring reconnection..", ConsoleColor.Yellow);
return;
}
try
{
await ReconnectSynchronized(ReconnectionType.ByUser, failFast, null).ConfigureAwait(false);
}
finally
{
_reconnecting = false;
}
}
private async Task ReconnectSynchronized(ReconnectionType type, bool failFast, Exception causedException)
{
using (await _locker.LockAsync())
{
await Reconnect(type, failFast, causedException);
}
}
private async Task Reconnect(ReconnectionType type, bool failFast, Exception causedException)
{
IsRunning = false;
if (_disposing)
return;
_reconnecting = true;
var disType = TranslateTypeToDisconnection(type);
var disInfo = DisconnectionInfo.Create(disType, _client, causedException);
if (type != ReconnectionType.Error)
{
_disconnectedSubject.OnNext(disInfo);
if (disInfo.CancelReconnection)
{
// reconnection canceled by user, do nothing
Utils.WriteLine($"Reconnecting canceled by user, exiting.", ConsoleColor.Yellow);
}
}
_cancellation.Cancel();
_client?.Abort();
_client?.Dispose();
if (!IsReconnectionEnabled || disInfo.CancelReconnection)
{
// reconnection disabled, do nothing
IsStarted = false;
_reconnecting = false;
return;
}
Utils.WriteLine("Reconnecting...", ConsoleColor.Yellow);
_cancellation = new CancellationTokenSource();
await StartClient(_url, _cancellation.Token, type, failFast).ConfigureAwait(false);
_reconnecting = false;
}
private void ActivateLastChance()
{
var timerMs = 1000 * 1;
_lastChanceTimer = new Timer(LastChance, null, timerMs, timerMs);
}
private void DeactivateLastChance()
{
_lastChanceTimer?.Dispose();
_lastChanceTimer = null;
}
private void LastChance(object state)
{
if (!IsReconnectionEnabled || ReconnectTimeout == null)
{
// reconnection disabled, do nothing
DeactivateLastChance();
return;
}
var timeoutMs = Math.Abs(ReconnectTimeout.Value.TotalMilliseconds);
var diffMs = Math.Abs(DateTime.UtcNow.Subtract(_lastReceivedMsg).TotalMilliseconds);
if (diffMs > timeoutMs)
{
Utils.WriteLine($"Last message received more than {timeoutMs:F} ms ago. Hard restart..", ConsoleColor.Yellow);
DeactivateLastChance();
_ = ReconnectSynchronized(ReconnectionType.NoMessageReceived, false, null);
}
}
}
}