mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 23:17:20 +01:00
Merge pull request #950 from tgstation/865-IRCKeys
Allows joining IRC channels with keys
This commit is contained in:
+1
-1
@@ -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,52 +377,68 @@ namespace Tgstation.Server.Host.Components.Chat.Providers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<IReadOnlyCollection<ChannelRepresentation>> MapChannels(IEnumerable<Api.Models.ChatChannel> channels, CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
|
||||
{
|
||||
if (channels.Any(x => x.IrcChannel == null))
|
||||
throw new InvalidOperationException("ChatChannel missing IrcChannel!");
|
||||
lock (this)
|
||||
public override Task<IReadOnlyCollection<ChannelRepresentation>> MapChannels(
|
||||
IEnumerable<ChatChannel> channels,
|
||||
CancellationToken cancellationToken)
|
||||
=> Task.Factory.StartNew(() =>
|
||||
{
|
||||
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 I in toPart)
|
||||
client.RfcPart(I, "Pretty nice abscond!");
|
||||
foreach (var I in hs)
|
||||
client.RfcJoin(I);
|
||||
|
||||
return (IReadOnlyCollection<ChannelRepresentation>)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<string, string>();
|
||||
var hs = new HashSet<string>(); // 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<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 =>
|
||||
{
|
||||
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);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task SendMessage(ulong channelId, string message, CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user