Start adding some line handlers
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Ben Harris 2020-05-13 14:21:49 -04:00
parent ba63e42be4
commit b93174070a
6 changed files with 277 additions and 70 deletions

22
IrcStates/Commands.cs Normal file
View File

@ -0,0 +1,22 @@
namespace IrcStates
{
public static class Commands
{
public const string Nick = "NICK";
public const string Join = "JOIN";
public const string Mode = "MODE";
public const string Part = "PART";
public const string Kick = "KICK";
public const string Quit = "QUIT";
public const string Error = "ERROR";
public const string Topic = "TOPIC";
public const string Privmsg = "PRIVMSG";
public const string Notice = "NOTICE";
public const string Tagmsg = "TAGMSG";
public const string Chghost = "CHGHOST";
public const string Setname = "SETNAME";
public const string Away = "AWAY";
public const string Account = "ACCOUNT";
public const string Cap = "CAP";
}
}

View File

@ -12,13 +12,13 @@ namespace IrcStates
public bool Self { get; set; }
public bool SelfSource { get; set; }
public bool SelfTarget { get; set; }
public Tests.User User { get; set; }
public Tests.User UserSource { get; set; }
public Tests.User UserTarget { get; set; }
public List<Tests.User> Users { get; set; }
public Tests.Channel Channel { get; set; }
public Tests.Channel ChannelSource { get; set; }
public Tests.Channel ChannelTarget { get; set; }
public User User { get; set; }
public User UserSource { get; set; }
public User UserTarget { get; set; }
public List<User> Users { get; set; }
public Channel Channel { get; set; }
public Channel ChannelSource { get; set; }
public Channel ChannelTarget { get; set; }
public string Target { get; set; }
}
}

View File

@ -1,15 +0,0 @@
using System;
namespace IrcStates
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
internal class HandlesAttribute : Attribute
{
private string Command { get; }
public HandlesAttribute(string command)
{
Command = command;
}
}
}

View File

