-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactored standard client, added new endpoints, and created new WebS…
…ocket streaming client
- Loading branch information
Showing
14 changed files
with
359 additions
and
53 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using Newtonsoft.Json; | ||
|
||
namespace FinnHubSharp.DataModels.Request | ||
{ | ||
public class StreamingSubscription | ||
{ | ||
[JsonProperty("type")] | ||
public string Type { get; set; } | ||
|
||
[JsonProperty("symbol")] | ||
public string Symbol { get; set; } | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
using Newtonsoft.Json; | ||
|
||
namespace FinnHubSharp.DataModels.Response | ||
{ | ||
public class ListedSymbol | ||
{ | ||
[JsonProperty("currency")] | ||
public string Currency { get; set; } | ||
|
||
[JsonProperty("description")] | ||
public string Description { get; set; } | ||
|
||
[JsonProperty("displaySymbol")] | ||
public string DisplaySymbol { get; set; } | ||
|
||
[JsonProperty("figi")] | ||
public string Figi { get; set; } | ||
|
||
[JsonProperty("mic")] | ||
public string Mic { get; set; } | ||
|
||
[JsonProperty("symbol")] | ||
public string Symbol { get; set; } | ||
|
||
[JsonProperty("type")] | ||
public string Type { get; set; } | ||
} | ||
} |
5 changes: 1 addition & 4 deletions
5
FinnHubSharp/DataModels/Quote.cs → FinnHubSharp/DataModels/Response/Quote.cs
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using Newtonsoft.Json; | ||
|
||
namespace FinnHubSharp.DataModels.Response | ||
{ | ||
public class StreamingQuote | ||
{ | ||
[JsonProperty("data")] | ||
public List<Data> Data { get; set; } | ||
|
||
[JsonProperty("type")] | ||
public string Type { get; set; } | ||
} | ||
|
||
public class Data | ||
{ | ||
[JsonProperty("p")] | ||
public double Price { get; set; } | ||
|
||
[JsonProperty("s")] | ||
public string Symbol { get; set; } | ||
|
||
[JsonProperty("t")] | ||
public long Timestamp { get; set; } | ||
|
||
[JsonProperty("v")] | ||
public double Volume { get; set; } | ||
|
||
[JsonProperty("c")] | ||
public string TradeCondition { get; set; } | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using System.Collections.Generic; | ||
using Newtonsoft.Json; | ||
|
||
namespace FinnHubSharp.DataModels.Response | ||
{ | ||
public class SymbolInfo | ||
{ | ||
[JsonProperty("count")] | ||
public long Count { get; set; } | ||
|
||
[JsonProperty("result")] | ||
public List<Result> Result { get; set; } | ||
} | ||
|
||
public partial class Result | ||
{ | ||
[JsonProperty("description")] | ||
public string Description { get; set; } | ||
|
||
[JsonProperty("displaySymbol")] | ||
public string DisplaySymbol { get; set; } | ||
|
||
[JsonProperty("symbol")] | ||
public string Symbol { get; set; } | ||
|
||
[JsonProperty("type")] | ||
public string Type { get; set; } | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
using FinnHubSharp.DataModels.Response; | ||
using FinnHubSharp.Interfaces; | ||
using FinnHubSharp.Logging; | ||
using Microsoft.Extensions.Logging; | ||
using Newtonsoft.Json; | ||
|
||
namespace FinnHubSharp.Implementations | ||
{ | ||
public class FinnHubClient : IFinnHubClient | ||
{ | ||
private readonly string _apiKey; | ||
private readonly HttpClient _client; | ||
private readonly ILogger _logger; | ||
|
||
public FinnHubClient(HttpClient client, string apiKey, ILogger logger) | ||
{ | ||
_client = client ?? new HttpClient(); | ||
_apiKey = apiKey ?? throw new ArgumentNullException(nameof(apiKey)); | ||
_logger = logger ?? new Logger<FinnHubSharpLogger>(new LoggerFactory()); | ||
} | ||
|
||
public async Task<Quote> GetQuoteAsync(string symbol) | ||
{ | ||
try | ||
{ | ||
var endpoint = $"https://finnhub.io/api/v1/quote?symbol={symbol}&token={_apiKey}"; | ||
var response = await _client.GetAsync(endpoint); | ||
string responseString = await response.Content.ReadAsStringAsync(); | ||
|
||
_logger.LogInformation(FinnHubSharpLogger.BuildHttpLogUsing(response)); | ||
|
||
var jsonResponse = JsonConvert.DeserializeObject<Quote>(responseString); | ||
return jsonResponse; | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.LogCritical(e.ToString()); | ||
throw; | ||
} | ||
} | ||
|
||
public async Task<SymbolInfo> GetSymbolInfoAsync(string symbolOrSecurityName) | ||
{ | ||
try | ||
{ | ||
var endpoint = $"https://finnhub.io/api/v1/search?q={symbolOrSecurityName}&token={_apiKey}"; | ||
var response = await _client.GetAsync(endpoint); | ||
|
||
_logger.LogInformation(FinnHubSharpLogger.BuildHttpLogUsing(response)); | ||
|
||
string responseString = await response.Content.ReadAsStringAsync(); | ||
var jsonResponse = JsonConvert.DeserializeObject<SymbolInfo>(responseString); | ||
return jsonResponse; | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.LogCritical(e.ToString()); | ||
throw; | ||
} | ||
} | ||
|
||
public async Task<IEnumerable<ListedSymbol>> GetAllSymbols(string exchange) | ||
{ | ||
try | ||
{ | ||
var endpoint = $"https://finnhub.io/api/v1/stock/symbol?exchange={exchange}&token={_apiKey}"; | ||
var response = await _client.GetAsync(endpoint); | ||
|
||
_logger.LogInformation(FinnHubSharpLogger.BuildHttpLogUsing(response)); | ||
|
||
string responseString = await response.Content.ReadAsStringAsync(); | ||
var jsonResponse = JsonConvert.DeserializeObject<List<ListedSymbol>>(responseString); | ||
return jsonResponse; | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.LogCritical(e.ToString()); | ||
throw; | ||
} | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Net.WebSockets; | ||
using System.Text; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using FinnHubSharp.DataModels.Request; | ||
using FinnHubSharp.DataModels.Response; | ||
using FinnHubSharp.Interfaces; | ||
using Newtonsoft.Json; | ||
|
||
namespace FinnHubSharp.Implementations | ||
{ | ||
public class FinnHubStreamerClient : IFinnHubStreamerClient, IDisposable | ||
{ | ||
private readonly string _apiKey; | ||
private readonly ClientWebSocket _webSocketClient; | ||
|
||
public FinnHubStreamerClient(ClientWebSocket webSocketClient, string apiKey) | ||
{ | ||
_webSocketClient = webSocketClient ?? new ClientWebSocket(); | ||
_apiKey = apiKey ?? throw new ArgumentNullException(nameof(apiKey)); | ||
} | ||
|
||
public async IAsyncEnumerable<IAsyncEnumerable<StreamingQuote>> GetStreamingQuotes( | ||
params StreamingSubscription[] subscriptions) | ||
{ | ||
while(true) | ||
{ | ||
using (var socket = _webSocketClient) | ||
{ | ||
await socket.ConnectAsync(new Uri($"wss://ws.finnhub.io?token={_apiKey}"), CancellationToken.None); | ||
foreach (var sub in subscriptions.ToList()) | ||
{ | ||
await SendSubscription(socket, JsonConvert.SerializeObject(sub)); | ||
} | ||
yield return ReceiveStreamingData(socket); | ||
} | ||
} | ||
} | ||
|
||
public async Task Disconnect() | ||
{ | ||
if (_webSocketClient is {State: WebSocketState.Open}) | ||
{ | ||
await _webSocketClient.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None); | ||
} | ||
} | ||
|
||
private async Task SendSubscription(ClientWebSocket socket, string data) => | ||
await socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(data)), WebSocketMessageType.Text, true, CancellationToken.None); | ||
|
||
private async IAsyncEnumerable<StreamingQuote> ReceiveStreamingData(ClientWebSocket socket) | ||
{ | ||
var buffer = new ArraySegment<byte>(new byte[2048]); | ||
while (true) | ||
{ | ||
using (var memoryStream = new MemoryStream()) | ||
{ | ||
WebSocketReceiveResult result; | ||
do | ||
{ | ||
result = await socket.ReceiveAsync(buffer, CancellationToken.None); | ||
memoryStream.Write(buffer.Array ?? Array.Empty<byte>(), buffer.Offset, result.Count); | ||
} while (!result.EndOfMessage); | ||
|
||
if (result.MessageType == WebSocketMessageType.Close) | ||
await Disconnect(); | ||
|
||
memoryStream.Seek(0, SeekOrigin.Begin); | ||
using (var reader = new StreamReader(memoryStream, Encoding.UTF8)) | ||
{ | ||
yield return JsonConvert.DeserializeObject<StreamingQuote>(await reader.ReadToEndAsync()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public async void Dispose() | ||
{ | ||
await Disconnect(); | ||
_webSocketClient?.Dispose(); | ||
} | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using FinnHubSharp.DataModels.Response; | ||
|
||
namespace FinnHubSharp.Interfaces | ||
{ | ||
public interface IFinnHubClient | ||
{ | ||
Task<Quote> GetQuoteAsync(string symbol); | ||
|
||
Task<SymbolInfo> GetSymbolInfoAsync(string symbolOrSecurityName); | ||
|
||
Task<IEnumerable<ListedSymbol>> GetAllSymbols(string exchange); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using FinnHubSharp.DataModels.Request; | ||
using FinnHubSharp.DataModels.Response; | ||
|
||
namespace FinnHubSharp.Interfaces | ||
{ | ||
public interface IFinnHubStreamerClient | ||
{ | ||
IAsyncEnumerable<IAsyncEnumerable<StreamingQuote>> GetStreamingQuotes(params StreamingSubscription[] subscriptions); | ||
|
||
Task Disconnect(); | ||
} | ||
} |
Oops, something went wrong.