-
-
Save strax/3854815 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using System.Net.Sockets; | |
using System.Net; | |
namespace Irc | |
{ | |
public class MessageReceivedEventArgs: EventArgs | |
{ | |
public Message Message; | |
public MessageReceivedEventArgs(Message message) | |
{ | |
Message = message; | |
} | |
} | |
public class Message | |
{ | |
} | |
public class Client: IDisposable | |
{ | |
const string CRLF = "\r\n"; | |
Socket _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.TCP); | |
#region Properties | |
public string Host { get; private set; } | |
public short Port { get; private set; } | |
public string Username { get; private set; } | |
public string Name { get; private set; } | |
public string Nickname { get; set; } | |
#endregion | |
public event EventHandler<MessageReceivedEventArgs> MessageReceived; | |
public Client(string host, short port = 6667) | |
{ | |
Host = host; | |
Port = port; | |
} | |
public async Task ConnectAsync() | |
{ | |
await _socket.BeginConnect(Host, Port); | |
// Start receiving on a background thread | |
Task.Run(() => Receive()); | |
// Wait for the server to send AUTH messages and such | |
await Task.Delay(1000); | |
await SendCommandAsync("USER {0} 8 * :{1}", Username, Name); | |
await SendCommandAsync("NICK {0}", Nickname); | |
} | |
protected Task Receive() | |
{ | |
int read = 0, pos; | |
var buffer = new byte[512]; | |
while((read = await Task<int>.Factory.FromAsync( | |
_socket.BeginReceive(buffer, read, 512 - read, 0, null, null), _socket.EndReceive)) > 0) | |
{ | |
string message = Encoding.ASCII.GetString(buffer); | |
if((pos = message.IndexOf(CRLF)) != -1) | |
{ | |
// message contains CLRF | |
try | |
{ | |
OnMessage(ParseMessage(message.substring(pos))); | |
// Move the remaining bytes to the start of the buffer so we can read the rest later | |
Buffer.BlockCopy(buffer, pos + 2, buffer, 0, 512 - (pos + 2)); | |
read -= pos + 2; | |
} | |
catch(Exception ex) | |
{ | |
Console.Error.WriteLine("Cannot read message"); | |
// Gracefully move to next message | |
read = 0; | |
} | |
} | |
} | |
// We read 0 bytes (= disconnected) | |
Disconnect(); | |
} | |
public async Task SendCommandAsync(string command, params object[] args) | |
{ | |
if(!socket.Connected) throw new InvalidStateException("Not connected"); | |
string message = String.Format(command, args) + CLRF; | |
byte[] buffer = Encoding.ASCII.GetBytes(message); | |
await Task.Factory.FromAsync( | |
_socket.BeginSend(buffer, 0, buffer.Length, 0, null, null), _socket.EndSend); | |
} | |
public void Disconnect() | |
{ | |
_socket.Shutdown(); | |
_socket.Close(); | |
// TODO shutdown the Receive task (see cancel tokens) | |
} | |
// Use events here so we can broadcast messages to many subscribers | |
protected virtual void OnMessage(EventArgs message) | |
{ | |
var handler = MessageReceived; | |
if(handler != null) | |
{ | |
handler(this, e); | |
} | |
} | |
#region IDisposable | |
public void Dispose() | |
{ | |
_socket.Dispose(); | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment