mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-14 09:52:53 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d06bd5f176 | |||
| d55fc8da65 | |||
| 01184f2c5d | |||
| cadc93c2f0 | |||
| 2600a51461 | |||
| 9e6a86ba8b | |||
| c4430d63fa | |||
| f3e1cfef33 | |||
| cc3053719c | |||
| cd6907e601 | |||
| 8fe00693bd | |||
| fb90d1e015 | |||
| 4b44861e43 | |||
| e42ca4ab5a | |||
| 5b97f6dd67 | |||
| a9813ecb0a | |||
| c7069a4049 | |||
| 5683ae0b3c | |||
| 1c8cf5ac98 |
@@ -6,10 +6,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="17.1.0-preview-20211130-02"></packagereference>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0-preview-20211130-02"></PackageReference>
|
||||||
<PackageReference Include="Moq" Version="4.16.1" />
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
<packagereference Include="NUnit" Version="3.13.2"></packagereference>
|
<PackageReference Include="NUnit" Version="3.13.2"></PackageReference>
|
||||||
<packagereference Include="NUnit3TestAdapter" Version="4.2.0"></packagereference>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0"></PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected int MaxSocketConnections { get; set; } = 9999;
|
protected int MaxSocketConnections { get; set; } = 9999;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Keep alive interval for websocket connection
|
||||||
|
/// </summary>
|
||||||
|
protected TimeSpan KeepAliveInterval { get; set; } = TimeSpan.FromSeconds(10);
|
||||||
|
/// <summary>
|
||||||
/// Delegate used for processing byte data received from socket connections before it is processed by handlers
|
/// Delegate used for processing byte data received from socket connections before it is processed by handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Func<byte[], string>? dataInterpreterBytes;
|
protected Func<byte[], string>? dataInterpreterBytes;
|
||||||
@@ -574,6 +578,7 @@ namespace CryptoExchange.Net
|
|||||||
if (ClientOptions.Proxy != null)
|
if (ClientOptions.Proxy != null)
|
||||||
socket.SetProxy(ClientOptions.Proxy);
|
socket.SetProxy(ClientOptions.Proxy);
|
||||||
|
|
||||||
|
socket.KeepAliveInterval = KeepAliveInterval;
|
||||||
socket.Timeout = ClientOptions.SocketNoDataTimeout;
|
socket.Timeout = ClientOptions.SocketNoDataTimeout;
|
||||||
socket.DataInterpreterBytes = dataInterpreterBytes;
|
socket.DataInterpreterBytes = dataInterpreterBytes;
|
||||||
socket.DataInterpreterString = dataInterpreterString;
|
socket.DataInterpreterString = dataInterpreterString;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate time offset between local and server
|
// Calculate time offset between local and server
|
||||||
var offset = result.Data - localTime;
|
var offset = result.Data - (localTime.AddMilliseconds(result.ResponseTime!.Value.TotalMilliseconds / 2));
|
||||||
timeSyncParams.UpdateTimeOffset(offset);
|
timeSyncParams.UpdateTimeOffset(offset);
|
||||||
timeSyncParams.TimeSyncState.Semaphore.Release();
|
timeSyncParams.TimeSyncState.Semaphore.Release();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
if(reader.TokenType is JsonToken.Integer)
|
if(reader.TokenType is JsonToken.Integer)
|
||||||
{
|
{
|
||||||
var longValue = (long)reader.Value;
|
var longValue = (long)reader.Value;
|
||||||
if (longValue == 0)
|
if (longValue == 0 || longValue == -1)
|
||||||
return objectType == typeof(DateTime) ? default(DateTime): null;
|
return objectType == typeof(DateTime) ? default(DateTime): null;
|
||||||
if (longValue < 19999999999)
|
if (longValue < 19999999999)
|
||||||
return ConvertFromSeconds(longValue);
|
return ConvertFromSeconds(longValue);
|
||||||
@@ -45,6 +45,9 @@ namespace CryptoExchange.Net.Converters
|
|||||||
else if (reader.TokenType is JsonToken.Float)
|
else if (reader.TokenType is JsonToken.Float)
|
||||||
{
|
{
|
||||||
var doubleValue = (double)reader.Value;
|
var doubleValue = (double)reader.Value;
|
||||||
|
if (doubleValue == 0 || doubleValue == -1)
|
||||||
|
return objectType == typeof(DateTime) ? default(DateTime) : null;
|
||||||
|
|
||||||
if (doubleValue < 19999999999)
|
if (doubleValue < 19999999999)
|
||||||
return ConvertFromSeconds(doubleValue);
|
return ConvertFromSeconds(doubleValue);
|
||||||
|
|
||||||
@@ -56,6 +59,9 @@ namespace CryptoExchange.Net.Converters
|
|||||||
if (string.IsNullOrWhiteSpace(stringValue))
|
if (string.IsNullOrWhiteSpace(stringValue))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(stringValue) || stringValue == "0" || stringValue == "-1")
|
||||||
|
return objectType == typeof(DateTime) ? default(DateTime) : null;
|
||||||
|
|
||||||
if (stringValue.Length == 8)
|
if (stringValue.Length == 8)
|
||||||
{
|
{
|
||||||
// Parse 20211103 format
|
// Parse 20211103 format
|
||||||
|
|||||||
@@ -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>5.1.8</PackageVersion>
|
<PackageVersion>5.1.11</PackageVersion>
|
||||||
<AssemblyVersion>5.1.8</AssemblyVersion>
|
<AssemblyVersion>5.1.11</AssemblyVersion>
|
||||||
<FileVersion>5.1.8</FileVersion>
|
<FileVersion>5.1.11</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>5.1.8 - Cleanup socket code, fixed an issue which could cause connections to never reconnect when connection was lost, Added support for sending requests which expect an empty response, Fixed issue with the DateTimeConverter date interpretation</PackageReleaseNotes>
|
<PackageReleaseNotes>5.1.11 - Added KeepAliveInterval setting, Fixed port not being copied when setting parameters on request, Fixed inconsistent PackageReference casing in csproj</PackageReleaseNotes>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>9.0</LangVersion>
|
<LangVersion>9.0</LangVersion>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
|||||||
@@ -426,6 +426,7 @@ namespace CryptoExchange.Net
|
|||||||
var uriBuilder = new UriBuilder();
|
var uriBuilder = new UriBuilder();
|
||||||
uriBuilder.Scheme = baseUri.Scheme;
|
uriBuilder.Scheme = baseUri.Scheme;
|
||||||
uriBuilder.Host = baseUri.Host;
|
uriBuilder.Host = baseUri.Host;
|
||||||
|
uriBuilder.Port = baseUri.Port;
|
||||||
uriBuilder.Path = baseUri.AbsolutePath;
|
uriBuilder.Path = baseUri.AbsolutePath;
|
||||||
var httpValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
var httpValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
||||||
foreach (var parameter in parameters)
|
foreach (var parameter in parameters)
|
||||||
@@ -454,6 +455,7 @@ namespace CryptoExchange.Net
|
|||||||
var uriBuilder = new UriBuilder();
|
var uriBuilder = new UriBuilder();
|
||||||
uriBuilder.Scheme = baseUri.Scheme;
|
uriBuilder.Scheme = baseUri.Scheme;
|
||||||
uriBuilder.Host = baseUri.Host;
|
uriBuilder.Host = baseUri.Host;
|
||||||
|
uriBuilder.Port = baseUri.Port;
|
||||||
uriBuilder.Path = baseUri.AbsolutePath;
|
uriBuilder.Path = baseUri.AbsolutePath;
|
||||||
var httpValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
var httpValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
||||||
foreach (var parameter in parameters)
|
foreach (var parameter in parameters)
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
TimeSpan Timeout { get; set; }
|
TimeSpan Timeout { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The interval at which to send a ping frame to the server
|
||||||
|
/// </summary>
|
||||||
|
TimeSpan KeepAliveInterval { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// Set a proxy to use when connecting
|
/// Set a proxy to use when connecting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="proxy"></param>
|
/// <param name="proxy"></param>
|
||||||
|
|||||||
@@ -258,24 +258,32 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
}
|
}
|
||||||
|
|
||||||
_subscription = startResult.Data;
|
_subscription = startResult.Data;
|
||||||
_subscription.ConnectionLost += () =>
|
_subscription.ConnectionLost += HandleConnectionLost;
|
||||||
{
|
_subscription.ConnectionClosed += HandleConnectionClosed;
|
||||||
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} connection lost");
|
_subscription.ConnectionRestored += HandleConnectionRestored;
|
||||||
Status = OrderBookStatus.Reconnecting;
|
|
||||||
Reset();
|
|
||||||
};
|
|
||||||
_subscription.ConnectionClosed += () =>
|
|
||||||
{
|
|
||||||
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} disconnected");
|
|
||||||
Status = OrderBookStatus.Disconnected;
|
|
||||||
_ = StopAsync();
|
|
||||||
};
|
|
||||||
|
|
||||||
_subscription.ConnectionRestored += async time => await ResyncAsync().ConfigureAwait(false);
|
|
||||||
Status = OrderBookStatus.Synced;
|
Status = OrderBookStatus.Synced;
|
||||||
return new CallResult<bool>(true);
|
return new CallResult<bool>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleConnectionLost() {
|
||||||
|
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} connection lost");
|
||||||
|
if (Status != OrderBookStatus.Disposed) {
|
||||||
|
Status = OrderBookStatus.Reconnecting;
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleConnectionClosed() {
|
||||||
|
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} disconnected");
|
||||||
|
Status = OrderBookStatus.Disconnected;
|
||||||
|
_ = StopAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void HandleConnectionRestored(TimeSpan _) {
|
||||||
|
await ResyncAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task StopAsync()
|
public async Task StopAsync()
|
||||||
{
|
{
|
||||||
@@ -286,8 +294,12 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
if (_processTask != null)
|
if (_processTask != null)
|
||||||
await _processTask.ConfigureAwait(false);
|
await _processTask.ConfigureAwait(false);
|
||||||
|
|
||||||
if (_subscription != null)
|
if (_subscription != null) {
|
||||||
await _subscription.CloseAsync().ConfigureAwait(false);
|
await _subscription.CloseAsync().ConfigureAwait(false);
|
||||||
|
_subscription.ConnectionLost -= HandleConnectionLost;
|
||||||
|
_subscription.ConnectionClosed -= HandleConnectionClosed;
|
||||||
|
_subscription.ConnectionRestored -= HandleConnectionRestored;
|
||||||
|
}
|
||||||
log.Write(LogLevel.Trace, $"{Id} order book {Symbol} stopped");
|
log.Write(LogLevel.Trace, $"{Id} order book {Symbol} stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,13 +613,13 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
|
|
||||||
private async Task ProcessQueue()
|
private async Task ProcessQueue()
|
||||||
{
|
{
|
||||||
while (Status != OrderBookStatus.Disconnected)
|
while (Status != OrderBookStatus.Disconnected && Status != OrderBookStatus.Disposed)
|
||||||
{
|
{
|
||||||
await _queueEvent.WaitAsync().ConfigureAwait(false);
|
await _queueEvent.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
while (_processQueue.TryDequeue(out var item))
|
while (_processQueue.TryDequeue(out var item))
|
||||||
{
|
{
|
||||||
if (Status == OrderBookStatus.Disconnected)
|
if (Status == OrderBookStatus.Disconnected || Status == OrderBookStatus.Disposed)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (_stopProcessing)
|
if (_stopProcessing)
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TimeSpan Timeout { get; set; }
|
public TimeSpan Timeout { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public TimeSpan KeepAliveInterval { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public double IncomingKbps
|
public double IncomingKbps
|
||||||
{
|
{
|
||||||
@@ -280,8 +283,14 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
_sendEvent.Set();
|
_sendEvent.Set();
|
||||||
|
|
||||||
if (_socket.State == WebSocketState.Open)
|
if (_socket.State == WebSocketState.Open)
|
||||||
await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Closing", default).ConfigureAwait(false);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Closing", default).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch(Exception)
|
||||||
|
{ } // Can sometimes throw an exception when socket is in aborted state due to timing
|
||||||
|
}
|
||||||
log.Write(LogLevel.Debug, $"Socket {Id} closed");
|
log.Write(LogLevel.Debug, $"Socket {Id} closed");
|
||||||
Handle(closeHandlers);
|
Handle(closeHandlers);
|
||||||
}
|
}
|
||||||
@@ -326,7 +335,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
socket.Options.Cookies = cookieContainer;
|
socket.Options.Cookies = cookieContainer;
|
||||||
foreach (var header in headers)
|
foreach (var header in headers)
|
||||||
socket.Options.SetRequestHeader(header.Key, header.Value);
|
socket.Options.SetRequestHeader(header.Key, header.Value);
|
||||||
socket.Options.KeepAliveInterval = TimeSpan.FromSeconds(10);
|
socket.Options.KeepAliveInterval = KeepAliveInterval;
|
||||||
socket.Options.SetBuffer(65536, 65536); // Setting it to anything bigger than 65536 throws an exception in .net framework
|
socket.Options.SetBuffer(65536, 65536); // Setting it to anything bigger than 65536 throws an exception in .net framework
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
private readonly List<PendingRequest> pendingRequests;
|
private readonly List<PendingRequest> pendingRequests;
|
||||||
private Task? _socketProcessReconnectTask;
|
private Task? _socketProcessReconnectTask;
|
||||||
|
|
||||||
|
private SocketStatus _status;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The underlying websocket
|
/// The underlying websocket
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -217,10 +219,24 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
subscription.CancellationTokenRegistration.Value.Dispose();
|
subscription.CancellationTokenRegistration.Value.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await _socket.CloseAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (_socketProcessReconnectTask != null)
|
if (_status == SocketStatus.Reconnecting)
|
||||||
await _socketProcessReconnectTask.ConfigureAwait(false);
|
{
|
||||||
|
// Wait for reconnect task to finish
|
||||||
|
log.Write(LogLevel.Trace, "In reconnecting state, waiting for reconnecting to end");
|
||||||
|
if (_socketProcessReconnectTask != null)
|
||||||
|
await _socketProcessReconnectTask.ConfigureAwait(false);
|
||||||
|
|
||||||
|
await _socket.CloseAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Close before waiting for process task to finish
|
||||||
|
await _socket.CloseAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (_socketProcessReconnectTask != null)
|
||||||
|
await _socketProcessReconnectTask.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
_socket.Dispose();
|
_socket.Dispose();
|
||||||
}
|
}
|
||||||
@@ -232,7 +248,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task CloseAsync(SocketSubscription subscription)
|
public async Task CloseAsync(SocketSubscription subscription)
|
||||||
{
|
{
|
||||||
if (!_socket.IsOpen)
|
if (!_socket.IsOpen || _status == SocketStatus.Disposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (subscription.CancellationTokenRegistration.HasValue)
|
if (subscription.CancellationTokenRegistration.HasValue)
|
||||||
@@ -255,9 +271,11 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
private void StartProcessingTask()
|
private void StartProcessingTask()
|
||||||
{
|
{
|
||||||
log.Write(LogLevel.Trace, $"Starting {SocketId} process/reconnect task");
|
log.Write(LogLevel.Trace, $"Starting {SocketId} process/reconnect task");
|
||||||
|
_status = SocketStatus.Processing;
|
||||||
_socketProcessReconnectTask = Task.Run(async () =>
|
_socketProcessReconnectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await _socket.ProcessAsync().ConfigureAwait(false);
|
await _socket.ProcessAsync().ConfigureAwait(false);
|
||||||
|
_status = SocketStatus.Reconnecting;
|
||||||
await ReconnectAsync().ConfigureAwait(false);
|
await ReconnectAsync().ConfigureAwait(false);
|
||||||
log.Write(LogLevel.Trace, $"Process/reconnect {SocketId} task finished");
|
log.Write(LogLevel.Trace, $"Process/reconnect {SocketId} task finished");
|
||||||
});
|
});
|
||||||
@@ -283,7 +301,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (!lostTriggered)
|
if (!lostTriggered)
|
||||||
{
|
{
|
||||||
lostTriggered = true;
|
lostTriggered = true;
|
||||||
ConnectionLost?.Invoke();
|
_ = Task.Run(() => ConnectionLost?.Invoke());
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ShouldReconnect)
|
while (ShouldReconnect)
|
||||||
@@ -372,7 +390,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (lostTriggered)
|
if (lostTriggered)
|
||||||
{
|
{
|
||||||
lostTriggered = false;
|
lostTriggered = false;
|
||||||
_ = Task.Run(() => ConnectionRestored?.Invoke(time.HasValue ? DateTime.UtcNow - time.Value : TimeSpan.FromSeconds(0))).ConfigureAwait(false);
|
_ = Task.Run(() => ConnectionRestored?.Invoke(time.HasValue ? DateTime.UtcNow - time.Value : TimeSpan.FromSeconds(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -396,6 +414,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_status = SocketStatus.Disposed;
|
||||||
_socket.Dispose();
|
_socket.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,7 +477,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
var total = DateTime.UtcNow - timestamp;
|
var total = DateTime.UtcNow - timestamp;
|
||||||
if (userProcessTime.TotalMilliseconds > 500)
|
if (userProcessTime.TotalMilliseconds > 500)
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} message processing slow ({(int)total.TotalMilliseconds}ms), consider offloading data handling to another thread. " +
|
log.Write(LogLevel.Debug, $"Socket {SocketId} message processing slow ({(int)total.TotalMilliseconds}ms, {(int)userProcessTime.TotalMilliseconds}ms user code), consider offloading data handling to another thread. " +
|
||||||
"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.");
|
||||||
|
|
||||||
log.Write(LogLevel.Trace, $"Socket {SocketId} message processed in {(int)total.TotalMilliseconds}ms, ({(int)userProcessTime.TotalMilliseconds}ms user code)");
|
log.Write(LogLevel.Trace, $"Socket {SocketId} message processed in {(int)total.TotalMilliseconds}ms, ({(int)userProcessTime.TotalMilliseconds}ms user code)");
|
||||||
@@ -671,5 +690,13 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
return await socketClient.SubscribeAndWaitAsync(this, socketSubscription.Request!, socketSubscription).ConfigureAwait(false);
|
return await socketClient.SubscribeAndWaitAsync(this, socketSubscription.Request!, socketSubscription).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum SocketStatus
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Processing,
|
||||||
|
Reconnecting,
|
||||||
|
Disposed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,21 @@ I develop and maintain this package on my own for free in my spare time. Donatio
|
|||||||
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 5.1.11 - 24 May 2022
|
||||||
|
* Added KeepAliveInterval setting
|
||||||
|
* Fixed port not being copied when setting parameters on request
|
||||||
|
* Fixed inconsistent PackageReference casing in csproj
|
||||||
|
|
||||||
|
* Version 5.1.10 - 22 May 2022
|
||||||
|
* Fixed order book reconnecting while Diposed
|
||||||
|
* Fixed exception when disposing socket client while reconnecting
|
||||||
|
* Added additional null/default checking in DateTimeConverter
|
||||||
|
* Changed ConnectionLost subscription event to run in seperate task to prevent exception/longer operations from intervering with reconnecting
|
||||||
|
|
||||||
|
* Version 5.1.9 - 08 May 2022
|
||||||
|
* Added latency to the timesync calculation
|
||||||
|
* Small fix for exception in socket close handling
|
||||||
|
|
||||||
* Version 5.1.8 - 01 May 2022
|
* Version 5.1.8 - 01 May 2022
|
||||||
* Cleanup socket code, fixed an issue which could cause connections to never reconnect when connection was lost
|
* Cleanup socket code, fixed an issue which could cause connections to never reconnect when connection was lost
|
||||||
* Added support for sending requests which expect an empty response
|
* Added support for sending requests which expect an empty response
|
||||||
|
|||||||
@@ -62,3 +62,6 @@ var client = new BinanceClient(new BinanceClientOptions
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### How are timezones handled / Timestamps are off by xx
|
||||||
|
Exchange API's treat all timestamps as UTC, both incoming and outgoing. The client libraries do no conversion so be sure to use UTC as well.
|
||||||
Reference in New Issue
Block a user