Added ability to construct IRC messages from parts when sending them.

This commit is contained in:
Cameron
2024-03-25 05:06:51 -05:00
parent 81651a0e59
commit 1bf8afc68b
4 changed files with 77 additions and 22 deletions

View File

@@ -139,12 +139,52 @@ namespace TwitchIrcClient.IRC
var bytes = Encoding.UTF8.GetBytes(line + ENDL);
_Stream.Write(bytes, 0, bytes.Length);
}
//TODO make this unit testable?
/// <summary>
/// Construct an IRC message from parts and sends it. Does little to no validation on inputs.
/// </summary>
/// <param name="command"></param>
/// <param name="parameters"></param>
/// <param name="tags"></param>
/// <param name="prefix"></param>
public void SendMessage(IrcMessageType command, IEnumerable<string>? parameters = null,
Dictionary<string, string?>? tags = null, string? prefix = null)
{
var message = "";
if (tags is not null && tags.Count != 0)
{
message = "@" + string.Join(';',
tags.OrderBy(p => p.Key).Select(p => $"{p.Key}={EscapeTagValue(p.Value)}"))
+ " ";
}
if (prefix is not null && !string.IsNullOrWhiteSpace(prefix))
message += ":" + prefix + " ";
message += command.ToCommand() + " ";
if (parameters is not null && parameters.Any())
{
message += string.Join(' ', parameters.SkipLast(1));
message += " :" + parameters.Last();
}
SendLine(message);
}
private static string EscapeTagValue(string? s)
{
if (s is null)
return "";
return string.Join("", s.Select(c => c switch
{
';' => @"\:",
' ' => @"\s",
'\\' => @"\\",
'\r' => @"\r",
'\n' => @"\n",
char ch => ch.ToString(),
}));
}
public void Authenticate(string? user, string? pass)
{
if (user == null)
user = $"justinfan{Random.Shared.NextInt64(10000):D4}";
if (pass == null)
pass = "pass";
user ??= $"justinfan{Random.Shared.NextInt64(10000):D4}";
pass ??= "pass";
SendLine($"NICK {user}");
SendLine($"PASS {pass}");
}

View File

@@ -6,6 +6,9 @@ using System.Threading.Tasks;
namespace TwitchIrcClient.IRC
{
/// <summary>
/// Represents the "command" of an IRC message.
/// </summary>
public enum IrcMessageType
{
//twitch standard messages
@@ -174,12 +177,26 @@ namespace TwitchIrcClient.IRC
}
public static class IrcMessageTypeHelper
{
//parses a string that is either a numeric code or the command name
/// <summary>
/// Parses a string that is either a numeric code or the command name.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
/// <remarks>
/// The value range 000-999 is reserved for numeric commands, and will
/// be converted to a numeric string when forming a message.
/// </remarks>
public static IrcMessageType Parse(string s)
{
if (int.TryParse(s, out int result))
return (IrcMessageType)result;
return Enum.Parse<IrcMessageType>(s);
}
public static string ToCommand(this IrcMessageType type)
{
if ((int)type >= 0 && (int)type < 1000)
return $"{(int)type,3}";
return type.ToString();
}
}
}

View File

@@ -9,11 +9,9 @@ RateLimiter limiter = new(20, 30);
bool ssl = true;
async Task<IrcConnection> CreateConnection(string channel)
{
IrcConnection connection;
if (ssl)
connection = new IrcConnection("irc.chat.twitch.tv", 6697, limiter, true, true);
else
connection = new IrcConnection("irc.chat.twitch.tv", 6667, limiter, true, false);
IrcConnection connection = ssl
? connection = new IrcConnection("irc.chat.twitch.tv", 6697, limiter, true, true)
: connection = new IrcConnection("irc.chat.twitch.tv", 6667, limiter, true, false);
connection.AddCallback(new MessageCallbackItem(
(o, m) =>
{
@@ -51,7 +49,7 @@ async Task<IrcConnection> CreateConnection(string channel)
}
Console.Write("Channel: ");
var channelName = Console.ReadLine();
ArgumentNullException.ThrowIfNull(channelName, nameof(Channel));
ArgumentNullException.ThrowIfNullOrWhiteSpace(channelName, nameof(channelName));
var connection = await CreateConnection(channelName);
while (true)
{