IRC parsing, tokenization, and state handling in C#

wip

+288 -2
+2 -2
Directory.Packages.props
··· 3 3 <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> 4 4 </PropertyGroup> 5 5 <ItemGroup> 6 - <PackageVersion Include="Microsoft.SourceLink.Gitea" Version="8.0.0" /> 7 - <PackageVersion Include="TUnit" Version="1.2.11" /> 6 + <PackageVersion Include="Microsoft.SourceLink.Gitea" Version="10.0.103" /> 7 + <PackageVersion Include="TUnit" Version="1.16.4" /> 8 8 <PackageVersion Include="YamlDotNet" Version="16.3.0" /> 9 9 </ItemGroup> 10 10 </Project>
+46
IRCRobots/Bot.cs
··· 1 + namespace IRCRobots; 2 + 3 + public class Bot : IBot 4 + { 5 + private readonly Dictionary<string, Server> _servers = []; 6 + private readonly Queue<Server> _serverQueue = []; 7 + 8 + public Server CreateServer(string name) 9 + { 10 + throw new NotImplementedException(); 11 + } 12 + 13 + public Task Disconnected(Server server) 14 + { 15 + throw new NotImplementedException(); 16 + } 17 + 18 + public async Task DisconnectAsync(Server server) 19 + { 20 + _servers.Remove(server.Name); 21 + await server.DisconnectAsync(); 22 + } 23 + 24 + public async Task<Server> AddServerAsync(string name, ConnectionParams connectionParams) 25 + { 26 + var server = CreateServer(name); 27 + _servers[name] = server; 28 + await server.ConnectAsync(); 29 + _serverQueue.Enqueue(server); 30 + return server; 31 + } 32 + 33 + public Task RunAsync() 34 + { 35 + return Task.CompletedTask; 36 + } 37 + } 38 + 39 + public interface IBot 40 + { 41 + Server CreateServer(string name); 42 + Task Disconnected(Server server); 43 + Task DisconnectAsync(Server server); 44 + Task<Server> AddServerAsync(string name, ConnectionParams connectionParams); 45 + Task RunAsync(); 46 + }
+18
IRCRobots/IRCRobots.csproj
··· 1 + <Project Sdk="Microsoft.NET.Sdk"> 2 + <PropertyGroup> 3 + <TargetFramework>netstandard2.0</TargetFramework> 4 + <PackageId>IRCRobots</PackageId> 5 + <IsPackable>true</IsPackable> 6 + <GeneratePackageOnBuild>true</GeneratePackageOnBuild> 7 + <DebugType>embedded</DebugType> 8 + </PropertyGroup> 9 + <ItemGroup> 10 + <ProjectReference Include="..\IRCStates\IRCStates.csproj" /> 11 + </ItemGroup> 12 + <ItemGroup> 13 + <None Include="README.md" Pack="true" PackagePath="\" /> 14 + </ItemGroup> 15 + <ItemGroup> 16 + <PackageReference Include="Microsoft.SourceLink.Gitea" PrivateAssets="All" /> 17 + </ItemGroup> 18 + </Project>
+64
IRCRobots/Params.cs
··· 1 + namespace IRCRobots; 2 + 3 + public abstract class SaslParams 4 + { 5 + public virtual string Mechanism { get; set; } 6 + } 7 + 8 + public class SaslUserPass : SaslParams 9 + { 10 + public override string Mechanism => "USERPASS"; 11 + public string Username { get; set; } 12 + public string Password { get; set; } 13 + } 14 + 15 + public class SaslSCRAM : SaslUserPass 16 + { 17 + public override string Mechanism => "SCRAM"; 18 + } 19 + 20 + public class SaslExternal : SaslParams 21 + { 22 + public override string Mechanism => "EXTERNAL"; 23 + } 24 + 25 + public record struct STSPolicy 26 + { 27 + public int Created { get; set; } 28 + public int Port { get; set; } 29 + public int Duration { get; set; } 30 + public bool Preload { get; set; } 31 + } 32 + 33 + public record struct ResumePolicy 34 + { 35 + public string Address { get; set; } 36 + public string Token { get; set; } 37 + } 38 + 39 + public record struct ConnectionParams() 40 + { 41 + public string Nickname { get; set; } 42 + public string Host { get; set; } 43 + public int Port { get; set; } 44 + 45 + public string Username { get; set; } 46 + public string Realname { get; set; } 47 + public string Bindhost { get; set; } 48 + 49 + public string Password { get; set; } 50 + public SaslParams Sasl { get; set; } 51 + 52 + public STSPolicy STS { get; set; } 53 + public ResumePolicy Resume { get; set; } 54 + 55 + public int Reconnect { get; set; } = 10; 56 + public List<string> AlternateNicknames { get; set; } = []; 57 + 58 + public List<string> Autojoin { get; set; } = []; 59 + 60 + public static ConnectionParams FromHoststring(string nickname, string hoststring) 61 + { 62 + return new(); 63 + } 64 + }
+12
IRCRobots/Security.cs
··· 1 + using System.Net.Security; 2 + 3 + namespace IRCRobots; 4 + 5 + public abstract class Tls((string, string) ClientKeypair) 6 + { 7 + } 8 + 9 + public class TlsNoVerify((string, string) clientKeypair) : Tls(clientKeypair); 10 + public class TlsVerifyChain((string, string) clientKeypair) : Tls(clientKeypair); 11 + public class TlsVerifyHash((string, string) clientKeypair) : TlsNoVerify(clientKeypair); 12 + public class TlsVerifySha512((string, string) clientKeypair) : TlsVerifyHash(clientKeypair);
+145
IRCRobots/Server.cs
··· 1 + using IRCTokens; 2 + 3 + namespace IRCRobots; 4 + 5 + public class Server : IServer 6 + { 7 + public string Name { get; set; } 8 + public IBot Bot { get; set; } 9 + public bool Disconnected { get; set; } 10 + public ConnectionParams Params { get; set; } 11 + public List<ICapability> DesiredCaps { get; set; } 12 + public float LastRead { get; set; } 13 + 14 + private int _sentCount = 0; 15 + 16 + public Task<SentLine> SendRawAsync(string line, SendPriority priority = SendPriority.Medium) => 17 + SendAsync(new(line), priority); 18 + 19 + public Task<SentLine> SendAsync(Line line, SendPriority priority = SendPriority.Medium) 20 + { 21 + LinePresend(line); 22 + var sentLine = new SentLine(_sentCount++, priority, line); 23 + 24 + var label = CapAvailable(CAP_LABEL); 25 + if (label is not null) 26 + { 27 + } 28 + } 29 + 30 + public Task<Line> WaitForAsync() 31 + { 32 + throw new NotImplementedException(); 33 + } 34 + 35 + public void SetThrottle(int rate, float time) 36 + { 37 + throw new NotImplementedException(); 38 + } 39 + 40 + public (string, int) ServerAddress() 41 + { 42 + throw new NotImplementedException(); 43 + } 44 + 45 + public Task ConnectAsync(ITcpTransport transport, ConnectionParams connectionParams) 46 + { 47 + throw new NotImplementedException(); 48 + } 49 + 50 + public Task DisconnectAsync() 51 + { 52 + throw new NotImplementedException(); 53 + } 54 + 55 + public void LinePreread(Line line) 56 + { 57 + throw new NotImplementedException(); 58 + } 59 + 60 + public void LinePresend(Line line) 61 + { 62 + throw new NotImplementedException(); 63 + } 64 + 65 + public Task LineReadAsync(Line line) 66 + { 67 + throw new NotImplementedException(); 68 + } 69 + 70 + public Task LineSendAsync(Line line) 71 + { 72 + throw new NotImplementedException(); 73 + } 74 + 75 + public Task StsPolicyAsync(STSPolicy sts) 76 + { 77 + throw new NotImplementedException(); 78 + } 79 + 80 + public Task ResumePolicyAsync(ResumePolicy resume) 81 + { 82 + throw new NotImplementedException(); 83 + } 84 + 85 + public bool CapAgreed(ICapability capability) 86 + { 87 + throw new NotImplementedException(); 88 + } 89 + 90 + public string CapAvailable(ICapability capability) 91 + { 92 + throw new NotImplementedException(); 93 + } 94 + 95 + public Task<bool> SaslAuthAsync(SaslParams sasl) 96 + { 97 + throw new NotImplementedException(); 98 + } 99 + } 100 + 101 + public enum SendPriority 102 + { 103 + High = 0, 104 + Medium = 10, 105 + Low = 20, 106 + Default = Medium 107 + } 108 + public interface IServer 109 + { 110 + Task<SentLine> SendRawAsync(string line, SendPriority priority = SendPriority.Default); 111 + Task<SentLine> SendAsync(Line line, SendPriority priority = SendPriority.Default); 112 + 113 + Task<Line> WaitForAsync(); 114 + void SetThrottle(int rate, float time); 115 + (string, int) ServerAddress(); 116 + 117 + Task ConnectAsync(ITcpTransport transport, ConnectionParams connectionParams); 118 + Task DisconnectAsync(); 119 + 120 + void LinePreread(Line line); 121 + void LinePresend(Line line); 122 + Task LineReadAsync(Line line); 123 + Task LineSendAsync(Line line); 124 + Task StsPolicyAsync(STSPolicy sts); 125 + Task ResumePolicyAsync(ResumePolicy resume); 126 + 127 + bool CapAgreed(ICapability capability); 128 + string CapAvailable(ICapability capability); 129 + 130 + Task<bool> SaslAuthAsync(SaslParams sasl); 131 + } 132 + 133 + public interface ITcpTransport 134 + { 135 + (ITcpReader, ITcpWriter) Connect(string hostname, int port, Tls tls, string bindhost); 136 + } 137 + 138 + public interface ICapability 139 + { 140 + string Available(IEnumerable<string> capabilities); 141 + bool Match(string capability); 142 + ICapability Copy(); 143 + } 144 + 145 + public record struct SentLine(int Id, SendPriority Priority, Line Line);
+1
IRCSharp.slnx
··· 3 3 <Project Path="Examples/States/States.csproj" /> 4 4 <Project Path="Examples/Tokens/Tokens.csproj" /> 5 5 </Folder> 6 + <Project Path="IRCRobots/IRCRobots.csproj" /> 6 7 <Project Path="IRCSharp.Tests/IRCSharp.Tests.csproj" /> 7 8 <Project Path="IRCStates/IRCStates.csproj" /> 8 9 <Project Path="IRCTokens/IRCTokens.csproj" />