Add adjustable reconnects and settings revisions

This commit is contained in:
Alexander Horner
2023-10-09 21:11:07 +01:00
parent 68b0bf3eb9
commit 0155cfb8fc
6 changed files with 266 additions and 103 deletions

View File

@@ -31,16 +31,16 @@ namespace ntfysh_client.Notifications
ServicePointManager.DefaultConnectionLimit = 100;
}
private async Task ListenToTopicWithHttpLongJsonAsync(HttpRequestMessage message, CancellationToken cancellationToken, SubscribedTopic topic)
private async Task ListenToTopicWithHttpLongJsonAsync(HttpRequestMessage message, SubscribedTopic topic, int reconnectAttempts = 10, int reconnectAttemptDelay = 3, CancellationToken cancellationToken = default)
{
int connectionAttempts = 0;
while (!cancellationToken.IsCancellationRequested)
{
//See if we have exceeded maximum attempts
if (connectionAttempts >= 10)
if (reconnectAttempts != 0 && connectionAttempts >= reconnectAttempts)
{
//10 connection failures (1 initial + 9 reattempts)! Do not retry
//<reconnectAttempts> connection failures (1 initial + (<reconnectAttempts> - 1) reattempts)! Do not retry
OnConnectionMultiAttemptFailure?.Invoke(this, topic);
return;
}
@@ -119,16 +119,16 @@ namespace ntfysh_client.Notifications
}
finally
{
//We land here if we fail to connect or our connection gets closed (and if we are canceeling, but that gets ignored)
//We land here if we fail to connect or our connection gets closed (and if we are canceling, but that gets ignored)
if (!cancellationToken.IsCancellationRequested)
{
//Not cancelling, legitimate connection failure or termination
if (connectionAttempts != 0)
if (reconnectAttempts == 0 || connectionAttempts != 0)
{
//On our first reconnect attempt, try instantly. On consecutive, wait 3 seconds before each attempt
await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
//On our first reconnect attempt, try instantly (unless we have infinite retries). On consecutive, wait <reconnectAttemptDelay> seconds before each attempt
await Task.Delay(TimeSpan.FromSeconds(reconnectAttemptDelay), cancellationToken);
}
//Increment attempts
@@ -140,16 +140,16 @@ namespace ntfysh_client.Notifications
}
}
private async Task ListenToTopicWithWebsocketAsync(Uri uri, string? credentials, CancellationToken cancellationToken, SubscribedTopic topic)
private async Task ListenToTopicWithWebsocketAsync(Uri uri, string? credentials, SubscribedTopic topic, int reconnectAttempts = 10, int reconnectAttemptDelay = 3, CancellationToken cancellationToken = default)
{
int connectionAttempts = 0;
while (!cancellationToken.IsCancellationRequested)
{
//See if we have exceeded maximum attempts
if (connectionAttempts >= 10)
if (reconnectAttempts != 0 && connectionAttempts >= reconnectAttempts)
{
//10 connection failures (1 initial + 9 reattempts)! Do not retry
//<reconnectAttempts> connection failures (1 initial + (<reconnectAttempts> - 1) reattempts)! Do not retry
OnConnectionMultiAttemptFailure?.Invoke(this, topic);
return;
}
@@ -223,16 +223,16 @@ namespace ntfysh_client.Notifications
}
finally
{
//We land here if we fail to connect or our connection gets closed (and if we are canceeling, but that gets ignored)
//We land here if we fail to connect or our connection gets closed (and if we are canceling, but that gets ignored)
if (!cancellationToken.IsCancellationRequested)
{
//Not cancelling, legitimate connection failure or termination
if (connectionAttempts != 0)
if (reconnectAttempts == 0 || connectionAttempts != 0)
{
//On our first reconnect attempt, try instantly. On consecutive, wait 3 seconds before each attempt
await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
//On our first reconnect attempt, try instantly (unless we have infinite retries). On consecutive, wait <reconnectAttemptDelay> seconds before each attempt
await Task.Delay(TimeSpan.FromSeconds(reconnectAttemptDelay), cancellationToken);
}
//Increment attempts
@@ -261,13 +261,16 @@ namespace ntfysh_client.Notifications
}
}
public void SubscribeToTopicUsingLongHttpJson(string unique, string topicId, string serverUrl, string? username, string? password)
public void SubscribeToTopicUsingLongHttpJson(string unique, string topicId, string serverUrl, string? username, string? password, int reconnectAttempts, int reconnectAttemptDelay)
{
if (SubscribedTopicsByUnique.ContainsKey(unique)) throw new InvalidOperationException("A topic with this unique already exists");
if (SubscribedTopicsByUnique.ContainsKey(unique)) throw new ArgumentException("A topic with this unique already exists", nameof(unique));
if (string.IsNullOrWhiteSpace(username)) username = null;
if (string.IsNullOrWhiteSpace(password)) password = null;
if (reconnectAttempts < 0) throw new ArgumentException("Reconnect attempts must be 0 or more", nameof(reconnectAttempts));
if (reconnectAttemptDelay < 0) throw new ArgumentException("Reconnect attempt delay; must be 0 or more", nameof(reconnectAttemptDelay));
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, $"{serverUrl}/{HttpUtility.UrlEncode(topicId)}/json");
if (username is not null && password is not null)
@@ -280,20 +283,23 @@ namespace ntfysh_client.Notifications
SubscribedTopic newTopic = new(topicId, serverUrl, username, password);
CancellationTokenSource listenCanceller = new();
Task listenTask = ListenToTopicWithHttpLongJsonAsync(message, listenCanceller.Token, newTopic);
Task listenTask = ListenToTopicWithHttpLongJsonAsync(message, newTopic, reconnectAttempts, reconnectAttemptDelay, listenCanceller.Token);
newTopic.SetAssociatedRunner(listenTask, listenCanceller);
SubscribedTopicsByUnique.Add(unique, newTopic);
}
public void SubscribeToTopicUsingWebsocket(string unique, string topicId, string serverUrl, string? username, string? password)
public void SubscribeToTopicUsingWebsocket(string unique, string topicId, string serverUrl, string? username, string? password, int reconnectAttempts, int reconnectAttemptDelay)
{
if (SubscribedTopicsByUnique.ContainsKey(unique)) throw new InvalidOperationException("A topic with this unique already exists");
if (SubscribedTopicsByUnique.ContainsKey(unique)) throw new ArgumentException("A topic with this unique already exists", nameof(unique));
if (string.IsNullOrWhiteSpace(username)) username = null;
if (string.IsNullOrWhiteSpace(password)) password = null;
if (reconnectAttempts < 0) throw new ArgumentException("Reconnect attempts must be 0 or more", nameof(reconnectAttempts));
if (reconnectAttemptDelay < 0) throw new ArgumentException("Reconnect attempt delay; must be 0 or more", nameof(reconnectAttemptDelay));
SubscribedTopic newTopic = new(topicId, serverUrl, username, password);
string? credentials = null;
@@ -306,7 +312,7 @@ namespace ntfysh_client.Notifications
}
CancellationTokenSource listenCanceller = new();
Task listenTask = ListenToTopicWithWebsocketAsync(new Uri($"{serverUrl}/{HttpUtility.UrlEncode(topicId)}/ws"), credentials, listenCanceller.Token, newTopic);
Task listenTask = ListenToTopicWithWebsocketAsync(new Uri($"{serverUrl}/{HttpUtility.UrlEncode(topicId)}/ws"), credentials, newTopic, reconnectAttempts, reconnectAttemptDelay, listenCanceller.Token);
newTopic.SetAssociatedRunner(listenTask, listenCanceller);