IRC parsing, tokenization, and state handling in C#
1using System.Net.Sockets;
2using IRCTokens;
3
4// ReSharper disable StringLiteralTypo
5
6namespace Tokens;
7
8public class Client
9{
10 private readonly byte[] _bytes = new byte[1024];
11 private readonly StatefulDecoder _decoder = new();
12 private readonly StatefulEncoder _encoder = new();
13 private readonly Socket _socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
14
15 public void Start()
16 {
17 _socket.Connect("127.0.0.1", 6667);
18 while (!_socket.Connected)
19 {
20 Thread.Sleep(1000);
21 }
22
23 Send(new Line("NICK", "tokensbot"));
24 Send(new Line("USER", "tokensbot", "0", "*", "real name"));
25
26 while (true)
27 {
28 var bytesReceived = _socket.Receive(_bytes);
29
30 if (bytesReceived == 0)
31 {
32 Console.WriteLine("! disconnected");
33 _socket.Shutdown(SocketShutdown.Both);
34 _socket.Close();
35 break;
36 }
37
38 var lines = _decoder.Push(_bytes, bytesReceived);
39
40 foreach (var line in lines)
41 {
42 Console.WriteLine($"< {line.Format()}");
43
44 switch (line.Command)
45 {
46 case "PING": Send(new Line("PONG", line.Params[0])); break;
47 case "001": Send(new Line("JOIN", "#irctokens")); break;
48 case "PRIVMSG": Send(new Line("PRIVMSG", line.Params[0], "hello there")); break;
49 }
50 }
51 }
52 }
53
54 private void Send(Line line)
55 {
56 Console.WriteLine($"> {line.Format()}");
57 _encoder.Push(line);
58 while (_encoder.PendingBytes.Length > 0)
59 {
60 _encoder.Pop(_socket.Send(_encoder.PendingBytes, SocketFlags.None));
61 }
62 }
63}