1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-08-16 19:03:01 +00:00

Websocket refactoring (#190)

Websocket refactoring
This commit is contained in:
Jan Korf
2024-02-24 19:21:47 +01:00
committed by GitHub
parent d91755dff5
commit d533557324
585 changed files with 114831 additions and 2198 deletions
+8 -1
View File
@@ -70,7 +70,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="originalData"></param>
/// <param name="error"></param>
#pragma warning disable 8618
protected CallResult([AllowNull]T data, string? originalData, Error? error): base(error)
public CallResult([AllowNull]T data, string? originalData, Error? error): base(error)
#pragma warning restore 8618
{
OriginalData = originalData;
@@ -91,6 +91,13 @@ namespace CryptoExchange.Net.Objects
/// <param name="error">The erro rto return</param>
public CallResult(Error error) : this(default, null, error) { }
/// <summary>
/// Create a new error result
/// </summary>
/// <param name="error">The error to return</param>
/// <param name="originalData">The original response data</param>
public CallResult(Error error, string? originalData) : this(default, originalData, error) { }
/// <summary>
/// Overwrite bool check so we can use if(callResult) instead of if(callResult.Success)
/// </summary>
+1 -1
View File
@@ -278,7 +278,7 @@ namespace CryptoExchange.Net.Objects
/// <param name="code"></param>
/// <param name="message"></param>
/// <param name="data"></param>
protected CancellationRequestedError(int? code, string message, object? data): base(code, message, data) { }
public CancellationRequestedError(int? code, string message, object? data): base(code, message, data) { }
}
/// <summary>
@@ -0,0 +1,81 @@
using System;
namespace CryptoExchange.Net.Objects.Sockets
{
/// <summary>
/// An update received from a socket update subscription
/// </summary>
/// <typeparam name="T">The type of the data</typeparam>
public class DataEvent<T>
{
/// <summary>
/// The timestamp the data was received
/// </summary>
public DateTime Timestamp { get; set; }
/// <summary>
/// The topic of the update, what symbol/asset etc..
/// </summary>
public string? Topic { get; set; }
/// <summary>
/// The original data that was received, only available when OutputOriginalData is set to true in the client options
/// </summary>
public string? OriginalData { get; set; }
/// <summary>
/// Type of update
/// </summary>
public SocketUpdateType? UpdateType { get; set; }
/// <summary>
/// The received data deserialized into an object
/// </summary>
public T Data { get; set; }
internal DataEvent(T data, string? topic, string? originalData, DateTime timestamp, SocketUpdateType? updateType)
{
Data = data;
Topic = topic;
OriginalData = originalData;
Timestamp = timestamp;
UpdateType = updateType;
}
/// <summary>
/// Create a new DataEvent with data in the from of type K based on the current DataEvent. Topic, 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>
/// <returns></returns>
public DataEvent<K> As<K>(K data)
{
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>
/// <returns></returns>
public DataEvent<K> As<K>(K data, string? topic)
{
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);
}
}
}
@@ -0,0 +1,128 @@
using CryptoExchange.Net.Sockets;
using System;
using System.Threading.Tasks;
namespace CryptoExchange.Net.Objects.Sockets
{
/// <summary>
/// Subscription to a data stream
/// </summary>
public class UpdateSubscription
{
private readonly SocketConnection _connection;
private readonly Subscription _listener;
/// <summary>
/// Event when the connection is lost. The socket will automatically reconnect when possible.
/// </summary>
public event Action ConnectionLost
{
add => _connection.ConnectionLost += value;
remove => _connection.ConnectionLost -= value;
}
/// <summary>
/// Event when the connection is closed and will not be reconnected
/// </summary>
public event Action ConnectionClosed
{
add => _connection.ConnectionClosed += value;
remove => _connection.ConnectionClosed -= value;
}
/// <summary>
/// Event when the connection is restored. Timespan parameter indicates the time the socket has been offline for before reconnecting.
/// Note that when the executing code is suspended and resumed at a later period (for example, a laptop going to sleep) the disconnect time will be incorrect as the diconnect
/// will only be detected after resuming the code, so the initial disconnect time is lost. Use the timespan only for informational purposes.
/// </summary>
public event Action<TimeSpan> ConnectionRestored
{
add => _connection.ConnectionRestored += value;
remove => _connection.ConnectionRestored -= value;
}
/// <summary>
/// Event when the connection to the server is paused based on a server indication. No operations can be performed while paused
/// </summary>
public event Action ActivityPaused
{
add => _connection.ActivityPaused += value;
remove => _connection.ActivityPaused -= value;
}
/// <summary>
/// Event when the connection to the server is unpaused after being paused
/// </summary>
public event Action ActivityUnpaused
{
add => _connection.ActivityUnpaused += value;
remove => _connection.ActivityUnpaused -= value;
}
/// <summary>
/// Event when an exception happens during the handling of the data
/// </summary>
public event Action<Exception> Exception
{
add => _listener.Exception += value;
remove => _listener.Exception -= value;
}
/// <summary>
/// The id of the socket
/// </summary>
public int SocketId => _connection.SocketId;
/// <summary>
/// The id of the subscription
/// </summary>
public int Id => _listener.Id;
/// <summary>
/// ctor
/// </summary>
/// <param name="connection">The socket connection the subscription is on</param>
/// <param name="subscription">The subscription</param>
public UpdateSubscription(SocketConnection connection, Subscription subscription)
{
_connection = connection;
_listener = subscription;
}
/// <summary>
/// Close the subscription
/// </summary>
/// <returns></returns>
public Task CloseAsync()
{
return _connection.CloseAsync(_listener);
}
/// <summary>
/// Close the socket to cause a reconnect
/// </summary>
/// <returns></returns>
public Task ReconnectAsync()
{
return _connection.TriggerReconnectAsync();
}
/// <summary>
/// Unsubscribe a subscription
/// </summary>
/// <returns></returns>
internal async Task UnsubscribeAsync()
{
await _connection.UnsubscribeAsync(_listener).ConfigureAwait(false);
}
/// <summary>
/// Resubscribe this subscription
/// </summary>
/// <returns></returns>
internal async Task<CallResult> ResubscribeAsync()
{
return await _connection.ResubscribeAsync(_listener).ConfigureAwait(false);
}
}
}
@@ -0,0 +1,74 @@
using CryptoExchange.Net.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
namespace CryptoExchange.Net.Objects.Sockets
{
/// <summary>
/// Parameters for a websocket
/// </summary>
public class WebSocketParameters
{
/// <summary>
/// The uri to connect to
/// </summary>
public Uri Uri { get; set; }
/// <summary>
/// Headers to send in the connection handshake
/// </summary>
public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>();
/// <summary>
/// Cookies to send in the connection handshake
/// </summary>
public IDictionary<string, string> Cookies { get; set; } = new Dictionary<string, string>();
/// <summary>
/// The time to wait between reconnect attempts
/// </summary>
public TimeSpan ReconnectInterval { get; set; } = TimeSpan.FromSeconds(5);
/// <summary>
/// Proxy for the connection
/// </summary>
public ApiProxy? Proxy { get; set; }
/// <summary>
/// Whether the socket should automatically reconnect when connection is lost
/// </summary>
public bool AutoReconnect { get; set; }
/// <summary>
/// The maximum time of no data received before considering the connection lost and closting/reconnecting the socket
/// </summary>
public TimeSpan? Timeout { get; set; }
/// <summary>
/// Interval at which to send ping frames
/// </summary>
public TimeSpan? KeepAliveInterval { get; set; }
/// <summary>
/// The rate limiters for the socket connection
/// </summary>
public IEnumerable<IRateLimiter>? RateLimiters { get; set; }
/// <summary>
/// Encoding for sending/receiving data
/// </summary>
public Encoding Encoding { get; set; } = Encoding.UTF8;
/// <summary>
/// ctor
/// </summary>
/// <param name="uri">Uri</param>
/// <param name="autoReconnect">Auto reconnect</param>
public WebSocketParameters(Uri uri, bool autoReconnect)
{
Uri = uri;
AutoReconnect = autoReconnect;
}
}
}
@@ -1,6 +1,4 @@
using System.Collections.Generic;
namespace CryptoExchange.Net.Objects
namespace CryptoExchange.Net.Objects
{
/// <summary>
/// Trade environment names