tgstation-server 6.12.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
Provider.cs
Go to the documentation of this file.
1using System;
5
7
13
15{
17 abstract class Provider : IProvider
18 {
21
25 protected ChatBot ChatBot { get; }
26
30 protected IAsyncDelayer AsyncDelayer { get; }
31
35 protected ILogger<Provider> Logger { get; }
36
41
46
50 readonly TaskCompletionSource initialConnectionTcs;
51
56
60 TaskCompletionSource nextMessage;
61
66
71
77 protected static string GetEngineCompilerPrefix(Api.Models.EngineType engineType)
78 => engineType switch
79 {
82 _ => throw new InvalidOperationException($"Unsupported engine type: {engineType}"),
83 };
84
93 {
95 AsyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer));
96 Logger = logger ?? throw new ArgumentNullException(nameof(logger));
98
99 if (chatBot.Instance == null)
100 throw new ArgumentException("chatBot must have Instance!", nameof(chatBot));
101
103 nextMessage = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
104 initialConnectionTcs = new TaskCompletionSource();
106
107 logger.LogTrace("Created.");
108 }
109
111 public abstract bool Connected { get; }
112
114 public abstract string BotMention { get; }
115
117 public bool Disposed { get; private set; }
118
120 public virtual async ValueTask DisposeAsync()
121 {
122 Disposed = true;
124
125 // queue a final message to shutdown the NextMessage Task
126 EnqueueMessage(null);
127 Logger.LogTrace("Disposed");
128 }
129
131 public async ValueTask Disconnect(CancellationToken cancellationToken)
132 {
134
135 if (Connected)
136 {
137 Logger.LogTrace("Disconnecting...");
139 Logger.LogTrace("Disconnected");
140 }
141 }
142
144 public void InitialMappingComplete() => initialConnectionTcs.TrySetResult();
145
148 {
149 ArgumentNullException.ThrowIfNull(channels);
150
151 try
152 {
154 }
155 catch
156 {
157 initialConnectionTcs.TrySetResult();
158 throw;
159 }
160 }
161
164 {
165 while (true)
166 {
167 await nextMessage.Task.WaitAsync(cancellationToken);
169 if (messageQueue.Count > 0)
170 {
171 var result = messageQueue.Dequeue();
172 if (messageQueue.Count == 0)
173 nextMessage = new TaskCompletionSource();
174 return result;
175 }
176 }
177 }
178
195
198
202 Api.Models.EngineVersion engineVersion,
204 string? gitHubOwner,
205 string? gitHubRepo,
206 ulong channelId,
208 CancellationToken cancellationToken);
209
215 protected abstract ValueTask Connect(CancellationToken cancellationToken);
216
222 protected abstract ValueTask DisconnectImpl(CancellationToken cancellationToken);
223
232 CancellationToken cancellationToken);
233
239 {
240 if (message == null)
241 Logger.LogTrace("Requesting channel remap...");
242
244 {
245 messageQueue.Enqueue(message);
246 nextMessage.TrySetResult();
247 }
248 }
249
255 {
256 Logger.LogTrace("StopReconnectionTimer");
258 if (reconnectCts != null)
259 {
260 reconnectCts.Cancel();
261 reconnectCts.Dispose();
262 reconnectCts = null;
263 var reconnectTask = this.reconnectTask!;
264 this.reconnectTask = null;
265 return reconnectTask;
266 }
267 else
268 Logger.LogTrace("Timer wasn't running");
269
270 return Task.CompletedTask;
271 }
272
281 {
282 do
283 {
284 try
285 {
286 if (!connectNow)
288 else
289 connectNow = false;
290 if (!Connected)
291 {
292 var job = Job.Create(Api.Models.JobCode.ReconnectChatBot, null, ChatBot.Instance!, ChatBotRights.WriteEnabled);
293 job.Description += $": {ChatBot.Name}";
294
296 job,
297 async (core, databaseContextFactory, paramJob, progressReporter, jobCancellationToken) =>
298 {
299 try
300 {
301 if (Connected)
302 {
303 Logger.LogTrace("Disconnecting...");
305 }
306 else
307 Logger.LogTrace("Already disconnected not doing disconnection attempt!");
308
309 Logger.LogTrace("Connecting...");
311 Logger.LogTrace("Connected successfully");
312 EnqueueMessage(null);
313 }
314 catch
315 {
316 // we set this here because otherwise there could be stuff waiting on to connect us forever
317 initialConnectionTcs.TrySetResult();
318 throw;
319 }
320 },
322
324 }
325 }
327 {
328 Logger.LogTrace(e, "ReconnectionLoop cancelled");
329 }
330 catch (Exception e)
331 {
332 Logger.LogError(e, "Error reconnecting!");
333 }
334 }
335 while (!cancellationToken.IsCancellationRequested);
336
337 Logger.LogTrace("ReconnectionLoop exiting...");
338 }
339 }
340}
Represents a message received by a IProvider.
Definition Message.cs:9
ValueTask Connect(CancellationToken cancellationToken)
Attempt to connect the Provider.
bool Disposed
If the IProvider was disposed.
Definition Provider.cs:117
Task StopReconnectionTimer()
Stops and awaits the reconnectTask.
Definition Provider.cs:254
async ValueTask Disconnect(CancellationToken cancellationToken)
Gracefully disconnects the provider. Permanently stops the reconnection timer.A ValueTask representin...
Definition Provider.cs:131
ValueTask DisconnectImpl(CancellationToken cancellationToken)
Gracefully disconnects the provider.
Provider(IJobManager jobManager, IAsyncDelayer asyncDelayer, ILogger< Provider > logger, ChatBot chatBot)
Initializes a new instance of the Provider class.
Definition Provider.cs:92
ValueTask< Dictionary< ChatChannel, IEnumerable< ChannelRepresentation > > > MapChannelsImpl(IEnumerable< ChatChannel > channels, CancellationToken cancellationToken)
Implementation of MapChannels(IEnumerable<ChatChannel>, CancellationToken).
async Task< Message?> NextMessage(CancellationToken cancellationToken)
Get a Task<TResult> resulting in the next Message the IProvider receives or null on a disconnect....
Definition Provider.cs:163
void EnqueueMessage(Message? message)
Queues a message for NextMessage(CancellationToken).
Definition Provider.cs:238
bool Connected
If the IProvider is currently connected.
Definition Provider.cs:111
readonly Queue< Message?> messageQueue
Queue<T> of received Messages.
Definition Provider.cs:45
readonly TaskCompletionSource initialConnectionTcs
The backing TaskCompletionSource for InitialConnectionJob.
Definition Provider.cs:50
static string GetEngineCompilerPrefix(Api.Models.EngineType engineType)
Get the prefix for messages about deployments.
TaskCompletionSource nextMessage
TaskCompletionSource that completes while messageQueue isn't empty.
Definition Provider.cs:60
Task InitialConnectionJob
A Task that completes once the IProvider finishes it's first connection attempt regardless of success...
Definition Provider.cs:20
CancellationTokenSource? reconnectCts
CancellationTokenSource for reconnectTask.
Definition Provider.cs:70
readonly IJobManager jobManager
The IJobManager for the Provider.
Definition Provider.cs:40
async ValueTask< Dictionary< ChatChannel, IEnumerable< ChannelRepresentation > > > MapChannels(IEnumerable< ChatChannel > channels, CancellationToken cancellationToken)
Get the ChannelRepresentations for given channels .A ValueTask<TResult> resulting in a Dictionary<TKe...
Definition Provider.cs:147
ILogger< Provider > Logger
The ILogger for the Provider.
Definition Provider.cs:35
readonly object reconnectTaskLock
Used for synchronizing access to reconnectCts and reconnectTask.
Definition Provider.cs:55
Task SetReconnectInterval(uint reconnectInterval, bool connectNow)
Set the interval at which the provider starts jobs to try to reconnect.A Task representing the runnin...
Definition Provider.cs:180
async Task ReconnectionLoop(uint reconnectInterval, bool connectNow, CancellationToken cancellationToken)
Creates a Task that will attempt to reconnect the Provider every reconnectInterval minutes.
Definition Provider.cs:280
string BotMention
The string that indicates the IProvider was mentioned.
Definition Provider.cs:114
ValueTask< Func< string?, string, ValueTask< Func< bool, ValueTask > > > > SendUpdateMessage(RevisionInformation revisionInformation, Api.Models.EngineVersion engineVersion, DateTimeOffset? estimatedCompletionTime, string? gitHubOwner, string? gitHubRepo, ulong channelId, bool localCommitPushed, CancellationToken cancellationToken)
Send the message for a deployment.A ValueTask<TResult> resulting in a Func<T1, T2,...
void InitialMappingComplete()
Indicate to the provider that at least one MapChannels(IEnumerable<ChatChannel>, CancellationToken) c...
ValueTask SendMessage(Message? replyTo, MessageContent message, ulong channelId, CancellationToken cancellationToken)
Send a message to the IProvider.A ValueTask representing the running operation.
Represents a message to send to a chat provider.
Instance? Instance
The parent Models.Instance.
Definition ChatBot.cs:27
static Job Create(JobCode code, User? startedBy, Api.Models.Instance instance)
Creates a new job for registering in the Jobs.IJobService.
async ValueTask Delay(TimeSpan timeSpan, CancellationToken cancellationToken)
Create a Task that completes after a given timeSpan .A ValueTask representing the running operation.
Manages the runtime of Jobs.
ValueTask< bool?> WaitForJobCompletion(Job job, User? canceller, CancellationToken jobCancellationToken, CancellationToken cancellationToken)
Wait for a given job to complete.
ValueTask RegisterOperation(Job job, JobEntrypoint operation, CancellationToken cancellationToken)
Registers a given Job and begins running it.
ChatBotRights
Rights for chat bots.
@ List
User may list files if the Models.Instance allows it.