From f6f3e7e0c535aaf3627f815dd63970aec6c73f75 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Wed, 6 May 2020 21:27:36 -0400 Subject: start impl --- IrcStates/Extensions.cs | 32 +++++++++++++++++ IrcStates/HandlesAttribute.cs | 15 ++++++++ IrcStates/Server.cs | 80 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 IrcStates/Extensions.cs create mode 100644 IrcStates/HandlesAttribute.cs diff --git a/IrcStates/Extensions.cs b/IrcStates/Extensions.cs new file mode 100644 index 0000000..dde0edb --- /dev/null +++ b/IrcStates/Extensions.cs @@ -0,0 +1,32 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace IrcStates +{ + public static class Extensions + { + public static Delegate CreateDelegate(this MethodInfo methodInfo, object target) + { + if (methodInfo == null) return null; + + var types = methodInfo.GetParameters().Select(p => p.ParameterType); + + Func getType; + if (methodInfo.ReturnType == typeof(void)) + { + getType = Expression.GetActionType; + } + else + { + getType = Expression.GetFuncType; + types = types.Concat(new[] {methodInfo.ReturnType}); + } + + return methodInfo.IsStatic + ? Delegate.CreateDelegate(getType(types.ToArray()), methodInfo) + : Delegate.CreateDelegate(getType(types.ToArray()), target, methodInfo); + } + } +} diff --git a/IrcStates/HandlesAttribute.cs b/IrcStates/HandlesAttribute.cs new file mode 100644 index 0000000..8f3b271 --- /dev/null +++ b/IrcStates/HandlesAttribute.cs @@ -0,0 +1,15 @@ +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; + } + } +} diff --git a/IrcStates/Server.cs b/IrcStates/Server.cs index 7199668..1d4f90f 100644 --- a/IrcStates/Server.cs +++ b/IrcStates/Server.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; using IrcTokens; namespace IrcStates @@ -10,8 +13,6 @@ namespace IrcStates public const string WhoType = "525"; // randomly generated private readonly StatefulDecoder _decoder; - public Dictionary>> LineHandlers; - private Dictionary TempCaps; public Server(string name) @@ -21,7 +22,6 @@ namespace IrcStates Modes = new List(); Motd = new List(); _decoder = new StatefulDecoder(); - LineHandlers = new Dictionary>>(); Users = new Dictionary(); Channels = new Dictionary(); ISupport = new ISupport(); @@ -29,6 +29,12 @@ namespace IrcStates TempCaps = new Dictionary(); AvailableCaps = new Dictionary(); AgreedCaps = new List(); + RegisterHandlersByAttribute(); + } + + private void RegisterHandlersByAttribute() + { + throw new NotImplementedException(); } public string Name { get; set; } @@ -51,6 +57,9 @@ namespace IrcStates public ISupport ISupport { get; set; } public bool HasCap { get; set; } + public delegate Emit MessageHandler(Server server, Line line); + private Dictionary> Handlers { get; set; } + public override string ToString() { return $"Server(name={Name})"; @@ -58,20 +67,21 @@ namespace IrcStates 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(); - var emits = lines.Select(ParseTokens).ToList(); - return null; + return lines.Select(l => (l, ParseTokens(l))).ToList(); } public Emit ParseTokens(Line line) { - if (line != null && !LineHandlers.ContainsKey(line.Command)) return null; + if (line == null || !Handlers.ContainsKey(line.Command)) return null; var ret = new Emit(); - var handlers = LineHandlers[line.Command] - .Select(callback => callback(line.Command, line)) + var handlers = Handlers[line.Command] + .Select(callback => callback(this, line)) .Where(emit => emit != null); foreach (var emit in handlers) @@ -87,5 +97,59 @@ namespace IrcStates { return Casemap.CaseFold(ISupport.CaseMapping, str); } + + public bool CaseFoldEquals(string s1, string s2) + { + return CaseFold(s1) == CaseFold(s2); + } + + public bool IsMe(string nickname) + { + return CaseFold(nickname) == NickNameLower; + } + + public bool HasUser(string nickname) + { + return Users.ContainsKey(CaseFold(nickname)); + } + + private void AddUser(string nickname, string nicknameLower) + { + var user = CreateUser(nickname, nicknameLower); + Users[nicknameLower] = user; + } + + private User CreateUser(string nickname, string nicknameLower) + { + var user = new User(); + user.SetNickName(nickname, nicknameLower); + return user; + } + + public bool IsChannel(string target) + { + return !string.IsNullOrEmpty(target) && + ISupport.ChanTypes.Contains(target[0].ToString(CultureInfo.InvariantCulture)); + } + + public bool HasChannel(string name) + { + return Channels.ContainsKey(CaseFold(name)); + } + + public Channel GetChannel(string name) + { + return HasChannel(name) ? Channels[name] : null; + } + + [Handles(Numeric.RPL_WELCOME)] + private Emit HandleWelcome(Line line) + { + NickName = line.Params[0]; + NickNameLower = CaseFold(line.Params[0]); + Registered = true; + return new Emit(); + } + } } -- cgit 1.4.1