diff --git a/src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs b/src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs
index b4cb64a8118..18e8a14df6e 100644
--- a/src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs
+++ b/src/Tgstation.Server.Api/Models/IrcConnectionStringBuilder.cs
@@ -88,6 +88,7 @@ public IrcConnectionStringBuilder(string connectionString)
case IrcPasswordType.NickServ:
case IrcPasswordType.Sasl:
case IrcPasswordType.Server:
+ case IrcPasswordType.Oper:
PasswordType = passwordType;
break;
default:
diff --git a/src/Tgstation.Server.Api/Models/IrcPasswordType.cs b/src/Tgstation.Server.Api/Models/IrcPasswordType.cs
index add54b1565f..9a0fca38c46 100644
--- a/src/Tgstation.Server.Api/Models/IrcPasswordType.cs
+++ b/src/Tgstation.Server.Api/Models/IrcPasswordType.cs
@@ -19,5 +19,10 @@ public enum IrcPasswordType
/// Use NickServ authentication.
///
NickServ,
+
+ ///
+ /// Use OPER authentication.
+ ///
+ Oper,
}
}
diff --git a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
index ad83a80b18b..3a532f6b425 100644
--- a/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
+++ b/src/Tgstation.Server.Host/Components/Chat/Providers/IrcProvider.cs
@@ -42,11 +42,6 @@ sealed class IrcProvider : Provider
///
public override string BotMention => client.Nickname;
- ///
- /// The client.
- ///
- readonly IrcFeatures client;
-
///
/// Address of the server to connect to.
///
@@ -57,6 +52,11 @@ sealed class IrcProvider : Provider
///
readonly ushort port;
+ ///
+ /// Wether or not this IRC client is to use ssl.
+ ///
+ readonly bool ssl;
+
///
/// IRC nickname.
///
@@ -82,6 +82,16 @@ sealed class IrcProvider : Provider
///
readonly Dictionary queryChannelIdMap;
+ ///
+ /// The version string obtained from .
+ ///
+ readonly string versionString;
+
+ ///
+ /// The client.
+ ///
+ IrcFeatures client;
+
///
/// The used for .
///
@@ -92,11 +102,6 @@ sealed class IrcProvider : Provider
///
ulong channelIdCounter;
- ///
- /// If we are disconnecting.
- ///
- bool disconnecting;
-
///
/// Initializes a new instance of the class.
///
@@ -121,33 +126,15 @@ public IrcProvider(
address = ircBuilder.Address!;
port = ircBuilder.Port!.Value;
+ ssl = ircBuilder.UseSsl!.Value;
nickname = ircBuilder.Nickname!;
password = ircBuilder.Password!;
passwordType = ircBuilder.PasswordType;
- client = new IrcFeatures
- {
- SupportNonRfc = true,
- CtcpUserInfo = "You are going to play. And I am going to watch. And everything will be just fine...",
- AutoRejoin = true,
- AutoRejoinOnKick = true,
- AutoRelogin = true,
- AutoRetry = false,
- AutoReconnect = false,
- ActiveChannelSyncing = true,
- AutoNickHandling = true,
- CtcpVersion = assemblyInformationProvider.VersionString,
- UseSsl = ircBuilder.UseSsl!.Value,
- };
- if (ircBuilder.UseSsl.Value)
- client.ValidateServerCertificate = true; // dunno if it defaults to that or what
-
- client.OnChannelMessage += Client_OnChannelMessage;
- client.OnQueryMessage += Client_OnQueryMessage;
+ versionString = assemblyInformationProvider.VersionString;
- /*client.OnReadLine += (sender, e) => Logger.LogTrace("READ: {line}", e.Line);
- client.OnWriteLine += (sender, e) => Logger.LogTrace("WRITE: {line}", e.Line);*/
+ client = InstantiateClient();
channelIdMap = new Dictionary();
queryChannelIdMap = new Dictionary();
@@ -369,12 +356,15 @@ await SendMessage(
///
protected override async ValueTask Connect(CancellationToken cancellationToken)
{
- disconnecting = false;
cancellationToken.ThrowIfCancellationRequested();
try
{
await Task.Factory.StartNew(
- () => client.Connect(address, port),
+ () =>
+ {
+ client = InstantiateClient();
+ client.Connect(address, port);
+ },
cancellationToken,
DefaultIOManager.BlockingTaskCreationOptions,
TaskScheduler.Current)
@@ -382,70 +372,50 @@ await Task.Factory.StartNew(
cancellationToken.ThrowIfCancellationRequested();
+ listenTask = Task.Factory.StartNew(
+ () =>
+ {
+ Logger.LogTrace("Starting blocking listen...");
+ try
+ {
+ client.Listen();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogWarning(ex, "IRC Main Listen Exception!");
+ }
+
+ Logger.LogTrace("Exiting listening task...");
+ }, cancellationToken, DefaultIOManager.BlockingTaskCreationOptions, TaskScheduler.Current);
+
Logger.LogTrace("Authenticating ({passwordType})...", passwordType);
switch (passwordType)
{
case IrcPasswordType.Server:
- client.Login(nickname, nickname, 0, nickname, password);
+ client.RfcPass(password);
+ await Login(client, nickname);
break;
case IrcPasswordType.NickServ:
- client.Login(nickname, nickname, 0, nickname);
+ await Login(client, nickname);
cancellationToken.ThrowIfCancellationRequested();
client.SendMessage(SendType.Message, "NickServ", String.Format(CultureInfo.InvariantCulture, "IDENTIFY {0}", password));
break;
case IrcPasswordType.Sasl:
await SaslAuthenticate(cancellationToken);
break;
+ case IrcPasswordType.Oper:
+ await Login(client, nickname);
+ cancellationToken.ThrowIfCancellationRequested();
+ client.RfcOper(nickname, password, Priority.Critical);
+ break;
case null:
- client.Login(nickname, nickname, 0, nickname);
+ await Login(client, nickname);
break;
default:
throw new InvalidOperationException($"Invalid IrcPasswordType: {passwordType.Value}");
}
cancellationToken.ThrowIfCancellationRequested();
- Logger.LogTrace("Processing initial messages...");
- await NonBlockingListen(cancellationToken);
-
- var nickCheckCompleteTcs = new TaskCompletionSource();
- using (cancellationToken.Register(() => nickCheckCompleteTcs.TrySetCanceled(cancellationToken)))
- {
- listenTask = Task.Factory.StartNew(
- async () =>
- {
- Logger.LogTrace("Entering nick check loop");
- while (!disconnecting && client.IsConnected && client.Nickname != nickname)
- {
- client.ListenOnce(true);
- if (disconnecting || !client.IsConnected)
- break;
- await NonBlockingListen(cancellationToken);
-
- // ensure we have the correct nick
- if (client.GetIrcUser(nickname) == null)
- client.RfcNick(nickname);
- }
-
- nickCheckCompleteTcs.TrySetResult();
-
- Logger.LogTrace("Starting blocking listen...");
- try
- {
- client.Listen();
- }
- catch (Exception ex)
- {
- Logger.LogWarning(ex, "IRC Main Listen Exception!");
- }
-
- Logger.LogTrace("Exiting listening task...");
- },
- cancellationToken,
- DefaultIOManager.BlockingTaskCreationOptions,
- TaskScheduler.Current);
-
- await nickCheckCompleteTcs.Task;
- }
Logger.LogTrace("Connection established!");
}
@@ -487,6 +457,37 @@ await Task.Factory.StartNew(
}
}
+ ///
+ /// Register the client on the network.
+ ///
+ /// IRC client.
+ /// Nickname.
+ /// that resolves when registration has been completed.
+ /// If the IRC server fails to respond.
+ private async Task Login(IrcFeatures client, string nickname)
+ {
+ var promise = new TaskCompletionSource