1 using Microsoft.Extensions.Logging;
3 using System.Collections.Generic;
5 using System.Threading.Tasks;
16 protected ILogger Logger {
get; }
48 protected Provider(ILogger logger, uint reconnectInterval)
50 Logger = logger ??
throw new ArgumentNullException(nameof(logger));
52 messageQueue =
new Queue<Message>();
53 nextMessage =
new TaskCompletionSource<object>();
55 reconnectTaskLock =
new object();
57 SetReconnectInterval(reconnectInterval).GetAwaiter().GetResult();
58 logger.LogTrace(
"Created.");
62 public abstract bool Connected {
get; }
65 public abstract string BotMention {
get; }
75 messageQueue.Enqueue(message);
76 nextMessage.TrySetResult(null);
83 StopReconnectionTimer().GetAwaiter().GetResult();
84 Logger.LogTrace(
"Disposed");
88 public abstract Task<bool> Connect(CancellationToken cancellationToken);
95 protected abstract Task DisconnectImpl(CancellationToken cancellationToken);
98 public async Task
Disconnect(CancellationToken cancellationToken)
100 await StopReconnectionTimer().ConfigureAwait(
false);
101 await DisconnectImpl(cancellationToken).ConfigureAwait(
false);
105 public abstract Task<IReadOnlyCollection<ChannelRepresentation>> MapChannels(IEnumerable<Api.Models.ChatChannel> channels, CancellationToken cancellationToken);
108 public async Task<Message>
NextMessage(CancellationToken cancellationToken)
110 var cancelTcs =
new TaskCompletionSource<object>();
111 using (cancellationToken.Register(() => cancelTcs.SetCanceled()))
112 await Task.WhenAny(nextMessage.Task, cancelTcs.Task).ConfigureAwait(
false);
113 cancellationToken.ThrowIfCancellationRequested();
116 var result = messageQueue.Dequeue();
117 if (messageQueue.Count == 0)
118 nextMessage =
new TaskCompletionSource<object>();
129 lock (reconnectTaskLock)
130 if (reconnectCts != null)
132 reconnectCts.Cancel();
133 reconnectCts.Dispose();
135 Task reconnectTask = this.reconnectTask;
136 this.reconnectTask = null;
137 return reconnectTask;
140 return Task.CompletedTask;
146 if (reconnectInterval == 0)
147 throw new ArgumentOutOfRangeException(nameof(reconnectInterval), reconnectInterval,
"Reconnect interval cannot be zero!");
149 Task stopOldTimerTask;
150 lock (reconnectTaskLock)
152 stopOldTimerTask = StopReconnectionTimer();
153 reconnectCts =
new CancellationTokenSource();
154 reconnectTask = ReconnectionLoop(reconnectInterval, reconnectCts.Token);
157 return stopOldTimerTask;
172 await Task.Delay(TimeSpan.FromMinutes(reconnectInterval), cancellationToken).ConfigureAwait(
false);
175 Logger.LogInformation(
"Attempting to reconnect provider...");
176 await Disconnect(cancellationToken).ConfigureAwait(
false);
177 if (await Connect(cancellationToken).ConfigureAwait(
false))
178 EnqueueMessage(null);
181 catch (OperationCanceledException)
187 Logger.LogError(e,
"Error reconnecting!");
194 public abstract Task SendMessage(ulong channelId,
string message, CancellationToken cancellationToken);
197 public abstract Task<Func<string, string, Task>> SendUpdateMessage(
199 Version byondVersion,
200 DateTimeOffset? estimatedCompletionTime,
204 bool localCommitPushed,
205 CancellationToken cancellationToken);
Task reconnectTask
The auto reconnect Task
readonly object reconnectTaskLock
Used for synchronizing access to reconnectCts and reconnectTask.
Use server authentication
CancellationTokenSource reconnectCts
CancellationTokenSource for reconnectTask
Represents a message recieved by a IProvider
For interacting with a chat service
async Task Disconnect(CancellationToken cancellationToken)
Gracefully disconnects the provider. Permanently stops the reconnection timer.
async Task< Message > NextMessage(CancellationToken cancellationToken)
Get a Task<TResult> resulting in the next Message the IProvider recieves or on a disconnect ...
TaskCompletionSource< object > nextMessage
TaskCompletionSource<TResult> that completes while messageQueue isn't empty
Task SetReconnectInterval(uint reconnectInterval)
Set the interval at which the provider tries to reconnect.
Task StopReconnectionTimer()
Stops and awaits the reconnectTask.
Provider(ILogger logger, uint reconnectInterval)
Construct a Provider
readonly Queue< Message > messageQueue
Queue<T> of received Messages
async Task ReconnectionLoop(uint reconnectInterval, CancellationToken cancellationToken)
Creates a Task that will attempt to reconnect the Provider every reconnectInterval minutes...
void EnqueueMessage(Message message)
Queues a message for NextMessage(CancellationToken)