From d145f484e827f2354d27fe1935afe65799e4e6b2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 18 Nov 2023 21:44:21 -0500 Subject: [PATCH] Disallow custom chat commands while the server is rebooting Also a bunch of cleanups in `ChatManager.ProcessMessage` --- .../Components/Chat/ChatManager.cs | 107 ++++++------------ .../Components/Session/ISessionController.cs | 5 - .../Components/Session/SessionController.cs | 8 +- .../Components/Watchdog/BasicWatchdog.cs | 2 - 4 files changed, 41 insertions(+), 81 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs index ecb0fa6498..fb1b617625 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs +++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs @@ -154,7 +154,7 @@ namespace Tgstation.Server.Host.Components.Chat synchronizationLock = new object(); - builtinCommands = new Dictionary(); + builtinCommands = new Dictionary(StringComparer.OrdinalIgnoreCase); providers = new Dictionary(); mappedChannels = new Dictionary(); trackingContexts = new List(); @@ -713,6 +713,18 @@ namespace Tgstation.Server.Host.Components.Chat return; } + ValueTask TextReply(string reply) => SendMessage( + new List + { + message.User.Channel.RealId, + }, + message, + new MessageContent + { + Text = reply, + }, + cancellationToken); + if (message.User.Channel.IsPrivateChannel) lock (mappedChannels) if (!mappedChannel.HasValue) @@ -753,17 +765,7 @@ namespace Tgstation.Server.Host.Components.Chat logger.LogTrace("message: {messageJson}", JsonConvert.SerializeObject(message)); lock (mappedChannels) logger.LogTrace("mappedChannels: {mappedChannelsJson}", JsonConvert.SerializeObject(mappedChannels)); - await SendMessage( - new List - { - message.User.Channel.RealId, - }, - message, - new MessageContent - { - Text = "TGS: Processing error, check logs!", - }, - cancellationToken); + await TextReply("TGS: Processing error, check logs!"); return; } @@ -805,41 +807,29 @@ namespace Tgstation.Server.Host.Components.Chat if (splits.Count == 0) { // just a mention - await SendMessage( - new List - { - message.User.Channel.RealId, - }, - message, - new MessageContent - { - Text = "Hi!", - }, - cancellationToken); + await TextReply("Hi!"); return; } - var command = splits[0].ToUpperInvariant(); + var command = splits[0]; splits.RemoveAt(0); var arguments = String.Join(" ", splits); - ICommand GetCommand(string commandName) + Tuple GetCommand() { - if (!builtinCommands.TryGetValue(commandName, out var handler)) - { - handler = trackingContexts - .Where(x => x.CustomCommands != null) - .SelectMany(x => x.CustomCommands) - .Where(x => x.Name.ToUpperInvariant() == commandName) + if (!builtinCommands.TryGetValue(command, out var handler)) + return trackingContexts + .Where(trackingContext => trackingContext.Active) + .SelectMany(trackingContext => trackingContext.CustomCommands.Select(customCommand => Tuple.Create(customCommand, trackingContext))) + .Where(tuple => tuple.Item1.Name.Equals(command, StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); - } - return handler; + return Tuple.Create(handler, null); } - const string UnknownCommandMessage = "Unknown command! Type '?' or 'help' for available commands."; + const string UnknownCommandMessage = "TGS: Unknown command! Type '?' or 'help' for available commands."; - if (command == "HELP" || command == "?") + if (command.Equals("help", StringComparison.OrdinalIgnoreCase) || command == "?") { string helpText; if (splits.Count == 0) @@ -847,56 +837,40 @@ namespace Tgstation.Server.Host.Components.Chat var allCommands = builtinCommands.Select(x => x.Value).ToList(); allCommands.AddRange( trackingContexts - .Where(x => x.CustomCommands != null) .SelectMany( x => x.CustomCommands)); helpText = String.Format(CultureInfo.InvariantCulture, "Available commands (Type '?' or 'help' and then a command name for more details): {0}", String.Join(", ", allCommands.Select(x => x.Name))); } else { - var helpHandler = GetCommand(splits[0].ToUpperInvariant()); + var (helpHandler, _) = GetCommand(); if (helpHandler != default) helpText = String.Format(CultureInfo.InvariantCulture, "{0}: {1}{2}", helpHandler.Name, helpHandler.HelpText, helpHandler.AdminOnly ? " - May only be used in admin channels" : String.Empty); else helpText = UnknownCommandMessage; } - await SendMessage( - new List { message.User.Channel.RealId }, - message, - new MessageContent - { - Text = helpText, - }, - cancellationToken); + await TextReply(helpText); return; } - var commandHandler = GetCommand(command); + var (commandHandler, trackingContext) = GetCommand(); if (commandHandler == default) { - await SendMessage( - new List { message.User.Channel.RealId }, - message, - new MessageContent - { - Text = UnknownCommandMessage, - }, - cancellationToken); + await TextReply(UnknownCommandMessage); + return; + } + + if (trackingContext?.Active == false) + { + await TextReply("TGS: The server is rebooting, please try again later"); return; } if (commandHandler.AdminOnly && !message.User.Channel.IsAdminChannel) { - await SendMessage( - new List { message.User.Channel.RealId }, - message, - new MessageContent - { - Text = "Use this command in an admin channel!", - }, - cancellationToken); + await TextReply("TGS: Use this command in an admin channel!"); return; } @@ -912,14 +886,7 @@ namespace Tgstation.Server.Host.Components.Chat { // error bc custom commands should reply about why it failed logger.LogError(e, "Error processing chat command"); - await SendMessage( - new List { message.User.Channel.RealId }, - message, - new MessageContent - { - Text = "TGS: Internal error processing command! Check server logs!", - }, - cancellationToken); + await TextReply("TGS: Internal error processing command! Check server logs!"); } finally { diff --git a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs index 72e66c2066..0372a32ec0 100644 --- a/src/Tgstation.Server.Host/Components/Session/ISessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/ISessionController.cs @@ -119,11 +119,6 @@ namespace Tgstation.Server.Host.Components.Session /// void ResetRebootState(); - /// - /// Enables the reading of custom chat commands from the . - /// - void EnableCustomChatCommands(); - /// /// Replace the in use with a given , disposing the old one. /// diff --git a/src/Tgstation.Server.Host/Components/Session/SessionController.cs b/src/Tgstation.Server.Host/Components/Session/SessionController.cs index 93e05417a3..04a34af9aa 100644 --- a/src/Tgstation.Server.Host/Components/Session/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Session/SessionController.cs @@ -401,9 +401,6 @@ namespace Tgstation.Server.Host.Components.Session } } - /// - public void EnableCustomChatCommands() => chatTrackingContext.Active = DMApiAvailable; - /// public ValueTask Release() { @@ -751,6 +748,7 @@ namespace Tgstation.Server.Host.Components.Session break; case BridgeCommandType.Kill: Logger.LogInformation("Bridge requested process termination!"); + chatTrackingContext.Active = false; TerminationWasRequested = true; process.Terminate(); break; @@ -839,15 +837,17 @@ namespace Tgstation.Server.Host.Components.Session // Load custom commands chatTrackingContext.CustomCommands = parameters.CustomCommands; + chatTrackingContext.Active = true; Interlocked.Exchange(ref startupTcs, new TaskCompletionSource()).SetResult(); break; case BridgeCommandType.Reboot: Interlocked.Increment(ref rebootBridgeRequestsProcessing); try { + chatTrackingContext.Active = false; + if (ClosePortOnReboot) { - chatTrackingContext.Active = false; response.NewPort = 0; portClosedForReboot = true; } diff --git a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs index d915a8b935..ee110646fa 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/BasicWatchdog.cs @@ -256,8 +256,6 @@ namespace Tgstation.Server.Host.Components.Watchdog await SessionStartupPersist(cancellationToken); await CheckLaunchResult(Server, "Server", cancellationToken); - - Server.EnableCustomChatCommands(); } catch (Exception ex) {