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..e4dc424f34 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,52 +377,68 @@ namespace Tgstation.Server.Host.Components.Chat.Providers } /// - 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) + public override Task> MapChannels( + IEnumerable channels, + CancellationToken cancellationToken) + => Task.Factory.StartNew(() => { - 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 I in toPart) - client.RfcPart(I, "Pretty nice abscond!"); - foreach (var I in hs) - client.RfcJoin(I); - - return (IReadOnlyCollection)channels.Select(x => + if (channels.Any(x => x.IrcChannel == null)) + throw new InvalidOperationException("ChatChannel missing IrcChannel!"); + lock (this) { - ulong? id = null; - if (!channelIdMap.Any(y => + var channelsWithKeys = new Dictionary(); + var hs = new HashSet(); // for unique inserts + foreach (var channel in channels) { - if (y.Value != x.IrcChannel) - return false; - id = y.Key; - return true; - })) - { - id = channelIdCounter++; - channelIdMap.Add(id.Value, x.IrcChannel); + var name = channel.GetIrcChannelName(); + var key = channel.GetIrcChannelKey(); + if (hs.Add(name) && key != null) + channelsWithKeys.Add(name, key); } - return new ChannelRepresentation - { - RealId = id.Value, - IsAdminChannel = x.IsAdminChannel == true, - ConnectionName = address, - FriendlyName = channelIdMap[id.Value], - IsPrivateChannel = false, - Tag = x.Tag - }; - }).ToList(); - } - }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current); + 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 => + { + var channelName = x.GetIrcChannelName(); + ulong? id = null; + if (!channelIdMap.Any(y => + { + if (y.Value != channelName) + return false; + id = y.Key; + return true; + })) + { + id = channelIdCounter++; + channelIdMap.Add(id.Value, channelName); + } + + return new ChannelRepresentation + { + RealId = id.Value, + IsAdminChannel = x.IsAdminChannel == true, + ConnectionName = address, + FriendlyName = channelIdMap[id.Value], + IsPrivateChannel = false, + Tag = x.Tag + }; + }) + .ToList(); + } + }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current); /// public override Task SendMessage(ulong channelId, string message, CancellationToken cancellationToken) => Task.Factory.StartNew(() => 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); + } + } +} diff --git a/tests/Tgstation.Server.Tests/VersionsTest.cs b/tests/Tgstation.Server.Tests/VersionsTest.cs index 81bcc68c41..0bc638dec2 100644 --- a/tests/Tgstation.Server.Tests/VersionsTest.cs +++ b/tests/Tgstation.Server.Tests/VersionsTest.cs @@ -60,19 +60,6 @@ namespace Tgstation.Server.Tests Assert.AreEqual(expected, actual); } - [TestMethod] - public void TestClientVersionFollowingApiVersion() - { - var versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsApiVersion").Value + ".0"; - Assert.IsNotNull(versionString); - Assert.IsTrue(Version.TryParse(versionString, out var apiVersion)); - - versionString = versionsPropertyGroup.Element(xmlNamespace + "TgsClientVersion").Value + ".0"; - Assert.IsNotNull(versionString); - Assert.IsTrue(Version.TryParse(versionString, out var clientVersion)); - Assert.IsTrue(clientVersion >= apiVersion); - } - [TestMethod] public void TestWatchdogVersion() {