mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-09 08:56:13 +00:00
wip
This commit is contained in:
parent
1ba66be29f
commit
c41e128900
@ -169,6 +169,9 @@ namespace CryptoExchange.Net
|
|||||||
if (_disposing)
|
if (_disposing)
|
||||||
return new CallResult<UpdateSubscription>(new InvalidOperationError("Client disposed, can't subscribe"));
|
return new CallResult<UpdateSubscription>(new InvalidOperationError("Client disposed, can't subscribe"));
|
||||||
|
|
||||||
|
if (subscription.Authenticated && AuthenticationProvider == null)
|
||||||
|
return new CallResult<UpdateSubscription>(new NoApiCredentialsError());
|
||||||
|
|
||||||
SocketConnection socketConnection;
|
SocketConnection socketConnection;
|
||||||
var released = false;
|
var released = false;
|
||||||
// Wait for a semaphore here, so we only connect 1 socket at a time.
|
// Wait for a semaphore here, so we only connect 1 socket at a time.
|
||||||
@ -243,6 +246,8 @@ namespace CryptoExchange.Net
|
|||||||
|
|
||||||
return new CallResult<UpdateSubscription>(subResult.Error!);
|
return new CallResult<UpdateSubscription>(subResult.Error!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subscription.HandleSubQueryResponse(subQuery.Response);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -355,6 +360,9 @@ namespace CryptoExchange.Net
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual async Task<CallResult<bool>> AuthenticateSocketAsync(SocketConnection socket)
|
public virtual async Task<CallResult<bool>> AuthenticateSocketAsync(SocketConnection socket)
|
||||||
{
|
{
|
||||||
|
if (AuthenticationProvider == null)
|
||||||
|
return new CallResult<bool>(new NoApiCredentialsError());
|
||||||
|
|
||||||
_logger.Log(LogLevel.Debug, $"Socket {socket.SocketId} Attempting to authenticate");
|
_logger.Log(LogLevel.Debug, $"Socket {socket.SocketId} Attempting to authenticate");
|
||||||
var authRequest = GetAuthenticationRequest();
|
var authRequest = GetAuthenticationRequest();
|
||||||
var result = await socket.SendAndWaitQueryAsync(authRequest).ConfigureAwait(false);
|
var result = await socket.SendAndWaitQueryAsync(authRequest).ConfigureAwait(false);
|
||||||
|
83
CryptoExchange.Net/Converters/JTokenAccessor.cs
Normal file
83
CryptoExchange.Net/Converters/JTokenAccessor.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using CryptoExchange.Net.Interfaces;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.Converters
|
||||||
|
{
|
||||||
|
internal class JTokenAccessor : IMessageAccessor
|
||||||
|
{
|
||||||
|
private readonly JToken _token;
|
||||||
|
private Dictionary<string, JToken?> _cache = new Dictionary<string, JToken?>();
|
||||||
|
|
||||||
|
public JTokenAccessor(JToken token)
|
||||||
|
{
|
||||||
|
_token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? GetArrayIntValue(string? key, int index)
|
||||||
|
{
|
||||||
|
var accessToken = key == null ? _token : GetToken(key);
|
||||||
|
if (accessToken == null || accessToken is not JArray arr)
|
||||||
|
return null;
|
||||||
|
return arr[index].Value<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? GetArrayStringValue(string? key, int index)
|
||||||
|
{
|
||||||
|
var accessToken = key == null ? _token : GetToken(key);
|
||||||
|
if (accessToken == null || accessToken is not JArray arr)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (arr.Count <= index)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return arr[index].Value<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? GetCount(string key)
|
||||||
|
{
|
||||||
|
var accessToken = GetToken(key);
|
||||||
|
return accessToken.Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? GetIntValue(string key)
|
||||||
|
{
|
||||||
|
var accessToken = GetToken(key);
|
||||||
|
return accessToken?.Value<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? GetStringValue(string key)
|
||||||
|
{
|
||||||
|
var accessToken = GetToken(key);
|
||||||
|
if (accessToken?.Type == JTokenType.Object)
|
||||||
|
return ((JObject)accessToken).Properties().First().Name;
|
||||||
|
|
||||||
|
return accessToken?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private JToken? GetToken(string key)
|
||||||
|
{
|
||||||
|
if (_cache.TryGetValue(key, out var token))
|
||||||
|
return token;
|
||||||
|
|
||||||
|
var splitTokens = key.Split(new char[] { ':' });
|
||||||
|
var accessToken = _token;
|
||||||
|
foreach (var splitToken in splitTokens)
|
||||||
|
{
|
||||||
|
if (accessToken.Type == JTokenType.Array)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
accessToken = accessToken[splitToken];
|
||||||
|
|
||||||
|
if (accessToken == null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache.Add(key, accessToken);
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Converters
|
namespace CryptoExchange.Net.Converters
|
||||||
@ -22,13 +23,16 @@ namespace CryptoExchange.Net.Converters
|
|||||||
public abstract MessageInterpreterPipeline InterpreterPipeline { get; }
|
public abstract MessageInterpreterPipeline InterpreterPipeline { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public BaseParsedMessage? ReadJson(Stream stream, Dictionary<string, Type> processors, bool outputOriginalData)
|
public BaseParsedMessage? ReadJson(WebSocketMessageType websocketMessageType, Stream stream, Dictionary<string, Type> 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
|
||||||
// Once all id properties have been read callback to see what the deserialization type should be
|
// Once all id properties have been read callback to see what the deserialization type should be
|
||||||
// Deserialize to the correct type
|
// Deserialize to the correct type
|
||||||
|
|
||||||
|
if (InterpreterPipeline.PreProcessCallback != null)
|
||||||
|
stream = InterpreterPipeline.PreProcessCallback(websocketMessageType, stream);
|
||||||
|
|
||||||
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)
|
foreach (var callback in InterpreterPipeline.PreInspectCallbacks)
|
||||||
{
|
{
|
||||||
@ -56,14 +60,36 @@ namespace CryptoExchange.Net.Converters
|
|||||||
{
|
{
|
||||||
token = JToken.Load(jsonTextReader);
|
token = JToken.Load(jsonTextReader);
|
||||||
}
|
}
|
||||||
catch(Exception)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
// Not a json message
|
// Not a json message
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var accessor = new JTokenAccessor(token);
|
||||||
|
|
||||||
|
if (InterpreterPipeline.GetIdentity != null)
|
||||||
|
{
|
||||||
|
var identity = InterpreterPipeline.GetIdentity(accessor);
|
||||||
|
if (identity != null)
|
||||||
|
{
|
||||||
|
if (processors.TryGetValue(identity, out var type))
|
||||||
|
{
|
||||||
|
var idInstance = InterpreterPipeline.ObjectInitializer(token, type);
|
||||||
|
if (outputOriginalData)
|
||||||
|
{
|
||||||
|
stream.Position = 0;
|
||||||
|
idInstance.OriginalData = sr.ReadToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
idInstance.Identifier = identity;
|
||||||
|
idInstance.Parsed = true;
|
||||||
|
return idInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PostInspectResult? inspectResult = null;
|
PostInspectResult? inspectResult = null;
|
||||||
Dictionary<string, string?> typeIdDict = new Dictionary<string, string?>();
|
|
||||||
object? usedParser = null;
|
object? usedParser = null;
|
||||||
if (token.Type == JTokenType.Object)
|
if (token.Type == JTokenType.Object)
|
||||||
{
|
{
|
||||||
@ -72,22 +98,20 @@ namespace CryptoExchange.Net.Converters
|
|||||||
bool allFieldsPresent = true;
|
bool allFieldsPresent = true;
|
||||||
foreach (var field in callback.TypeFields)
|
foreach (var field in callback.TypeFields)
|
||||||
{
|
{
|
||||||
var value = typeIdDict.TryGetValue(field, out var cachedValue) ? cachedValue : GetValueForKey(token, field);
|
var value = accessor.GetStringValue(field.Key);
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
if (callback.AllFieldPresentNeeded)
|
if (field.Required)
|
||||||
{
|
{
|
||||||
allFieldsPresent = false;
|
allFieldsPresent = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typeIdDict[field] = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allFieldsPresent)
|
if (allFieldsPresent)
|
||||||
{
|
{
|
||||||
inspectResult = callback.Callback(typeIdDict, processors);
|
inspectResult = callback.Callback(accessor, processors);
|
||||||
usedParser = callback;
|
usedParser = callback;
|
||||||
if (inspectResult.Type != null)
|
if (inspectResult.Type != null)
|
||||||
break;
|
break;
|
||||||
@ -126,7 +150,10 @@ 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");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
BaseParsedMessage instance;
|
BaseParsedMessage instance;
|
||||||
if (inspectResult.Type != null)
|
if (inspectResult.Type != null)
|
||||||
@ -152,6 +179,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private string? GetValueForKey(JToken token, string key)
|
private string? GetValueForKey(JToken token, string key)
|
||||||
{
|
{
|
||||||
var splitTokens = key.Split(new char[] { ':' });
|
var splitTokens = key.Split(new char[] { ':' });
|
||||||
@ -170,6 +198,9 @@ namespace CryptoExchange.Net.Converters
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (accessToken?.Type == JTokenType.Object)
|
||||||
|
return ((JObject)accessToken).Properties().First().Name;
|
||||||
|
|
||||||
return accessToken?.ToString();
|
return accessToken?.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
CryptoExchange.Net/Interfaces/IMessageAccessor.cs
Normal file
15
CryptoExchange.Net/Interfaces/IMessageAccessor.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.Interfaces
|
||||||
|
{
|
||||||
|
public interface IMessageAccessor
|
||||||
|
{
|
||||||
|
string? GetStringValue(string key);
|
||||||
|
int? GetIntValue(string key);
|
||||||
|
public int? GetCount(string key);
|
||||||
|
public int? GetArrayIntValue(string? key, int index);
|
||||||
|
public string? GetArrayStringValue(string? key, int index);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
|
using CryptoExchange.Net.Sockets;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -11,7 +12,7 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
{
|
{
|
||||||
public int Id { get; }
|
public int Id { get; }
|
||||||
public List<string> Identifiers { get; }
|
public List<string> Identifiers { get; }
|
||||||
Task<CallResult> HandleMessageAsync(DataEvent<BaseParsedMessage> message);
|
Task<CallResult> HandleMessageAsync(SocketConnection connection, DataEvent<BaseParsedMessage> message);
|
||||||
public Type ExpectedMessageType { get; }
|
public Type ExpectedMessageType { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using CryptoExchange.Net.Sockets;
|
using CryptoExchange.Net.Sockets;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net.WebSockets;
|
||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -20,7 +21,7 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Websocket message received event
|
/// Websocket message received event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event Func<Stream, Task> OnStreamMessage;
|
event Func<WebSocketMessageType, Stream, Task> OnStreamMessage;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Websocket sent event, RequestId as parameter
|
/// Websocket sent event, RequestId as parameter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -5,13 +5,16 @@ using Newtonsoft.Json.Linq;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Objects.Sockets
|
namespace CryptoExchange.Net.Objects.Sockets
|
||||||
{
|
{
|
||||||
public class MessageInterpreterPipeline
|
public class MessageInterpreterPipeline
|
||||||
{
|
{
|
||||||
|
public Func<WebSocketMessageType, Stream, Stream>? PreProcessCallback { get; set; }
|
||||||
public List<PreInspectCallback> PreInspectCallbacks { get; set; } = new List<PreInspectCallback>();
|
public List<PreInspectCallback> PreInspectCallbacks { get; set; } = new List<PreInspectCallback>();
|
||||||
|
public Func<IMessageAccessor, string?> GetIdentity { get; set; }
|
||||||
public List<object> PostInspectCallbacks { get; set; } = new List<object>();
|
public List<object> PostInspectCallbacks { get; set; } = new List<object>();
|
||||||
public Func<JToken, Type, BaseParsedMessage> ObjectInitializer { get; set; } = SocketConverter.InstantiateMessageObject;
|
public Func<JToken, Type, BaseParsedMessage> ObjectInitializer { get; set; } = SocketConverter.InstantiateMessageObject;
|
||||||
}
|
}
|
||||||
@ -23,9 +26,20 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
|
|
||||||
public class PostInspectCallback
|
public class PostInspectCallback
|
||||||
{
|
{
|
||||||
public bool AllFieldPresentNeeded { get; set; } = true;
|
public List<TypeField> TypeFields { get; set; } = new List<TypeField>();
|
||||||
public List<string> TypeFields { get; set; } = new List<string>();
|
public Func<IMessageAccessor, Dictionary<string, Type>, PostInspectResult> Callback { get; set; }
|
||||||
public Func<Dictionary<string, string?>, Dictionary<string, Type>, PostInspectResult> Callback { get; set; }
|
}
|
||||||
|
|
||||||
|
public class TypeField
|
||||||
|
{
|
||||||
|
public string Key { get; set; }
|
||||||
|
public bool Required { get; set; }
|
||||||
|
|
||||||
|
public TypeField(string key, bool required = true)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Required = required;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PostInspectArrayCallback
|
public class PostInspectArrayCallback
|
||||||
|
@ -33,7 +33,7 @@ namespace CryptoExchange.Net.Objects.Testing
|
|||||||
var bytes = Encoding.UTF8.GetBytes(data);
|
var bytes = Encoding.UTF8.GetBytes(data);
|
||||||
var stream = new MemoryStream(bytes);
|
var stream = new MemoryStream(bytes);
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
_ = ProcessData(stream);
|
_ = ProcessData(System.Net.WebSockets.WebSocketMessageType.Text, stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
public event Action? OnClose;
|
public event Action? OnClose;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public event Func<Stream, Task>? OnStreamMessage;
|
public event Func<WebSocketMessageType, Stream, Task>? OnStreamMessage;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public event Action<int>? OnRequestSent;
|
public event Action<int>? OnRequestSent;
|
||||||
@ -521,7 +521,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
{
|
{
|
||||||
// Received a complete message and it's not multi part
|
// Received a complete message and it's not multi part
|
||||||
_logger.Log(LogLevel.Trace, $"Socket {Id} received {receiveResult.Count} bytes in single message");
|
_logger.Log(LogLevel.Trace, $"Socket {Id} received {receiveResult.Count} bytes in single message");
|
||||||
await ProcessData(new MemoryStream(buffer.Array, buffer.Offset, receiveResult.Count)).ConfigureAwait(false);
|
await ProcessData(receiveResult.MessageType, new MemoryStream(buffer.Array, buffer.Offset, receiveResult.Count)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -555,7 +555,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
{
|
{
|
||||||
// Reassemble complete message from memory stream
|
// Reassemble complete message from memory stream
|
||||||
_logger.Log(LogLevel.Trace, $"Socket {Id} reassembled message of {memoryStream!.Length} bytes");
|
_logger.Log(LogLevel.Trace, $"Socket {Id} reassembled message of {memoryStream!.Length} bytes");
|
||||||
await ProcessData(memoryStream).ConfigureAwait(false);
|
await ProcessData(receiveResult.MessageType, memoryStream).ConfigureAwait(false);
|
||||||
memoryStream.Dispose();
|
memoryStream.Dispose();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -580,13 +580,13 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task ProcessData(Stream stream)
|
protected async Task ProcessData(WebSocketMessageType type, Stream stream)
|
||||||
{
|
{
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
if (Parameters.Interceptor != null)
|
if (Parameters.Interceptor != null)
|
||||||
stream = Parameters.Interceptor.Invoke(stream);
|
stream = Parameters.Interceptor.Invoke(stream);
|
||||||
if (OnStreamMessage != null)
|
if (OnStreamMessage != null)
|
||||||
await OnStreamMessage.Invoke(stream).ConfigureAwait(false);
|
await OnStreamMessage.Invoke(type, stream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -21,6 +21,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
public bool Completed { get; set; }
|
public bool Completed { get; set; }
|
||||||
public DateTime RequestTimestamp { get; set; }
|
public DateTime RequestTimestamp { get; set; }
|
||||||
public CallResult? Result { get; set; }
|
public CallResult? Result { get; set; }
|
||||||
|
public BaseParsedMessage Response { get; set; }
|
||||||
|
|
||||||
protected AsyncResetEvent _event;
|
protected AsyncResetEvent _event;
|
||||||
protected CancellationTokenSource? _cts;
|
protected CancellationTokenSource? _cts;
|
||||||
@ -96,7 +97,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract Task<CallResult> HandleMessageAsync(DataEvent<BaseParsedMessage> message);
|
public abstract Task<CallResult> HandleMessageAsync(SocketConnection connection, DataEvent<BaseParsedMessage> message);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,10 +125,11 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task<CallResult> HandleMessageAsync(DataEvent<BaseParsedMessage> message)
|
public override async Task<CallResult> HandleMessageAsync(SocketConnection connection, DataEvent<BaseParsedMessage> message)
|
||||||
{
|
{
|
||||||
Completed = true;
|
Completed = true;
|
||||||
Result = await HandleMessageAsync(message.As((ParsedMessage<TResponse>)message.Data)).ConfigureAwait(false);
|
Response = message.Data;
|
||||||
|
Result = await HandleMessageAsync(connection, message.As((ParsedMessage<TResponse>)message.Data)).ConfigureAwait(false);
|
||||||
_event.Set();
|
_event.Set();
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
@ -137,7 +139,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual Task<CallResult<TResponse>> HandleMessageAsync(DataEvent<ParsedMessage<TResponse>> message) => Task.FromResult(new CallResult<TResponse>(message.Data.TypedData!));
|
public virtual Task<CallResult<TResponse>> HandleMessageAsync(SocketConnection connection, DataEvent<ParsedMessage<TResponse>> message) => Task.FromResult(new CallResult<TResponse>(message.Data.TypedData!));
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Timeout()
|
public override void Timeout()
|
||||||
|
@ -308,9 +308,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stream"></param>
|
/// <param name="stream"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual async Task HandleStreamMessage(Stream stream)
|
protected virtual async Task HandleStreamMessage(WebSocketMessageType type, Stream stream)
|
||||||
{
|
{
|
||||||
var result = ApiClient.StreamConverter.ReadJson(stream, _listenerManager.GetMapping(), ApiClient.ApiOptions.OutputOriginalData ?? ApiClient.ClientOptions.OutputOriginalData);
|
var result = ApiClient.StreamConverter.ReadJson(type, stream, _listenerManager.GetMapping(), ApiClient.ApiOptions.OutputOriginalData ?? ApiClient.ClientOptions.OutputOriginalData);
|
||||||
if(result == null)
|
if(result == null)
|
||||||
{
|
{
|
||||||
// Not able to parse at all
|
// Not able to parse at all
|
||||||
@ -331,7 +331,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await _listenerManager.InvokeListenersAsync(result.Identifier, result).ConfigureAwait(false))
|
if (!await _listenerManager.InvokeListenersAsync(this, result.Identifier, result).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
// Not able to find a listener for this message
|
// Not able to find a listener for this message
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
@ -608,7 +608,11 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (subQuery == null)
|
if (subQuery == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
taskList.Add(SendAndWaitQueryAsync(subQuery));
|
taskList.Add(SendAndWaitQueryAsync(subQuery).ContinueWith((x) =>
|
||||||
|
{
|
||||||
|
subscription.HandleSubQueryResponse(subQuery.Response);
|
||||||
|
return x.Result;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.WhenAll(taskList).ConfigureAwait(false);
|
await Task.WhenAll(taskList).ConfigureAwait(false);
|
||||||
@ -645,7 +649,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (subQuery == null)
|
if (subQuery == null)
|
||||||
return new CallResult(null);
|
return new CallResult(null);
|
||||||
|
|
||||||
return await SendAndWaitQueryAsync(subQuery).ConfigureAwait(false);
|
var result = await SendAndWaitQueryAsync(subQuery).ConfigureAwait(false);
|
||||||
|
subscription.HandleSubQueryResponse(subQuery.Response);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -64,7 +64,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> InvokeListenersAsync(string id, BaseParsedMessage data)
|
public async Task<bool> InvokeListenersAsync(SocketConnection connection, string id, BaseParsedMessage data)
|
||||||
{
|
{
|
||||||
List<IMessageProcessor> listeners;
|
List<IMessageProcessor> listeners;
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
@ -91,7 +91,15 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
// Matched based on identifier
|
// Matched based on identifier
|
||||||
var userSw = Stopwatch.StartNew();
|
var userSw = Stopwatch.StartNew();
|
||||||
var dataEvent = new DataEvent<BaseParsedMessage>(data, null, data.OriginalData, DateTime.UtcNow, null);
|
var dataEvent = new DataEvent<BaseParsedMessage>(data, null, data.OriginalData, DateTime.UtcNow, null);
|
||||||
await listener.HandleMessageAsync(dataEvent).ConfigureAwait(false);
|
try
|
||||||
|
{
|
||||||
|
await listener.HandleMessageAsync(connection, dataEvent).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
userSw.Stop();
|
userSw.Stop();
|
||||||
if (userSw.ElapsedMilliseconds > 500)
|
if (userSw.ElapsedMilliseconds > 500)
|
||||||
{
|
{
|
||||||
|
@ -91,17 +91,20 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract BaseQuery? GetSubQuery(SocketConnection connection);
|
public abstract BaseQuery? GetSubQuery(SocketConnection connection);
|
||||||
|
|
||||||
|
public virtual void HandleSubQueryResponse(BaseParsedMessage message) { }
|
||||||
|
public virtual void HandleUnsubQueryResponse(BaseParsedMessage message) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the unsubscribe object to send when unsubscribing
|
/// Get the unsubscribe object to send when unsubscribing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract BaseQuery? GetUnsubQuery();
|
public abstract BaseQuery? GetUnsubQuery();
|
||||||
|
|
||||||
public async Task<CallResult> HandleMessageAsync(DataEvent<BaseParsedMessage> message)
|
public async Task<CallResult> HandleMessageAsync(SocketConnection connection, DataEvent<BaseParsedMessage> message)
|
||||||
{
|
{
|
||||||
ConnectionInvocations++;
|
ConnectionInvocations++;
|
||||||
TotalInvocations++;
|
TotalInvocations++;
|
||||||
return await DoHandleMessageAsync(message).ConfigureAwait(false);
|
return await DoHandleMessageAsync(connection, message).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -109,7 +112,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract Task<CallResult> DoHandleMessageAsync(DataEvent<BaseParsedMessage> message);
|
public abstract Task<CallResult> DoHandleMessageAsync(SocketConnection connection, DataEvent<BaseParsedMessage> message);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoke the exception event
|
/// Invoke the exception event
|
||||||
@ -149,14 +152,25 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Task<CallResult> DoHandleMessageAsync(DataEvent<BaseParsedMessage> message)
|
public override Task<CallResult> DoHandleMessageAsync(SocketConnection connection, DataEvent<BaseParsedMessage> message)
|
||||||
=> HandleEventAsync(message.As((ParsedMessage<TEvent>)message.Data));
|
=> HandleEventAsync(connection, message.As((ParsedMessage<TEvent>)message.Data));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle the update message
|
/// Handle the update message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract Task<CallResult> HandleEventAsync(DataEvent<ParsedMessage<TEvent>> message);
|
public abstract Task<CallResult> HandleEventAsync(SocketConnection connection, DataEvent<ParsedMessage<TEvent>> message);
|
||||||
|
|
||||||
|
public override void HandleSubQueryResponse(BaseParsedMessage message)
|
||||||
|
=> HandleSubQueryResponse((ParsedMessage<TSubResponse>)message);
|
||||||
|
|
||||||
|
public virtual void HandleSubQueryResponse(ParsedMessage<TSubResponse> message) { }
|
||||||
|
|
||||||
|
public override void HandleUnsubQueryResponse(BaseParsedMessage message)
|
||||||
|
=> HandleUnsubQueryResponse((ParsedMessage<TUnsubResponse>)message);
|
||||||
|
|
||||||
|
public virtual void HandleUnsubQueryResponse(ParsedMessage<TUnsubResponse> message) { }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,13 +30,13 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
public abstract class SystemSubscription<T> : SystemSubscription
|
public abstract class SystemSubscription<T> : SystemSubscription
|
||||||
{
|
{
|
||||||
public override Type ExpectedMessageType => typeof(T);
|
public override Type ExpectedMessageType => typeof(T);
|
||||||
public override Task<CallResult> DoHandleMessageAsync(DataEvent<BaseParsedMessage> message)
|
public override Task<CallResult> DoHandleMessageAsync(SocketConnection connection, DataEvent<BaseParsedMessage> message)
|
||||||
=> HandleMessageAsync(message.As((ParsedMessage<T>)message.Data));
|
=> HandleMessageAsync(connection, message.As((ParsedMessage<T>)message.Data));
|
||||||
|
|
||||||
protected SystemSubscription(ILogger logger, bool authenticated) : base(logger, authenticated)
|
protected SystemSubscription(ILogger logger, bool authenticated) : base(logger, authenticated)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Task<CallResult> HandleMessageAsync(DataEvent<ParsedMessage<T>> message);
|
public abstract Task<CallResult> HandleMessageAsync(SocketConnection connection, DataEvent<ParsedMessage<T>> message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user