Allows joining IRC channels with keys

- API bump to 6.1.0.
- Store the key colon separated with the channel.
This commit is contained in:
Jordan Brown
2020-04-27 19:44:45 -04:00
parent 2ee6277bfd
commit 99b343da0d
4 changed files with 74 additions and 13 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
<!-- This is the authorative version list -->
<!-- Integration tests will ensure they match across the board -->
<TgsCoreVersion>4.1.0</TgsCoreVersion>
<TgsApiVersion>6.0.0</TgsApiVersion>
<TgsApiVersion>6.1.0</TgsApiVersion>
<TgsClientVersion>6.0.0</TgsClientVersion>
<TgsDmapiVersion>5.0.0</TgsDmapiVersion>
<TgsControlPanelVersion>0.4.0</TgsControlPanelVersion>
@@ -8,7 +8,8 @@ namespace Tgstation.Server.Api.Models
public class ChatChannel
{
/// <summary>
/// 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.
/// </summary>
[StringLength(Limits.MaximumIndexableStringLength)]
public string IrcChannel { get; set; }
@@ -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
}
/// <inheritdoc />
public override Task<IReadOnlyCollection<ChannelRepresentation>> MapChannels(IEnumerable<Api.Models.ChatChannel> channels, CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
public override Task<IReadOnlyCollection<ChannelRepresentation>> MapChannels(IEnumerable<ChatChannel> 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<string, string>();
var hs = new HashSet<string>(); // for unique inserts
foreach (var I in channels)
hs.Add(I.IrcChannel);
var toPart = new List<string>();
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<string>();
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<ChannelRepresentation>)channels.Select(x =>
{
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Tgstation.Server.Api.Models;
namespace Tgstation.Server.Host.Extensions
{
/// <summary>
/// Extensions for the <see cref="ChatChannel"/> <see langword="class"/>.
/// </summary>
static class ChatChannelExtensions
{
/// <summary>
/// Gets the IRC channel name from a given <paramref name="chatChannel"/>.
/// </summary>
/// <param name="chatChannel">The <see cref="ChatChannel"/> to retrieve information from.</param>
/// <returns>The IRC channel name stored in the <paramref name="chatChannel"/>.</returns>
public static string GetIrcChannelName(this ChatChannel chatChannel) => GetIrcChannelSplits(chatChannel).First();
/// <summary>
/// Gets the IRC channel key from a given <paramref name="chatChannel"/>.
/// </summary>
/// <param name="chatChannel">The <see cref="ChatChannel"/> to retrieve information from.</param>
/// <returns>The IRC channel key stored in the <paramref name="chatChannel"/> if it exists, <see langword="null"/> otherwise.</returns>
public static string GetIrcChannelKey(this ChatChannel chatChannel)
{
var splits = GetIrcChannelSplits(chatChannel);
if (splits.Count < 2)
return null;
return splits.Last();
}
/// <summary>
/// Split a given <paramref name="chatChannel"/>'s <see cref="ChatChannel.IrcChannel"/>.
/// </summary>
/// <param name="chatChannel">The <see cref="ChatChannel"/> to work with.</param>
/// <returns>A <see cref="IReadOnlyCollection{T}"/> of the <paramref name="chatChannel"/>'s <see cref="ChatChannel.IrcChannel"/> <see cref="string"/> separated by the ':' <see cref="char"/>.</returns>
static IReadOnlyCollection<string> 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);
}
}
}