From d7b8689576640eebcb3575f52df5698e3c218488 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Fri, 13 Jul 2018 15:58:14 -0400 Subject: [PATCH] Work on implementing chat --- .../Models/ChatChannel.cs | 5 + .../Models/ChatProvider.cs | 17 ++ .../Models/ChatSettings.cs | 14 +- .../Models/Internal/ChatSettings.cs | 43 ++--- .../Rights/ChatSettingsRights.cs | 28 +-- .../Components/Chat/Channel.cs | 14 ++ .../Components/Chat/ChannelMapping.cs | 9 + .../Components/Chat/Chat.cs | 162 +++++++++++++++--- .../Components/Chat/IChat.cs | 22 ++- ...kingContext.cs => IJsonTrackingContext.cs} | 2 +- .../Components/Chat/IProviderFactory.cs | 18 ++ .../Components/Chat/Message.cs | 8 + .../Components/Chat/ProviderFactory.cs | 27 +++ .../Components/Chat/Providers/IProvider.cs | 52 ++++++ .../Chat/{ChatResponse.cs => Response.cs} | 2 +- .../Components/Chat/User.cs | 10 ++ .../Components/Watchdog/SessionController.cs | 6 +- .../Components/Watchdog/Watchdog.cs | 4 +- .../Models/ChatChannel.cs | 2 +- .../Models/ChatSettings.cs | 7 +- 20 files changed, 355 insertions(+), 97 deletions(-) create mode 100644 src/Tgstation.Server.Api/Models/ChatProvider.cs create mode 100644 src/Tgstation.Server.Host/Components/Chat/Channel.cs create mode 100644 src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs rename src/Tgstation.Server.Host/Components/Chat/{IChatJsonTrackingContext.cs => IJsonTrackingContext.cs} (73%) create mode 100644 src/Tgstation.Server.Host/Components/Chat/IProviderFactory.cs create mode 100644 src/Tgstation.Server.Host/Components/Chat/Message.cs create mode 100644 src/Tgstation.Server.Host/Components/Chat/ProviderFactory.cs create mode 100644 src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs rename src/Tgstation.Server.Host/Components/Chat/{ChatResponse.cs => Response.cs} (93%) create mode 100644 src/Tgstation.Server.Host/Components/Chat/User.cs diff --git a/src/Tgstation.Server.Api/Models/ChatChannel.cs b/src/Tgstation.Server.Api/Models/ChatChannel.cs index a927090029..c7ab3b9b32 100644 --- a/src/Tgstation.Server.Api/Models/ChatChannel.cs +++ b/src/Tgstation.Server.Api/Models/ChatChannel.cs @@ -19,5 +19,10 @@ /// If the is an admin channel /// public bool IsAdminChannel { get; set; } + + /// + /// If the is a watchdog channel + /// + public bool IsWatchdogChannel { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/ChatProvider.cs b/src/Tgstation.Server.Api/Models/ChatProvider.cs new file mode 100644 index 0000000000..f41d9de9c5 --- /dev/null +++ b/src/Tgstation.Server.Api/Models/ChatProvider.cs @@ -0,0 +1,17 @@ +namespace Tgstation.Server.Api.Models +{ + /// + /// Represents a chat service provider + /// + public enum ChatProvider + { + /// + /// Internet relay chat + /// + Irc, + /// + /// Superior chat service + /// + Discord + } +} diff --git a/src/Tgstation.Server.Api/Models/ChatSettings.cs b/src/Tgstation.Server.Api/Models/ChatSettings.cs index 2900a7e055..aab5431e9a 100644 --- a/src/Tgstation.Server.Api/Models/ChatSettings.cs +++ b/src/Tgstation.Server.Api/Models/ChatSettings.cs @@ -6,22 +6,10 @@ namespace Tgstation.Server.Api.Models /// public sealed class ChatSettings : Internal.ChatSettings { - /// - /// If the IRC connection is established - /// - [Permissions(DenyWrite = true)] - bool IrcConnected { get; set; } - - /// - /// If the Discord connection is established - /// - [Permissions(DenyWrite = true)] - bool DiscordConnected { get; set; } - /// /// Channels the Discord bot should listen/announce in /// - [Permissions(WriteRight = ChatSettingsRights.SetChannels)] + [Permissions(WriteRight = ChatSettingsRights.WriteChannels)] public List Channels { get; set; } } } diff --git a/src/Tgstation.Server.Api/Models/Internal/ChatSettings.cs b/src/Tgstation.Server.Api/Models/Internal/ChatSettings.cs index a672895d3c..3357c507b1 100644 --- a/src/Tgstation.Server.Api/Models/Internal/ChatSettings.cs +++ b/src/Tgstation.Server.Api/Models/Internal/ChatSettings.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; using Tgstation.Server.Api.Rights; namespace Tgstation.Server.Api.Models.Internal @@ -8,44 +6,39 @@ namespace Tgstation.Server.Api.Models.Internal /// /// Manage the server chat bots /// - [Model(RightsType.ChatSettings, RequiresInstance = true)] + [Model(RightsType.ChatSettings, RequiresInstance = true, CanCrud = true, ReadRight = ChatSettingsRights.Read)] public class ChatSettings { /// - /// If the IRC client is enabled + /// The settings id /// - [Permissions(WriteRight = ChatSettingsRights.SetIrcEnabled)] - public bool IrcEnabled { get; set; } + [Permissions(DenyWrite = true)] + public long Id { get; set; } /// - /// The IRC server name + /// The name of the connection /// - [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)] + [Permissions(WriteRight = ChatSettingsRights.WriteName)] [Required] - public string IrcHost { get; set; } + public string Name { get; set; } /// - /// The IRC server port + /// If the connection is enabled /// - [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)] - public ushort IrcPort { get; set; } + [Permissions(WriteRight = ChatSettingsRights.WriteEnabled)] + public bool Enabled { get; set; } /// - /// The IRC server NickServ password + /// The used for the connection /// - [Permissions(ReadRight = ChatSettingsRights.SetIrcSettings, WriteRight = ChatSettingsRights.SetIrcSettings)] - public string IrcNickServPassword { get; set; } + [Permissions(WriteRight = ChatSettingsRights.WriteProvider)] + public ChatProvider Provider { get; set; } /// - /// If the Discord bot is enabled + /// The information used to connect to the /// - [Permissions(WriteRight = ChatSettingsRights.SetDiscordEnabled)] - public bool DiscordEnabled { get; set; } - - /// - /// The Discord bot token - /// - [Permissions(ReadRight = ChatSettingsRights.SetDiscordSettings, WriteRight = ChatSettingsRights.SetDiscordSettings)] - public string DiscordBotToken { get; set; } + [Permissions(ReadRight = ChatSettingsRights.ReadConnectionString, WriteRight = ChatSettingsRights.ReadConnectionString)] + [Required] + public string ConnectionString { get; set; } } } diff --git a/src/Tgstation.Server.Api/Rights/ChatSettingsRights.cs b/src/Tgstation.Server.Api/Rights/ChatSettingsRights.cs index d27723c28c..e8803311ac 100644 --- a/src/Tgstation.Server.Api/Rights/ChatSettingsRights.cs +++ b/src/Tgstation.Server.Api/Rights/ChatSettingsRights.cs @@ -13,24 +13,32 @@ namespace Tgstation.Server.Api.Rights /// None = 0, /// - /// User can enable/disable the IRC client + /// User can change /// - SetIrcEnabled = 1, + WriteEnabled = 1, /// - /// User can change the IRC settings + /// User can change /// - SetIrcSettings = 2, + WriteProvider = 2, /// - /// User can change the chat channels + /// User can change /// - SetChannels = 4, + WriteChannels = 4, /// - /// User can enable/disable the Discord bot + /// User can change /// - SetDiscordEnabled = 8, + WriteConnectionString = 8, /// - /// User can change the Discord settings + /// User can read /// - SetDiscordSettings = 16, + ReadConnectionString = 16, + /// + /// User can read all chat settings except + /// + Read = 32, + /// + /// User can change + /// + WriteName = 32 } } diff --git a/src/Tgstation.Server.Host/Components/Chat/Channel.cs b/src/Tgstation.Server.Host/Components/Chat/Channel.cs new file mode 100644 index 0000000000..d9916a1014 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Chat/Channel.cs @@ -0,0 +1,14 @@ +namespace Tgstation.Server.Host.Components.Chat +{ + sealed class Channel + { + public long Id { get; set; } + + public string FriendlyName { get; set; } + + public string ConnectionName { get; set; } + + public bool IsAdminChannel { get; set; } + public bool IsPrivateChannel { get; set; } + } +} diff --git a/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs b/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs new file mode 100644 index 0000000000..cdf098287a --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Chat/ChannelMapping.cs @@ -0,0 +1,9 @@ +namespace Tgstation.Server.Host.Components.Chat +{ + sealed class ChannelMapping + { + public long ProviderId { get; set; } + public long ProviderChannelId { get; set; } + public bool IsWatchdogChannel { get; set; } + } +} diff --git a/src/Tgstation.Server.Host/Components/Chat/Chat.cs b/src/Tgstation.Server.Host/Components/Chat/Chat.cs index 1b5a0fdf09..86cc30b99c 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Chat.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Chat.cs @@ -1,59 +1,175 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; -using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Components.Chat.Providers; +using Tgstation.Server.Host.Core; namespace Tgstation.Server.Host.Components.Chat { /// sealed class Chat : IChat { - /// - public bool IrcConnected => throw new System.NotImplementedException(); + /// + /// The for the + /// + readonly IProviderFactory providerFactory; - /// - public bool DiscordConnected => throw new System.NotImplementedException(); + /// + /// The for the + /// + readonly IIOManager ioManager; - /// - public Task ChangeChannels(IEnumerable newChannels, CancellationToken cancellationToken) + /// + /// Map of s in use, keyed by + /// + readonly Dictionary providers; + + /// + /// Map of s to s + /// + readonly Dictionary mappedChannels; + + /// + /// Used for remapping s + /// + long channelIdCounter; + + /// + /// Construct a + /// + /// The value of + /// The value of + public Chat(IProviderFactory providerFactory, IIOManager ioManager) { - throw new System.NotImplementedException(); + this.providerFactory = providerFactory ?? throw new ArgumentNullException(nameof(providerFactory)); + this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager)); + + providers = new Dictionary(); + mappedChannels = new Dictionary(); + channelIdCounter = 1; } /// - public Task ChangeSettings(Api.Models.Internal.ChatSettings newSettings, CancellationToken cancellationToken) + public void Dispose() { - throw new System.NotImplementedException(); + foreach (var I in providers) + I.Value.Dispose(); + } + + /// + 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; + var results = await provider.MapChannels(newChannels, cancellationToken).ConfigureAwait(false); + if (results == null) //aborted + return; + var mappings = Enumerable.Zip(newChannels, results, (x, y) => new ChannelMapping + { + IsWatchdogChannel = x.IsWatchdogChannel, + ProviderChannelId = y.Id, + ProviderId = connectionId + }); + + long baseId; + lock (this) + { + baseId = channelIdCounter; + channelIdCounter += results.Count; + } + lock (mappedChannels) + { + lock (providers) + if (!providers.TryGetValue(connectionId, out IProvider verify) || verify != provider) //aborted again + return; + foreach (var I in mappings) + mappedChannels.Add(baseId++, I); + } + } + + /// + public async Task ChangeSettings(ChatSettings newSettings, CancellationToken cancellationToken) + { + if (newSettings == null) + throw new ArgumentNullException(nameof(newSettings)); + IProvider provider; + lock (providers) + { + //raw settings changes forces a rebuild of the provider + if (providers.TryGetValue(newSettings.Id, out provider)) + { + providers.Remove(newSettings.Id); + provider.Dispose(); + } + if (newSettings.Enabled) + { + provider = providerFactory.CreateProvider(newSettings); + providers.Add(newSettings.Id, provider); + } + } + lock (mappedChannels) + foreach (var channelId in mappedChannels.Where(x => x.Value.ProviderId == newSettings.Id).Select(x => x.Key)) + mappedChannels.Remove(channelId); + if (newSettings.Enabled) + await provider.Connect(cancellationToken).ConfigureAwait(false); } /// public Task SendMessage(string message, IEnumerable channelIds, CancellationToken cancellationToken) { - throw new System.NotImplementedException(); + if (message == null) + throw new ArgumentNullException(nameof(message)); + if (channelIds == null) + throw new ArgumentNullException(nameof(channelIds)); + + return Task.WhenAll(channelIds.Select(x => + { + ChannelMapping channelMapping; + lock(mappedChannels) + if (!mappedChannels.TryGetValue(x, out channelMapping)) + return Task.CompletedTask; + IProvider provider; + lock (providers) + if (!providers.TryGetValue(channelMapping.ProviderId, out provider)) + return Task.CompletedTask; + return provider.SendMessage(channelMapping.ProviderChannelId, message, cancellationToken); + })); } /// public Task SendWatchdogMessage(string message, CancellationToken cancellationToken) { - throw new System.NotImplementedException(); + 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); } /// - public Task StartAsync(CancellationToken cancellationToken) + public Task StartAsync(CancellationToken cancellationToken) => Task.WhenAll(providers.Select(x => x.Value).Select(x => x.Connect(cancellationToken))); + + /// + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + + /// + public Task TrackJsons(string basePath, string channelsJsonName, string commandsJsonName, CancellationToken cancellationToken) { - throw new System.NotImplementedException(); + ioManager.ResolvePath("."); + throw new NotImplementedException(); } /// - public Task StopAsync(CancellationToken cancellationToken) + public bool Connected(long connectionId) { - throw new System.NotImplementedException(); - } - - /// - public Task TrackJsons(string basePath, string channelsJsonName, string commandsJsonName, CancellationToken cancellationToken) - { - throw new System.NotImplementedException(); + lock (providers) + return providers.TryGetValue(connectionId, out var provider) && provider.Connected; } } } diff --git a/src/Tgstation.Server.Host/Components/Chat/IChat.cs b/src/Tgstation.Server.Host/Components/Chat/IChat.cs index f73805eb2b..26eacbfd4f 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChat.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IChat.cs @@ -10,33 +10,31 @@ namespace Tgstation.Server.Host.Components.Chat /// /// For managing connected chat services /// - public interface IChat : IHostedService + public interface IChat : IHostedService, IDisposable { /// - /// If the IRC client is connected + /// If a given set of is connected /// - bool IrcConnected { get; } + /// The of the connection + /// if it is connected, otherwise + bool Connected(long connectionId); /// - /// If the Discord client is connected - /// - bool DiscordConnected { get; } - - /// - /// Change chat settings + /// Change chat settings. If the is not currently in use, a new connection will be made instead /// /// The new /// The for the operation - /// A representing the running operation + /// A representing the running operation. Will complete immediately if the property of is Task ChangeSettings(ChatSettings newSettings, CancellationToken cancellationToken); /// /// Change chat channels /// + /// The of the connection /// An of the new list of s /// The for the operation /// A representing the running operation - Task ChangeChannels(IEnumerable newChannels, CancellationToken cancellationToken); + Task ChangeChannels(long connectionId, IEnumerable newChannels, CancellationToken cancellationToken); /// /// Send a chat to a given set of @@ -63,6 +61,6 @@ namespace Tgstation.Server.Host.Components.Chat /// The name of the chat commands json /// The for the operation /// A resulting in a tied to the lifetime of the json trackings - Task TrackJsons(string basePath, string channelsJsonName, string commandsJsonName, CancellationToken cancellationToken); + Task TrackJsons(string basePath, string channelsJsonName, string commandsJsonName, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/Chat/IChatJsonTrackingContext.cs b/src/Tgstation.Server.Host/Components/Chat/IJsonTrackingContext.cs similarity index 73% rename from src/Tgstation.Server.Host/Components/Chat/IChatJsonTrackingContext.cs rename to src/Tgstation.Server.Host/Components/Chat/IJsonTrackingContext.cs index 8926b33291..5988619602 100644 --- a/src/Tgstation.Server.Host/Components/Chat/IChatJsonTrackingContext.cs +++ b/src/Tgstation.Server.Host/Components/Chat/IJsonTrackingContext.cs @@ -5,7 +5,7 @@ namespace Tgstation.Server.Host.Components.Chat /// /// Represents a tracking of dynamic chat json files /// - public interface IChatJsonTrackingContext : IDisposable + public interface IJsonTrackingContext : IDisposable { } } \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/Chat/IProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/IProviderFactory.cs new file mode 100644 index 0000000000..b4b47f2d5b --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Chat/IProviderFactory.cs @@ -0,0 +1,18 @@ +using Tgstation.Server.Api.Models.Internal; +using Tgstation.Server.Host.Components.Chat.Providers; + +namespace Tgstation.Server.Host.Components.Chat +{ + /// + /// Factory for s + /// + interface IProviderFactory + { + /// + /// Create a + /// + /// The for the new provider + /// A new + IProvider CreateProvider(ChatSettings settings); + } +} diff --git a/src/Tgstation.Server.Host/Components/Chat/Message.cs b/src/Tgstation.Server.Host/Components/Chat/Message.cs new file mode 100644 index 0000000000..e9b90e6560 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Chat/Message.cs @@ -0,0 +1,8 @@ +namespace Tgstation.Server.Host.Components.Chat.Providers +{ + sealed class Message + { + string Content { get; set; } + User User { get; set; } + } +} \ No newline at end of file diff --git a/src/Tgstation.Server.Host/Components/Chat/ProviderFactory.cs b/src/Tgstation.Server.Host/Components/Chat/ProviderFactory.cs new file mode 100644 index 0000000000..b16cd3617c --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Chat/ProviderFactory.cs @@ -0,0 +1,27 @@ +using System; +using System.Globalization; +using Tgstation.Server.Api.Models; +using Tgstation.Server.Host.Components.Chat.Providers; + +namespace Tgstation.Server.Host.Components.Chat +{ + /// + sealed class ProviderFactory : IProviderFactory + { + /// + public IProvider CreateProvider(Api.Models.Internal.ChatSettings settings) + { + if (settings == null) + throw new ArgumentNullException(nameof(settings)); + switch (settings.Provider) + { + case ChatProvider.Irc: + throw new NotImplementedException(); + case ChatProvider.Discord: + throw new NotImplementedException(); + default: + throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Invalid ChatProvider: {0}", settings.Provider)); + } + } + } +} diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs new file mode 100644 index 0000000000..278ffa5813 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IProvider.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Tgstation.Server.Host.Components.Chat.Providers +{ + /// + /// For interacting with a chat service + /// + interface IProvider : IDisposable + { + /// + /// If the + /// + bool Connected { get; } + + /// + /// The that indicates the was mentioned + /// + string BotMention { get; } + + /// + /// Get a resulting in the next the recieves or on a disconnect + /// + Task NextMessage { get; } + + /// + /// Attempt to connect the + /// + /// The for the operation + /// A resulting in on success, otherwise + Task Connect(CancellationToken cancellationToken); + + /// + /// Get the s for given + /// + /// The s to map + /// The for the operation + /// A resulting in a of the s representing + Task> MapChannels(IEnumerable channels, CancellationToken cancellationToken); + + /// + /// Send a message to the + /// + /// The to send to + /// The message contents + /// The for the operation + /// A representing the running operation + Task SendMessage(long channelId, string message, CancellationToken cancellationToken); + } +} diff --git a/src/Tgstation.Server.Host/Components/Chat/ChatResponse.cs b/src/Tgstation.Server.Host/Components/Chat/Response.cs similarity index 93% rename from src/Tgstation.Server.Host/Components/Chat/ChatResponse.cs rename to src/Tgstation.Server.Host/Components/Chat/Response.cs index 67f8cf6782..855752e790 100644 --- a/src/Tgstation.Server.Host/Components/Chat/ChatResponse.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Response.cs @@ -5,7 +5,7 @@ namespace Tgstation.Server.Host.Components.Chat /// /// Represents a chat message requested by DD /// - sealed class ChatResponse + sealed class Response { /// /// The message string diff --git a/src/Tgstation.Server.Host/Components/Chat/User.cs b/src/Tgstation.Server.Host/Components/Chat/User.cs new file mode 100644 index 0000000000..cc081dfaa9 --- /dev/null +++ b/src/Tgstation.Server.Host/Components/Chat/User.cs @@ -0,0 +1,10 @@ +namespace Tgstation.Server.Host.Components.Chat +{ + class User + { + long Id { get; set; } + string FriendlyName { get; set; } + string Mention { get; set; } + Channel channel { get; set; } + } +} diff --git a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs index 4d61522620..4937f7e170 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/SessionController.cs @@ -102,9 +102,9 @@ namespace Tgstation.Server.Host.Components.Watchdog readonly ISession session; /// - /// The for the + /// The for the /// - readonly IChatJsonTrackingContext chatJsonTrackingContext; + readonly IJsonTrackingContext chatJsonTrackingContext; /// /// The for the @@ -154,7 +154,7 @@ namespace Tgstation.Server.Host.Components.Watchdog /// The value of /// The value of /// The value of - public SessionController(ReattachInformation reattachInformation, ISession session, IByondTopicSender byondTopicSender, IInteropRegistrar interopRegistrar, IChatJsonTrackingContext chatJsonTrackingContext, IChat chat, ILogger logger) + public SessionController(ReattachInformation reattachInformation, ISession session, IByondTopicSender byondTopicSender, IInteropRegistrar interopRegistrar, IJsonTrackingContext chatJsonTrackingContext, IChat chat, ILogger logger) { this.chatJsonTrackingContext = chatJsonTrackingContext; //null valid this.reattachInformation = reattachInformation ?? throw new ArgumentNullException(nameof(reattachInformation)); diff --git a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs index c0f07beaa5..70ce656dc0 100644 --- a/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host/Components/Watchdog/Watchdog.cs @@ -539,10 +539,10 @@ namespace Tgstation.Server.Host.Components.Watchdog if (results == null) return; - List responses; + List responses; try { - responses = JsonConvert.DeserializeObject>(results); + responses = JsonConvert.DeserializeObject>(results); } catch { diff --git a/src/Tgstation.Server.Host/Models/ChatChannel.cs b/src/Tgstation.Server.Host/Models/ChatChannel.cs index 8f57e1e885..3bd53864fd 100644 --- a/src/Tgstation.Server.Host/Models/ChatChannel.cs +++ b/src/Tgstation.Server.Host/Models/ChatChannel.cs @@ -9,7 +9,7 @@ public long Id { get; set; } /// - /// The + /// The /// public long ChatSettingsId { get; set; } diff --git a/src/Tgstation.Server.Host/Models/ChatSettings.cs b/src/Tgstation.Server.Host/Models/ChatSettings.cs index 5d3df56af5..1152181268 100644 --- a/src/Tgstation.Server.Host/Models/ChatSettings.cs +++ b/src/Tgstation.Server.Host/Models/ChatSettings.cs @@ -5,12 +5,7 @@ namespace Tgstation.Server.Host.Models { /// public sealed class ChatSettings : Api.Models.Internal.ChatSettings - { - /// - /// The row Id - /// - public long Id { get; set; } - + { /// /// The ///