tgstation-server 6.16.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
203 Api.Models.EngineVersion engineVersion,
204 DateTimeOffset? estimatedCompletionTime,
205 string? gitHubOwner,
206 string? gitHubRepo,
207 ulong channelId,
209 CancellationToken cancellationToken);
210
216 protected abstract ValueTask Connect(CancellationToken cancellationToken);
217
223 protected abstract ValueTask DisconnectImpl(CancellationToken cancellationToken);
224
233 CancellationToken cancellationToken);
234
240 {
241 if (message == null)
242 Logger.LogTrace("Requesting channel remap...");
243
245 {
246 messageQueue.Enqueue(message);
247 nextMessage.TrySetResult();
248 }
249 }
250
256 {
257 Logger.LogTrace("StopReconnectionTimer");
259 if (reconnectCts != null)
260 {
261 reconnectCts.Cancel();
262 reconnectCts.Dispose();
263 reconnectCts = null;
264 var reconnectTask = this.reconnectTask!;
265 this.reconnectTask = null;
266 return reconnectTask;
267 }
268 else
269 Logger.LogTrace("Timer wasn't running");
270
271 return Task.CompletedTask;
272 }
273
282 {
283 do
284 {
285 try
286 {
287 if (!connectNow)
289 else
290 connectNow = false;
291 if (!Connected)
292 {
293 var job = Job.Create(Api.Models.JobCode.ReconnectChatBot, null, ChatBot.Instance!, ChatBotRights.WriteEnabled);
294 job.Description += $": {ChatBot.Name}";
295
297 job,
298 async (core, databaseContextFactory, paramJob, progressReporter, jobCancellationToken) =>
299 {
300 try
301 {
302 if (Connected)
303 {
304 Logger.LogTrace("Disconnecting...");
306 }
307 else
308 Logger.LogTrace("Already disconnected not doing disconnection attempt!");
309
310 Logger.LogTrace("Connecting...");
312 Logger.LogTrace("Connected successfully");
313 EnqueueMessage(null);
314 }
315 catch
316 {
317 // we set this here because otherwise there could be stuff waiting on to connect us forever
318 initialConnectionTcs.TrySetResult();
319 throw;
320 }
321 },
323
325 }
326 }
328 {
329 Logger.LogTrace(e, "ReconnectionLoop cancelled");
330 }
331 catch (Exception e)
332 {
333 Logger.LogError(e, "Error reconnecting!");
334 }
335 }
336 while (!cancellationToken.IsCancellationRequested);
337
338 Logger.LogTrace("ReconnectionLoop exiting...");
339 }
340 }
341}
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:255
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:239
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:281
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, RevisionInformation? previousRevisionInformation, 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.