diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm
index c3daf1a380..628b17cac6 100644
--- a/src/DMAPI/tgs.dm
+++ b/src/DMAPI/tgs.dm
@@ -103,7 +103,7 @@
//represents a chat user
/datum/tgs_chat_user
- var/id //Internal user representation
+ var/id //Internal user representation, requires channel to be unique
var/friendly_name //The user's public name
var/mention //The text to use to ping this user in a message
var/datum/tgs_chat_channel/channel //The /datum/tgs_chat_channel this user was from
diff --git a/src/Tgstation.Server.Api/Models/ChatChannel.cs b/src/Tgstation.Server.Api/Models/ChatChannel.cs
index 942154e506..d5131f4ff1 100644
--- a/src/Tgstation.Server.Api/Models/ChatChannel.cs
+++ b/src/Tgstation.Server.Api/Models/ChatChannel.cs
@@ -13,7 +13,7 @@
///
/// The Discord channel ID
///
- public long? DiscordChannelId { get; set; }
+ public ulong? DiscordChannelId { get; set; }
///
/// If the is an admin channel
diff --git a/src/Tgstation.Server.Host/Components/Chat/Channel.cs b/src/Tgstation.Server.Host/Components/Chat/Channel.cs
index c2eab84dd8..b29dc5c90c 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Channel.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Channel.cs
@@ -9,7 +9,7 @@
/// The channel Id.
///
/// remaps this to an internal id using
- public long Id { get; set; }
+ public ulong Id { get; set; }
///
/// The user friendly name of the
diff --git a/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs b/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs
index 243bf71206..a1ed4dd808 100644
--- a/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs
@@ -3,7 +3,7 @@
sealed class ChannelMapping
{
public long ProviderId { get; set; }
- public long ProviderChannelId { get; set; }
+ public ulong ProviderChannelId { get; set; }
public bool IsWatchdogChannel { get; set; }
public Channel Channel { get; set; }
diff --git a/src/Tgstation.Server.Host/Components/Chat/Chat.cs b/src/Tgstation.Server.Host/Components/Chat/Chat.cs
index 07a29865c9..82a8989940 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Chat.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Chat.cs
@@ -13,6 +13,8 @@ namespace Tgstation.Server.Host.Components.Chat
///
sealed class Chat : IChat
{
+ const string CommonMention = "!tgs";
+
///
/// The for the
///
@@ -36,7 +38,7 @@ namespace Tgstation.Server.Host.Components.Chat
///
/// Map of s to s
///
- readonly Dictionary mappedChannels;
+ readonly Dictionary mappedChannels;
///
/// The active s for the
@@ -51,7 +53,7 @@ namespace Tgstation.Server.Host.Components.Chat
///
/// Used for remapping s
///
- long channelIdCounter;
+ ulong channelIdCounter;
///
/// If has been called
@@ -71,7 +73,7 @@ namespace Tgstation.Server.Host.Components.Chat
builtinCommands = commandFactory?.GenerateCommands() ?? throw new ArgumentNullException(nameof(commandFactory));
providers = new Dictionary();
- mappedChannels = new Dictionary();
+ mappedChannels = new Dictionary();
trackingContexts = new List();
channelIdCounter = 1;
}
@@ -131,11 +133,11 @@ namespace Tgstation.Server.Host.Components.Chat
Channel = y
});
- long baseId;
+ ulong baseId;
lock (this)
{
baseId = channelIdCounter;
- channelIdCounter += results.Count;
+ channelIdCounter += (ulong)results.Count;
}
Task task;
@@ -185,7 +187,7 @@ namespace Tgstation.Server.Host.Components.Chat
}
///
- public Task SendMessage(string message, IEnumerable channelIds, CancellationToken cancellationToken)
+ public Task SendMessage(string message, IEnumerable channelIds, CancellationToken cancellationToken)
{
if (message == null)
throw new ArgumentNullException(nameof(message));
@@ -209,7 +211,7 @@ namespace Tgstation.Server.Host.Components.Chat
///
public Task SendWatchdogMessage(string message, CancellationToken cancellationToken)
{
- List wdChannels;
+ List wdChannels;
lock (mappedChannels) //so it doesn't change while we're using it
wdChannels = mappedChannels.Where(x => x.Value.IsWatchdogChannel).Select(x => x.Key).ToList();
return SendMessage(message, wdChannels, cancellationToken);
diff --git a/src/Tgstation.Server.Host/Components/Chat/IChat.cs b/src/Tgstation.Server.Host/Components/Chat/IChat.cs
index 68c12aa1ed..15e6e939bc 100644
--- a/src/Tgstation.Server.Host/Components/Chat/IChat.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/IChat.cs
@@ -57,7 +57,7 @@ namespace Tgstation.Server.Host.Components.Chat
/// The s of the s to send to
/// The for the operation
/// A representing the running operation
- Task SendMessage(string message, IEnumerable channelIds, CancellationToken cancellationToken);
+ Task SendMessage(string message, IEnumerable channelIds, CancellationToken cancellationToken);
///
/// Send a chat to configured watchdog channels
diff --git a/src/Tgstation.Server.Host/Components/Chat/Message.cs b/src/Tgstation.Server.Host/Components/Chat/Message.cs
index e9b90e6560..34ba645541 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Message.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Message.cs
@@ -2,7 +2,7 @@
{
sealed class Message
{
- string Content { get; set; }
- User User { get; set; }
+ public string Content { get; set; }
+ public User User { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs
new file mode 100644
index 0000000000..367973b919
--- /dev/null
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/DiscordProvider.cs
@@ -0,0 +1,248 @@
+using Discord;
+using Discord.Net;
+using Discord.WebSocket;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Tgstation.Server.Api.Models;
+
+namespace Tgstation.Server.Host.Components.Chat.Providers
+{
+ ///
+ /// for the Discord app
+ ///
+ sealed class DiscordProvider : IProvider
+ {
+ ///
+ public bool Connected { get; private set; }
+
+ ///
+ public string BotMention
+ {
+ get
+ {
+ if (!Connected)
+ throw new InvalidOperationException("Provider not connected");
+ return client.CurrentUser.Mention;
+ }
+ }
+
+ readonly ILogger logger;
+
+ ///
+ /// The for the
+ ///
+ readonly DiscordSocketClient client;
+
+ ///
+ /// The name used for populating
+ ///
+ readonly string connectionName;
+
+ ///
+ /// The token used for connecting to discord
+ ///
+ readonly string botToken;
+
+ ///
+ /// of received s
+ ///
+ readonly Queue messageQueue;
+
+ ///
+ /// of mapped s
+ ///
+ readonly List mappedChannels;
+
+ ///
+ /// that completes while isn't empty
+ ///
+ TaskCompletionSource