mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-10 09:26:22 +00:00
wip
This commit is contained in:
parent
cf941fe5c9
commit
5539320827
@ -8,12 +8,27 @@ using System.Text;
|
||||
|
||||
namespace CryptoExchange.Net.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket message converter
|
||||
/// </summary>
|
||||
public abstract class SocketConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Fields to use for the message subscription identifier
|
||||
/// </summary>
|
||||
public virtual string[]? SubscriptionIdFields => null;
|
||||
/// <summary>
|
||||
/// Fields to use for the message type identifier
|
||||
/// </summary>
|
||||
public abstract string[] TypeIdFields { get; }
|
||||
|
||||
public abstract Type? GetDeserializationType(Dictionary<string, string> idValues, List<MessageListener> listeners);
|
||||
/// <summary>
|
||||
/// Return the type of object that the message should be parsed to based on the type id values dictionary
|
||||
/// </summary>
|
||||
/// <param name="idValues"></param>
|
||||
/// <param name="listeners"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Type? GetDeserializationType(Dictionary<string, string?> idValues, List<MessageListener> listeners);
|
||||
|
||||
/// <inheritdoc />
|
||||
public ParsedMessage? ReadJson(Stream stream, List<MessageListener> listeners, bool outputOriginalData)
|
||||
@ -37,8 +52,9 @@ namespace CryptoExchange.Net.Converters
|
||||
{
|
||||
token = JToken.Load(jsonTextReader);
|
||||
}
|
||||
catch(Exception ex)
|
||||
catch(Exception)
|
||||
{
|
||||
// Not a json message
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -48,62 +64,47 @@ namespace CryptoExchange.Net.Converters
|
||||
token = token.First!;
|
||||
}
|
||||
|
||||
var typeIdDict = new Dictionary<string, string>();
|
||||
foreach(var idField in TypeIdFields)
|
||||
var typeIdDict = new Dictionary<string, string?>();
|
||||
string idString = "";
|
||||
foreach (var idField in TypeIdFields)
|
||||
{
|
||||
var splitTokens = idField.Split(new char[] { ':' });
|
||||
var accessToken = token;
|
||||
foreach (var splitToken in splitTokens)
|
||||
{
|
||||
accessToken = accessToken[splitToken];
|
||||
|
||||
if (accessToken == null)
|
||||
break;
|
||||
|
||||
if (accessToken.Type == JTokenType.Array)
|
||||
{
|
||||
// Received array, take first item as reference
|
||||
accessToken = accessToken.First!;
|
||||
}
|
||||
}
|
||||
|
||||
typeIdDict[idField] = accessToken?.ToString();
|
||||
var val = GetValueForKey(token, idField);
|
||||
idString += val;
|
||||
typeIdDict[idField] = val;
|
||||
}
|
||||
|
||||
string idString = "";
|
||||
if (SubscriptionIdFields != null)
|
||||
{
|
||||
idString = "";
|
||||
foreach (var idField in SubscriptionIdFields)
|
||||
{
|
||||
var splitTokens = idField.Split(new char[] { ':' });
|
||||
var accessToken = token;
|
||||
foreach (var splitToken in splitTokens)
|
||||
{
|
||||
accessToken = accessToken[splitToken];
|
||||
if (accessToken == null)
|
||||
break;
|
||||
}
|
||||
idString += accessToken?.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in typeIdDict)
|
||||
idString += item.Value;
|
||||
idString += GetValueForKey(token, idField);
|
||||
}
|
||||
|
||||
result.Identifier = idString;
|
||||
var resultType = GetDeserializationType(typeIdDict, listeners);
|
||||
result.Data = resultType == null ? null : token.ToObject(resultType);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class ParsedMessage
|
||||
{
|
||||
public string Identifier { get; set; } = null!;
|
||||
public string? OriginalData { get; set; }
|
||||
public object? Data { get; set; }
|
||||
private string? GetValueForKey(JToken token, string key)
|
||||
{
|
||||
var splitTokens = key.Split(new char[] { ':' });
|
||||
var accessToken = token;
|
||||
foreach (var splitToken in splitTokens)
|
||||
{
|
||||
accessToken = accessToken[splitToken];
|
||||
|
||||
if (accessToken == null)
|
||||
break;
|
||||
|
||||
if (accessToken.Type == JTokenType.Array)
|
||||
{
|
||||
// Received array, take first item as reference
|
||||
accessToken = accessToken.First!;
|
||||
}
|
||||
}
|
||||
|
||||
return accessToken?.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
21
CryptoExchange.Net/Objects/Sockets/ParsedMessage.cs
Normal file
21
CryptoExchange.Net/Objects/Sockets/ParsedMessage.cs
Normal file
@ -0,0 +1,21 @@
|
||||
namespace CryptoExchange.Net.Objects.Sockets
|
||||
{
|
||||
/// <summary>
|
||||
/// Parsed message object
|
||||
/// </summary>
|
||||
public class ParsedMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifier string
|
||||
/// </summary>
|
||||
public string Identifier { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Original data if the option is enabled
|
||||
/// </summary>
|
||||
public string? OriginalData { get; set; }
|
||||
/// <summary>
|
||||
/// Parsed data object
|
||||
/// </summary>
|
||||
public object? Data { get; set; }
|
||||
}
|
||||
}
|
@ -322,14 +322,13 @@ namespace CryptoExchange.Net.Sockets
|
||||
protected virtual async Task HandleStreamMessage(Stream stream)
|
||||
{
|
||||
var timestamp = DateTime.UtcNow;
|
||||
//var streamMessage = new StreamMessage(this, stream, timestamp);
|
||||
TimeSpan userCodeDuration = TimeSpan.Zero;
|
||||
|
||||
List<MessageListener> listeners;
|
||||
lock (_listenerLock)
|
||||
listeners = _messageListeners.OrderByDescending(x => x.Priority).ToList();
|
||||
|
||||
var result = ApiClient.StreamConverter.ReadJson(stream, listeners.OfType<MessageListener>().ToList(), ApiClient.ApiOptions.OutputOriginalData ?? ApiClient.ClientOptions.OutputOriginalData); // TODO
|
||||
var result = ApiClient.StreamConverter.ReadJson(stream, listeners, ApiClient.ApiOptions.OutputOriginalData ?? ApiClient.ClientOptions.OutputOriginalData); // TODO
|
||||
if(result == null)
|
||||
{
|
||||
stream.Position = 0;
|
||||
@ -358,78 +357,42 @@ namespace CryptoExchange.Net.Sockets
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var pendingRequest in _pendingRequests)
|
||||
List<PendingRequest> pendingRequests;
|
||||
lock (_pendingRequests)
|
||||
pendingRequests = _pendingRequests.ToList();
|
||||
|
||||
foreach (var pendingRequest in pendingRequests)
|
||||
{
|
||||
if (pendingRequest.MessageMatchesHandler(result))
|
||||
{
|
||||
await pendingRequest.ProcessAsync(result).ConfigureAwait(false);
|
||||
lock (_pendingRequests)
|
||||
_pendingRequests.Remove(pendingRequest);
|
||||
|
||||
if (pendingRequest.Completed)
|
||||
{
|
||||
// Answer to a timed out request, unsub if it is a subscription request
|
||||
if (pendingRequest.MessageListener != null)
|
||||
{
|
||||
_logger.Log(LogLevel.Warning, $"Socket {SocketId} Received subscription info after request timed out; unsubscribing. Consider increasing the RequestTimeout");
|
||||
_ = UnsubscribeAsync(pendingRequest.MessageListener).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Trace, $"Socket {SocketId} - msg {pendingRequest.Id} - received data matched to pending request");
|
||||
await pendingRequest.ProcessAsync(result).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogWarning("Message not matched"); // TODO
|
||||
return;
|
||||
|
||||
//if (_messageIdentifierListeners.TryGetValue(result.Identifier.ToLowerInvariant(), out var idListener))
|
||||
//{
|
||||
// var userSw = Stopwatch.StartNew();
|
||||
// await idListener.ProcessAsync(streamMessage).ConfigureAwait(false);
|
||||
// userSw.Stop();
|
||||
// userCodeDuration = userSw.Elapsed;
|
||||
// handledResponse = true;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// foreach (var listener in listeners)
|
||||
// {
|
||||
// if (listener.MessageMatches(streamMessage))
|
||||
// {
|
||||
// if (listener is PendingRequest pendingRequest)
|
||||
// {
|
||||
// lock (_messageListeners)
|
||||
// _messageListeners.Remove(pendingRequest);
|
||||
|
||||
// if (pendingRequest.Completed)
|
||||
// {
|
||||
// // Answer to a timed out request, unsub if it is a subscription request
|
||||
// if (pendingRequest.MessageListener != null)
|
||||
// {
|
||||
// _logger.Log(LogLevel.Warning, $"Socket {SocketId} Received subscription info after request timed out; unsubscribing. Consider increasing the RequestTimeout");
|
||||
// _ = UnsubscribeAsync(pendingRequest.MessageListener).ConfigureAwait(false);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _logger.Log(LogLevel.Trace, $"Socket {SocketId} - msg {pendingRequest.Id} - received data matched to pending request");
|
||||
// await pendingRequest.ProcessAsync(streamMessage).ConfigureAwait(false);
|
||||
// }
|
||||
|
||||
// if (!ApiClient.ContinueOnQueryResponse)
|
||||
// return;
|
||||
|
||||
// handledResponse = true;
|
||||
// break;
|
||||
// }
|
||||
// else if (listener is MessageListener subscription)
|
||||
// {
|
||||
// currentSubscription = subscription;
|
||||
// handledResponse = true;
|
||||
// var userSw = Stopwatch.StartNew();
|
||||
// await subscription.ProcessAsync(streamMessage).ConfigureAwait(false);
|
||||
// userSw.Stop();
|
||||
// userCodeDuration = userSw.Elapsed;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//if (!handledResponse)
|
||||
//{
|
||||
// if (!ApiClient.UnhandledMessageExpected)
|
||||
// _logger.Log(LogLevel.Warning, $"Socket {SocketId} Message not handled: " + streamMessage.Get(ParsingUtils.GetString));
|
||||
// UnhandledMessage?.Invoke(streamMessage);
|
||||
//}
|
||||
stream.Position = 0;
|
||||
var unhandledBuffer = new byte[stream.Length];
|
||||
stream.Read(unhandledBuffer, 0, unhandledBuffer.Length);
|
||||
|
||||
_logger.Log(LogLevel.Warning, $"Socket {SocketId} Message not handled: " + Encoding.UTF8.GetString(unhandledBuffer));
|
||||
UnhandledMessage?.Invoke(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,12 +1,7 @@
|
||||
using CryptoExchange.Net.Converters;
|
||||
using CryptoExchange.Net.Interfaces;
|
||||
using CryptoExchange.Net.Objects;
|
||||
using CryptoExchange.Net.Objects;
|
||||
using CryptoExchange.Net.Objects.Sockets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.Sockets
|
||||
@ -16,8 +11,6 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// </summary>
|
||||
public abstract class Subscription
|
||||
{
|
||||
private bool _outputOriginalData;
|
||||
|
||||
/// <summary>
|
||||
/// Logger
|
||||
/// </summary>
|
||||
@ -28,18 +21,19 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// </summary>
|
||||
public bool Authenticated { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Strings to identify this subscription with
|
||||
/// </summary>
|
||||
public abstract List<string> Identifiers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="apiClient"></param>
|
||||
/// <param name="authenticated"></param>
|
||||
public Subscription(ILogger logger, ISocketApiClient apiClient, bool authenticated)
|
||||
public Subscription(ILogger logger, bool authenticated)
|
||||
{
|
||||
_logger = logger;
|
||||
_outputOriginalData = apiClient.ApiOptions.OutputOriginalData ?? apiClient.ClientOptions.OutputOriginalData;
|
||||
Authenticated = authenticated;
|
||||
}
|
||||
|
||||
@ -67,52 +61,11 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// <returns></returns>
|
||||
public abstract (bool, CallResult?) MessageMatchesUnsubRequest(ParsedMessage message);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the message is an update for this subscription
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
//public abstract bool MessageMatchesEvent(ParsedMessage message);
|
||||
/// <summary>
|
||||
/// Handle the update message
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public abstract Task HandleEventAsync(DataEvent<ParsedMessage> message);
|
||||
|
||||
///// <summary>
|
||||
///// Create a data event
|
||||
///// </summary>
|
||||
///// <typeparam name="T"></typeparam>
|
||||
///// <param name="obj"></param>
|
||||
///// <param name="message"></param>
|
||||
///// <param name="topic"></param>
|
||||
///// <param name="type"></param>
|
||||
///// <returns></returns>
|
||||
//protected virtual DataEvent<T> CreateDataEvent<T>(T obj, ParsedMessage message, string? topic = null, SocketUpdateType? type = null)
|
||||
//{
|
||||
// string? originalData = null;
|
||||
// if (_outputOriginalData)
|
||||
// originalData = message.Get(ParsingUtils.GetString);
|
||||
|
||||
// return new DataEvent<T>(obj, topic, originalData, message.Timestamp, type);
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// Deserialize the message to an object using Json.Net
|
||||
///// </summary>
|
||||
///// <typeparam name="T"></typeparam>
|
||||
///// <param name="message"></param>
|
||||
///// <param name="settings"></param>
|
||||
///// <returns></returns>
|
||||
//protected virtual Task<CallResult<T>> DeserializeAsync<T>(StreamMessage message, JsonSerializerSettings settings)
|
||||
//{
|
||||
// var serializer = JsonSerializer.Create(settings);
|
||||
// using var sr = new StreamReader(message.Stream, Encoding.UTF8, false, (int)message.Stream.Length, true);
|
||||
// using var jsonTextReader = new JsonTextReader(sr);
|
||||
// var result = serializer.Deserialize<T>(jsonTextReader);
|
||||
// message.Stream.Position = 0;
|
||||
// return Task.FromResult(new CallResult<T>(result!));
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,8 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// ctor
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="socketApiClient"></param>
|
||||
/// <param name="authenticated"></param>
|
||||
public SystemSubscription(ILogger logger, ISocketApiClient socketApiClient, bool authenticated = false) : base(logger, socketApiClient, authenticated)
|
||||
public SystemSubscription(ILogger logger, bool authenticated = false) : base(logger, authenticated)
|
||||
{
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user