mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-10-14 15:11:44 +00:00
WebSocket covered subscriptions
Updated WebSocket duplicate subscription handling Fixed incorrect status keeping of WebSocket subscriptions which don't expect a response
This commit is contained in:
@@ -23,6 +23,10 @@ namespace CryptoExchange.Net.SharedApis
|
|||||||
/// Get user funding history capability.
|
/// Get user funding history capability.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static SharedRestCapability<IGetUserFundingHistory, IGetUserFundingHistoryRest> GetUserFundingHistory { get; } = new();
|
public static SharedRestCapability<IGetUserFundingHistory, IGetUserFundingHistoryRest> GetUserFundingHistory { get; } = new();
|
||||||
|
/// <summary>
|
||||||
|
/// Subscribe to funding info updates capability.
|
||||||
|
/// </summary>
|
||||||
|
public static SharedCapabilityReference<ISubscribeFundingInfoSocket> SubscribeFundingInfo { get; } = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -702,7 +702,7 @@ namespace CryptoExchange.Net.Sockets.Default
|
|||||||
if (subscription.CancellationTokenRegistration.HasValue)
|
if (subscription.CancellationTokenRegistration.HasValue)
|
||||||
subscription.CancellationTokenRegistration.Value.Dispose();
|
subscription.CancellationTokenRegistration.Value.Dispose();
|
||||||
|
|
||||||
bool anyDuplicateSubscription = _listeners.OfType<Subscription>().Any(x => x != subscription && x.MessageRouter.Routes.All(l => subscription.MessageRouter.ContainsCheck(l)));
|
bool anyDuplicateSubscription = SubscriptionIsCovered(subscription);
|
||||||
bool shouldCloseConnection = _listeners.OfType<Subscription>().All(r => !r.UserSubscription || r.Status == SubscriptionStatus.Closing || r.Status == SubscriptionStatus.Closed) && !DedicatedRequestConnection.IsDedicatedRequestConnection;
|
bool shouldCloseConnection = _listeners.OfType<Subscription>().All(r => !r.UserSubscription || r.Status == SubscriptionStatus.Closing || r.Status == SubscriptionStatus.Closed) && !DedicatedRequestConnection.IsDedicatedRequestConnection;
|
||||||
|
|
||||||
if (!anyDuplicateSubscription)
|
if (!anyDuplicateSubscription)
|
||||||
@@ -1069,6 +1069,32 @@ namespace CryptoExchange.Net.Sockets.Default
|
|||||||
return CallResult.Ok();
|
return CallResult.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether there is currently a subscription covering all the routes the subscription lists
|
||||||
|
/// </summary>
|
||||||
|
protected bool SubscriptionIsCovered(Subscription subscription)
|
||||||
|
=> _listeners.OfType<Subscription>().Any(
|
||||||
|
x => x != subscription
|
||||||
|
&& x.Active
|
||||||
|
&& x.MessageRouter.Routes.All(l => subscription.MessageRouter.ContainsCheck(l)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether there is a subscription earlier in the list covering all the routes the subscription lists
|
||||||
|
/// </summary>
|
||||||
|
protected bool IsCoveredByEarlierSubscription(Subscription subscription)
|
||||||
|
{
|
||||||
|
foreach (var other in _listeners.OfType<Subscription>())
|
||||||
|
{
|
||||||
|
if (other == subscription)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (other.Active && other.MessageRouter.Routes.All(x => subscription.MessageRouter.ContainsCheck(x)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Try to subscribe a new subscription by sending the subscribe query and wait for the result as needed
|
/// Try to subscribe a new subscription by sending the subscribe query and wait for the result as needed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1103,11 +1129,11 @@ namespace CryptoExchange.Net.Sockets.Default
|
|||||||
return WebSocketResult.Ok(ApiClient.Exchange, SocketId, default, 0, ConnectionUriString);
|
return WebSocketResult.Ok(ApiClient.Exchange, SocketId, default, 0, ConnectionUriString);
|
||||||
}
|
}
|
||||||
|
|
||||||
var subCompleteHandler = () =>
|
var subCompleteHandler = (bool success) =>
|
||||||
{
|
{
|
||||||
subscription.Status = subQuery.Success ? SubscriptionStatus.Subscribed : SubscriptionStatus.Pending;
|
subscription.Status = success ? SubscriptionStatus.Subscribed : SubscriptionStatus.Pending;
|
||||||
subscription.HandleSubQueryResponse(this, subQuery.Response);
|
subscription.HandleSubQueryResponse(this, subQuery.Response);
|
||||||
if (newSubscription && subQuery.Success)
|
if (newSubscription && success)
|
||||||
{
|
{
|
||||||
subscription.TokenExpired += HandleTokenExpired;
|
subscription.TokenExpired += HandleTokenExpired;
|
||||||
if (subCancelToken != default)
|
if (subCancelToken != default)
|
||||||
@@ -1122,6 +1148,14 @@ namespace CryptoExchange.Net.Sockets.Default
|
|||||||
};
|
};
|
||||||
subQuery.OnComplete = subCompleteHandler;
|
subQuery.OnComplete = subCompleteHandler;
|
||||||
|
|
||||||
|
// For duplicate subscription don't send another subscribe request but just handle it internally
|
||||||
|
// Unsubscribe also doesn't unsubscribe when there is still a duplicate subscription running
|
||||||
|
if (IsCoveredByEarlierSubscription(subscription))
|
||||||
|
{
|
||||||
|
subQuery.Complete();
|
||||||
|
return WebSocketResult.Ok(ApiClient.Exchange, SocketId, default, subQuery.Id, ConnectionUriString);
|
||||||
|
}
|
||||||
|
|
||||||
var subQueryResult = await SendAndWaitQueryAsync(subQuery).ConfigureAwait(false);
|
var subQueryResult = await SendAndWaitQueryAsync(subQuery).ConfigureAwait(false);
|
||||||
if (!subQueryResult.Success)
|
if (!subQueryResult.Success)
|
||||||
{
|
{
|
||||||
@@ -1132,9 +1166,6 @@ namespace CryptoExchange.Net.Sockets.Default
|
|||||||
return WebSocketResult.Fail(ApiClient.Exchange, subQueryResult.Error!);
|
return WebSocketResult.Fail(ApiClient.Exchange, subQueryResult.Error!);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!subQuery.ExpectsResponse)
|
|
||||||
subCompleteHandler();
|
|
||||||
|
|
||||||
return subQueryResult;
|
return subQueryResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// On complete callback
|
/// On complete callback
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action? OnComplete { get; set; }
|
public Action<bool>? OnComplete { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public event Action? OnMessageRouterUpdated;
|
public event Action? OnMessageRouterUpdated;
|
||||||
@@ -157,8 +157,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Completed = true;
|
Complete();
|
||||||
_event.Set();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +174,11 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void Timeout();
|
public abstract void Timeout();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mark request as successfully completed
|
||||||
|
/// </summary>
|
||||||
|
public abstract void Complete();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mark request as failed
|
/// Mark request as failed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -248,7 +252,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
{
|
{
|
||||||
Completed = true;
|
Completed = true;
|
||||||
_event.Set();
|
_event.Set();
|
||||||
OnComplete?.Invoke();
|
OnComplete?.Invoke(Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handled;
|
return handled;
|
||||||
@@ -267,7 +271,19 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
Completed = true;
|
Completed = true;
|
||||||
_event.Set();
|
_event.Set();
|
||||||
OnComplete?.Invoke();
|
OnComplete?.Invoke(Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Complete()
|
||||||
|
{
|
||||||
|
if (Completed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Result = CallResult<THandlerResponse>.Ok(default!);
|
||||||
|
Completed = true;
|
||||||
|
_event.Set();
|
||||||
|
OnComplete?.Invoke(Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -280,7 +296,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
Completed = true;
|
Completed = true;
|
||||||
|
|
||||||
_event.Set();
|
_event.Set();
|
||||||
OnComplete?.Invoke();
|
OnComplete?.Invoke(Success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user