diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
index a56464cb72..af798e4ae6 100644
--- a/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/ChatManager.cs
@@ -761,7 +761,7 @@ namespace Tgstation.Server.Host.Components.Chat
{
messageTasks.Remove(undisposedMessageTaskKvp.Key);
if (undisposedMessageTaskKvp.Value.IsCompleted)
- (await undisposedMessageTaskKvp.Value.ConfigureAwait(false))?.Context?.Dispose();
+ await undisposedMessageTaskKvp.Value.ConfigureAwait(false);
}
// add new ones
@@ -786,7 +786,6 @@ namespace Tgstation.Server.Host.Components.Chat
foreach (var completedMessageTaskKvp in messageTasks.Where(x => x.Value.IsCompleted).ToList())
{
var message = await completedMessageTaskKvp.Value.ConfigureAwait(false);
- using var messageContext = message?.Context;
var messageNumber = Interlocked.Increment(ref messagesProcessed);
using (LogContext.PushProperty("ChatMessage", messageNumber))
await ProcessMessage(completedMessageTaskKvp.Key, message, cancellationToken).ConfigureAwait(false);
diff --git a/src/Tgstation.Server.Host/Components/Chat/Message.cs b/src/Tgstation.Server.Host/Components/Chat/Message.cs
index 8f04d8b2ea..ba4befa0a9 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Message.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Message.cs
@@ -1,6 +1,4 @@
-using System;
-
-namespace Tgstation.Server.Host.Components.Chat.Providers
+namespace Tgstation.Server.Host.Components.Chat.Providers
{
///
/// Represents a message recieved by a .
@@ -16,10 +14,5 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
/// The who sent the .
///
public ChatUser User { get; set; }
-
- ///
- /// The that should be d once the is processed.
- ///
- public IDisposable Context { get; set; }
}
}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs
new file mode 100644
index 0000000000..42bbe937d9
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordForwardingResponder.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Remora.Discord.API.Abstractions.Gateway.Events;
+using Remora.Discord.Gateway.Responders;
+using Remora.Results;
+
+namespace Tgstation.Server.Host.Components.Chat.Providers
+{
+ ///
+ /// An that forwards to another .
+ ///
+ sealed class DiscordForwardingResponder : IDiscordResponders
+ {
+ ///
+ /// The to forward the event to.
+ ///
+ readonly IDiscordResponders targetResponder;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value of .
+ public DiscordForwardingResponder(IDiscordResponders targetResponder)
+ {
+ this.targetResponder = targetResponder ?? throw new ArgumentNullException(nameof(targetResponder));
+ }
+
+ ///
+ public Task RespondAsync(IMessageCreate gatewayEvent, CancellationToken ct) => targetResponder.RespondAsync(gatewayEvent, ct);
+
+ ///
+ public Task RespondAsync(IReady gatewayEvent, CancellationToken ct = default) => targetResponder.RespondAsync(gatewayEvent, ct);
+ }
+}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs
index f04f9ba1bb..160bdebd9c 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs
@@ -1,12 +1,20 @@
using System;
using System.Collections.Generic;
+using System.Drawing;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
-using Discord;
-using Discord.WebSocket;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Remora.Discord.API.Abstractions.Gateway.Events;
+using Remora.Discord.API.Abstractions.Objects;
+using Remora.Discord.API.Abstractions.Rest;
+using Remora.Discord.API.Objects;
+using Remora.Discord.Core;
+using Remora.Discord.Gateway;
+using Remora.Discord.Gateway.Extensions;
+using Remora.Results;
using Tgstation.Server.Api.Models;
using Tgstation.Server.Host.Jobs;
@@ -18,10 +26,11 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
///
/// for the Discord app.
///
- sealed class DiscordProvider : Provider
+ #pragma warning disable CA1506
+ sealed class DiscordProvider : Provider, IDiscordResponders
{
///
- public override bool Connected => client.ConnectionState != ConnectionState.Disconnected;
+ public override bool Connected => gatewayTask?.IsCompleted == false;
///
public override string BotMention
@@ -30,7 +39,7 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
{
if (!Connected)
throw new InvalidOperationException("Provider not connected");
- return NormalizeMentions(client.CurrentUser.Mention);
+ return NormalizeMentions($"<@{currentUserId}>");
}
}
@@ -40,19 +49,19 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
readonly IAssemblyInformationProvider assemblyInformationProvider;
///
- /// The for the .
+ /// The containing Discord services.
///
- readonly DiscordSocketClient client;
+ readonly ServiceProvider serviceProvider;
///
- /// of mapped s.
+ /// of mapped channel s.
///
readonly List mappedChannels;
///
- /// The Discord bot token.
+ /// Lock used to sychronize connect/disconnect operations.
///
- readonly string botToken;
+ readonly object connectDisconnectLock;
///
/// to enable based mode. Will auto reply with a youtube link to a video that says "based on the hardware that's installed in it" to anyone saying 'based on what?' case-insensitive.
@@ -64,6 +73,26 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
///
readonly DiscordDMOutputDisplayType outputDisplayType;
+ ///
+ /// The for the .
+ ///
+ CancellationTokenSource gatewayCts;
+
+ ///
+ /// The for the initial gateway connection event.
+ ///
+ TaskCompletionSource