mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-13 09:23:04 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f08ed16f2a | |||
| 212d457a6a | |||
| ac5f333766 | |||
| 640e4387c1 | |||
| a16b19019f | |||
| 2443f576ac | |||
| 4fd7e44015 | |||
| a0a3bda1c5 | |||
| 6bda7a3c73 | |||
| 69a7a714cd |
@@ -15,7 +15,6 @@ using CryptoExchange.Net.Requests;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using static CryptoExchange.Net.Objects.RateLimiter;
|
|
||||||
|
|
||||||
namespace CryptoExchange.Net
|
namespace CryptoExchange.Net
|
||||||
{
|
{
|
||||||
@@ -558,7 +557,7 @@ namespace CryptoExchange.Net
|
|||||||
{
|
{
|
||||||
// Handle retry after header
|
// Handle retry after header
|
||||||
var retryAfterHeader = responseHeaders.SingleOrDefault(r => r.Key.Equals("Retry-After", StringComparison.InvariantCultureIgnoreCase));
|
var retryAfterHeader = responseHeaders.SingleOrDefault(r => r.Key.Equals("Retry-After", StringComparison.InvariantCultureIgnoreCase));
|
||||||
if (!retryAfterHeader.Value.Any())
|
if (retryAfterHeader.Value?.Any() != true)
|
||||||
return new ServerRateLimitError(data);
|
return new ServerRateLimitError(data);
|
||||||
|
|
||||||
var value = retryAfterHeader.Value.First();
|
var value = retryAfterHeader.Value.First();
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ namespace CryptoExchange.Net
|
|||||||
if (!authenticated || socket.Authenticated)
|
if (!authenticated || socket.Authenticated)
|
||||||
return new CallResult<bool>(true);
|
return new CallResult<bool>(true);
|
||||||
|
|
||||||
_logger.Log(LogLevel.Debug, $"Attempting to authenticate {socket.SocketId}");
|
_logger.Log(LogLevel.Debug, $"Socket {socket.SocketId} Attempting to authenticate");
|
||||||
var result = await AuthenticateSocketAsync(socket).ConfigureAwait(false);
|
var result = await AuthenticateSocketAsync(socket).ConfigureAwait(false);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
@@ -414,6 +414,7 @@ namespace CryptoExchange.Net
|
|||||||
return new CallResult<bool>(result.Error);
|
return new CallResult<bool>(result.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.Log(LogLevel.Debug, $"Socket {socket.SocketId} authenticated");
|
||||||
socket.Authenticated = true;
|
socket.Authenticated = true;
|
||||||
return new CallResult<bool>(true);
|
return new CallResult<bool>(true);
|
||||||
}
|
}
|
||||||
@@ -511,7 +512,7 @@ namespace CryptoExchange.Net
|
|||||||
if (typeof(T) == typeof(string))
|
if (typeof(T) == typeof(string))
|
||||||
{
|
{
|
||||||
var stringData = (T)Convert.ChangeType(messageEvent.JsonData.ToString(), typeof(T));
|
var stringData = (T)Convert.ChangeType(messageEvent.JsonData.ToString(), typeof(T));
|
||||||
dataHandler(new DataEvent<T>(stringData, null, OutputOriginalData ? messageEvent.OriginalData : null, messageEvent.ReceivedTimestamp));
|
dataHandler(new DataEvent<T>(stringData, null, OutputOriginalData ? messageEvent.OriginalData : null, messageEvent.ReceivedTimestamp, null));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,7 +523,7 @@ namespace CryptoExchange.Net
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dataHandler(new DataEvent<T>(desResult.Data, null, OutputOriginalData ? messageEvent.OriginalData : null, messageEvent.ReceivedTimestamp));
|
dataHandler(new DataEvent<T>(desResult.Data, null, OutputOriginalData ? messageEvent.OriginalData : null, messageEvent.ReceivedTimestamp, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
var subscription = request == null
|
var subscription = request == null
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.Converters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Boolean converter with support for "0"/"1" (strings)
|
||||||
|
/// </summary>
|
||||||
|
public class BoolConverter : JsonConverter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this instance can convert the specified object type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
if (Nullable.GetUnderlyingType(objectType) != null)
|
||||||
|
return Nullable.GetUnderlyingType(objectType) == typeof(bool);
|
||||||
|
return objectType == typeof(bool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param>
|
||||||
|
/// <param name="objectType">Type of the object.</param>
|
||||||
|
/// <param name="existingValue">The existing value of object being read.</param>
|
||||||
|
/// <param name="serializer">The calling serializer.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The object value.
|
||||||
|
/// </returns>
|
||||||
|
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
switch (reader.Value?.ToString().ToLower().Trim())
|
||||||
|
{
|
||||||
|
case "true":
|
||||||
|
case "yes":
|
||||||
|
case "y":
|
||||||
|
case "1":
|
||||||
|
case "on":
|
||||||
|
return true;
|
||||||
|
case "false":
|
||||||
|
case "no":
|
||||||
|
case "n":
|
||||||
|
case "0":
|
||||||
|
case "off":
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach here, we're pretty much going to throw an error so let's let Json.NET throw it's pretty-fied error message.
|
||||||
|
return new JsonSerializer().Deserialize(reader, objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that this converter will not participate in writing results.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanWrite { get { return false; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the JSON representation of the object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The <see cref="T:Newtonsoft.Json.JsonWriter"/> to write to.</param><param name="value">The value.</param><param name="serializer">The calling serializer.</param>
|
||||||
|
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,20 @@ namespace CryptoExchange.Net.Converters
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class EnumConverter : JsonConverter
|
public class EnumConverter : JsonConverter
|
||||||
{
|
{
|
||||||
|
private bool _warnOnMissingEntry = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
public EnumConverter() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="warnOnMissingEntry"></param>
|
||||||
|
public EnumConverter(bool warnOnMissingEntry)
|
||||||
|
{
|
||||||
|
_warnOnMissingEntry = warnOnMissingEntry;
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<Type, List<KeyValuePair<object, string>>> _mapping = new();
|
private static readonly ConcurrentDictionary<Type, List<KeyValuePair<object, string>>> _mapping = new();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -51,8 +65,12 @@ namespace CryptoExchange.Net.Converters
|
|||||||
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Received empty string as enum value, but property type is not a nullable enum. EnumType: {enumType.Name}. If you think {enumType.Name} should be nullable please open an issue on the Github repo");
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Received empty string as enum value, but property type is not a nullable enum. EnumType: {enumType.Name}. If you think {enumType.Name} should be nullable please open an issue on the Github repo");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
// We received an enum value but weren't able to parse it.
|
// We received an enum value but weren't able to parse it.
|
||||||
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Cannot map enum value. EnumType: {enumType.Name}, Value: {reader.Value}, Known values: {string.Join(", ", mapping.Select(m => m.Value))}. If you think {reader.Value} should added please open an issue on the Github repo");
|
if (_warnOnMissingEntry)
|
||||||
|
Trace.WriteLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss:fff} | Warning | Cannot map enum value. EnumType: {enumType.Name}, Value: {reader.Value}, Known values: {string.Join(", ", mapping.Select(m => m.Value))}. If you think {reader.Value} should added please open an issue on the Github repo");
|
||||||
|
}
|
||||||
|
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
<PackageId>CryptoExchange.Net</PackageId>
|
<PackageId>CryptoExchange.Net</PackageId>
|
||||||
<Authors>JKorf</Authors>
|
<Authors>JKorf</Authors>
|
||||||
<Description>A base package for implementing cryptocurrency API's</Description>
|
<Description>A base package for implementing cryptocurrency API's</Description>
|
||||||
<PackageVersion>6.1.1</PackageVersion>
|
<PackageVersion>6.1.5</PackageVersion>
|
||||||
<AssemblyVersion>6.1.1</AssemblyVersion>
|
<AssemblyVersion>6.1.5</AssemblyVersion>
|
||||||
<FileVersion>6.1.1</FileVersion>
|
<FileVersion>6.1.5</FileVersion>
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<RepositoryUrl>https://github.com/JKorf/CryptoExchange.Net.git</RepositoryUrl>
|
<RepositoryUrl>https://github.com/JKorf/CryptoExchange.Net.git</RepositoryUrl>
|
||||||
<PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl>
|
||||||
<NeutralLanguage>en</NeutralLanguage>
|
<NeutralLanguage>en</NeutralLanguage>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<PackageReleaseNotes>6.1.1 - Fixes for json converters</PackageReleaseNotes>
|
<PackageReleaseNotes>6.1.5 - Added UpdateType to socket DataEvent, Added additional scenarios for BoolConverter, Updated some logging</PackageReleaseNotes>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>10.0</LangVersion>
|
<LangVersion>10.0</LangVersion>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ namespace CryptoExchange.Net
|
|||||||
return value / 1.000000000000000000000000000000000m;
|
return value / 1.000000000000000000000000000000000m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generate a new unique id. The id is staticly stored so it is guarenteed to be unique
|
/// Generate a new unique id. The id is staticly stored so it is guarenteed to be unique
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -124,4 +124,19 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Closest
|
Closest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of the update
|
||||||
|
/// </summary>
|
||||||
|
public enum SocketUpdateType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A update
|
||||||
|
/// </summary>
|
||||||
|
Update,
|
||||||
|
/// <summary>
|
||||||
|
/// A snapshot, generally send at the start of the connection
|
||||||
|
/// </summary>
|
||||||
|
Snapshot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,10 +117,10 @@ namespace CryptoExchange.Net.Objects
|
|||||||
{
|
{
|
||||||
int totalWaitTime = 0;
|
int totalWaitTime = 0;
|
||||||
|
|
||||||
EndpointRateLimiter? endpointLimit;
|
List<EndpointRateLimiter> endpointLimits;
|
||||||
lock (_limiterLock)
|
lock (_limiterLock)
|
||||||
endpointLimit = _limiters.OfType<EndpointRateLimiter>().SingleOrDefault(h => h.Endpoints.Contains(endpoint) && (h.Method == null || h.Method == method));
|
endpointLimits = _limiters.OfType<EndpointRateLimiter>().Where(h => h.Endpoints.Contains(endpoint) && (h.Method == null || h.Method == method)).ToList();
|
||||||
if(endpointLimit != null)
|
foreach (var endpointLimit in endpointLimits)
|
||||||
{
|
{
|
||||||
var waitResult = await ProcessTopic(logger, endpointLimit, endpoint, requestWeight, limitBehaviour, ct).ConfigureAwait(false);
|
var waitResult = await ProcessTopic(logger, endpointLimit, endpoint, requestWeight, limitBehaviour, ct).ConfigureAwait(false);
|
||||||
if (!waitResult)
|
if (!waitResult)
|
||||||
@@ -129,7 +129,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
totalWaitTime += waitResult.Data;
|
totalWaitTime += waitResult.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (endpointLimit?.IgnoreOtherRateLimits == true)
|
if (endpointLimits.Any(l => l.IgnoreOtherRateLimits))
|
||||||
return new CallResult<int>(totalWaitTime);
|
return new CallResult<int>(totalWaitTime);
|
||||||
|
|
||||||
List<PartialEndpointRateLimiter> partialEndpointLimits;
|
List<PartialEndpointRateLimiter> partialEndpointLimits;
|
||||||
@@ -169,10 +169,10 @@ namespace CryptoExchange.Net.Objects
|
|||||||
if(partialEndpointLimits.Any(p => p.IgnoreOtherRateLimits))
|
if(partialEndpointLimits.Any(p => p.IgnoreOtherRateLimits))
|
||||||
return new CallResult<int>(totalWaitTime);
|
return new CallResult<int>(totalWaitTime);
|
||||||
|
|
||||||
ApiKeyRateLimiter? apiLimit;
|
List<ApiKeyRateLimiter> apiLimits;
|
||||||
lock (_limiterLock)
|
lock (_limiterLock)
|
||||||
apiLimit = _limiters.OfType<ApiKeyRateLimiter>().SingleOrDefault(h => h.Type == RateLimitType.ApiKey);
|
apiLimits = _limiters.OfType<ApiKeyRateLimiter>().Where(h => h.Type == RateLimitType.ApiKey).ToList();
|
||||||
if (apiLimit != null)
|
foreach (var apiLimit in apiLimits)
|
||||||
{
|
{
|
||||||
if(apiKey == null)
|
if(apiKey == null)
|
||||||
{
|
{
|
||||||
@@ -206,13 +206,13 @@ namespace CryptoExchange.Net.Objects
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((signed || apiLimit?.OnlyForSignedRequests == false) && apiLimit?.IgnoreTotalRateLimit == true)
|
if ((signed || apiLimits.All(l => !l.OnlyForSignedRequests)) && apiLimits.Any(l => l.IgnoreTotalRateLimit))
|
||||||
return new CallResult<int>(totalWaitTime);
|
return new CallResult<int>(totalWaitTime);
|
||||||
|
|
||||||
TotalRateLimiter? totalLimit;
|
List<TotalRateLimiter> totalLimits;
|
||||||
lock (_limiterLock)
|
lock (_limiterLock)
|
||||||
totalLimit = _limiters.OfType<TotalRateLimiter>().SingleOrDefault();
|
totalLimits = _limiters.OfType<TotalRateLimiter>().ToList();
|
||||||
if (totalLimit != null)
|
foreach(var totalLimit in totalLimits)
|
||||||
{
|
{
|
||||||
var waitResult = await ProcessTopic(logger, totalLimit, endpoint, requestWeight, limitBehaviour, ct).ConfigureAwait(false);
|
var waitResult = await ProcessTopic(logger, totalLimit, endpoint, requestWeight, limitBehaviour, ct).ConfigureAwait(false);
|
||||||
if (!waitResult)
|
if (!waitResult)
|
||||||
|
|||||||
@@ -464,7 +464,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
{
|
{
|
||||||
var pbList = _processBuffer.ToList();
|
var pbList = _processBuffer.ToList();
|
||||||
if (pbList.Count > 0)
|
if (pbList.Count > 0)
|
||||||
_logger.Log(LogLevel.Debug, $"Processing {pbList.Count} buffered updates");
|
_logger.Log(LogLevel.Debug, $"{Id} Processing {pbList.Count} buffered updates");
|
||||||
|
|
||||||
foreach (var bufferEntry in pbList)
|
foreach (var bufferEntry in pbList)
|
||||||
{
|
{
|
||||||
@@ -661,7 +661,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
|
|
||||||
if (_stopProcessing)
|
if (_stopProcessing)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Trace, "Skipping message because of resubscribing");
|
_logger.Log(LogLevel.Trace, $"{Id} Skipping message because of resubscribing");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var bytes = Parameters.Encoding.GetBytes(data);
|
var bytes = Parameters.Encoding.GetBytes(data);
|
||||||
_logger.Log(LogLevel.Trace, $"Socket {Id} - msg {id} - Adding {bytes.Length} to send buffer");
|
_logger.Log(LogLevel.Trace, $"Socket {Id} - msg {id} - Adding {bytes.Length} bytes to send buffer");
|
||||||
_sendBuffer.Enqueue(new SendItem { Id = id, Weight = weight, Bytes = bytes });
|
_sendBuffer.Enqueue(new SendItem { Id = id, Weight = weight, Bytes = bytes });
|
||||||
_sendEvent.Set();
|
_sendEvent.Set();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using CryptoExchange.Net.Objects;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Sockets
|
namespace CryptoExchange.Net.Sockets
|
||||||
{
|
{
|
||||||
@@ -23,35 +24,23 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? OriginalData { get; set; }
|
public string? OriginalData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of update
|
||||||
|
/// </summary>
|
||||||
|
public SocketUpdateType? UpdateType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The received data deserialized into an object
|
/// The received data deserialized into an object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T Data { get; set; }
|
public T Data { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
internal DataEvent(T data, string? topic, string? originalData, DateTime timestamp, SocketUpdateType? updateType)
|
||||||
/// Ctor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data"></param>
|
|
||||||
/// <param name="timestamp"></param>
|
|
||||||
public DataEvent(T data, DateTime timestamp)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Timestamp = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DataEvent(T data, string? topic, DateTime timestamp)
|
|
||||||
{
|
|
||||||
Data = data;
|
|
||||||
Topic = topic;
|
|
||||||
Timestamp = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal DataEvent(T data, string? topic, string? originalData, DateTime timestamp)
|
|
||||||
{
|
{
|
||||||
Data = data;
|
Data = data;
|
||||||
Topic = topic;
|
Topic = topic;
|
||||||
OriginalData = originalData;
|
OriginalData = originalData;
|
||||||
Timestamp = timestamp;
|
Timestamp = timestamp;
|
||||||
|
UpdateType = updateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,7 +51,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public DataEvent<K> As<K>(K data)
|
public DataEvent<K> As<K>(K data)
|
||||||
{
|
{
|
||||||
return new DataEvent<K>(data, Topic, OriginalData, Timestamp);
|
return new DataEvent<K>(data, Topic, OriginalData, Timestamp, UpdateType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -74,7 +63,20 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public DataEvent<K> As<K>(K data, string? topic)
|
public DataEvent<K> As<K>(K data, string? topic)
|
||||||
{
|
{
|
||||||
return new DataEvent<K>(data, topic, OriginalData, Timestamp);
|
return new DataEvent<K>(data, topic, OriginalData, Timestamp, UpdateType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new DataEvent with data in the from of type K based on the current DataEvent. OriginalData and Timestamp will be copied over
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="K">The type of the new data</typeparam>
|
||||||
|
/// <param name="data">The new data</param>
|
||||||
|
/// <param name="topic">The new topic</param>
|
||||||
|
/// <param name="updateType">The type of update</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public DataEvent<K> As<K>(K data, string? topic, SocketUpdateType updateType)
|
||||||
|
{
|
||||||
|
return new DataEvent<K>(data, topic, OriginalData, Timestamp, updateType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
var reconnectSuccessful = await ProcessReconnectAsync().ConfigureAwait(false);
|
var reconnectSuccessful = await ProcessReconnectAsync().ConfigureAwait(false);
|
||||||
if (!reconnectSuccessful)
|
if (!reconnectSuccessful)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Warning, $"Failed reconnect processing: {reconnectSuccessful.Error}, reconnecting again");
|
_logger.Log(LogLevel.Warning, $"Socket {SocketId} Failed reconnect processing: {reconnectSuccessful.Error}, reconnecting again");
|
||||||
await _socket.ReconnectAsync().ConfigureAwait(false);
|
await _socket.ReconnectAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -291,10 +291,13 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <param name="requestId">Id of the request sent</param>
|
/// <param name="requestId">Id of the request sent</param>
|
||||||
protected virtual void HandleRequestSent(int requestId)
|
protected virtual void HandleRequestSent(int requestId)
|
||||||
{
|
{
|
||||||
var pendingRequest = _pendingRequests.SingleOrDefault(p => p.Id == requestId);
|
PendingRequest pendingRequest;
|
||||||
|
lock (_pendingRequests)
|
||||||
|
pendingRequest = _pendingRequests.SingleOrDefault(p => p.Id == requestId);
|
||||||
|
|
||||||
if (pendingRequest == null)
|
if (pendingRequest == null)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Debug, $"Socket {SocketId} - msg {requestId} - message sent, but not pending");
|
_logger.Log(LogLevel.Debug, $"Socket {SocketId} - msg {requestId} - message sent, but not pending");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +348,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
// Answer to a timed out request, unsub if it is a subscription request
|
// Answer to a timed out request, unsub if it is a subscription request
|
||||||
if (pendingRequest.Subscription != null)
|
if (pendingRequest.Subscription != null)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Warning, "Received subscription info after request timed out; unsubscribing. Consider increasing the RequestTimeout");
|
_logger.Log(LogLevel.Warning, $"Socket {SocketId} Received subscription info after request timed out; unsubscribing. Consider increasing the RequestTimeout");
|
||||||
_ = ApiClient.UnsubscribeAsync(this, pendingRequest.Subscription).ConfigureAwait(false);
|
_ = ApiClient.UnsubscribeAsync(this, pendingRequest.Subscription).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,7 +383,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
"Data from this socket may arrive late or not at all if message processing is continuously slow.");
|
"Data from this socket may arrive late or not at all if message processing is continuously slow.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Log(LogLevel.Trace, $"Socket {SocketId}{(subscription == null ? "" : " subscription " + subscription!.Id)} message processed in {(int)total.TotalMilliseconds}ms, ({(int)userProcessTime.TotalMilliseconds}ms user code)");
|
_logger.Log(LogLevel.Trace, $"Socket {SocketId}{(subscription == null ? "" : " subscription " + subscription!.Id)} message processed in {(int)total.TotalMilliseconds}ms ({(int)userProcessTime.TotalMilliseconds}ms user code)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -711,7 +714,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
var result = await ApiClient.RevitalizeRequestAsync(subscription.Request!).ConfigureAwait(false);
|
var result = await ApiClient.RevitalizeRequestAsync(subscription.Request!).ConfigureAwait(false);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Warning, "Failed request revitalization: " + result.Error);
|
_logger.Log(LogLevel.Warning, $"Socket {SocketId} Failed request revitalization: " + result.Error);
|
||||||
return result.As<bool>(false);
|
return result.As<bool>(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,22 @@ Make a one time donation in a crypto currency of your choice. If you prefer to d
|
|||||||
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf).
|
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf).
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
|
* Version 6.1.5 - 08 Oct 2023
|
||||||
|
* Added UpdateType to socket DataEvent
|
||||||
|
* Added additional scenarios for BoolConverter
|
||||||
|
* Updated some logging
|
||||||
|
|
||||||
|
* Version 6.1.4 - 23 Sep 2023
|
||||||
|
* Added BoolConverter
|
||||||
|
* Added parameter for logging warning message on missing enum entry to EnumConverter
|
||||||
|
|
||||||
|
* Version 6.1.3 - 18 Sep 2023
|
||||||
|
* Fix for concurrency exception in socket subscription
|
||||||
|
|
||||||
|
* Version 6.1.2 - 11 Sep 2023
|
||||||
|
* Added support for multiple of the same ratelimiting type in the same rate limiter
|
||||||
|
* Fixed nullreference on rate limit error if no Retry-After header is returned
|
||||||
|
|
||||||
* Version 6.1.1 - 04 Sep 2023
|
* Version 6.1.1 - 04 Sep 2023
|
||||||
* Fixes for json converters
|
* Fixes for json converters
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user