mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-18 11:52:54 +00:00
Websocket performance update (#261)
Performance update: Authentication Added Ed25519 signing support for NET8.0 and newer Added static methods on ApiCredentials to create credentials of a specific type Added static ApiCredentials.ReadFromFile method to read a key from file Added required abstract SupportedCredentialTypes property on AuthenticationProvider base class General Performance Added checks before logging statements to prevent overhead of building the log string if logging is not needed Added ExchangeHelpers.ProcessQueuedAsync method to process updates async Replaced locking object types from object to Lock in NET9.0 and newer Replaced some Task response types with ValueTask to prevent allocation overhead on hot paths Updated Json ArrayConverter to reduce some allocation overhead Updated Json BoolConverter to prevent boxing Updated Json DateTimeConverter to prevent boxing Updated Json EnumConverter caching to reduce lookup overhead Updated ExtensionMethods.CreateParamString to reduce allocations Updated ExtensionMethods.AppendPath to reduce overhead REST Refactored REST message processing to separate IRestMessageHandler instance Split RestApiClient.PrepareAsync into CheckTimeSync and RateLimitAsync Updated IRequest.Accept type from string to MediaTypeWithQualityHeaderValue to prevent creation on each request Updated IRequest.GetHeaders response type from KeyValuePair<string, string[]>[] to HttpRequestHeaders to prevent additional mapping Updated IResponse.ResponseHeaders type from KeyValuePair<string, string[]>[] to HttpResponseHeaders to prevent additional mapping Updated WebCallResult RequestHeaders and ResponseHeaders types to HttpRequestHeaders and HttpResponseHeaders Removed unnecessary empty dictionary initializations for each request Removed CallResult creation in internal methods to prevent having to create multiple versions for different result types Socket Added HighPerformance websocket client implementation which significantly reduces memory overhead and improves speed but with certain limitations Added MaxIndividualSubscriptionsPerConnection setting in SocketApiClient to limit the number of individual stream subscriptions on a connection Added SocketIndividualSubscriptionCombineTarget option to set the target number of individual stream subscriptions per connection Added new websocket message handling logic which is faster and reduces memory allocation Added UseUpdatedDeserialization option to toggle between updated deserialization and old deserialization Added Exchange property to DataEvent to prevent additional mapping overhead for Shared apis Refactored message callback to be sync instead of async to prevent async overhead Refactored CryptoExchangeWebSocketClient.IncomingKbps calculation to significantly reduce overhead Moved websocket client creation from SocketApiClient to SocketConnection Removed DataEvent.As and DataEvent.ToCallResult methods in favor of single ToType method Removed DataEvent creation on lower levels to prevent having to create multiple versions for different result types Removed Subscription<TSubResponse, TUnsubResponse> as its no longer used Other Added null check to ParameterCollection for required parameters Added Net10.0 target framework Updated dependency versions Updated Shared asset aliases check to be culture invariant Updated Error string representation Updated some namespaces Updated SymbolOrderBook processing of buffered updates to prevent additional allocation Removed ExchangeEvent type which is no longer needed Removed unused usings
This commit is contained in:
+1
-2
@@ -1,10 +1,9 @@
|
||||
using CryptoExchange.Net.Authentication;
|
||||
using CryptoExchange.Net.Objects;
|
||||
using CryptoExchange.Net.Objects.Options;
|
||||
using CryptoExchange.Net.SharedApis;
|
||||
using System;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
namespace CryptoExchange.Net.Interfaces.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Base api client
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
namespace CryptoExchange.Net.Interfaces.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Client for accessing REST API's for different exchanges
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
namespace CryptoExchange.Net.Interfaces.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Client for accessing Websocket API's for different exchanges
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
namespace CryptoExchange.Net.Interfaces.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Base rest API client
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using CryptoExchange.Net.Objects.Options;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
namespace CryptoExchange.Net.Interfaces.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for rest API implementations
|
||||
+7
-1
@@ -1,9 +1,11 @@
|
||||
using CryptoExchange.Net.Objects;
|
||||
using CryptoExchange.Net.Objects.Options;
|
||||
using CryptoExchange.Net.Objects.Sockets;
|
||||
using CryptoExchange.Net.Sockets.Default.Interfaces;
|
||||
using CryptoExchange.Net.Sockets.HighPerf.Interfaces;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
namespace CryptoExchange.Net.Interfaces.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Socket API client
|
||||
@@ -27,6 +29,10 @@ namespace CryptoExchange.Net.Interfaces
|
||||
/// </summary>
|
||||
IWebsocketFactory SocketFactory { get; set; }
|
||||
/// <summary>
|
||||
/// High performance websocket factory
|
||||
/// </summary>
|
||||
IHighPerfConnectionFactory? HighPerfConnectionFactory { get; set; }
|
||||
/// <summary>
|
||||
/// Current client options
|
||||
/// </summary>
|
||||
SocketExchangeOptions ClientOptions { get; }
|
||||
+1
-1
@@ -3,7 +3,7 @@ using System.Threading.Tasks;
|
||||
using CryptoExchange.Net.Objects.Options;
|
||||
using CryptoExchange.Net.Objects.Sockets;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
namespace CryptoExchange.Net.Interfaces.Clients
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for socket API implementations
|
||||
@@ -1,7 +1,6 @@
|
||||
using CryptoExchange.Net.Converters.MessageParsing;
|
||||
using CryptoExchange.Net.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using CryptoExchange.Net.Objects;
|
||||
using CryptoExchange.Net.Objects.Sockets;
|
||||
using CryptoExchange.Net.Sockets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Message processor
|
||||
/// </summary>
|
||||
public interface IMessageProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// Id of the processor
|
||||
/// </summary>
|
||||
public int Id { get; }
|
||||
/// <summary>
|
||||
/// The matcher for this listener
|
||||
/// </summary>
|
||||
public MessageMatcher MessageMatcher { get; }
|
||||
/// <summary>
|
||||
/// Handle a message
|
||||
/// </summary>
|
||||
Task<CallResult> Handle(SocketConnection connection, DataEvent<object> message, MessageHandlerLink matchedHandler);
|
||||
/// <summary>
|
||||
/// Deserialize a message into object of type
|
||||
/// </summary>
|
||||
/// <param name="accessor"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
CallResult<object> Deserialize(IMessageAccessor accessor, Type type);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializer interface
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace CryptoExchange.Net.Interfaces
|
||||
/// <summary>
|
||||
/// Accept header
|
||||
/// </summary>
|
||||
string Accept { set; }
|
||||
MediaTypeWithQualityHeaderValue Accept { set; }
|
||||
/// <summary>
|
||||
/// Content
|
||||
/// </summary>
|
||||
@@ -58,7 +58,7 @@ namespace CryptoExchange.Net.Interfaces
|
||||
/// Get all headers
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
KeyValuePair<string, string[]>[] GetHeaders();
|
||||
HttpRequestHeaders GetHeaders();
|
||||
|
||||
/// <summary>
|
||||
/// Get the response
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace CryptoExchange.Net.Interfaces
|
||||
/// <summary>
|
||||
/// The response headers
|
||||
/// </summary>
|
||||
KeyValuePair<string, string[]>[] ResponseHeaders { get; }
|
||||
HttpResponseHeaders ResponseHeaders { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the response stream
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CryptoExchange.Net.Objects;
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
using CryptoExchange.Net.Objects;
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Websocket connection interface
|
||||
/// </summary>
|
||||
public interface IWebsocket: IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Websocket closed event
|
||||
/// </summary>
|
||||
event Func<Task> OnClose;
|
||||
/// <summary>
|
||||
/// Websocket message received event
|
||||
/// </summary>
|
||||
event Func<WebSocketMessageType, ReadOnlyMemory<byte>, Task> OnStreamMessage;
|
||||
/// <summary>
|
||||
/// Websocket sent event, RequestId as parameter
|
||||
/// </summary>
|
||||
event Func<int, Task> OnRequestSent;
|
||||
/// <summary>
|
||||
/// Websocket query was ratelimited and couldn't be send
|
||||
/// </summary>
|
||||
event Func<int, Task>? OnRequestRateLimited;
|
||||
/// <summary>
|
||||
/// Connection was ratelimited and couldn't be established
|
||||
/// </summary>
|
||||
event Func<Task>? OnConnectRateLimited;
|
||||
/// <summary>
|
||||
/// Websocket error event
|
||||
/// </summary>
|
||||
event Func<Exception, Task> OnError;
|
||||
/// <summary>
|
||||
/// Websocket opened event
|
||||
/// </summary>
|
||||
event Func<Task> OnOpen;
|
||||
/// <summary>
|
||||
/// Websocket has lost connection to the server and is attempting to reconnect
|
||||
/// </summary>
|
||||
event Func<Task> OnReconnecting;
|
||||
/// <summary>
|
||||
/// Websocket has reconnected to the server
|
||||
/// </summary>
|
||||
event Func<Task> OnReconnected;
|
||||
/// <summary>
|
||||
/// Get reconnection url
|
||||
/// </summary>
|
||||
Func<Task<Uri?>>? GetReconnectionUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique id for this socket
|
||||
/// </summary>
|
||||
int Id { get; }
|
||||
/// <summary>
|
||||
/// The current kilobytes per second of data being received, averaged over the last 3 seconds
|
||||
/// </summary>
|
||||
double IncomingKbps { get; }
|
||||
/// <summary>
|
||||
/// The uri the socket connects to
|
||||
/// </summary>
|
||||
Uri Uri { get; }
|
||||
/// <summary>
|
||||
/// Whether the socket connection is closed
|
||||
/// </summary>
|
||||
bool IsClosed { get; }
|
||||
/// <summary>
|
||||
/// Whether the socket connection is open
|
||||
/// </summary>
|
||||
bool IsOpen { get; }
|
||||
/// <summary>
|
||||
/// Connect the socket
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<CallResult> ConnectAsync(CancellationToken ct);
|
||||
/// <summary>
|
||||
/// Send string data
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="weight"></param>
|
||||
bool Send(int id, string data, int weight);
|
||||
/// <summary>
|
||||
/// Send byte data
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="weight"></param>
|
||||
bool Send(int id, byte[] data, int weight);
|
||||
/// <summary>
|
||||
/// Reconnect the socket
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task ReconnectAsync();
|
||||
/// <summary>
|
||||
/// Close the connection
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task CloseAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Update proxy setting
|
||||
/// </summary>
|
||||
void UpdateProxy(ApiProxy? proxy);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using CryptoExchange.Net.Objects.Sockets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Websocket factory interface
|
||||
/// </summary>
|
||||
public interface IWebsocketFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a websocket for an url
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger</param>
|
||||
/// <param name="parameters">The parameters to use for the connection</param>
|
||||
/// <returns></returns>
|
||||
IWebsocket CreateWebsocket(ILogger logger, WebSocketParameters parameters);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user