From 5c4f55850c9036cfee63fb5ed3dc5124d3b225ff Mon Sep 17 00:00:00 2001 From: craftxbox Date: Fri, 20 Sep 2024 04:02:11 -0230 Subject: [PATCH 1/6] Refactor IrcProvider just a little --- .../Models/IrcConnectionStringBuilder.cs | 1 + .../Models/IrcPasswordType.cs | 5 + .../Components/Chat/Providers/IrcProvider.cs | 198 +++++++++++------- .../Chat/Providers/TestIrcProvider.cs | 11 + 4 files changed, 135 insertions(+), 80 deletions(-) diff --git a/src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs b/src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs index b4cb64a8118..18e8a14df6e 100644 --- a/src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs +++ b/src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs @@ -88,6 +88,7 @@ public IrcConnectionStringBuilder(string connectionString) case IrcPasswordType.NickServ: case IrcPasswordType.Sasl: case IrcPasswordType.Server: + case IrcPasswordType.Oper: PasswordType = passwordType; break; default: diff --git a/src/Tgstation.Server.Api/Models/IrcPasswordType.cs b/src/Tgstation.Server.Api/Models/IrcPasswordType.cs index add54b1565f..9a0fca38c46 100644 --- a/src/Tgstation.Server.Api/Models/IrcPasswordType.cs +++ b/src/Tgstation.Server.Api/Models/IrcPasswordType.cs @@ -19,5 +19,10 @@ public enum IrcPasswordType /// Use NickServ authentication. /// NickServ, + + /// + /// Use OPER authentication. + /// + Oper, } } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index ad83a80b18b..3a532f6b425 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -42,11 +42,6 @@ sealed class IrcProvider : Provider /// public override string BotMention => client.Nickname; - /// - /// The client. - /// - readonly IrcFeatures client; - /// /// Address of the server to connect to. /// @@ -57,6 +52,11 @@ sealed class IrcProvider : Provider /// readonly ushort port; + /// + /// Wether or not this IRC client is to use ssl. + /// + readonly bool ssl; + /// /// IRC nickname. /// @@ -82,6 +82,16 @@ sealed class IrcProvider : Provider /// readonly Dictionary queryChannelIdMap; + /// + /// The version string obtained from . + /// + readonly string versionString; + + /// + /// The client. + /// + IrcFeatures client; + /// /// The used for . /// @@ -92,11 +102,6 @@ sealed class IrcProvider : Provider /// ulong channelIdCounter; - /// - /// If we are disconnecting. - /// - bool disconnecting; - /// /// Initializes a new instance of the class. /// @@ -121,33 +126,15 @@ public IrcProvider( address = ircBuilder.Address!; port = ircBuilder.Port!.Value; + ssl = ircBuilder.UseSsl!.Value; nickname = ircBuilder.Nickname!; password = ircBuilder.Password!; passwordType = ircBuilder.PasswordType; - client = new IrcFeatures - { - SupportNonRfc = true, - CtcpUserInfo = "You are going to play. And I am going to watch. And everything will be just fine...", - AutoRejoin = true, - AutoRejoinOnKick = true, - AutoRelogin = true, - AutoRetry = false, - AutoReconnect = false, - ActiveChannelSyncing = true, - AutoNickHandling = true, - CtcpVersion = assemblyInformationProvider.VersionString, - UseSsl = ircBuilder.UseSsl!.Value, - }; - if (ircBuilder.UseSsl.Value) - client.ValidateServerCertificate = true; // dunno if it defaults to that or what - - client.OnChannelMessage += Client_OnChannelMessage; - client.OnQueryMessage += Client_OnQueryMessage; + versionString = assemblyInformationProvider.VersionString; - /*client.OnReadLine += (sender, e) => Logger.LogTrace("READ: {line}", e.Line); - client.OnWriteLine += (sender, e) => Logger.LogTrace("WRITE: {line}", e.Line);*/ + client = InstantiateClient(); channelIdMap = new Dictionary(); queryChannelIdMap = new Dictionary(); @@ -369,12 +356,15 @@ await SendMessage( /// protected override async ValueTask Connect(CancellationToken cancellationToken) { - disconnecting = false; cancellationToken.ThrowIfCancellationRequested(); try { await Task.Factory.StartNew( - () => client.Connect(address, port), + () => + { + client = InstantiateClient(); + client.Connect(address, port); + }, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current) @@ -382,70 +372,50 @@ await Task.Factory.StartNew( cancellationToken.ThrowIfCancellationRequested(); + listenTask = Task.Factory.StartNew( + () => + { + Logger.LogTrace("Starting blocking listen..."); + try + { + client.Listen(); + } + catch (Exception ex) + { + Logger.LogWarning(ex, "IRC Main Listen Exception!"); + } + + Logger.LogTrace("Exiting listening task..."); + }, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current); + Logger.LogTrace("Authenticating ({passwordType})...", passwordType); switch (passwordType) { case IrcPasswordType.Server: - client.Login(nickname, nickname, 0, nickname, password); + client.RfcPass(password); + await Login(client, nickname); break; case IrcPasswordType.NickServ: - client.Login(nickname, nickname, 0, nickname); + await Login(client, nickname); cancellationToken.ThrowIfCancellationRequested(); client.SendMessage(SendType.Message, "NickServ", String.Format(CultureInfo.InvariantCulture, "IDENTIFY {0}", password)); break; case IrcPasswordType.Sasl: await SaslAuthenticate(cancellationToken); break; + case IrcPasswordType.Oper: + await Login(client, nickname); + cancellationToken.ThrowIfCancellationRequested(); + client.RfcOper(nickname, password, Priority.Critical); + break; case null: - client.Login(nickname, nickname, 0, nickname); + await Login(client, nickname); break; default: throw new InvalidOperationException($"Invalid IrcPasswordType: {passwordType.Value}"); } cancellationToken.ThrowIfCancellationRequested(); - Logger.LogTrace("Processing initial messages..."); - await NonBlockingListen(cancellationToken); - - var nickCheckCompleteTcs = new TaskCompletionSource(); - using (cancellationToken.Register(() => nickCheckCompleteTcs.TrySetCanceled(cancellationToken))) - { - listenTask = Task.Factory.StartNew( - async () => - { - Logger.LogTrace("Entering nick check loop"); - while (!disconnecting && client.IsConnected && client.Nickname != nickname) - { - client.ListenOnce(true); - if (disconnecting || !client.IsConnected) - break; - await NonBlockingListen(cancellationToken); - - // ensure we have the correct nick - if (client.GetIrcUser(nickname) == null) - client.RfcNick(nickname); - } - - nickCheckCompleteTcs.TrySetResult(); - - Logger.LogTrace("Starting blocking listen..."); - try - { - client.Listen(); - } - catch (Exception ex) - { - Logger.LogWarning(ex, "IRC Main Listen Exception!"); - } - - Logger.LogTrace("Exiting listening task..."); - }, - cancellationToken, - DefaultIOManager.BlockingTaskCreationOptions, - TaskScheduler.Current); - - await nickCheckCompleteTcs.Task; - } Logger.LogTrace("Connection established!"); } @@ -487,6 +457,37 @@ await Task.Factory.StartNew( } } + /// + /// Register the client on the network. + /// + /// IRC client. + /// Nickname. + /// that resolves when registration has been completed. + /// If the IRC server fails to respond. + private async Task Login(IrcFeatures client, string nickname) + { + var promise = new TaskCompletionSource(); + + void Callback(object? sender, EventArgs e) + { + Logger.LogTrace("IRC Registered."); + promise.TrySetResult(e); + } + + client.OnRegistered += Callback; + + client.Login(nickname, nickname, 0, nickname); + + var completed = await Task.WhenAny(promise.Task, Task.Delay(30 * 1000)); + if (completed == promise.Task) + { + client.OnRegistered -= Callback; + return; + } + + throw new TimeoutException("Timed out waiting for IRC registration."); + } + /// /// Handle an IRC message. /// @@ -667,8 +668,6 @@ async ValueTask HardDisconnect(CancellationToken cancellationToken) Logger.LogTrace("Hard disconnect"); - disconnecting = true; - // This call blocks permanently randomly sometimes // Frankly I don't give a shit var disconnectTask = Task.Factory.StartNew( @@ -693,5 +692,44 @@ await Task.WhenAny( listenTask ?? Task.CompletedTask), AsyncDelayer.Delay(TimeSpan.FromSeconds(5), cancellationToken)); } + + /// + /// Creates a new instance of the IRC client. + /// Reusing the same client after a disconnection seems to cause issues. + /// + /// The client to use. + private IrcFeatures InstantiateClient() + { + IrcFeatures newClient = new IrcFeatures + { + SupportNonRfc = true, + CtcpUserInfo = "You are going to play. And I am going to watch. And everything will be just fine...", + AutoRejoin = true, + AutoRejoinOnKick = true, + AutoRelogin = false, + AutoRetry = false, + AutoReconnect = false, + ActiveChannelSyncing = true, + AutoNickHandling = true, + CtcpVersion = versionString, + UseSsl = ssl, + EnableUTF8Recode = true, + }; + if (ssl) + newClient.ValidateServerCertificate = true; // dunno if it defaults to that or what + + newClient.OnChannelMessage += Client_OnChannelMessage; + newClient.OnQueryMessage += Client_OnQueryMessage; + + newClient.OnReadLine += (sender, e) => Logger.LogTrace("READ: {line}", e.Line); + newClient.OnWriteLine += (sender, e) => Logger.LogTrace("WRITE: {line}", e.Line); + newClient.OnError += (sender, e) => + { + Logger.LogError("IRC ERROR: {error}", e.ErrorMessage); + newClient.Disconnect(); + }; + + return newClient; + } } } diff --git a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs index 3f1e0502191..6a343b40a04 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs @@ -88,6 +88,17 @@ public async Task TestConnectAndDisconnect() await InvokeConnect(provider); Assert.IsTrue(provider.Connected); + await Task.Delay(2000); // IRC servers do not like it when you connect and disconnect in rapid succession + + await provider.Disconnect(default); + Assert.IsFalse(provider.Connected); + + await Task.Delay(2000); // same as above + + await InvokeConnect(provider); + await Task.Delay(2000); // make sure it stays connected after a reconnect attempt + Assert.IsTrue(provider.Connected); + await provider.Disconnect(default); Assert.IsFalse(provider.Connected); } From 8e9cb0eb3aae86cafe07a46106ae94f4c170dd1d Mon Sep 17 00:00:00 2001 From: craftxbox Date: Fri, 20 Sep 2024 17:13:13 -0230 Subject: [PATCH 2/6] Changes from review --- .../Components/Chat/Providers/IrcProvider.cs | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 3a532f6b425..c383c75da88 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -83,9 +83,9 @@ sealed class IrcProvider : Provider readonly Dictionary queryChannelIdMap; /// - /// The version string obtained from . + /// The obtained from constructor, used for the CTCP version string. /// - readonly string versionString; + readonly IAssemblyInformationProvider assemblyInfo; /// /// The client. @@ -132,7 +132,7 @@ public IrcProvider( password = ircBuilder.Password!; passwordType = ircBuilder.PasswordType; - versionString = assemblyInformationProvider.VersionString; + assemblyInfo = assemblyInformationProvider; client = InstantiateClient(); @@ -386,17 +386,20 @@ await Task.Factory.StartNew( } Logger.LogTrace("Exiting listening task..."); - }, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current); + }, + cancellationToken, + DefaultIOManager.BlockingTaskCreationOptions, + TaskScheduler.Current); Logger.LogTrace("Authenticating ({passwordType})...", passwordType); switch (passwordType) { case IrcPasswordType.Server: client.RfcPass(password); - await Login(client, nickname); + await Login(client, nickname, cancellationToken); break; case IrcPasswordType.NickServ: - await Login(client, nickname); + await Login(client, nickname, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); client.SendMessage(SendType.Message, "NickServ", String.Format(CultureInfo.InvariantCulture, "IDENTIFY {0}", password)); break; @@ -404,12 +407,12 @@ await Task.Factory.StartNew( await SaslAuthenticate(cancellationToken); break; case IrcPasswordType.Oper: - await Login(client, nickname); + await Login(client, nickname, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); client.RfcOper(nickname, password, Priority.Critical); break; case null: - await Login(client, nickname); + await Login(client, nickname, cancellationToken); break; default: throw new InvalidOperationException($"Invalid IrcPasswordType: {passwordType.Value}"); @@ -462,9 +465,10 @@ await Task.Factory.StartNew( /// /// IRC client. /// Nickname. + /// Cancellation token. /// that resolves when registration has been completed. /// If the IRC server fails to respond. - private async Task Login(IrcFeatures client, string nickname) + async ValueTask Login(IrcFeatures client, string nickname, CancellationToken cancellationToken) { var promise = new TaskCompletionSource(); @@ -478,14 +482,20 @@ void Callback(object? sender, EventArgs e) client.Login(nickname, nickname, 0, nickname); - var completed = await Task.WhenAny(promise.Task, Task.Delay(30 * 1000)); - if (completed == promise.Task) + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(TimeSpan.FromSeconds(30)); + + try { + await promise.Task.WaitAsync(cts.Token); client.OnRegistered -= Callback; - return; } - - throw new TimeoutException("Timed out waiting for IRC registration."); + catch (OperationCanceledException) + { + if (client.IsConnected) + client.Disconnect(); + throw new JobException("Timed out waiting for IRC Registration"); + } } /// @@ -698,9 +708,9 @@ await Task.WhenAny( /// Reusing the same client after a disconnection seems to cause issues. /// /// The client to use. - private IrcFeatures InstantiateClient() + IrcFeatures InstantiateClient() { - IrcFeatures newClient = new IrcFeatures + var newClient = new IrcFeatures { SupportNonRfc = true, CtcpUserInfo = "You are going to play. And I am going to watch. And everything will be just fine...", @@ -711,7 +721,7 @@ private IrcFeatures InstantiateClient() AutoReconnect = false, ActiveChannelSyncing = true, AutoNickHandling = true, - CtcpVersion = versionString, + CtcpVersion = assemblyInfo.VersionString, UseSsl = ssl, EnableUTF8Recode = true, }; @@ -721,8 +731,9 @@ private IrcFeatures InstantiateClient() newClient.OnChannelMessage += Client_OnChannelMessage; newClient.OnQueryMessage += Client_OnQueryMessage; - newClient.OnReadLine += (sender, e) => Logger.LogTrace("READ: {line}", e.Line); - newClient.OnWriteLine += (sender, e) => Logger.LogTrace("WRITE: {line}", e.Line); + /* newClient.OnReadLine += (sender, e) => Logger.LogTrace("READ: {line}", e.Line); + newClient.OnWriteLine += (sender, e) => Logger.LogTrace("WRITE: {line}", e.Line); */ + newClient.OnError += (sender, e) => { Logger.LogError("IRC ERROR: {error}", e.ErrorMessage); From 0efd4c400f2ed6998dde6ea2c46417b30661be6d Mon Sep 17 00:00:00 2001 From: craftxbox Date: Wed, 2 Oct 2024 18:56:56 -0230 Subject: [PATCH 3/6] debug var for irc provider --- .../Components/Chat/Providers/IrcProvider.cs | 28 +++++++++++++------ .../Chat/Providers/ProviderFactory.cs | 13 +++++++-- .../Configuration/FileLoggingConfiguration.cs | 5 ++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index c383c75da88..f32698a3b09 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -13,6 +13,7 @@ using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Components.Interop; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.IO; using Tgstation.Server.Host.Jobs; @@ -87,6 +88,11 @@ sealed class IrcProvider : Provider /// readonly IAssemblyInformationProvider assemblyInfo; + /// + /// The for the . + /// + readonly FileLoggingConfiguration loggingConfiguration; + /// /// The client. /// @@ -110,12 +116,14 @@ sealed class IrcProvider : Provider /// The for the . /// The to get the from. /// The for the . + /// The for the . public IrcProvider( IJobManager jobManager, IAsyncDelayer asyncDelayer, ILogger logger, IAssemblyInformationProvider assemblyInformationProvider, - Models.ChatBot chatBot) + Models.ChatBot chatBot, + FileLoggingConfiguration loggingConfiguration) : base(jobManager, asyncDelayer, logger, chatBot) { ArgumentNullException.ThrowIfNull(assemblyInformationProvider); @@ -132,7 +140,8 @@ public IrcProvider( password = ircBuilder.Password!; passwordType = ircBuilder.PasswordType; - assemblyInfo = assemblyInformationProvider; + assemblyInfo = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); + this.loggingConfiguration = loggingConfiguration ?? throw new ArgumentNullException(nameof(loggingConfiguration)); client = InstantiateClient(); @@ -731,14 +740,17 @@ IrcFeatures InstantiateClient() newClient.OnChannelMessage += Client_OnChannelMessage; newClient.OnQueryMessage += Client_OnQueryMessage; - /* newClient.OnReadLine += (sender, e) => Logger.LogTrace("READ: {line}", e.Line); - newClient.OnWriteLine += (sender, e) => Logger.LogTrace("WRITE: {line}", e.Line); */ + if (loggingConfiguration.ProviderNetworkDebug) + { + newClient.OnReadLine += (sender, e) => Logger.LogTrace("READ: {line}", e.Line); + newClient.OnWriteLine += (sender, e) => Logger.LogTrace("WRITE: {line}", e.Line); + } newClient.OnError += (sender, e) => - { - Logger.LogError("IRC ERROR: {error}", e.ErrorMessage); - newClient.Disconnect(); - }; + { + Logger.LogError("IRC ERROR: {error}", e.ErrorMessage); + newClient.Disconnect(); + }; return newClient; } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs index ed3608b92da..41113d196f9 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/ProviderFactory.cs @@ -40,6 +40,11 @@ sealed class ProviderFactory : IProviderFactory /// readonly GeneralConfiguration generalConfiguration; + /// + /// The for the . + /// + readonly FileLoggingConfiguration loggingConfiguration; + /// /// Initializes a new instance of the class. /// @@ -48,18 +53,21 @@ sealed class ProviderFactory : IProviderFactory /// The value of . /// The value of . /// The containing the value of . + /// The containing the value of . public ProviderFactory( IJobManager jobManager, IAssemblyInformationProvider assemblyInformationProvider, IAsyncDelayer asyncDelayer, ILoggerFactory loggerFactory, - IOptions generalConfigurationOptions) + IOptions generalConfigurationOptions, + IOptions loggingConfigurationOptions) { this.jobManager = jobManager ?? throw new ArgumentNullException(nameof(jobManager)); this.loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); this.asyncDelayer = asyncDelayer ?? throw new ArgumentNullException(nameof(asyncDelayer)); this.assemblyInformationProvider = assemblyInformationProvider ?? throw new ArgumentNullException(nameof(assemblyInformationProvider)); generalConfiguration = generalConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(generalConfigurationOptions)); + loggingConfiguration = loggingConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(loggingConfigurationOptions)); } /// @@ -73,7 +81,8 @@ public IProvider CreateProvider(Models.ChatBot settings) asyncDelayer, loggerFactory.CreateLogger(), assemblyInformationProvider, - settings), + settings, + loggingConfiguration), ChatProvider.Discord => new DiscordProvider( jobManager, asyncDelayer, diff --git a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs index 534daf8ebb9..6bd98f20397 100644 --- a/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs +++ b/src/Tgstation.Server.Host/Configuration/FileLoggingConfiguration.cs @@ -29,6 +29,11 @@ public sealed class FileLoggingConfiguration /// public bool Disable { get; set; } + /// + /// If Chat Providers should log their network traffic. Normally disabled because it is too noisy. + /// + public bool ProviderNetworkDebug { get; set; } + /// /// The minimum to display in logs. /// From 16e035955f5e03708b82e0b6bfaa88d5c0722487 Mon Sep 17 00:00:00 2001 From: craftxbox Date: Wed, 2 Oct 2024 19:31:13 -0230 Subject: [PATCH 4/6] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ed43da7fb11..a03445fd6b5 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,8 @@ Create an `appsettings.Production.yml` file next to `appsettings.yml`. This will - `FileLogging:LogLevel`: Can be one of `Trace`, `Debug`, `Information`, `Warning`, `Error`, or `Critical`. Restricts what is put into the log files. Currently `Debug` is reccommended for help with error reporting. +- `FileLogging:ProviderNetworkDebug`: Boolean controlling whether or not Chat bot providers should log their raw network traffic. Currently only applies to IrcProvider. + - `Kestrel:Endpoints:Http:Url`: The URL (i.e. interface and ports) your application should listen on. General use case should be `http://localhost:` for restricted local connections. See the Remote Access section for configuring public access to the World Wide Web. This doesn't need to be changed using the docker setup and should be mapped with the `-p` option instead - `Database:DatabaseType`: Can be one of `SqlServer`, `MariaDB`, `MySql`, `PostgresSql`, or `Sqlite`. From 4123991fe5cea6ac2119b2558eecaa791494f8c0 Mon Sep 17 00:00:00 2001 From: craftxbox Date: Thu, 3 Oct 2024 21:36:58 -0230 Subject: [PATCH 5/6] bump the config version also style fixes --- build/Version.props | 2 +- .../Components/Chat/Providers/IrcProvider.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/Version.props b/build/Version.props index 9c784ed4d7f..e1726021b4f 100644 --- a/build/Version.props +++ b/build/Version.props @@ -4,7 +4,7 @@ 6.10.0 - 5.2.0 + 5.3.0 10.10.0 7.0.0 16.0.0 diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index f32698a3b09..ca526f725b5 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -747,10 +747,10 @@ IrcFeatures InstantiateClient() } newClient.OnError += (sender, e) => - { - Logger.LogError("IRC ERROR: {error}", e.ErrorMessage); - newClient.Disconnect(); - }; + { + Logger.LogError("IRC ERROR: {error}", e.ErrorMessage); + newClient.Disconnect(); + }; return newClient; } From 94aafc1f9ad01a75f0962664a88534c003c6360e Mon Sep 17 00:00:00 2001 From: craftxbox Date: Fri, 4 Oct 2024 01:11:25 -0230 Subject: [PATCH 6/6] fix the tests (i forgot about them) --- .../Components/Chat/Providers/IrcProvider.cs | 1 + .../Chat/Providers/TestIrcProvider.cs | 24 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index ca526f725b5..0eedc7c9491 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -127,6 +127,7 @@ public IrcProvider( : base(jobManager, asyncDelayer, logger, chatBot) { ArgumentNullException.ThrowIfNull(assemblyInformationProvider); + ArgumentNullException.ThrowIfNull(loggingConfiguration); var builder = chatBot.CreateConnectionStringBuilder(); if (builder == null || !builder.Valid || builder is not IrcConnectionStringBuilder ircBuilder) diff --git a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs index 6a343b40a04..bc1ecbf0a49 100644 --- a/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs +++ b/tests/Tgstation.Server.Host.Tests/Components/Chat/Providers/TestIrcProvider.cs @@ -9,6 +9,7 @@ using Moq; using Tgstation.Server.Api.Models; +using Tgstation.Server.Host.Configuration; using Tgstation.Server.Host.Jobs; using Tgstation.Server.Host.Models; using Tgstation.Server.Host.System; @@ -22,15 +23,15 @@ public sealed class TestIrcProvider [TestMethod] public async Task TestConstructionAndDisposal() { - Assert.ThrowsException(() => new IrcProvider(null, null, null, null, null)); + Assert.ThrowsException(() => new IrcProvider(null, null, null, null, null, null)); var mockJobManager = new Mock(); - Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, null, null, null, null)); + Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, null, null, null, null, null)); var mockAsyncDelayer = new Mock(); - Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, null, null, null)); + Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, null, null, null, null)); var mockLogger = new Mock>(); - Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, null, null)); + Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, null, null, null)); var mockAss = new Mock(); - Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockAss.Object, null)); + Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockAss.Object, null, null)); var mockBot = new ChatBot { @@ -38,8 +39,10 @@ public async Task TestConstructionAndDisposal() Instance = new Models.Instance(), Provider = ChatProvider.Irc }; + Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockAss.Object, mockBot, null)); - Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockAss.Object, mockBot)); + var mockLogConf = new FileLoggingConfiguration(); + Assert.ThrowsException(() => new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockAss.Object, mockBot, mockLogConf)); mockBot.ConnectionString = new IrcConnectionStringBuilder { @@ -49,7 +52,7 @@ public async Task TestConstructionAndDisposal() Port = 6667 }.ToString(); - await new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockAss.Object, mockBot).DisposeAsync(); + await new IrcProvider(mockJobManager.Object, mockAsyncDelayer.Object, mockLogger.Object, mockAss.Object, mockBot, mockLogConf).DisposeAsync(); } static ValueTask InvokeConnect(IProvider provider, CancellationToken cancellationToken = default) => (ValueTask)provider.GetType().GetMethod("Connect", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(provider, new object[] { cancellationToken }); @@ -78,12 +81,15 @@ public async Task TestConnectAndDisconnect() .Setup(x => x.WaitForJobCompletion(It.IsNotNull(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(ValueTask.FromResult(true)); var mockJobManager = mockSetup.Object; - await using var provider = new IrcProvider(mockJobManager, new AsyncDelayer(), loggerFactory.CreateLogger(), Mock.Of(), new ChatBot + + var chatBot = new ChatBot { ConnectionString = actualToken, Provider = ChatProvider.Irc, Instance = new Models.Instance(), - }); + }; + + await using var provider = new IrcProvider(mockJobManager, new AsyncDelayer(), loggerFactory.CreateLogger(), Mock.Of(), chatBot, new FileLoggingConfiguration()); Assert.IsFalse(provider.Connected); await InvokeConnect(provider); Assert.IsTrue(provider.Connected);