IRC parsing, tokenization, and state handling in C#
1using System;
2using System.Net.Sockets;
3using System.Threading;
4using IRCTokens;
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) Thread.Sleep(1000);
19
20 Send(new("NICK", "tokensbot"));
21 Send(new("USER", "tokensbot", "0", "*", "real name"));
22
23 while (true)
24 {
25 var bytesReceived = _socket.Receive(_bytes);
26
27 if (bytesReceived == 0)
28 {
29 Console.WriteLine("! disconnected");
30 _socket.Shutdown(SocketShutdown.Both);
31 _socket.Close();
32 break;
33 }
34
35 var lines = _decoder.Push(_bytes, bytesReceived);
36
37 foreach (var line in lines)
38 {
39 Console.WriteLine($"< {line.Format()}");
40
41 switch (line.Command)
42 {
43 case "PING":
44 Send(new("PONG", line.Params[0]));
45 break;
46 case "001":
47 Send(new("JOIN", "#irctokens"));
48 break;
49 case "PRIVMSG":
50 Send(new("PRIVMSG", line.Params[0], "hello there"));
51 break;
52 }
53 }
54 }
55 }
56
57 private void Send(Line line)
58 {
59 Console.WriteLine($"> {line.Format()}");
60 _encoder.Push(line);
61 while (_encoder.PendingBytes.Length > 0)
62 _encoder.Pop(_socket.Send(_encoder.PendingBytes, SocketFlags.None));
63 }
64}