Nullify ChatManager

This commit is contained in:
Jordan Dominion
2023-12-17 23:25:34 -05:00
parent 85207f6ce8
commit de1872cd7f
@@ -21,8 +21,6 @@ using Tgstation.Server.Host.Components.Interop;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Utils;
#nullable disable
namespace Tgstation.Server.Host.Components.Chat
{
/// <inheritdoc cref="IChatManager" />
@@ -103,17 +101,17 @@ namespace Tgstation.Server.Host.Components.Chat
/// <summary>
/// The <see cref="ICustomCommandHandler"/> for the <see cref="ChangeChannels(long, IEnumerable{Models.ChatChannel}, CancellationToken)"/>.
/// </summary>
ICustomCommandHandler customCommandHandler;
ICustomCommandHandler? customCommandHandler;
/// <summary>
/// The <see cref="Task"/> that monitors incoming chat messages.
/// </summary>
Task chatHandler;
Task? chatHandler;
/// <summary>
/// A <see cref="Task"/> that represents the <see cref="IProvider"/>s initial connection.
/// </summary>
Task initialProviderConnectionsTask;
Task? initialProviderConnectionsTask;
/// <summary>
/// A <see cref="Task"/> that represents all sent messages.
@@ -256,7 +254,7 @@ namespace Tgstation.Server.Host.Components.Chat
lock (mappedChannels)
{
lock (providers)
if (!providers.TryGetValue(connectionId, out IProvider verify) || verify != provider) // aborted again
if (!providers.TryGetValue(connectionId, out var verify) || verify != provider) // aborted again
return;
foreach (var newMapping in newMappings)
{
@@ -270,7 +268,7 @@ namespace Tgstation.Server.Host.Components.Chat
// we only want to update contexts if everything at startup has connected once already
// otherwise we could send an incomplete channel set to the DMAPI, which will then spout all its queued messages into it instead of all relevant chatbots
// The watchdog can call this if it needs to after starting up
if (initialProviderConnectionsTask.IsCompleted)
if (initialProviderConnectionsTask!.IsCompleted)
await UpdateTrackingContexts(cancellationToken);
}
finally
@@ -288,23 +286,25 @@ namespace Tgstation.Server.Host.Components.Chat
logger.LogTrace("ChangeSettings...");
Task disconnectTask;
IProvider provider = null;
IProvider? provider = null;
var newSettingsId = Models.ModelExtensions.Require(newSettings, x => x.Id);
var newSettingsEnabled = Models.ModelExtensions.Require(newSettings, x => x.Enabled);
lock (providers)
{
// raw settings changes forces a rebuild of the provider
if (providers.ContainsKey(newSettings.Id.Value))
disconnectTask = DeleteConnection(newSettings.Id.Value, cancellationToken);
if (providers.ContainsKey(newSettingsId))
disconnectTask = DeleteConnection(newSettingsId, cancellationToken);
else
disconnectTask = Task.CompletedTask;
if (newSettings.Enabled.Value)
if (newSettingsEnabled)
{
provider = providerFactory.CreateProvider(newSettings);
providers.Add(newSettings.Id.Value, provider);
providers.Add(newSettingsId, provider);
}
}
lock (mappedChannels)
foreach (var oldMappedChannelId in mappedChannels.Where(x => x.Value.ProviderId == newSettings.Id).Select(x => x.Key).ToList())
foreach (var oldMappedChannelId in mappedChannels.Where(x => x.Value.ProviderId == newSettingsId).Select(x => x.Key).ToList())
mappedChannels.Remove(oldMappedChannelId);
await disconnectTask;
@@ -318,8 +318,8 @@ namespace Tgstation.Server.Host.Components.Chat
}
var reconnectionUpdateTask = provider?.SetReconnectInterval(
newSettings.ReconnectionInterval.Value,
newSettings.Enabled.Value)
Models.ModelExtensions.Require(newSettings, x => x.ReconnectionInterval),
newSettingsEnabled)
?? Task.CompletedTask;
lock (activeChatBots)
{
@@ -358,7 +358,7 @@ namespace Tgstation.Server.Host.Components.Chat
message = String.Format(CultureInfo.InvariantCulture, "WD: {0}", message);
if (!initialProviderConnectionsTask.IsCompleted)
if (!initialProviderConnectionsTask!.IsCompleted)
logger.LogTrace("Waiting for initial provider connections before sending watchdog message...");
// Reimplementing QueueMessage
@@ -397,11 +397,11 @@ namespace Tgstation.Server.Host.Components.Chat
wdChannels.Select(
async x =>
{
ChannelMapping channelMapping;
ChannelMapping? channelMapping;
lock (mappedChannels)
if (!mappedChannels.TryGetValue(x, out channelMapping))
return;
IProvider provider;
IProvider? provider;
lock (providers)
if (!providers.TryGetValue(channelMapping.ProviderId, out provider))
return;
@@ -432,7 +432,7 @@ namespace Tgstation.Server.Host.Components.Chat
AddMessageTask(task);
Task callbackTask;
Func<bool, Task> finalUpdateAction = null;
Func<bool, Task>? finalUpdateAction = null;
async Task CallbackTask(string errorMessage, string dreamMakerOutput)
{
await task;
@@ -458,7 +458,7 @@ namespace Tgstation.Server.Host.Components.Chat
return;
}
AddMessageTask(finalUpdateAction(active));
AddMessageTask(finalUpdateAction!(active));
}
return (errorMessage, dreamMakerOutput) =>
@@ -496,7 +496,7 @@ namespace Tgstation.Server.Host.Components.Chat
if (customCommandHandler == null)
throw new InvalidOperationException("RegisterCommandHandler() hasn't been called!");
IChatTrackingContext context = null;
IChatTrackingContext context = null!;
lock (mappedChannels)
context = new ChatTrackingContext(
customCommandHandler,
@@ -525,7 +525,7 @@ namespace Tgstation.Server.Host.Components.Chat
await channelSink.UpdateChannels(channels, cancellationToken);
}
var waitingForInitialConnection = !initialProviderConnectionsTask.IsCompleted;
var waitingForInitialConnection = !initialProviderConnectionsTask!.IsCompleted;
if (waitingForInitialConnection)
{
logger.LogTrace("Waiting for initial chat bot connections before updating tracking contexts...");
@@ -563,7 +563,7 @@ namespace Tgstation.Server.Host.Components.Chat
? semaphore
: null)
using (hasSemaphore
? await SemaphoreSlimContext.Lock(semaphore, cancellationToken)
? await SemaphoreSlimContext.Lock(semaphore!, cancellationToken)
: null)
{
var provider = await RemoveProviderChannels(connectionId, true, cancellationToken);
@@ -590,7 +590,7 @@ namespace Tgstation.Server.Host.Components.Chat
}
/// <inheritdoc />
public ValueTask HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken)
public ValueTask HandleRestart(Version? updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken)
{
var message = updateVersion == null
? $"TGS: {(handlerMayDelayShutdownWithExtremelyLongRunningTasks ? "Graceful shutdown" : "Going down")}..."
@@ -619,10 +619,10 @@ namespace Tgstation.Server.Host.Components.Chat
/// <param name="removeProvider">If the provider should be removed from <see cref="providers"/> and <see cref="trackingContexts"/> should be update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask{TResult}"/> resulting in the <see cref="IProvider"/> being removed if it exists, <see langword="null"/> otherwise.</returns>
async ValueTask<IProvider> RemoveProviderChannels(long connectionId, bool removeProvider, CancellationToken cancellationToken)
async ValueTask<IProvider?> RemoveProviderChannels(long connectionId, bool removeProvider, CancellationToken cancellationToken)
{
logger.LogTrace("RemoveProviderChannels {connectionId}...", connectionId);
IProvider provider;
IProvider? provider;
lock (providers)
{
if (!providers.TryGetValue(connectionId, out provider))
@@ -664,7 +664,7 @@ namespace Tgstation.Server.Host.Components.Chat
async ValueTask RemapProvider(IProvider provider, CancellationToken cancellationToken)
{
logger.LogTrace("Remapping channels for provider reconnection...");
IEnumerable<Models.ChatChannel> channelsToMap;
IEnumerable<Models.ChatChannel>? channelsToMap;
long providerId;
lock (providers)
providerId = providers.Where(x => x.Value == provider).Select(x => x.Key).First();
@@ -685,7 +685,7 @@ namespace Tgstation.Server.Host.Components.Chat
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="ValueTask"/> representing the running operation.</returns>
#pragma warning disable CA1502
async ValueTask ProcessMessage(IProvider provider, Message message, bool recursed, CancellationToken cancellationToken)
async ValueTask ProcessMessage(IProvider provider, Message? message, bool recursed, CancellationToken cancellationToken)
#pragma warning restore CA1502
{
if (!provider.Connected)
@@ -843,16 +843,16 @@ namespace Tgstation.Server.Host.Components.Chat
splits.RemoveAt(0);
var arguments = String.Join(" ", splits);
Tuple<ICommand, IChatTrackingContext> GetCommand()
Tuple<ICommand, IChatTrackingContext?>? GetCommand()
{
if (!builtinCommands.TryGetValue(command, out var handler))
return trackingContexts
.Where(trackingContext => trackingContext.Active)
.SelectMany(trackingContext => trackingContext.CustomCommands.Select(customCommand => Tuple.Create<ICommand, IChatTrackingContext>(customCommand, trackingContext)))
.SelectMany(trackingContext => trackingContext.CustomCommands.Select(customCommand => Tuple.Create<ICommand, IChatTrackingContext?>(customCommand, trackingContext)))
.Where(tuple => tuple.Item1.Name.Equals(command, StringComparison.OrdinalIgnoreCase))
.FirstOrDefault();
return Tuple.Create<ICommand, IChatTrackingContext>(handler, null);
return Tuple.Create<ICommand, IChatTrackingContext?>(handler, null);
}
const string UnknownCommandMessage = "TGS: Unknown command! Type '?' or 'help' for available commands.";
@@ -935,11 +935,11 @@ namespace Tgstation.Server.Host.Components.Chat
async Task MonitorMessages(CancellationToken cancellationToken)
{
logger.LogTrace("Starting processing loop...");
var messageTasks = new Dictionary<IProvider, Task<Message>>();
var messageTasks = new Dictionary<IProvider, Task<Message?>>();
ValueTask activeProcessingTask = ValueTask.CompletedTask;
try
{
Task updatedTask = null;
Task? updatedTask = null;
while (!cancellationToken.IsCancellationRequested)
{
if (updatedTask?.IsCompleted != false)
@@ -1025,7 +1025,7 @@ namespace Tgstation.Server.Host.Components.Chat
/// <param name="message">The <see cref="MessageContent"/> to send.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
ValueTask SendMessage(IEnumerable<ulong> channelIds, Message replyTo, MessageContent message, CancellationToken cancellationToken)
ValueTask SendMessage(IEnumerable<ulong> channelIds, Message? replyTo, MessageContent message, CancellationToken cancellationToken)
{
var channelIdsList = channelIds.ToList();
@@ -1041,11 +1041,11 @@ namespace Tgstation.Server.Host.Components.Chat
return ValueTaskExtensions.WhenAll(
channelIdsList.Select(x =>
{
ChannelMapping channelMapping;
ChannelMapping? channelMapping;
lock (mappedChannels)
if (!mappedChannels.TryGetValue(x, out channelMapping))
return ValueTask.CompletedTask;
IProvider provider;
IProvider? provider;
lock (providers)
if (!providers.TryGetValue(channelMapping.ProviderId, out provider))
return ValueTask.CompletedTask;
@@ -1102,7 +1102,7 @@ namespace Tgstation.Server.Host.Components.Chat
{
var cancellationToken = handlerCts.Token;
if (waitForConnections)
await initialProviderConnectionsTask.WaitAsync(cancellationToken);
await initialProviderConnectionsTask!.WaitAsync(cancellationToken);
await SendMessage(
channelIdsFactory(),