Created
January 6, 2018 23:25
-
-
Save jcotton42/5f0f6e832265d48b74bf11097be71175 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Immutable; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
namespace ReactiveIRC { | |
public struct IRCMessage { | |
private const int MaxParams = 15; | |
private static readonly Regex MessageRegex = | |
new Regex(@"(@(?<tags>[^ ]*) +)?(:(?<prefix>[^ ]*) +)?(?<command>[^ ]+)( +(?<params>.*))?"); | |
public ImmutableDictionary<string, string> Tags { get; } | |
public string Source { get; } | |
public string Command { get; } | |
public ImmutableArray<string> Parameters { get; } | |
public IRCMessage(ImmutableDictionary<string, string> tags, string source, string command, | |
ImmutableArray<string> parameters) { | |
Tags = tags ?? throw new ArgumentNullException(nameof(tags)); | |
Source = source ?? throw new ArgumentNullException(nameof(source)); | |
Command = command ?? throw new ArgumentNullException(nameof(command)); | |
Parameters = parameters; | |
} | |
public static IRCMessage Parse(string message) { | |
if(message is null) { | |
throw new ArgumentNullException(nameof(message)); | |
} | |
var matches = MessageRegex.Match(message); | |
if(!matches.Success) { | |
throw new FormatException(nameof(message) + " is not a valid IRC message."); | |
} | |
return new IRCMessage( | |
ParseTags(matches.Groups["tags"].Value), | |
matches.Groups["prefix"].Value, | |
matches.Groups["command"].Value, | |
ParseParams(matches.Groups["params"].Value) | |
); | |
ImmutableDictionary<string, string> ParseTags(string tags) { | |
if(string.IsNullOrWhiteSpace(tags)) { | |
return ImmutableDictionary<string, string>.Empty; | |
} | |
return tags.Split(';').Select(ExtractKeyValuePair) | |
.ToImmutableDictionary(kvp => kvp.key, kvp => UnescapeValue(kvp.value)); | |
(string key, string value) ExtractKeyValuePair(string tag) { | |
var parts = tag.Split(new[] { '=' }, 2); | |
return (parts[0], parts.Length > 1 ? parts[1] : ""); | |
} | |
string UnescapeValue(string value) { | |
var sb = new StringBuilder(); | |
for(var i = 0; i < value.Length; i++) { | |
if(value[i] == '\\') { | |
i++; | |
if(i >= value.Length) { | |
break; | |
} | |
switch(value[i]) { | |
case ':': | |
sb.Append(';'); | |
break; | |
case 's': | |
sb.Append(' '); | |
break; | |
case '\\': | |
sb.Append('\\'); | |
break; | |
case 'r': | |
sb.Append('\r'); | |
break; | |
case 'n': | |
sb.Append('\n'); | |
break; | |
default: | |
sb.Append("\\" + value[i]); | |
break; | |
} | |
} else { | |
sb.Append(value[i]); | |
} | |
} | |
return sb.ToString(); | |
} | |
} | |
ImmutableArray<string> ParseParams(string parameters) { | |
// max params: 15 | |
// TODO: there is definitely a more efficient way to do this | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment