mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-08 16:36:15 +00:00
wip
This commit is contained in:
parent
ac434fa2c6
commit
b59fe9e3ef
@ -233,7 +233,7 @@ namespace CryptoExchange.Net
|
|||||||
if (subQuery != null)
|
if (subQuery != null)
|
||||||
{
|
{
|
||||||
// Send the request and wait for answer
|
// Send the request and wait for answer
|
||||||
var subResult = await socketConnection.SendAndWaitQueryAsync(subQuery).ConfigureAwait(false);
|
var subResult = await socketConnection.SendAndWaitQueryAsync(subQuery).ConfigureAwait(false); // TODO return null on timeout
|
||||||
if (!subResult)
|
if (!subResult)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Warning, $"Socket {socketConnection.SocketId} failed to subscribe: {subResult.Error}");
|
_logger.Log(LogLevel.Warning, $"Socket {socketConnection.SocketId} failed to subscribe: {subResult.Error}");
|
||||||
@ -532,7 +532,8 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="identifier">Identifier for the periodic send</param>
|
/// <param name="identifier">Identifier for the periodic send</param>
|
||||||
/// <param name="interval">How often</param>
|
/// <param name="interval">How often</param>
|
||||||
/// <param name="queryDelegate">Method returning the query to send</param>
|
/// <param name="queryDelegate">Method returning the query to send</param>
|
||||||
protected virtual void QueryPeriodic(string identifier, TimeSpan interval, Func<SocketConnection, BaseQuery> queryDelegate)
|
/// <param name="callback">The callback for processing the response</param>
|
||||||
|
protected virtual void QueryPeriodic(string identifier, TimeSpan interval, Func<SocketConnection, BaseQuery> queryDelegate, Action<CallResult>? callback)
|
||||||
{
|
{
|
||||||
if (queryDelegate == null)
|
if (queryDelegate == null)
|
||||||
throw new ArgumentNullException(nameof(queryDelegate));
|
throw new ArgumentNullException(nameof(queryDelegate));
|
||||||
@ -565,7 +566,8 @@ namespace CryptoExchange.Net
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await socketConnection.SendAndWaitQueryAsync(query).ConfigureAwait(false);
|
var result = await socketConnection.SendAndWaitQueryAsync(query).ConfigureAwait(false);
|
||||||
|
callback?.Invoke(result);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Interfaces;
|
||||||
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
using CryptoExchange.Net.Sockets;
|
using CryptoExchange.Net.Sockets;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@ -18,12 +19,10 @@ namespace CryptoExchange.Net.Converters
|
|||||||
{
|
{
|
||||||
private static JsonSerializer _serializer = JsonSerializer.Create(SerializerOptions.WithConverters);
|
private static JsonSerializer _serializer = JsonSerializer.Create(SerializerOptions.WithConverters);
|
||||||
|
|
||||||
public abstract List<StreamMessageParseCallback> InterpreterPipeline { get; }
|
public abstract MessageInterpreterPipeline InterpreterPipeline { get; }
|
||||||
|
|
||||||
public virtual string CreateIdentifierString(Dictionary<string, string?> idValues) => string.Join("-", idValues.Values.Where(v => v != null).Select(v => v!.ToLower()));
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public BaseParsedMessage? ReadJson(Stream stream, ConcurrentList<BasePendingRequest> pendingRequests, ConcurrentList<Subscription> listeners, bool outputOriginalData)
|
public BaseParsedMessage? ReadJson(Stream stream, IDictionary<string, IMessageProcessor> processors, bool outputOriginalData)
|
||||||
{
|
{
|
||||||
// Start reading the data
|
// Start reading the data
|
||||||
// Once we reach the properties that identify the message we save those in a dict
|
// Once we reach the properties that identify the message we save those in a dict
|
||||||
@ -31,6 +30,26 @@ namespace CryptoExchange.Net.Converters
|
|||||||
// Deserialize to the correct type
|
// Deserialize to the correct type
|
||||||
|
|
||||||
using var sr = new StreamReader(stream, Encoding.UTF8, false, (int)stream.Length, true);
|
using var sr = new StreamReader(stream, Encoding.UTF8, false, (int)stream.Length, true);
|
||||||
|
foreach (var callback in InterpreterPipeline.PreInspectCallbacks)
|
||||||
|
{
|
||||||
|
var result = callback.Callback(stream);
|
||||||
|
if (result.Matched)
|
||||||
|
{
|
||||||
|
var data = sr.ReadToEnd();
|
||||||
|
var messageType = typeof(ParsedMessage<>).MakeGenericType(typeof(string));
|
||||||
|
var preInstance = (BaseParsedMessage)Activator.CreateInstance(messageType, data);
|
||||||
|
if (outputOriginalData)
|
||||||
|
{
|
||||||
|
stream.Position = 0;
|
||||||
|
preInstance.OriginalData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
preInstance.Identifier = result.Identifier;
|
||||||
|
preInstance.Parsed = true;
|
||||||
|
return preInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using var jsonTextReader = new JsonTextReader(sr);
|
using var jsonTextReader = new JsonTextReader(sr);
|
||||||
JToken token;
|
JToken token;
|
||||||
try
|
try
|
||||||
@ -49,10 +68,10 @@ namespace CryptoExchange.Net.Converters
|
|||||||
token = token.First!;
|
token = token.First!;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type? resultType = null;
|
PostInspectResult? inspectResult = null;
|
||||||
Dictionary<string, string> typeIdDict = new Dictionary<string, string>();
|
Dictionary<string, string> typeIdDict = new Dictionary<string, string>();
|
||||||
StreamMessageParseCallback? usedParser = null;
|
PostInspectCallback? usedParser = null;
|
||||||
foreach (var callback in InterpreterPipeline)
|
foreach (var callback in InterpreterPipeline.PostInspectCallbacks)
|
||||||
{
|
{
|
||||||
bool allFieldsPresent = true;
|
bool allFieldsPresent = true;
|
||||||
foreach(var field in callback.TypeFields)
|
foreach(var field in callback.TypeFields)
|
||||||
@ -69,7 +88,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
|
|
||||||
if (allFieldsPresent)
|
if (allFieldsPresent)
|
||||||
{
|
{
|
||||||
resultType = callback.Callback(typeIdDict, pendingRequests, listeners);
|
inspectResult = callback.Callback(typeIdDict, processors);
|
||||||
usedParser = callback;
|
usedParser = callback;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -78,20 +97,16 @@ namespace CryptoExchange.Net.Converters
|
|||||||
if (usedParser == null)
|
if (usedParser == null)
|
||||||
throw new Exception("No parser found for message");
|
throw new Exception("No parser found for message");
|
||||||
|
|
||||||
var subIdDict = new Dictionary<string, string?>();
|
var resultMessageType = typeof(ParsedMessage<>).MakeGenericType(inspectResult.Type);
|
||||||
foreach (var field in usedParser.IdFields)
|
var instance = (BaseParsedMessage)Activator.CreateInstance(resultMessageType, inspectResult.Type == null ? null : token.ToObject(inspectResult.Type, _serializer));
|
||||||
subIdDict[field] = typeIdDict.TryGetValue(field, out var cachedValue) ? cachedValue : GetValueForKey(token, field);
|
|
||||||
|
|
||||||
var resultMessageType = typeof(ParsedMessage<>).MakeGenericType(resultType);
|
|
||||||
var instance = (BaseParsedMessage)Activator.CreateInstance(resultMessageType, resultType == null ? null : token.ToObject(resultType, _serializer));
|
|
||||||
if (outputOriginalData)
|
if (outputOriginalData)
|
||||||
{
|
{
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
instance.OriginalData = sr.ReadToEnd();
|
instance.OriginalData = sr.ReadToEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.Identifier = CreateIdentifierString(subIdDict);
|
instance.Identifier = inspectResult.Identifier;
|
||||||
instance.Parsed = resultType != null;
|
instance.Parsed = inspectResult.Type != null;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,5 +11,6 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
{
|
{
|
||||||
public int Id { get; }
|
public int Id { get; }
|
||||||
Task<CallResult> HandleMessageAsync(DataEvent<BaseParsedMessage> message);
|
Task<CallResult> HandleMessageAsync(DataEvent<BaseParsedMessage> message);
|
||||||
|
public Type ExpectedMessageType { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,39 @@
|
|||||||
using CryptoExchange.Net.Sockets;
|
using CryptoExchange.Net.Converters;
|
||||||
|
using CryptoExchange.Net.Interfaces;
|
||||||
|
using CryptoExchange.Net.Sockets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects.Sockets
|
namespace CryptoExchange.Net.Objects.Sockets
|
||||||
{
|
{
|
||||||
public class StreamMessageParseCallback
|
public class MessageInterpreterPipeline
|
||||||
|
{
|
||||||
|
public List<PreInspectCallback> PreInspectCallbacks { get; set; } = new List<PreInspectCallback>();
|
||||||
|
public List<PostInspectCallback> PostInspectCallbacks { get; set; } = new List<PostInspectCallback>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PreInspectCallback
|
||||||
|
{
|
||||||
|
public Func<Stream, PreInspectResult> Callback { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PostInspectCallback
|
||||||
{
|
{
|
||||||
public List<string> TypeFields { get; set; } = new List<string>();
|
public List<string> TypeFields { get; set; } = new List<string>();
|
||||||
public List<string> IdFields { get; set; } = new List<string>();
|
public Func<Dictionary<string, string>, IDictionary<string, IMessageProcessor>, PostInspectResult> Callback { get; set; }
|
||||||
public Func<Dictionary<string, string>, IEnumerable<BasePendingRequest>, IEnumerable<Subscription>, Type?> Callback { get; set; }
|
}
|
||||||
|
|
||||||
|
public class PreInspectResult
|
||||||
|
{
|
||||||
|
public bool Matched { get; set; }
|
||||||
|
public string Identifier { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PostInspectResult
|
||||||
|
{
|
||||||
|
public Type? Type { get; set; }
|
||||||
|
public string Identifier { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -40,6 +41,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public BasePendingRequest? PendingRequest { get; private set; }
|
public BasePendingRequest? PendingRequest { get; private set; }
|
||||||
|
|
||||||
|
public abstract Type ExpectedMessageType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -84,6 +87,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <typeparam name="TResponse">Response object type</typeparam>
|
/// <typeparam name="TResponse">Response object type</typeparam>
|
||||||
public abstract class Query<TResponse> : BaseQuery
|
public abstract class Query<TResponse> : BaseQuery
|
||||||
{
|
{
|
||||||
|
public override Type ExpectedMessageType => typeof(TResponse);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -307,7 +307,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
var timestamp = DateTime.UtcNow;
|
var timestamp = DateTime.UtcNow;
|
||||||
TimeSpan userCodeDuration = TimeSpan.Zero;
|
TimeSpan userCodeDuration = TimeSpan.Zero;
|
||||||
|
|
||||||
var result = ApiClient.StreamConverter.ReadJson(stream, _pendingRequests, _subscriptions, ApiClient.ApiOptions.OutputOriginalData ?? ApiClient.ClientOptions.OutputOriginalData);
|
var result = ApiClient.StreamConverter.ReadJson(stream, _messageIdMap, ApiClient.ApiOptions.OutputOriginalData ?? ApiClient.ClientOptions.OutputOriginalData);
|
||||||
if(result == null)
|
if(result == null)
|
||||||
{
|
{
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
@ -59,6 +59,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<Exception>? Exception;
|
public event Action<Exception>? Exception;
|
||||||
|
|
||||||
|
public abstract Type ExpectedMessageType { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -118,6 +120,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public abstract class Subscription<TSubResponse, TEvent, TUnsubResponse> : Subscription
|
public abstract class Subscription<TSubResponse, TEvent, TUnsubResponse> : Subscription
|
||||||
{
|
{
|
||||||
|
public override Type ExpectedMessageType => typeof(TEvent);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user