-
Notifications
You must be signed in to change notification settings - Fork 7
/
WebsocketSample.cs
151 lines (126 loc) · 5.73 KB
/
WebsocketSample.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
using System;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using Microsoft.AspNet.SignalR.Client;
namespace WebsocketSample
{
public sealed class BittrexWebsocket
{
public delegate void BittrexCallback(string info);
private HubConnection _hubConnection { get; }
private IHubProxy _hubProxy { get; }
private BittrexCallback _updateExchangeState { get; }
private BittrexCallback _updateOrderState { get; }
private BittrexCallback _updateBalanceState { get; }
public BittrexWebsocket(
string connectionUrl,
BittrexCallback updateExchangeState,
BittrexCallback updateOrderState,
BittrexCallback updateBalanceState
)
{
// Set delegates
_updateExchangeState = updateExchangeState;
_updateOrderState = updateOrderState;
_updateBalanceState = updateBalanceState;
// Create connection to c2 SignalR hub
_hubConnection = new HubConnection(connectionUrl);
_hubProxy = _hubConnection.CreateHubProxy("c2");
// Register callback for uE (exchange state delta) events
_hubProxy.On(
"uE",
exchangeStateDelta => _updateExchangeState?.Invoke(exchangeStateDelta)
);
// Register callback for uO (order status change) events
_hubProxy.On(
"uO",
orderStateDelta => _updateOrderState?.Invoke(orderStateDelta)
);
// Register callback for uB (balance status change) events
_hubProxy.On(
"uB",
balanceStateDelta => _updateBalanceState?.Invoke(balanceStateDelta)
);
_hubConnection.Start().Wait();
}
public void Shutdown() => _hubConnection.Stop();
// marketName example: "BTC-LTC"
public async Task<bool> SubscribeToExchangeDeltas(string marketName) => await _hubProxy.Invoke<bool>("SubscribeToExchangeDeltas", marketName);
// The return of GetAuthContext is a challenge string. Call CreateSignature(apiSecret, challenge)
// for the response to the challenge, and pass it to Authenticate().
public async Task<string> GetAuthContext(string apiKey) => await _hubProxy.Invoke<string>("GetAuthContext", apiKey);
public async Task<bool> Authenticate(string apiKey, string signedChallenge) => await _hubProxy.Invoke<bool>("Authenticate", apiKey, signedChallenge);
// Decode converts Bittrex CoreHub2 socket wire protocol data into JSON.
// Data goes from base64 encoded to gzip (byte[]) to minifed JSON.
public static string Decode(string wireData)
{
// Step 1: Base64 decode the wire data into a gzip blob
byte[] gzipData = Convert.FromBase64String(wireData);
// Step 2: Decompress gzip blob into minified JSON
using (var decompressedStream = new MemoryStream())
using (var compressedStream = new MemoryStream(gzipData))
using (var deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress))
{
deflateStream.CopyTo(decompressedStream);
decompressedStream.Position = 0;
using (var streamReader = new StreamReader(decompressedStream))
{
return streamReader.ReadToEnd();
}
}
}
public static string CreateSignature(string apiSecret, string challenge)
{
// Get hash by using apiSecret as key, and challenge as data
var hmacSha512 = new HMACSHA512(Encoding.ASCII.GetBytes(apiSecret));
var hash = hmacSha512.ComputeHash(Encoding.ASCII.GetBytes(challenge));
return BitConverter.ToString(hash).Replace("-", string.Empty);
}
}
class Program
{
static public BittrexWebsocket.BittrexCallback CreateCallback(string name)
{
//
// In a real app, your code would do something useful based on the
// information accompanying each event.
//
return (info) =>
{
Console.WriteLine($"Callback Invoked: {name}");
Console.WriteLine(
BittrexWebsocket.Decode(info)
);
};
}
static void Main(string[] args)
{
Task task = Task.Run(
async () =>
{
string apiKey = "YOUR_API_KEY";
string apiSecret = "YOUR_API_SECRET";
string baseUrl = "https://beta.bittrex.com/signalr";
var btx = new BittrexWebsocket(
baseUrl,
CreateCallback("exchange"),
CreateCallback("order"),
CreateCallback("balance")
);
// If we successfully authenticate, we'll be subscribed to the uO and uB events.
var isAuthenticated = await btx.Authenticate(
apiKey,
BittrexWebsocket.CreateSignature(apiSecret, await btx.GetAuthContext(apiKey))
);
// Register for orderbook updates on the BTC-ETH market
await btx.SubscribeToExchangeDeltas("BTC-ETH");
});
task.Wait();
Console.WriteLine("Press enter to exit sample...");
Console.ReadLine();
}
}
}