From 304df7805b9925c2edd992fd4177eef80197f807 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Thu, 14 May 2020 22:17:22 -0400 Subject: working ircstates example --- Examples/States/Client.cs | 84 ++++++++++++++++++++++++++++++++++++++++++++++ Examples/States/Program.cs | 7 ++-- IrcStates/README.md | 77 ++++++++++++++++++++++++++++++++++++++++++ IrcStates/Server.cs | 6 ++-- IrcTokens/README.md | 2 +- 5 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 Examples/States/Client.cs diff --git a/Examples/States/Client.cs b/Examples/States/Client.cs new file mode 100644 index 0000000..78d253f --- /dev/null +++ b/Examples/States/Client.cs @@ -0,0 +1,84 @@ +using System; +using System.Linq; +using System.Net.Sockets; +using System.Threading; +using IrcStates; +using IrcTokens; + +namespace StatesSample +{ + internal class Client + { + private readonly byte[] _bytes; + private readonly StatefulEncoder _encoder; + private readonly string _host; + private readonly string _nick; + private readonly int _port; + private readonly Server _server; + private readonly Socket _socket; + + public Client(string host, int port, string nick) + { + _server = new Server("test"); + _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _encoder = new StatefulEncoder(); + _host = host; + _port = port; + _nick = nick; + _bytes = new byte[1024]; + } + + private void Send(string raw) + { + _encoder.Push(new Line(raw)); + } + + public void Start() + { + _socket.Connect(_host, _port); + while (!_socket.Connected) Thread.Sleep(1000); + + Send("USER test 0 * test"); + Send($"NICK {_nick}"); + + while (true) + { + while (_encoder.PendingBytes.Any()) + { + var bytesSent = _socket.Send(_encoder.PendingBytes); + var sentLines = _encoder.Pop(bytesSent); + foreach (var line in sentLines) Console.WriteLine($"> {line.Format()}"); + } + + var bytesReceived = _socket.Receive(_bytes); + if (bytesReceived == 0) + { + Console.WriteLine("! disconnected"); + _socket.Shutdown(SocketShutdown.Both); + _socket.Close(); + break; + } + + var receivedLines = _server.Receive(_bytes, bytesReceived); + foreach (var (line, _) in receivedLines) + { + Console.WriteLine($"< {line.Format()}"); + + switch (line.Command) + { + case Commands.Privmsg: + if (line.Params[1].Contains(_server.NickName)) + Send($"PRIVMSG {line.Params[0]} :hi {line.Hostmask.NickName}!"); + break; + case "PING": + Send($"PONG :{line.Params[0]}"); + break; + case Numeric.RPL_WELCOME: + if (!_server.HasChannel("#test")) Send("JOIN #test"); + break; + } + } + } + } + } +} diff --git a/Examples/States/Program.cs b/Examples/States/Program.cs index 8fc42b8..8ad7bf7 100644 --- a/Examples/States/Program.cs +++ b/Examples/States/Program.cs @@ -1,12 +1,11 @@ -using System; - -namespace StatesSample +namespace StatesSample { public static class Program { private static void Main(string[] args) { - Console.WriteLine("Hello World!"); + var client = new Client("localhost", 6667, "statesbot"); + client.Start(); } } } diff --git a/IrcStates/README.md b/IrcStates/README.md index 60fcc44..05daa8c 100644 --- a/IrcStates/README.md +++ b/IrcStates/README.md @@ -3,3 +3,80 @@ port of [jesopo/ircstates](https://github.com/jesopo/ircstates) bare bones irc client state + +see the full example in [StatesSample/Client.cs](../Examples/States/Client.cs) + + internal class Client + { + private readonly byte[] _bytes; + private readonly StatefulEncoder _encoder; + private readonly string _host; + private readonly string _nick; + private readonly int _port; + private readonly Server _server; + private readonly Socket _socket; + + public Client(string host, int port, string nick) + { + _server = new Server("test"); + _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _encoder = new StatefulEncoder(); + _host = host; + _port = port; + _nick = nick; + _bytes = new byte[1024]; + } + + private void Send(string raw) + { + _encoder.Push(new Line(raw)); + } + + public void Start() + { + _socket.Connect(_host, _port); + while (!_socket.Connected) Thread.Sleep(1000); + + Send("USER test 0 * test"); + Send($"NICK {_nick}"); + + while (true) + { + while (_encoder.PendingBytes.Any()) + { + var bytesSent = _socket.Send(_encoder.PendingBytes); + var sentLines = _encoder.Pop(bytesSent); + foreach (var line in sentLines) Console.WriteLine($"> {line.Format()}"); + } + + var bytesReceived = _socket.Receive(_bytes); + if (bytesReceived == 0) + { + Console.WriteLine("! disconnected"); + _socket.Shutdown(SocketShutdown.Both); + _socket.Close(); + break; + } + + var receivedLines = _server.Receive(_bytes, bytesReceived); + foreach (var (line, _) in receivedLines) + { + Console.WriteLine($"< {line.Format()}"); + + switch (line.Command) + { + case Commands.Privmsg: + if (line.Params[1].Contains(_server.NickName)) + Send($"PRIVMSG {line.Params[0]} :hi {line.Hostmask.NickName}!"); + break; + case "PING": + Send($"PONG :{line.Params[0]}"); + break; + case Numeric.RPL_WELCOME: + if (!_server.HasChannel("#test")) Send("JOIN #test"); + break; + } + } + } + } + } \ No newline at end of file diff --git a/IrcStates/Server.cs b/IrcStates/Server.cs index ca812f6..2e80b75 100644 --- a/IrcStates/Server.cs +++ b/IrcStates/Server.cs @@ -95,7 +95,7 @@ namespace IrcStates ISupport.ChanTypes.Contains(target[0].ToString(CultureInfo.InvariantCulture)); } - private bool HasChannel(string name) + public bool HasChannel(string name) { return Channels.ContainsKey(CaseFold(name)); } @@ -201,11 +201,11 @@ namespace IrcStates } } - public List<(Line, Emit)> Recv(byte[] data) + public IEnumerable<(Line, Emit)> Receive(byte[] data, int length) { if (data == null) return null; - var lines = _decoder.Push(data, data.Length); + var lines = _decoder.Push(data, length); if (lines == null) throw new ServerDisconnectedException(); return lines.Select(l => (l, Parse(l))).ToList(); diff --git a/IrcTokens/README.md b/IrcTokens/README.md index 216dcf8..3981654 100644 --- a/IrcTokens/README.md +++ b/IrcTokens/README.md @@ -23,7 +23,7 @@ https://github.com/jesopo/irctokens) ### stateful -see the full example in [Examples/Tokens/Client.cs](../Examples/Tokens/Client.cs) +see the full example in [TokensSample/Client.cs](../Examples/Tokens/Client.cs) public class Client { -- cgit 1.4.1