Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Olivine-Labs/Alchemy-Websockets
Browse files Browse the repository at this point in the history
  • Loading branch information
ajacksified committed Jan 3, 2012
2 parents c7a17c7 + f9a0534 commit 3f4aa38
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 46 deletions.
Binary file added Alchemy.suo
Binary file not shown.
1 change: 1 addition & 0 deletions packages/repositories.config
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<repositories>
<repository path="..\test\Integration\Alchemy\packages.config" />
<repository path="..\test\Unit\Alchemy\packages.config" />
</repositories>
4 changes: 2 additions & 2 deletions src/Alchemy/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]

[assembly: AssemblyVersion("2.0.0.237")]
[assembly: AssemblyFileVersion("2.0.0.237")]
[assembly: AssemblyVersion("2.1.0.237")]
[assembly: AssemblyFileVersion("2.1.0.237")]
100 changes: 64 additions & 36 deletions src/Alchemy/WebSocketClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using Alchemy.Classes;
using Alchemy.Handlers.WebSocket.hybi10;
Expand All @@ -10,45 +11,63 @@ namespace Alchemy
public class WebSocketClient
{
public TimeSpan ConnectTimeout = new TimeSpan(0, 0, 0, 10);
public string Host = "localhost";

public bool IsAuthenticated;
public ReadyStates ReadyState = ReadyStates.CLOSED;
public string Origin;

public OnEventDelegate OnConnect = x => { };
public OnEventDelegate OnConnected = x => { };
public OnEventDelegate OnDisconnect = x => { };
public OnEventDelegate OnReceive = x => { };
public OnEventDelegate OnSend = x => { };
public String Origin = "localhost";
public String Path = "/";
public int Port = 81;
private TcpClient _client;

private TcpClient _client;
private bool _connecting;
private Context _context;
private ClientHandshake _handshake;

private readonly string _path;
private readonly int _port;
private readonly string _host;

public enum ReadyStates
{
CONNECTING,
OPEN,
CLOSING,
CLOSED
}

public Boolean Connected
{
get
{
if (_client != null)
{
return _client.Connected;
}
return false;
return _client != null && _client.Connected;
}
}

public WebSocketClient(string path)
{
var r = new Regex("^(wss?)://(.*)\\:([0-9]*)/(.*)$");
var matches = r.Match(path);

_host = matches.Groups[2].Value;
_port = Int32.Parse(matches.Groups[3].Value);
_path = matches.Groups[4].Value;
}

public void Connect()
{
if (_client == null)
{
try
{
ReadyState = ReadyStates.CONNECTING;

_client = new TcpClient();
_connecting = true;
_client.BeginConnect(Host, Port, OnRunClient, null);
_client.BeginConnect(_host, _port, OnRunClient, null);

var waiting = new TimeSpan();
while (_connecting && waiting < ConnectTimeout)
{
Expand Down Expand Up @@ -94,42 +113,45 @@ protected void OnRunClient(IAsyncResult result)
while (_context.Connection.Connected)
{
_context.ReceiveReady.Wait();

try
{
_context.Connection.Client.BeginReceive(_context.Buffer, 0, _context.Buffer.Length,
SocketFlags.None, DoReceive, _context);
_context.Connection.Client.BeginReceive(_context.Buffer, 0, _context.Buffer.Length, SocketFlags.None, DoReceive, _context);
}
catch (Exception)
{
break;
}

if (!IsAuthenticated)
{
Authenticate();
}
}
}

Disconnect();
}

private void Authenticate()
{
_handshake = new ClientHandshake
{Version = "8", Origin = Origin, Host = Host, Key = GenerateKey(), ResourcePath = Path};
_handshake = new ClientHandshake { Version = "8", Origin = Origin, Host = _host, Key = GenerateKey(), ResourcePath = _path };

_client.Client.Send(Encoding.UTF8.GetBytes(_handshake.ToString()));
}

private void CheckAuthenticationResponse(Context context)
{
String receivedData = context.UserContext.DataFrame.ToString();
var receivedData = context.UserContext.DataFrame.ToString();
var header = new Header(receivedData);
var handshake = new ServerHandshake(header);
if (Authentication.GenerateAccept(_handshake.Key) == handshake.Accept)
{
IsAuthenticated = true;
_connecting = false;
context.UserContext.OnConnected();
}

if (Authentication.GenerateAccept(_handshake.Key) != handshake.Accept) return;

ReadyState = ReadyStates.OPEN;
IsAuthenticated = true;
_connecting = false;
context.UserContext.OnConnected();
}

private void ReceiveData(Context context)
Expand Down Expand Up @@ -157,6 +179,7 @@ private void DoReceive(IAsyncResult result)
{
var context = (Context) result.AsyncState;
context.Reset();

try
{
context.ReceivedByteCount = context.Connection.Client.EndReceive(result);
Expand All @@ -177,31 +200,36 @@ private void DoReceive(IAsyncResult result)
}
}

private String GenerateKey()
private static String GenerateKey()
{
var bytes = new byte[16];
var random = new Random();
for (int index = 0; index < bytes.Length; index++)

for (var index = 0; index < bytes.Length; index++)
{
bytes[index] = (byte) random.Next(0, 255);
}

return Convert.ToBase64String(bytes);
}

public void Disconnect()
{
_connecting = false;
if (_client != null)
{
var dataFrame = new DataFrame();
dataFrame.Append(new byte[0]);

byte[] bytes = dataFrame.AsFrame()[0].Array;
bytes[0] = 0x88;
_context.UserContext.Send(bytes);
_client.Close();
_client = null;
}

if (_client == null) return;
var dataFrame = new DataFrame();
dataFrame.Append(new byte[0]);

var bytes = dataFrame.AsFrame()[0].Array;

ReadyState = ReadyStates.CLOSING;

bytes[0] = 0x88;
_context.UserContext.Send(bytes);
_client.Close();
_client = null;
ReadyState = ReadyStates.CLOSED;
}

public void Send(String data)
Expand Down
13 changes: 12 additions & 1 deletion test/Integration/Alchemy/Alchemy.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,15 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="nunit.framework, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />
<Reference Include="nunit.framework">
<HintPath>..\..\..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="nunit.mocks">
<HintPath>..\..\..\packages\NUnit.2.5.10.11092\lib\nunit.mocks.dll</HintPath>
</Reference>
<Reference Include="pnunit.framework">
<HintPath>..\..\..\packages\NUnit.2.5.10.11092\lib\pnunit.framework.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
Expand All @@ -50,6 +58,9 @@
<Name>Alchemy %28src\Alchemy%29</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
13 changes: 6 additions & 7 deletions test/Integration/Alchemy/ClientServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ public void SetUp()
{
_server = new WebSocketServer(54321, IPAddress.Loopback) {DefaultOnReceive = OnServerReceive};
_server.Start();
_client = new WebSocketClient
{Host = "127.0.0.1", Port = 54321, Origin = "localhost", OnReceive = OnClientReceive};
_client = new WebSocketClient("ws://127.0.0.1:54321/path") { Origin = "localhost", OnReceive = OnClientReceive };
_client.Connect();
}

Expand All @@ -32,15 +31,15 @@ public void TearDown()
_server = null;
}

private void OnServerReceive(UserContext context)
private static void OnServerReceive(UserContext context)
{
string data = context.DataFrame.ToString();
var data = context.DataFrame.ToString();
context.Send(data);
}

private void OnClientReceive(UserContext context)
{
string data = context.DataFrame.ToString();
var data = context.DataFrame.ToString();
if (data == "Test")
{
if (_forever && _clientDataPass)
Expand Down Expand Up @@ -78,9 +77,9 @@ public void ClientSendDataConcurrent()
_forever = true;
if (_client.Connected)
{
var client2 = new WebSocketClient
{Host = "127.0.0.1", Port = 54321, Origin = "localhost", OnReceive = OnClientReceive};
var client2 = new WebSocketClient("ws://127.0.0.1:54321/path") { OnReceive = OnClientReceive };
client2.Connect();

if (client2.Connected)
{
_client.Send("Test");
Expand Down
4 changes: 4 additions & 0 deletions test/Integration/Alchemy/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="2.5.10.11092" />
</packages>

0 comments on commit 3f4aa38

Please sign in to comment.