From 99b343da0d863f5aeb9f6f6bf34f2585317af2ab Mon Sep 17 00:00:00 2001 From: Jordan Brown Date: Mon, 27 Apr 2020 19:44:45 -0400 Subject: [PATCH] Allows joining IRC channels with keys - API bump to 6.1.0. - Store the key colon separated with the channel. --- build/Version.props | 2 +- .../Models/ChatChannel.cs | 3 +- .../Components/Chat/Providers/IrcProvider.cs | 33 ++++++++----- .../Extensions/ChatChannelExtensions.cs | 49 +++++++++++++++++++ 4 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs diff --git a/build/Version.props b/build/Version.props index 7878a900d9..b9cd0eadbd 100644 --- a/build/Version.props +++ b/build/Version.props @@ -3,7 +3,7 @@ 4.1.0 - 6.0.0 + 6.1.0 6.0.0 5.0.0 0.4.0 diff --git a/src/Tgstation.Server.Api/Models/ChatChannel.cs b/src/Tgstation.Server.Api/Models/ChatChannel.cs index d2c38df45d..0039e9bc20 100644 --- a/src/Tgstation.Server.Api/Models/ChatChannel.cs +++ b/src/Tgstation.Server.Api/Models/ChatChannel.cs @@ -8,7 +8,8 @@ namespace Tgstation.Server.Api.Models public class ChatChannel { /// - /// The IRC channel name + /// The IRC channel name. Also potentially contains the channel passsword (if separated by a colon). + /// If multiple copies of the same channel with different keys are added to the server, the one that will be used is undefined. /// [StringLength(Limits.MaximumIndexableStringLength)] public string IrcChannel { get; set; } diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs index 2b52d7c47f..c02ee8a0fa 100644 --- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs +++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Threading.Tasks; using Tgstation.Server.Api.Models; using Tgstation.Server.Host.Core; +using Tgstation.Server.Host.Extensions; using Tgstation.Server.Host.System; namespace Tgstation.Server.Host.Components.Chat.Providers @@ -376,24 +377,34 @@ namespace Tgstation.Server.Host.Components.Chat.Providers } /// - public override Task> MapChannels(IEnumerable channels, CancellationToken cancellationToken) => Task.Factory.StartNew(() => + public override Task> MapChannels(IEnumerable channels, CancellationToken cancellationToken) => Task.Factory.StartNew(() => { if (channels.Any(x => x.IrcChannel == null)) throw new InvalidOperationException("ChatChannel missing IrcChannel!"); lock (this) { + var channelsWithKeys = new Dictionary(); var hs = new HashSet(); // for unique inserts - foreach (var I in channels) - hs.Add(I.IrcChannel); - var toPart = new List(); - foreach (var I in client.JoinedChannels) - if (!hs.Remove(I)) - toPart.Add(I); + foreach (var channel in channels) + { + var name = channel.GetIrcChannelName(); + var key = channel.GetIrcChannelKey(); + if (hs.Add(name) && key != null) + channelsWithKeys.Add(name, key); + } - foreach (var I in toPart) - client.RfcPart(I, "Pretty nice abscond!"); - foreach (var I in hs) - client.RfcJoin(I); + var toPart = new List(); + foreach (var activeChannel in client.JoinedChannels) + if (!hs.Remove(activeChannel)) + toPart.Add(activeChannel); + + foreach (var channelToLeave in toPart) + client.RfcPart(channelToLeave, "Pretty nice abscond!"); + foreach (var channelToJoin in hs) + if (channelsWithKeys.TryGetValue(channelToJoin, out var key)) + client.RfcJoin(channelToJoin, key); + else + client.RfcJoin(channelToJoin); return (IReadOnlyCollection)channels.Select(x => { diff --git a/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs b/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs new file mode 100644 index 0000000000..be2afe14bd --- /dev/null +++ b/src/Tgstation.Server.Host/Extensions/ChatChannelExtensions.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Tgstation.Server.Api.Models; + +namespace Tgstation.Server.Host.Extensions +{ + /// + /// Extensions for the . + /// + static class ChatChannelExtensions + { + /// + /// Gets the IRC channel name from a given . + /// + /// The to retrieve information from. + /// The IRC channel name stored in the . + public static string GetIrcChannelName(this ChatChannel chatChannel) => GetIrcChannelSplits(chatChannel).First(); + + /// + /// Gets the IRC channel key from a given . + /// + /// The to retrieve information from. + /// The IRC channel key stored in the if it exists, otherwise. + public static string GetIrcChannelKey(this ChatChannel chatChannel) + { + var splits = GetIrcChannelSplits(chatChannel); + if (splits.Count < 2) + return null; + return splits.Last(); + } + + /// + /// Split a given 's . + /// + /// The to work with. + /// A of the 's separated by the ':' . + static IReadOnlyCollection GetIrcChannelSplits(ChatChannel chatChannel) + { + if (chatChannel == null) + throw new ArgumentNullException(nameof(chatChannel)); + + if (chatChannel.IrcChannel == null) + throw new ArgumentException("IrcChannel must be set!", nameof(chatChannel)); + + return chatChannel.IrcChannel.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + } + } +}