IRC parsing, tokenization, and state handling in C#
at tunit 70 lines 2.3 kB view raw
1using System.Net.Sockets; 2using IRCStates; 3using IRCTokens; 4// ReSharper disable StringLiteralTypo 5 6namespace States; 7 8internal class Client(string host, int port, string nick) 9{ 10 private readonly byte[] _bytes = new byte[1024]; 11 private readonly StatefulEncoder _encoder = new(); 12 private readonly Server _server = new("test"); 13 private readonly Socket _socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 14 15 private void Send(string raw) 16 { 17 _encoder.Push(new Line(raw)); 18 } 19 20 public void Start() 21 { 22 _socket.Connect(host, port); 23 while (!_socket.Connected) Thread.Sleep(1000); 24 25 Send("USER test 0 * test"); 26 Send($"NICK {nick}"); 27 28 while (true) 29 { 30 while (_encoder.PendingBytes.Length != 0) 31 { 32 foreach (var line in _encoder.Pop(_socket.Send(_encoder.PendingBytes))) 33 Console.WriteLine($"> {line.Format()}"); 34 } 35 36 var bytesReceived = _socket.Receive(_bytes); 37 if (bytesReceived == 0) 38 { 39 Console.WriteLine("! disconnected"); 40 _socket.Shutdown(SocketShutdown.Both); 41 _socket.Close(); 42 break; 43 } 44 45 var receivedLines = _server.Receive(_bytes, bytesReceived); 46 foreach (var (line, _) in receivedLines) 47 { 48 Console.WriteLine($"< {line.Format()}"); 49 50 switch (line.Command) 51 { 52 case Commands.Privmsg: 53 if (line.Params[1].Contains(_server.NickName)) 54 Send($"PRIVMSG {line.Params[0]} :hi {line.Hostmask.NickName}!"); 55 break; 56 case "PING": 57 Send($"PONG :{line.Params[0]}"); 58 break; 59 case Numeric.RPL_WELCOME: 60 if (!_server.HasChannel("#irctokens")) Send("JOIN #irctokens"); 61 break; 62 case "INVITE": 63 var c = line.Params[1]; 64 if (!_server.HasChannel(c)) Send($"JOIN {c}"); 65 break; 66 } 67 } 68 } 69 } 70}