Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
RobJohnston committed Oct 10, 2018
1 parent 738b60d commit 33ae251
Show file tree
Hide file tree
Showing 9 changed files with 454 additions and 13 deletions.
16 changes: 11 additions & 5 deletions AlphaPoint.Api.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,24 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2026
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlphaPoint.Api", "AlphaPoint.Api\AlphaPoint.Api.csproj", "{72D4524F-9A60-474A-B5C0-0C2A543C7364}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlphaPoint.Api", "src\AlphaPoint.Api\AlphaPoint.Api.csproj", "{2C4526A7-3CFA-430E-AA28-47BCAF4C6EF2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D1CDEE4D-DE6E-4792-9FA4-53F0BF276989}"
ProjectSection(SolutionItems) = preProject
CHANGELOG.md = CHANGELOG.md
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{72D4524F-9A60-474A-B5C0-0C2A543C7364}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{72D4524F-9A60-474A-B5C0-0C2A543C7364}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72D4524F-9A60-474A-B5C0-0C2A543C7364}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72D4524F-9A60-474A-B5C0-0C2A543C7364}.Release|Any CPU.Build.0 = Release|Any CPU
{2C4526A7-3CFA-430E-AA28-47BCAF4C6EF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2C4526A7-3CFA-430E-AA28-47BCAF4C6EF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2C4526A7-3CFA-430E-AA28-47BCAF4C6EF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2C4526A7-3CFA-430E-AA28-47BCAF4C6EF2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
8 changes: 0 additions & 8 deletions AlphaPoint.Api/Class1.cs

This file was deleted.

13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to Semantic Versioning.

## [Unreleased]


## 1.0.0-alpha1 - 2018-10-09
### Added
- First alpha release. A simple wrapper around the WebSocket to send and receive the message frame.

[Unreleased]: https://github.com/RobJohnston/AlphaPoint.Api/compare/v1.0.0...HEAD
157 changes: 157 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# AlphaPoint.Api
A .Net Standard client for the AlphaPoint API. Full documentation here: https://alphapoint.github.io/slate

This version is a wrapper around the WebSocket to simplify the sending and receiving of message frames.
A future version will use this as a base to more easily consume API methods and return well-defined objects.

## Example usage

```csharp
using AlphaPoint.Api;
using AlphaPoint.Api.Models;
using Newtonsoft.Json;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
class Program
{
private static readonly AutoResetEvent ExitEvent = new AutoResetEvent(false);

static void Main(string[] args)
{
try
{
var task = Task.Run(() => MainAsync());
task.Wait();

// Keep the console window open.
Console.WriteLine("Press <enter> key to exit.");
ConsoleKeyInfo keyInfo = Console.ReadKey();
while (keyInfo.Key != ConsoleKey.Enter)
keyInfo = Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex.Message);
}
}

private static async Task MainAsync()
{
Console.WriteLine("Hello NDAX!");

var uri = "wss://api.ndax.io/WSGateway/";

using (var socket = new AlphaPointWebSocketClient(new Uri(uri)))
{
// Handle events
socket.ReceivedMessageFrame += (o, e) =>
{
Console.WriteLine("MessageFrame received:");
Console.WriteLine(" m > " + e.MessageFrameResponse.MessageType);
Console.WriteLine(" i > " + e.MessageFrameResponse.SequenceNumber);
Console.WriteLine(" n > " + e.MessageFrameResponse.FunctionName);
Console.WriteLine(" o > " + e.MessageFrameResponse.Payload);

ExitEvent.Set();
};

// Create the payload
dynamic payload = new System.Dynamic.ExpandoObject();
payload.OMSId = 1;
payload.InstrumentId = 1;
payload.Depth = 100;

// Wrap a message into a frame object.
var frame = new MessageFrame()
{
MessageType = MessageType.Request,
SequenceNumber = 2,
FunctionName = "GetL2Snapshot",
Payload = JsonConvert.SerializeObject(payload),
};

// Start the client and send the message.
await socket.Start();
await socket.Send(frame);

ExitEvent.WaitOne();
}
}
}
}
```

### Output
```
Hello NDAX!
MessageFrame received:
m > Reply
i > 2
n > GetL2Snapshot
o > [[33653795,1,1539134020119,0,8550,1,8449.81,1,7,0],
[33653795,1,1539134020119,0,8550,1,8449.43,1,1.21310602,0],
[33653795,1,1539134020119,0,8550,1,8448.67,1,0.07465268,0],
[33653795,1,1539134020119,0,8550,1,8448.29,1,0.14189868,0],
[33653795,1,1539134020119,0,8550,1,8448.16,1,2.95022608,0],
[33653795,1,1539134020119,0,8550,1,8447.27,1,0.00253175,0],
[33653795,1,1539134020119,0,8550,1,8447.14,1,0.93315848,0],
[33653795,1,1539134020119,0,8550,1,8446.76,1,0.01014973,0],
[33653795,1,1539134020119,0,8550,1,8446.38,1,2.23211508,0],
[33653795,1,1539134020119,0,8550,1,8446.25,1,0.00922703,0],
[33653795,1,1539134020119,0,8550,1,8446,1,1.39973772,0],
[33653795,1,1539134020119,0,8550,1,8444.35,1,4.54448179,0],
[33653795,1,1539134020119,0,8550,1,8444.22,1,0.1403765,0],
[33653795,1,1539134020119,0,8550,1,8443.71,1,0.13997377,0],
[33653795,1,1539134020119,0,8550,1,8443.46,1,1.17992127,0],
[33653795,1,1539134020119,0,8550,1,8443.2,1,7,0],
[33653795,1,1539134020119,0,8550,1,8443.07,1,0.56167038,0],
[33653795,1,1539134020119,0,8550,1,8442.82,1,1.27881168,0],
[33653795,1,1539134020119,0,8550,1,8442.69,1,3.82594977,0],
[33653795,1,1539134020119,0,8550,1,8442.18,1,0.21066443,0],
[33653795,1,1539134020119,0,8550,1,8441.93,1,2.3328962,0],
[33653795,1,1539134020119,0,8550,1,8441.8,1,0.84265773,0],
[33653795,1,1539134020119,0,8550,1,8441.68,1,0.37326339,0],
[33653795,1,1539134020119,0,8550,1,8441.55,1,2.26066101,0],
[33653795,1,1539134020119,0,8550,1,8441.42,1,0.1866317,0],
[33653795,1,1539134020119,0,8550,1,8349.0077,1,1.67684598,0],
[33653795,2,1539134020119,0,8550,2,8200,1,0.21392684,0],
[33653795,0,1539134020119,0,8550,1,0.01,1,31,0],
[33653795,1,1539134020119,0,8550,1,8550,1,1.62613,1],
[33653795,1,1539134020119,0,8550,1,8600,1,2,1],
[33653795,1,1539134020119,0,8550,1,8700,1,2,1],
[33653795,1,1539134020119,0,8550,1,8751.73,1,7,1],
[33653795,1,1539134020119,0,8550,1,8751.86,1,0.38479167,1],
[33653795,1,1539134020119,0,8550,1,8752.25,1,0.1,1],
[33653795,1,1539134020119,0,8550,1,8752.38,1,0.12,1],
[33653795,1,1539134020119,0,8550,1,8752.78,1,0.41444587,1],[
33653795,1,1539134020119,0,8550,1,8753.96,1,0.011,1],
[33653795,1,1539134020119,0,8550,1,8754.1,1,1.20780263,1],
[33653795,1,1539134020119,0,8550,1,8754.23,1,0.01,1],
[33653795,1,1539134020119,0,8550,1,8756.2,1,0.17919283,1],
[33653795,1,1539134020119,0,8550,1,8756.33,1,0.4,1],
[33653795,1,1539134020119,0,8550,1,8756.47,1,0.27796986,1],
[33653795,1,1539134020119,0,8550,1,8756.6,1,0.63324654,1],
[33653795,1,1539134020119,0,8550,1,8756.73,1,0.18190475,1],
[33653795,1,1539134020119,0,8550,1,8757.26,1,0.02199081,1],
[33653795,1,1539134020119,0,8550,1,8757.39,1,1.98,1],
[33653795,1,1539134020119,0,8550,1,8757.52,1,0.28644275,1],
[33653795,1,1539134020119,0,8550,1,8757.65,1,0.12800312,1],
[33653795,1,1539134020119,0,8550,1,8757.78,1,0.3,1],
[33653795,1,1539134020119,0,8550,1,8757.92,1,0.026,1],
[33653795,1,1539134020119,0,8550,1,8758.05,1,0.22575335,1],
[33653795,1,1539134020119,0,8550,1,8758.18,1,7,1],
[33653795,1,1539134020119,0,8550,1,8758.44,1,0.2,1],
[33653795,1,1539134020119,0,8550,1,8758.57,1,0.13885664,1],
[33653795,1,1539134020119,0,8550,1,8758.71,1,0.65440634,1],
[33653795,1,1539134020119,0,8550,1,8758.84,1,0.1772403,1],
[33653795,1,1539134020119,0,8550,1,8800,1,2,1]]
Press <enter> key to exit.
```

## My related projects

* [Ndax.Api](https://github.com/RobJohnston/Ndax.Api)
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
</ItemGroup>

</Project>
163 changes: 163 additions & 0 deletions src/AlphaPoint.Api/AlphaPointWebSocketClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using AlphaPoint.Api.Models;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AlphaPoint.Api
{
public class AlphaPointWebSocketClient : IDisposable
{

#region Fields

private CancellationTokenSource _cancelation;
private ClientWebSocket _client;
private bool _disposing = false;
private readonly Uri _url;
private readonly int _reconnectDelayInMilliseconds = 30000;

#endregion

#region Constructors

public AlphaPointWebSocketClient(Uri url)
{
_url = url;
}

#endregion

#region Events

public event EventHandler<ReceivedMessageFrameEventArgs> ReceivedMessageFrame;

#endregion

#region Public methods

public Task Start()
{
Trace.WriteLine("Starting.");
_cancelation = new CancellationTokenSource();

return StartClient(_url, _cancelation.Token);
}

public async Task Send(MessageFrame frame)
{
Trace.WriteLine(string.Format("Sending frame {0}: {1}", frame.SequenceNumber, frame.Payload));
var json = JsonConvert.SerializeObject(frame);
var request = Encoding.UTF8.GetBytes(json);
var messageSegment = new ArraySegment<byte>(request);
var client = await GetClient();
await client.SendAsync(messageSegment, WebSocketMessageType.Text, true, _cancelation.Token);
}

public void Dispose()
{
_disposing = true;
Trace.WriteLine("Disposing.");
_cancelation?.Cancel();
_client?.Abort();
_client?.Dispose();
_cancelation?.Dispose();
Trace.WriteLine("Disposed.");
}

#endregion

#region Private methods

private async Task StartClient(Uri uri, CancellationToken token)
{
try
{
_client = new ClientWebSocket();
await _client.ConnectAsync(uri, token);

// Don't await. Start listening on another thread.
Task.Run(() => Listen(_client, token));
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
await Task.Delay(_reconnectDelayInMilliseconds, token);
await Reconnect();
}
}

private async Task<ClientWebSocket> GetClient()
{
if (_client == null || (_client.State != WebSocketState.Open && _client.State != WebSocketState.Connecting))
{
await Reconnect();
}
return _client;
}

private async Task Listen(ClientWebSocket client, CancellationToken token)
{
var bufferSize = 4096;
var bufferAmplifier = 20;
var temporaryBuffer = new byte[bufferSize];
var buffer = new byte[bufferSize * bufferAmplifier];
var offset = 0;
var result = string.Empty;
WebSocketReceiveResult response;

Trace.WriteLine("Listening...");

while (client.State == WebSocketState.Open)
{
do
{
response = await client.ReceiveAsync(new ArraySegment<byte>(temporaryBuffer), token);
temporaryBuffer.CopyTo(buffer, offset);
offset += response.Count;
temporaryBuffer = new byte[bufferSize];
} while (!response.EndOfMessage);

if (response.MessageType != WebSocketMessageType.Close)
{
result = Encoding.UTF8.GetString(buffer);
Trace.WriteLine(string.Format("Received message : {0}." + Environment.NewLine, result));

var json = Encoding.ASCII.GetString(buffer).TrimEnd('\0');
var frame = JsonConvert.DeserializeObject<MessageFrame>(json);

ReceivedMessageFrame?.Invoke(this, new ReceivedMessageFrameEventArgs(frame));

// Clear the buffer array.
buffer = new byte[bufferSize * bufferAmplifier];
offset = 0;
}
else
{
var message = "Close response received.";
Trace.WriteLine(message);

await
client.CloseAsync(WebSocketCloseStatus.NormalClosure, message, CancellationToken.None);
}
}
}

private async Task Reconnect()
{
if (!_disposing)
{
Trace.WriteLine("Reconnecting.");
_cancelation.Cancel();

_cancelation = new CancellationTokenSource();
await StartClient(_url, _cancelation.Token);
}
}

#endregion
}
}
Loading

0 comments on commit 33ae251

Please sign in to comment.