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