@ -31,8 +31,10 @@ namespace IrcStates
public int? Watch { get; set; }
public bool Whox { get; set; }
public void Parse(IList<string> tokens)
public void Parse(IEnumerable<string> tokens)
{
if (tokens == null) return;
foreach (var token in tokens)
{
var split = token.Split('=', 2);
@ -65,7 +67,8 @@ namespace IrcStates
Watch = int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture);
break;
case "CASEMAPPING":
if (Enum.TryParse(value, true, out Casemap.CaseMapping caseMapping)) CaseMapping = caseMapping;
if (Enum.TryParse(value, true, out Casemap.CaseMapping caseMapping))
CaseMapping = caseMapping;
break;
case "CHANTYPES":
ChanTypes = new List<string> {value};

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace IrcStates
{
@ -6,6 +7,8 @@ namespace IrcStates
{
public ISupportPrefix(string splitVal)
{
if (splitVal == null) throw new ArgumentNullException(nameof(splitVal));
var split = splitVal.Substring(1).Split(')', 2);
Modes = new List<string> {split[0]};
Prefixes = new List<string> {split[1]};

View File

@ -1,9 +1,7 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using IrcTokens;
namespace IrcStates
@ -29,12 +27,6 @@ namespace IrcStates
TempCaps = new Dictionary<string, string>();
AvailableCaps = new Dictionary<string, string>();
AgreedCaps = new List<string>();
RegisterHandlersByAttribute();
}
private void RegisterHandlersByAttribute()
{
throw new NotImplementedException();
}
public string Name { get; set; }
@ -57,42 +49,11 @@ namespace IrcStates
public ISupport ISupport { get; set; }
public bool HasCap { get; set; }
public delegate Emit MessageHandler(Server server, Line line);
private Dictionary<string, List<MessageHandler>> Handlers { get; set; }
public override string ToString()
{
return $"Server(name={Name})";
}
public List<(Line, Emit)> Recv(byte[] data)
{
if (data == null) return null;
var lines = _decoder.Push(data, data.Length);
if (lines == null) throw new ServerDisconnectedException();
return lines.Select(l => (l, ParseTokens(l))).ToList();
}
public Emit Parse(Line line)
{
if (line == null || !Handlers.ContainsKey(line.Command)) return null;
var ret = new Emit();
var handlers = Handlers[line.Command]
.Select(callback => callback(this, line))
.Where(emit => emit != null);
foreach (var emit in handlers)
{
emit.Command = line.Command;
ret = emit;
}
return ret;
}
public string CaseFold(string str)
{
return Casemap.CaseFold(ISupport.CaseMapping, str);
@ -142,14 +103,247 @@ namespace IrcStates
return HasChannel(name) ? Channels[name] : null;
}
[Handles(Numeric.RPL_WELCOME)]
private Emit HandleWelcome(Line line)
public List<(Line, Emit)> Recv(byte[] data)
{
NickName = line.Params[0];
NickNameLower = CaseFold(line.Params[0]);
Registered = true;
if (data == null) return null;
var lines = _decoder.Push(data, data.Length);
if (lines == null) throw new ServerDisconnectedException();
return lines.Select(l => (l, Parse(l))).ToList();
}
public Emit Parse(Line line)
{
if (line == null) return null;
switch (line.Command)
{
case Numeric.RPL_WELCOME: return HandleWelcome(line);
case Numeric.RPL_ISUPPORT: return HandleISupport(line);
case Numeric.RPL_MOTDSTART:
case Numeric.RPL_MOTD:
return HandleMotd(line);
case Commands.Nick: return HandleNick(line);
case Commands.Join: return HandleJoin(line);
case Commands.Part: return HandlePart(line);
case Commands.Kick: return HandleKick(line);
case Commands.Quit: return HandleQuit(line);
case Commands.Error: return HandleError(line);
case Numeric.RPL_NAMREPLY: return HandleNames(line);
case Numeric.RPL_CREATIONTIME: return HandleCreationTime(line);
case Commands.Topic: return HandleTopic(line);
case Numeric.RPL_TOPIC: return HandleTopicNumeric(line);
case Numeric.RPL_TOPICWHOTIME: return HandleTopicTime(line);
case Commands.Mode: return HandleMode(line);
case Numeric.RPL_CHANNELMODEIS: return HandleChannelModeIs(line);
case Numeric.RPL_UMODEIS: return HandleUModeIs(line);
case Commands.Privmsg:
case Commands.Notice:
case Commands.Tagmsg:
return HandleMessage(line);
case Numeric.RPL_VISIBLEHOST: return HandleVisibleHost(line);
case Numeric.RPL_WHOREPLY: return HandleWhoReply(line);
case Numeric.RPL_WHOSPCRPL: return HandleWhox(line);
case Numeric.RPL_WHOISUSER: return HandleWhoIsUser(line);
case Commands.Chghost: return HandleChghost(line);
case Commands.Setname: return HandleSetname(line);
case Commands.Away: return HandleAway(line);
case Commands.Account: return HandleAccount(line);
case Commands.Cap: return HandleCap(line);
case Numeric.RPL_LOGGEDIN: return HandleLoggedIn(line);
case Numeric.RPL_LOGGEDOUT: return HandleLoggedOut(line);
}
return new Emit();
}
private Emit HandleSetname(Line line)
{
throw new NotImplementedException();
}
private Emit HandleAway(Line line)
{
throw new NotImplementedException();
}
private Emit HandleAccount(Line line)
{
throw new NotImplementedException();
}
private Emit HandleCap(Line line)
{
throw new NotImplementedException();
}
private Emit HandleLoggedIn(Line line)
{
throw new NotImplementedException();
}
private Emit HandleChghost(Line line)
{
throw new NotImplementedException();
}
private Emit HandleWhoIsUser(Line line)
{
throw new NotImplementedException();
}
private Emit HandleWhox(Line line)
{
throw new NotImplementedException();
}
private Emit HandleWhoReply(Line line)
{
throw new NotImplementedException();
}
private Emit HandleVisibleHost(Line line)
{
throw new NotImplementedException();
}
private Emit HandleMessage(Line line)
{
throw new NotImplementedException();
}
private Emit HandleUModeIs(Line line)
{
throw new NotImplementedException();
}
private Emit HandleChannelModeIs(Line line)
{
throw new NotImplementedException();
}
private Emit HandleMode(Line line)
{
throw new NotImplementedException();
}
private Emit HandleTopicTime(Line line)
{
throw new NotImplementedException();
}
private Emit HandleTopicNumeric(Line line)
{
throw new NotImplementedException();
}
private Emit HandleTopic(Line line)
{
throw new NotImplementedException();
}
private Emit HandleCreationTime(Line line)
{
throw new NotImplementedException();
}
private Emit HandleNames(Line line)
{
throw new NotImplementedException();
}
private Emit HandleError(Line line)
{
throw new NotImplementedException();
}
private Emit HandleQuit(Line line)
{
throw new NotImplementedException();
}
private Emit HandleLoggedOut(Line line)
{
throw new NotImplementedException();
}
private Emit HandleKick(Line line)
{
throw new NotImplementedException();
}
private Emit HandlePart(Line line)
{
throw new NotImplementedException();
}
private Emit HandleJoin(Line line)
{
throw new NotImplementedException();
}
private Emit HandleNick(Line line)
{
var nick = line.Params[0];
var nickLower = CaseFold(line.Hostmask.NickName);
var emit = new Emit();
if (Users.ContainsKey(nickLower))
{
var user = Users[nick];
emit.User = user;
var oldNickLower = user.NickNameLower;
var newNickLower = CaseFold(nick);
user.SetNickName(nick, newNickLower);
Users[newNickLower] = user;
foreach (var channelLower in user.Channels)
{
var channel = Channels[channelLower];
var channelUser = channel.Users[oldNickLower];
channel.Users.Remove(oldNickLower);
channel.Users[newNickLower] = channelUser;
}
}
if (nickLower == NickNameLower)
{
emit.Self = true;
NickName = nick;
NickNameLower = CaseFold(nick);
}
return emit;
}
private Emit HandleMotd(Line line)
{
if (line.Command == Numeric.RPL_MOTDSTART)
{
Motd.Clear();
}
var emit = new Emit {Text = line.Params[1]};
Motd.Add(line.Params[1]);
return emit;
}
private Emit HandleISupport(Line line)
{
ISupport = new ISupport();
ISupport.Parse(line.Params.Skip(1).SkipLast(1));
return new Emit();
}
private Emit HandleWelcome(Line line)
{
NickName = line.Params[0];
NickNameLower = CaseFold(line.Params[0]);
Registered = true;
return new Emit();
}
}
}