mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-08 16:36:15 +00:00
Added rate limit options for socket connections
This commit is contained in:
parent
76d5c1c299
commit
ab072cb2f9
@ -1513,6 +1513,11 @@
|
|||||||
Reconnecting
|
Reconnecting
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Interfaces.IWebsocket.RatelimitPerSecond">
|
||||||
|
<summary>
|
||||||
|
The max amount of outgoing messages per second
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IWebsocket.DataInterpreterBytes">
|
<member name="P:CryptoExchange.Net.Interfaces.IWebsocket.DataInterpreterBytes">
|
||||||
<summary>
|
<summary>
|
||||||
Handler for byte data
|
Handler for byte data
|
||||||
@ -3079,6 +3084,11 @@
|
|||||||
If a message is received on the socket which is not handled by a handler this boolean determines whether this logs an error message
|
If a message is received on the socket which is not handled by a handler this boolean determines whether this logs an error message
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.SocketClient.RateLimitPerSocketPerSecond">
|
||||||
|
<summary>
|
||||||
|
The max amount of outgoing messages per socket per second
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.SocketClient.#ctor(System.String,CryptoExchange.Net.Objects.SocketClientOptions,CryptoExchange.Net.Authentication.AuthenticationProvider)">
|
<member name="M:CryptoExchange.Net.SocketClient.#ctor(System.String,CryptoExchange.Net.Objects.SocketClientOptions,CryptoExchange.Net.Authentication.AuthenticationProvider)">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
@ -3387,6 +3397,11 @@
|
|||||||
Encoding used for decoding the received bytes into a string
|
Encoding used for decoding the received bytes into a string
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.CryptoExchangeWebSocketClient.RatelimitPerSecond">
|
||||||
|
<summary>
|
||||||
|
The max amount of outgoing messages per second
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Sockets.CryptoExchangeWebSocketClient.Timeout">
|
<member name="P:CryptoExchange.Net.Sockets.CryptoExchangeWebSocketClient.Timeout">
|
||||||
<summary>
|
<summary>
|
||||||
The timespan no data is received on the socket. If no data is received within this time an error is generated
|
The timespan no data is received on the socket. If no data is received within this time an error is generated
|
||||||
@ -3889,148 +3904,5 @@
|
|||||||
<member name="M:CryptoExchange.Net.Sockets.WebsocketFactory.CreateWebsocket(CryptoExchange.Net.Logging.Log,System.String,System.Collections.Generic.IDictionary{System.String,System.String},System.Collections.Generic.IDictionary{System.String,System.String})">
|
<member name="M:CryptoExchange.Net.Sockets.WebsocketFactory.CreateWebsocket(CryptoExchange.Net.Logging.Log,System.String,System.Collections.Generic.IDictionary{System.String,System.String},System.Collections.Generic.IDictionary{System.String,System.String})">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.AllowNullAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that <see langword="null"/> is allowed as an input even if the
|
|
||||||
corresponding type disallows it.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.AllowNullAttribute.#ctor">
|
|
||||||
<summary>
|
|
||||||
Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.AllowNullAttribute"/> class.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.DisallowNullAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that <see langword="null"/> is disallowed as an input even if the
|
|
||||||
corresponding type allows it.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.DisallowNullAttribute.#ctor">
|
|
||||||
<summary>
|
|
||||||
Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.DisallowNullAttribute"/> class.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that a method that will never return under any circumstance.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute.#ctor">
|
|
||||||
<summary>
|
|
||||||
Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute"/> class.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that the method will not return if the associated <see cref="T:System.Boolean"/>
|
|
||||||
parameter is passed the specified value.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute.ParameterValue">
|
|
||||||
<summary>
|
|
||||||
Gets the condition parameter value.
|
|
||||||
Code after the method is considered unreachable by diagnostics if the argument
|
|
||||||
to the associated parameter matches this value.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute.#ctor(System.Boolean)">
|
|
||||||
<summary>
|
|
||||||
Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute"/>
|
|
||||||
class with the specified parameter value.
|
|
||||||
</summary>
|
|
||||||
<param name="parameterValue">
|
|
||||||
The condition parameter value.
|
|
||||||
Code after the method is considered unreachable by diagnostics if the argument
|
|
||||||
to the associated parameter matches this value.
|
|
||||||
</param>
|
|
||||||
</member>
|
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.MaybeNullAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that an output may be <see langword="null"/> even if the
|
|
||||||
corresponding type disallows it.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.MaybeNullAttribute.#ctor">
|
|
||||||
<summary>
|
|
||||||
Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.MaybeNullAttribute"/> class.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that when a method returns <see cref="P:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute.ReturnValue"/>,
|
|
||||||
the parameter may be <see langword="null"/> even if the corresponding type disallows it.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute.ReturnValue">
|
|
||||||
<summary>
|
|
||||||
Gets the return value condition.
|
|
||||||
If the method returns this value, the associated parameter may be <see langword="null"/>.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute.#ctor(System.Boolean)">
|
|
||||||
<summary>
|
|
||||||
Initializes the attribute with the specified return value condition.
|
|
||||||
</summary>
|
|
||||||
<param name="returnValue">
|
|
||||||
The return value condition.
|
|
||||||
If the method returns this value, the associated parameter may be <see langword="null"/>.
|
|
||||||
</param>
|
|
||||||
</member>
|
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.NotNullAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that an output is not <see langword="null"/> even if the
|
|
||||||
corresponding type allows it.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.NotNullAttribute.#ctor">
|
|
||||||
<summary>
|
|
||||||
Initializes a new instance of the <see cref="T:System.Diagnostics.CodeAnalysis.NotNullAttribute"/> class.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that the output will be non-<see langword="null"/> if the
|
|
||||||
named parameter is non-<see langword="null"/>.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute.ParameterName">
|
|
||||||
<summary>
|
|
||||||
Gets the associated parameter name.
|
|
||||||
The output will be non-<see langword="null"/> if the argument to the
|
|
||||||
parameter specified is non-<see langword="null"/>.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute.#ctor(System.String)">
|
|
||||||
<summary>
|
|
||||||
Initializes the attribute with the associated parameter name.
|
|
||||||
</summary>
|
|
||||||
<param name="parameterName">
|
|
||||||
The associated parameter name.
|
|
||||||
The output will be non-<see langword="null"/> if the argument to the
|
|
||||||
parameter specified is non-<see langword="null"/>.
|
|
||||||
</param>
|
|
||||||
</member>
|
|
||||||
<member name="T:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute">
|
|
||||||
<summary>
|
|
||||||
Specifies that when a method returns <see cref="P:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute.ReturnValue"/>,
|
|
||||||
the parameter will not be <see langword="null"/> even if the corresponding type allows it.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute.ReturnValue">
|
|
||||||
<summary>
|
|
||||||
Gets the return value condition.
|
|
||||||
If the method returns this value, the associated parameter will not be <see langword="null"/>.
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="M:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute.#ctor(System.Boolean)">
|
|
||||||
<summary>
|
|
||||||
Initializes the attribute with the specified return value condition.
|
|
||||||
</summary>
|
|
||||||
<param name="returnValue">
|
|
||||||
The return value condition.
|
|
||||||
If the method returns this value, the associated parameter will not be <see langword="null"/>.
|
|
||||||
</param>
|
|
||||||
</member>
|
|
||||||
</members>
|
</members>
|
||||||
</doc>
|
</doc>
|
||||||
|
@ -45,6 +45,10 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
bool Reconnecting { get; set; }
|
bool Reconnecting { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The max amount of outgoing messages per second
|
||||||
|
/// </summary>
|
||||||
|
public int? RatelimitPerSecond { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// Handler for byte data
|
/// Handler for byte data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Func<byte[], string>? DataInterpreterBytes { get; set; }
|
Func<byte[], string>? DataInterpreterBytes { get; set; }
|
||||||
|
@ -91,6 +91,11 @@ namespace CryptoExchange.Net
|
|||||||
/// If a message is received on the socket which is not handled by a handler this boolean determines whether this logs an error message
|
/// If a message is received on the socket which is not handled by a handler this boolean determines whether this logs an error message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal bool UnhandledMessageExpected { get; set; }
|
protected internal bool UnhandledMessageExpected { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The max amount of outgoing messages per socket per second
|
||||||
|
/// </summary>
|
||||||
|
protected internal int? RateLimitPerSocketPerSecond { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -531,6 +536,7 @@ namespace CryptoExchange.Net
|
|||||||
socket.Timeout = SocketNoDataTimeout;
|
socket.Timeout = SocketNoDataTimeout;
|
||||||
socket.DataInterpreterBytes = dataInterpreterBytes;
|
socket.DataInterpreterBytes = dataInterpreterBytes;
|
||||||
socket.DataInterpreterString = dataInterpreterString;
|
socket.DataInterpreterString = dataInterpreterString;
|
||||||
|
socket.RatelimitPerSecond = RateLimitPerSocketPerSecond;
|
||||||
socket.OnError += e =>
|
socket.OnError += e =>
|
||||||
{
|
{
|
||||||
if(e is WebSocketException wse)
|
if(e is WebSocketException wse)
|
||||||
|
@ -36,6 +36,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
private bool _closing;
|
private bool _closing;
|
||||||
private bool _startedSent;
|
private bool _startedSent;
|
||||||
private bool _startedReceive;
|
private bool _startedReceive;
|
||||||
|
private readonly List<DateTime> outgoingMessages;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Log
|
/// Log
|
||||||
@ -115,6 +116,10 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
_encoding = value;
|
_encoding = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// The max amount of outgoing messages per second
|
||||||
|
/// </summary>
|
||||||
|
public int? RatelimitPerSecond { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The timespan no data is received on the socket. If no data is received within this time an error is generated
|
/// The timespan no data is received on the socket. If no data is received within this time an error is generated
|
||||||
@ -178,6 +183,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
this.cookies = cookies;
|
this.cookies = cookies;
|
||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
|
|
||||||
|
outgoingMessages = new List<DateTime>();
|
||||||
_sendEvent = new AutoResetEvent(false);
|
_sendEvent = new AutoResetEvent(false);
|
||||||
_sendBuffer = new ConcurrentQueue<byte[]>();
|
_sendBuffer = new ConcurrentQueue<byte[]>();
|
||||||
_ctsSource = new CancellationTokenSource();
|
_ctsSource = new CancellationTokenSource();
|
||||||
@ -353,9 +359,24 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
while (_sendBuffer.TryDequeue(out var data))
|
while (_sendBuffer.TryDequeue(out var data))
|
||||||
{
|
{
|
||||||
|
if(RatelimitPerSecond != null)
|
||||||
|
{
|
||||||
|
// Wait for rate limit
|
||||||
|
DateTime? start = null;
|
||||||
|
while (MessagesSentLastSecond() >= RatelimitPerSecond)
|
||||||
|
{
|
||||||
|
start = DateTime.UtcNow;
|
||||||
|
await Task.Delay(10).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start != null)
|
||||||
|
log.Write(LogLevel.Trace, $"Websocket sent delayed {Math.Round((DateTime.UtcNow - start.Value).TotalMilliseconds)}ms because of rate limit");
|
||||||
|
|
||||||
|
outgoingMessages.Add(DateTime.UtcNow);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
log.Write(LogLevel.Debug, "Sending " + Encoding.UTF8.GetString(data));
|
|
||||||
await _socket.SendAsync(new ArraySegment<byte>(data, 0, data.Length), WebSocketMessageType.Text, true, _ctsSource.Token).ConfigureAwait(false);
|
await _socket.SendAsync(new ArraySegment<byte>(data, 0, data.Length), WebSocketMessageType.Text, true, _ctsSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@ -579,5 +600,12 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
return lastStreamId;
|
return lastStreamId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int MessagesSentLastSecond()
|
||||||
|
{
|
||||||
|
var testTime = DateTime.UtcNow;
|
||||||
|
outgoingMessages.RemoveAll(r => testTime - r > TimeSpan.FromSeconds(1));
|
||||||
|
return outgoingMessages.Count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user