mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-13 01:12:59 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f3e1cfef33 | |||
| cc3053719c | |||
| cd6907e601 | |||
| 8fe00693bd | |||
| fb90d1e015 | |||
| 4b44861e43 | |||
| e42ca4ab5a | |||
| 5b97f6dd67 | |||
| a9813ecb0a |
@@ -31,7 +31,7 @@ namespace CryptoExchange.Net.Converters
|
||||
if(reader.TokenType is JsonToken.Integer)
|
||||
{
|
||||
var longValue = (long)reader.Value;
|
||||
if (longValue == 0)
|
||||
if (longValue == 0 || longValue == -1)
|
||||
return objectType == typeof(DateTime) ? default(DateTime): null;
|
||||
if (longValue < 19999999999)
|
||||
return ConvertFromSeconds(longValue);
|
||||
@@ -45,6 +45,9 @@ namespace CryptoExchange.Net.Converters
|
||||
else if (reader.TokenType is JsonToken.Float)
|
||||
{
|
||||
var doubleValue = (double)reader.Value;
|
||||
if (doubleValue == 0 || doubleValue == -1)
|
||||
return objectType == typeof(DateTime) ? default(DateTime) : null;
|
||||
|
||||
if (doubleValue < 19999999999)
|
||||
return ConvertFromSeconds(doubleValue);
|
||||
|
||||
@@ -56,6 +59,9 @@ namespace CryptoExchange.Net.Converters
|
||||
if (string.IsNullOrWhiteSpace(stringValue))
|
||||
return null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(stringValue) || stringValue == "0" || stringValue == "-1")
|
||||
return objectType == typeof(DateTime) ? default(DateTime) : null;
|
||||
|
||||
if (stringValue.Length == 8)
|
||||
{
|
||||
// Parse 20211103 format
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
<PackageId>CryptoExchange.Net</PackageId>
|
||||
<Authors>JKorf</Authors>
|
||||
<Description>A base package for implementing cryptocurrency API's</Description>
|
||||
<PackageVersion>5.1.9</PackageVersion>
|
||||
<AssemblyVersion>5.1.9</AssemblyVersion>
|
||||
<FileVersion>5.1.9</FileVersion>
|
||||
<PackageVersion>5.1.10</PackageVersion>
|
||||
<AssemblyVersion>5.1.10</AssemblyVersion>
|
||||
<FileVersion>5.1.10</FileVersion>
|
||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<RepositoryUrl>https://github.com/JKorf/CryptoExchange.Net.git</RepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl>
|
||||
<NeutralLanguage>en</NeutralLanguage>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageReleaseNotes>5.1.9 - Added latency to the timesync calculation, Small fix for exception in socket close handling</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>5.1.10 - 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</PackageReleaseNotes>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
|
||||
@@ -258,24 +258,32 @@ namespace CryptoExchange.Net.OrderBook
|
||||
}
|
||||
|
||||
_subscription = startResult.Data;
|
||||
_subscription.ConnectionLost += () =>
|
||||
{
|
||||
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} connection lost");
|
||||
Status = OrderBookStatus.Reconnecting;
|
||||
Reset();
|
||||
};
|
||||
_subscription.ConnectionClosed += () =>
|
||||
{
|
||||
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} disconnected");
|
||||
Status = OrderBookStatus.Disconnected;
|
||||
_ = StopAsync();
|
||||
};
|
||||
_subscription.ConnectionLost += HandleConnectionLost;
|
||||
_subscription.ConnectionClosed += HandleConnectionClosed;
|
||||
_subscription.ConnectionRestored += HandleConnectionRestored;
|
||||
|
||||
_subscription.ConnectionRestored += async time => await ResyncAsync().ConfigureAwait(false);
|
||||
Status = OrderBookStatus.Synced;
|
||||
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/>
|
||||
public async Task StopAsync()
|
||||
{
|
||||
@@ -286,8 +294,12 @@ namespace CryptoExchange.Net.OrderBook
|
||||
if (_processTask != null)
|
||||
await _processTask.ConfigureAwait(false);
|
||||
|
||||
if (_subscription != null)
|
||||
if (_subscription != null) {
|
||||
await _subscription.CloseAsync().ConfigureAwait(false);
|
||||
_subscription.ConnectionLost -= HandleConnectionLost;
|
||||
_subscription.ConnectionClosed -= HandleConnectionClosed;
|
||||
_subscription.ConnectionRestored -= HandleConnectionRestored;
|
||||
}
|
||||
log.Write(LogLevel.Trace, $"{Id} order book {Symbol} stopped");
|
||||
}
|
||||
|
||||
@@ -601,13 +613,13 @@ namespace CryptoExchange.Net.OrderBook
|
||||
|
||||
private async Task ProcessQueue()
|
||||
{
|
||||
while (Status != OrderBookStatus.Disconnected)
|
||||
while (Status != OrderBookStatus.Disconnected && Status != OrderBookStatus.Disposed)
|
||||
{
|
||||
await _queueEvent.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
while (_processQueue.TryDequeue(out var item))
|
||||
{
|
||||
if (Status == OrderBookStatus.Disconnected)
|
||||
if (Status == OrderBookStatus.Disconnected || Status == OrderBookStatus.Disposed)
|
||||
break;
|
||||
|
||||
if (_stopProcessing)
|
||||
|
||||
@@ -141,6 +141,8 @@ namespace CryptoExchange.Net.Sockets
|
||||
private readonly List<PendingRequest> pendingRequests;
|
||||
private Task? _socketProcessReconnectTask;
|
||||
|
||||
private SocketStatus _status;
|
||||
|
||||
/// <summary>
|
||||
/// The underlying websocket
|
||||
/// </summary>
|
||||
@@ -217,10 +219,24 @@ namespace CryptoExchange.Net.Sockets
|
||||
subscription.CancellationTokenRegistration.Value.Dispose();
|
||||
}
|
||||
}
|
||||
await _socket.CloseAsync().ConfigureAwait(false);
|
||||
|
||||
if (_socketProcessReconnectTask != null)
|
||||
await _socketProcessReconnectTask.ConfigureAwait(false);
|
||||
if (_status == SocketStatus.Reconnecting)
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
@@ -232,7 +248,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// <returns></returns>
|
||||
public async Task CloseAsync(SocketSubscription subscription)
|
||||
{
|
||||
if (!_socket.IsOpen)
|
||||
if (!_socket.IsOpen || _status == SocketStatus.Disposed)
|
||||
return;
|
||||
|
||||
if (subscription.CancellationTokenRegistration.HasValue)
|
||||
@@ -255,9 +271,11 @@ namespace CryptoExchange.Net.Sockets
|
||||
private void StartProcessingTask()
|
||||
{
|
||||
log.Write(LogLevel.Trace, $"Starting {SocketId} process/reconnect task");
|
||||
_status = SocketStatus.Processing;
|
||||
_socketProcessReconnectTask = Task.Run(async () =>
|
||||
{
|
||||
await _socket.ProcessAsync().ConfigureAwait(false);
|
||||
_status = SocketStatus.Reconnecting;
|
||||
await ReconnectAsync().ConfigureAwait(false);
|
||||
log.Write(LogLevel.Trace, $"Process/reconnect {SocketId} task finished");
|
||||
});
|
||||
@@ -283,7 +301,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
if (!lostTriggered)
|
||||
{
|
||||
lostTriggered = true;
|
||||
ConnectionLost?.Invoke();
|
||||
_ = Task.Run(() => ConnectionLost?.Invoke());
|
||||
}
|
||||
|
||||
while (ShouldReconnect)
|
||||
@@ -372,7 +390,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
if (lostTriggered)
|
||||
{
|
||||
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;
|
||||
@@ -396,6 +414,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_status = SocketStatus.Disposed;
|
||||
_socket.Dispose();
|
||||
}
|
||||
|
||||
@@ -458,7 +477,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
|
||||
var total = DateTime.UtcNow - timestamp;
|
||||
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.");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private enum SocketStatus
|
||||
{
|
||||
None,
|
||||
Processing,
|
||||
Reconnecting,
|
||||
Disposed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,12 @@ 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)
|
||||
|
||||
## Release notes
|
||||
* 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
|
||||
|
||||
+4
-1
@@ -61,4 +61,7 @@ var client = new BinanceClient(new BinanceClientOptions
|
||||
BaseAddress = BinanceApiAddresses.TestNet.UsdFuturesRestClientAddress
|
||||
}
|
||||
});
|
||||
```
|
||||
```
|
||||
|
||||
### 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