130 lines
4.2 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|