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);
91 public abstract Task Disconnect(CancellationToken cancellationToken);
94 public abstract Task<IReadOnlyCollection<ChannelRepresentation>> MapChannels(IEnumerable<Api.Models.ChatChannel> channels, CancellationToken cancellationToken);
97 public async Task<Message>
NextMessage(CancellationToken cancellationToken)
99 var cancelTcs =
new TaskCompletionSource<object>();
100 using (cancellationToken.Register(() => cancelTcs.SetCanceled()))
101 await Task.WhenAny(nextMessage.Task, cancelTcs.Task).ConfigureAwait(
false);
102 cancellationToken.ThrowIfCancellationRequested();
105 var result = messageQueue.Dequeue();
106 if (messageQueue.Count == 0)
107 nextMessage =
new TaskCompletionSource<object>();
118 lock (reconnectTaskLock)
119 if (reconnectCts != null)
121 reconnectCts.Cancel();
122 reconnectCts.Dispose();
124 Task reconnectTask = this.reconnectTask;
125 this.reconnectTask = null;
126 return reconnectTask;
129 return Task.CompletedTask;
135 if (reconnectInterval == 0)
136 throw new ArgumentOutOfRangeException(nameof(reconnectInterval), reconnectInterval,
"Reconnect interval cannot be zero!");
138 Task stopOldTimerTask;
139 lock (reconnectTaskLock)
141 stopOldTimerTask = StopReconnectionTimer();
142 reconnectCts =
new CancellationTokenSource();
143 reconnectTask = ReconnectionLoop(reconnectInterval, reconnectCts.Token);
146 return stopOldTimerTask;
161 await Task.Delay(TimeSpan.FromMinutes(reconnectInterval), cancellationToken).ConfigureAwait(
false);
164 Logger.LogInformation(
"Attempting to reconnect provider...");
165 await Disconnect(cancellationToken).ConfigureAwait(
false);
166 if (await Connect(cancellationToken).ConfigureAwait(
false))
167 EnqueueMessage(null);
170 catch (OperationCanceledException)
176 Logger.LogError(e,
"Error reconnecting!");
183 public abstract Task SendMessage(ulong channelId,
string message, CancellationToken cancellationToken);
186 public abstract Task<Func<string, string, Task>> SendUpdateMessage(
188 Version byondVersion,
189 DateTimeOffset? estimatedCompletionTime,
193 bool localCommitPushed,
194 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< 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)