diff --git a/src/DMAPI/tgs.dm b/src/DMAPI/tgs.dm
index 4e9749084b..c3daf1a380 100644
--- a/src/DMAPI/tgs.dm
+++ b/src/DMAPI/tgs.dm
@@ -97,8 +97,7 @@
/datum/tgs_chat_channel
var/id //internal channel representation
var/friendly_name //user friendly channel name
- var/server_name //server name the channel resides on
- var/provider_name //chat provider for the channel
+ var/connection_name //the name of the configured chat connection
var/is_admin_channel //if the server operator has marked this channel for game admins only
var/is_private_channel //if this is a private chat channel
diff --git a/src/Tgstation.Server.Api/Models/ChatChannel.cs b/src/Tgstation.Server.Api/Models/ChatChannel.cs
index c7ab3b9b32..942154e506 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 long? 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 8a6cfc1d66..c2eab84dd8 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Channel.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Channel.cs
@@ -17,13 +17,18 @@
public string FriendlyName { get; set; }
///
- /// If this is considered a channel for admin commands
+ /// The name of the connection the belongs to
///
- public bool IsAdminChannel { get; set; }
+ public string ConnectionName { get; set; }
///
- /// If this i
+ /// If this is considered a channel for admin commands
///
- public bool IsPrivateChannel { get; set; }
+ public bool IsAdmin { get; set; }
+
+ ///
+ /// If this is a 1-to-1 chat channel
+ ///
+ public bool IsPrivate { get; set; }
}
}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Chat.cs b/src/Tgstation.Server.Host/Components/Chat/Chat.cs
index 9f3e8e4324..862096ae44 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Chat.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Chat.cs
@@ -1,8 +1,6 @@
-using Newtonsoft.Json;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Tgstation.Server.Api.Models.Internal;
@@ -40,6 +38,9 @@ namespace Tgstation.Server.Host.Components.Chat
///
readonly Dictionary mappedChannels;
+ ///
+ /// The active s for the
+ ///
readonly List trackingContexts;
///
@@ -52,6 +53,11 @@ namespace Tgstation.Server.Host.Components.Chat
///
long channelIdCounter;
+ ///
+ /// If has been called
+ ///
+ bool started;
+
///
/// Construct a
///
@@ -77,21 +83,43 @@ namespace Tgstation.Server.Host.Components.Chat
I.Value.Dispose();
}
+ ///
+ /// Remove a from and optionally updating the as well
+ ///
+ /// The of the to delete
+ /// If should be update
+ /// The for the operation
+ /// A resulting in the being removed if it exists, otherwise
+ async Task RemoveProvider(long connectionId, bool updateTrackings, CancellationToken cancellationToken)
+ {
+ IProvider provider;
+ lock (providers)
+ if (!providers.TryGetValue(connectionId, out provider))
+ return null;
+ Task task;
+ lock (mappedChannels)
+ {
+ foreach (var kvp in mappedChannels.Where(x => x.Value.ProviderId == connectionId))
+ mappedChannels.Remove(kvp.Key);
+
+ if (updateTrackings)
+ lock (trackingContexts)
+ task = Task.WhenAll(trackingContexts.Select(x => x.SetChannels(mappedChannels.Select(y => y.Value.Channel), cancellationToken)));
+ else
+ task = Task.CompletedTask;
+ }
+ await task.ConfigureAwait(false);
+ return provider;
+ }
+
///
public async Task ChangeChannels(long connectionId, IEnumerable newChannels, CancellationToken cancellationToken)
{
if (newChannels == null)
throw new ArgumentNullException(nameof(newChannels));
- IProvider provider;
- lock (providers)
- if (!providers.TryGetValue(connectionId, out provider))
- return;
- lock (mappedChannels)
- foreach (var kvp in mappedChannels.Where(x => x.Value.ProviderId == connectionId))
- {
- mappedChannels.Remove(kvp.Key);
-
- }
+ var provider = await RemoveProvider(connectionId, false, cancellationToken).ConfigureAwait(false);
+ if (provider == null)
+ return;
var results = await provider.MapChannels(newChannels, cancellationToken).ConfigureAwait(false);
if (results == null) //aborted
return;
@@ -152,7 +180,7 @@ namespace Tgstation.Server.Host.Components.Chat
lock (mappedChannels)
foreach (var channelId in mappedChannels.Where(x => x.Value.ProviderId == newSettings.Id).Select(x => x.Key))
mappedChannels.Remove(channelId);
- if (newSettings.Enabled)
+ if (newSettings.Enabled && started)
await provider.Connect(cancellationToken).ConfigureAwait(false);
}
@@ -188,10 +216,14 @@ namespace Tgstation.Server.Host.Components.Chat
}
///
- public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(providers.Select(x => x.Value).Select(x => x.Connect(cancellationToken)));
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ await Task.WhenAll(providers.Select(x => x.Value).Select(x => x.Connect(cancellationToken))).ConfigureAwait(false);
+ started = true;
+ }
///
- public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+ public Task StopAsync(CancellationToken cancellationToken) => Task.WhenAll(providers.Select(x => x.Value).Select(x => x.Disconnect(cancellationToken)));
///
public async Task TrackJsons(string basePath, string channelsJsonName, string commandsJsonName, CancellationToken cancellationToken)
@@ -229,5 +261,8 @@ namespace Tgstation.Server.Host.Components.Chat
throw new InvalidOperationException("RegisterCommandHandler() already called!");
this.customCommandHandler = customCommandHandler ?? throw new ArgumentNullException(nameof(customCommandHandler));
}
+
+ ///
+ public Task DeleteConnection(long connectionId, CancellationToken cancellationToken) => RemoveProvider(connectionId, true, cancellationToken);
}
}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/Command.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/Command.cs
index 8ad981aee0..d5f192ec59 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Commands/Command.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Commands/Command.cs
@@ -1,11 +1,29 @@
namespace Tgstation.Server.Host.Components.Chat.Commands
{
+ ///
+ /// Represents a command that can be invoked by talking to chat bots
+ ///
public abstract class Command
{
+ ///
+ /// The text to invoke the command. May not be "?" or "help" (case-insensitive)
+ ///
public string Name { get; set; }
+
+ ///
+ /// The help text to display when queires are made about the command
+ ///
public string HelpText { get; set; }
+
+ ///
+ /// If the command should only be available to s who's has set
+ ///
public bool AdminOnly { get; set; }
+ ///
+ /// Invoke the
+ ///
+ /// The text after with leading whitespace trimmed
public abstract void Invoke(string arguments);
}
}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs b/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs
index 94e8af328f..6221f531c1 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Commands/CustomCommand.cs
@@ -2,10 +2,20 @@
namespace Tgstation.Server.Host.Components.Chat.Commands
{
+ ///
+ /// Represents a command made from DM code
+ ///
public sealed class CustomCommand : Command
{
+ ///
+ /// The for the
+ ///
ICustomCommandHandler handler;
+ ///
+ /// Set a new
+ ///
+ /// The value of
public void SetHandler(ICustomCommandHandler handler)
{
if (this.handler != null)
diff --git a/src/Tgstation.Server.Host/Components/Chat/IChat.cs b/src/Tgstation.Server.Host/Components/Chat/IChat.cs
index a96d4b4fea..68c12aa1ed 100644
--- a/src/Tgstation.Server.Host/Components/Chat/IChat.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/IChat.cs
@@ -33,6 +33,14 @@ namespace Tgstation.Server.Host.Components.Chat
/// A representing the running operation. Will complete immediately if the property of is
Task ChangeSettings(ChatSettings newSettings, CancellationToken cancellationToken);
+ ///
+ /// Disconnects and deletes a given connection
+ ///
+ /// The of the connection
+ /// The for the operation
+ /// A representing the running operation
+ Task DeleteConnection(long connectionId, CancellationToken cancellationToken);
+
///
/// Change chat channels
///
diff --git a/src/Tgstation.Server.Host/Components/Chat/IJsonTrackingContext.cs b/src/Tgstation.Server.Host/Components/Chat/IJsonTrackingContext.cs
index a4273ee79c..778b6d0d3c 100644
--- a/src/Tgstation.Server.Host/Components/Chat/IJsonTrackingContext.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/IJsonTrackingContext.cs
@@ -11,7 +11,19 @@ namespace Tgstation.Server.Host.Components.Chat
///
public interface IJsonTrackingContext : IDisposable
{
+ ///
+ /// Read s from the
+ ///
+ /// The for the operation
+ /// A resulting in a of s in the
Task> GetCustomCommands(CancellationToken cancellationToken);
+
+ ///
+ /// Writes information about connected to the
+ ///
+ /// The s to write out
+ /// The for the operation
+ /// A representing the running operation
Task SetChannels(IEnumerable channels, CancellationToken cancellationToken);
}
}
\ No newline at end of file
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs
index 278ffa5813..7abe357269 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs
@@ -32,6 +32,13 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
/// A resulting in on success, otherwise
Task Connect(CancellationToken cancellationToken);
+ ///
+ /// Gracefully disconnects the provider. Implies a call to
+ ///
+ /// The for the operation
+ /// A representing the running operation
+ Task Disconnect(CancellationToken cancellationToken);
+
///
/// Get the s for given
///
diff --git a/src/Tgstation.Server.Host/Components/Chat/User.cs b/src/Tgstation.Server.Host/Components/Chat/User.cs
index 7b716dc419..12eff58285 100644
--- a/src/Tgstation.Server.Host/Components/Chat/User.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/User.cs
@@ -1,10 +1,13 @@
namespace Tgstation.Server.Host.Components.Chat
{
+ ///
+ ///
+ ///
public sealed class User
{
long Id { get; set; }
string FriendlyName { get; set; }
string Mention { get; set; }
- Channel channel { get; set; }
+ Channel Channel { get; set; }
}
}