1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-08 08:26:20 +00:00

added incoming kbps property for sockets, updated logging

This commit is contained in:
Jkorf 2021-09-29 13:28:35 +02:00
parent 89de0da724
commit aa07029c21
8 changed files with 137 additions and 164 deletions

View File

@ -1353,6 +1353,11 @@
<member name="P:CryptoExchange.Net.Interfaces.ISocketClient.MaxConcurrentResubscriptionsPerSocket"> <member name="P:CryptoExchange.Net.Interfaces.ISocketClient.MaxConcurrentResubscriptionsPerSocket">
<inheritdoc cref="P:CryptoExchange.Net.Objects.SocketClientOptions.MaxConcurrentResubscriptionsPerSocket"/> <inheritdoc cref="P:CryptoExchange.Net.Objects.SocketClientOptions.MaxConcurrentResubscriptionsPerSocket"/>
</member> </member>
<member name="P:CryptoExchange.Net.Interfaces.ISocketClient.IncomingKbps">
<summary>
The current kilobytes per second of data being received by all connection from this client, averaged over the last 3 seconds
</summary>
</member>
<member name="M:CryptoExchange.Net.Interfaces.ISocketClient.UnsubscribeAsync(CryptoExchange.Net.Sockets.UpdateSubscription)"> <member name="M:CryptoExchange.Net.Interfaces.ISocketClient.UnsubscribeAsync(CryptoExchange.Net.Sockets.UpdateSubscription)">
<summary> <summary>
Unsubscribe from a stream Unsubscribe from a stream
@ -1548,6 +1553,11 @@
The max amount of outgoing messages per second The max amount of outgoing messages per second
</summary> </summary>
</member> </member>
<member name="P:CryptoExchange.Net.Interfaces.IWebsocket.IncomingKbps">
<summary>
The current kilobytes per second of data being received, averaged over the last 3 seconds
</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
@ -1843,6 +1853,14 @@
<param name="error"></param> <param name="error"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:CryptoExchange.Net.Objects.CallResult`1.As``1(``0)">
<summary>
Copy the WebCallResult to a new data type
</summary>
<typeparam name="K">The new type</typeparam>
<param name="data">The data of the new type</param>
<returns></returns>
</member>
<member name="T:CryptoExchange.Net.Objects.WebCallResult"> <member name="T:CryptoExchange.Net.Objects.WebCallResult">
<summary> <summary>
The result of a request The result of a request
@ -3129,6 +3147,11 @@
The max amount of outgoing messages per socket per second The max amount of outgoing messages per socket per second
</summary> </summary>
</member> </member>
<member name="P:CryptoExchange.Net.SocketClient.IncomingKbps">
<summary>
The current kilobytes per second of data being received by all connection from this client, averaged over the last 3 seconds
</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
@ -3454,6 +3477,11 @@
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
</summary> </summary>
</member> </member>
<member name="P:CryptoExchange.Net.Sockets.CryptoExchangeWebSocketClient.IncomingKbps">
<summary>
The current kilobytes per second of data being received, averaged over the last 3 seconds
</summary>
</member>
<member name="E:CryptoExchange.Net.Sockets.CryptoExchangeWebSocketClient.OnClose"> <member name="E:CryptoExchange.Net.Sockets.CryptoExchangeWebSocketClient.OnClose">
<summary> <summary>
Socket closed event Socket closed event
@ -3969,148 +3997,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>

View File

@ -49,6 +49,10 @@ namespace CryptoExchange.Net.Interfaces
int? MaxResubscribeTries { get; } int? MaxResubscribeTries { get; }
/// <inheritdoc cref="SocketClientOptions.MaxConcurrentResubscriptionsPerSocket"/> /// <inheritdoc cref="SocketClientOptions.MaxConcurrentResubscriptionsPerSocket"/>
int MaxConcurrentResubscriptionsPerSocket { get; } int MaxConcurrentResubscriptionsPerSocket { get; }
/// <summary>
/// The current kilobytes per second of data being received by all connection from this client, averaged over the last 3 seconds
/// </summary>
double IncomingKbps { get; }
/// <summary> /// <summary>
/// Unsubscribe from a stream /// Unsubscribe from a stream

View File

@ -47,7 +47,11 @@ namespace CryptoExchange.Net.Interfaces
/// <summary> /// <summary>
/// The max amount of outgoing messages per second /// The max amount of outgoing messages per second
/// </summary> /// </summary>
public int? RatelimitPerSecond { get; set; } int? RatelimitPerSecond { get; set; }
/// <summary>
/// The current kilobytes per second of data being received, averaged over the last 3 seconds
/// </summary>
double IncomingKbps { get; }
/// <summary> /// <summary>
/// Handler for byte data /// Handler for byte data
/// </summary> /// </summary>

View File

@ -120,6 +120,17 @@ namespace CryptoExchange.Net.Objects
{ {
return new WebCallResult<T>(null, null, default, error); return new WebCallResult<T>(null, null, default, error);
} }
/// <summary>
/// Copy the WebCallResult to a new data type
/// </summary>
/// <typeparam name="K">The new type</typeparam>
/// <param name="data">The data of the new type</param>
/// <returns></returns>
public CallResult<K> As<K>([AllowNull] K data)
{
return new CallResult<K>(data, Error);
}
} }
/// <summary> /// <summary>

View File

@ -447,7 +447,8 @@ namespace CryptoExchange.Net.OrderBook
if (asks.First().Key < bids.First().Key) if (asks.First().Key < bids.First().Key)
{ {
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} detected out of sync order book. Resyncing"); log.Write(LogLevel.Warning, $"{Id} order book {Symbol} detected out of sync order book. First ask: {asks.First().Key}, first bid: {bids.First().Key}. Resyncing");
_stopProcessing = true;
Resubscribe(); Resubscribe();
return; return;
} }
@ -636,6 +637,7 @@ namespace CryptoExchange.Net.OrderBook
{ {
// Out of sync // Out of sync
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} out of sync (expected { LastSequenceNumber + 1}, was {sequence}), reconnecting"); log.Write(LogLevel.Warning, $"{Id} order book {Symbol} out of sync (expected { LastSequenceNumber + 1}, was {sequence}), reconnecting");
_stopProcessing = true;
Resubscribe(); Resubscribe();
return false; return false;
} }

View File

@ -96,6 +96,20 @@ namespace CryptoExchange.Net
/// The max amount of outgoing messages per socket per second /// The max amount of outgoing messages per socket per second
/// </summary> /// </summary>
protected internal int? RateLimitPerSocketPerSecond { get; set; } protected internal int? RateLimitPerSocketPerSecond { get; set; }
/// <summary>
/// The current kilobytes per second of data being received by all connection from this client, averaged over the last 3 seconds
/// </summary>
public double IncomingKbps
{
get
{
if (!sockets.Any())
return 0;
return sockets.Sum(s => s.Value.Socket.IncomingKbps);
}
}
#endregion #endregion
/// <summary> /// <summary>
@ -193,7 +207,7 @@ namespace CryptoExchange.Net
if (socketConnection.PausedActivity) if (socketConnection.PausedActivity)
{ {
log.Write(LogLevel.Information, "Socket has been paused, can't subscribe at this moment"); log.Write(LogLevel.Information, $"Socket {socketConnection.Socket.Id} has been paused, can't subscribe at this moment");
return new CallResult<UpdateSubscription>(default, new ServerError("Socket is paused")); return new CallResult<UpdateSubscription>(default, new ServerError("Socket is paused"));
} }
@ -284,7 +298,7 @@ namespace CryptoExchange.Net
if (socketConnection.PausedActivity) if (socketConnection.PausedActivity)
{ {
log.Write(LogLevel.Information, "Socket has been paused, can't send query at this moment"); log.Write(LogLevel.Information, $"Socket {socketConnection.Socket.Id} has been paused, can't send query at this moment");
return new CallResult<T>(default, new ServerError("Socket is paused")); return new CallResult<T>(default, new ServerError("Socket is paused"));
} }
@ -334,7 +348,7 @@ namespace CryptoExchange.Net
var result = await AuthenticateSocketAsync(socket).ConfigureAwait(false); var result = await AuthenticateSocketAsync(socket).ConfigureAwait(false);
if (!result) if (!result)
{ {
log.Write(LogLevel.Warning, "Socket authentication failed"); log.Write(LogLevel.Warning, $"Socket {socket.Socket.Id} authentication failed");
result.Error!.Message = "Authentication failed: " + result.Error.Message; result.Error!.Message = "Authentication failed: " + result.Error.Message;
return new CallResult<bool>(false, result.Error); return new CallResult<bool>(false, result.Error);
} }
@ -435,7 +449,7 @@ namespace CryptoExchange.Net
var desResult = Deserialize<T>(messageEvent.JsonData, false); var desResult = Deserialize<T>(messageEvent.JsonData, false);
if (!desResult) if (!desResult)
{ {
log.Write(LogLevel.Warning, $"Failed to deserialize data into type {typeof(T)}: {desResult.Error}"); log.Write(LogLevel.Warning, $"Socket {connection.Socket.Id} Failed to deserialize data into type {typeof(T)}: {desResult.Error}");
return; return;
} }
@ -528,7 +542,7 @@ namespace CryptoExchange.Net
protected virtual IWebsocket CreateSocket(string address) protected virtual IWebsocket CreateSocket(string address)
{ {
var socket = SocketFactory.CreateWebsocket(log, address); var socket = SocketFactory.CreateWebsocket(log, address);
log.Write(LogLevel.Debug, "Created new socket for " + address); log.Write(LogLevel.Debug, $"Socket {socket.Id} new socket created for " + address);
if (apiProxy != null) if (apiProxy != null)
socket.SetProxy(apiProxy); socket.SetProxy(apiProxy);
@ -566,9 +580,6 @@ namespace CryptoExchange.Net
if (disposing) if (disposing)
break; break;
if (sockets.Any())
log.Write(LogLevel.Debug, "Sending periodic");
foreach (var socket in sockets.Values) foreach (var socket in sockets.Values)
{ {
if (disposing) if (disposing)
@ -578,13 +589,15 @@ namespace CryptoExchange.Net
if (obj == null) if (obj == null)
continue; continue;
log.Write(LogLevel.Trace, $"Socket {socket.Socket.Id} sending periodic");
try try
{ {
socket.Send(obj); socket.Send(obj);
} }
catch (Exception ex) catch (Exception ex)
{ {
log.Write(LogLevel.Warning, "Periodic send failed: " + ex); log.Write(LogLevel.Warning, $"Socket {socket.Socket.Id} Periodic send failed: " + ex);
} }
} }
} }

View File

@ -7,6 +7,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Security.Authentication; using System.Security.Authentication;
@ -36,7 +37,11 @@ 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;
private readonly List<DateTime> _outgoingMessages;
protected readonly Dictionary<DateTime, int> _receivedMessages;
private DateTime _lastReceivedMessagesUpdate;
protected readonly object _receivedMessagesLock;
/// <summary> /// <summary>
/// Log /// Log
@ -126,6 +131,25 @@ namespace CryptoExchange.Net.Sockets
/// </summary> /// </summary>
public TimeSpan Timeout { get; set; } public TimeSpan Timeout { get; set; }
/// <summary>
/// The current kilobytes per second of data being received, averaged over the last 3 seconds
/// </summary>
public double IncomingKbps
{
get
{
UpdateReceivedMessages();
lock (_receivedMessagesLock)
{
if (!_receivedMessages.Any())
return 0;
return Math.Round(_receivedMessages.Values.Sum(v => v) / 1000 / 3d);
}
}
}
/// <summary> /// <summary>
/// Socket closed event /// Socket closed event
/// </summary> /// </summary>
@ -183,10 +207,12 @@ namespace CryptoExchange.Net.Sockets
this.cookies = cookies; this.cookies = cookies;
this.headers = headers; this.headers = headers;
outgoingMessages = new List<DateTime>(); _outgoingMessages = new List<DateTime>();
_receivedMessages = new Dictionary<DateTime, int>();
_sendEvent = new AutoResetEvent(false); _sendEvent = new AutoResetEvent(false);
_sendBuffer = new ConcurrentQueue<byte[]>(); _sendBuffer = new ConcurrentQueue<byte[]>();
_ctsSource = new CancellationTokenSource(); _ctsSource = new CancellationTokenSource();
_receivedMessagesLock = new object();
_socket = CreateSocket(); _socket = CreateSocket();
} }
@ -244,7 +270,7 @@ namespace CryptoExchange.Net.Sockets
public virtual void Send(string data) public virtual void Send(string data)
{ {
if (_closing) if (_closing)
throw new InvalidOperationException("Can't send data when socket is not connected"); throw new InvalidOperationException($"Socket {Id} Can't send data when socket is not connected");
var bytes = _encoding.GetBytes(data); var bytes = _encoding.GetBytes(data);
log.Write(LogLevel.Trace, $"Socket {Id} Adding {bytes.Length} to sent buffer"); log.Write(LogLevel.Trace, $"Socket {Id} Adding {bytes.Length} to sent buffer");
@ -371,14 +397,14 @@ namespace CryptoExchange.Net.Sockets
} }
if (start != null) if (start != null)
log.Write(LogLevel.Trace, $"Websocket sent delayed {Math.Round((DateTime.UtcNow - start.Value).TotalMilliseconds)}ms because of rate limit"); log.Write(LogLevel.Trace, $"Socket {Id} sent delayed {Math.Round((DateTime.UtcNow - start.Value).TotalMilliseconds)}ms because of rate limit");
outgoingMessages.Add(DateTime.UtcNow);
} }
try try
{ {
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);
_outgoingMessages.Add(DateTime.UtcNow);
log.Write(LogLevel.Trace, $"Socket {Id} sent {data.Length} bytes");
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -427,6 +453,8 @@ namespace CryptoExchange.Net.Sockets
{ {
receiveResult = await _socket.ReceiveAsync(buffer, _ctsSource.Token).ConfigureAwait(false); receiveResult = await _socket.ReceiveAsync(buffer, _ctsSource.Token).ConfigureAwait(false);
received += receiveResult.Count; received += receiveResult.Count;
lock(_receivedMessagesLock)
_receivedMessages.Add(DateTime.UtcNow, receiveResult.Count);
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
@ -462,20 +490,30 @@ namespace CryptoExchange.Net.Sockets
multiPartMessage = true; multiPartMessage = true;
if (memoryStream == null) if (memoryStream == null)
memoryStream = new MemoryStream(); memoryStream = new MemoryStream();
log.Write(LogLevel.Trace, $"Socket {Id} received {receiveResult.Count} bytes in partial message");
await memoryStream.WriteAsync(buffer.Array, buffer.Offset, receiveResult.Count).ConfigureAwait(false); await memoryStream.WriteAsync(buffer.Array, buffer.Offset, receiveResult.Count).ConfigureAwait(false);
} }
else else
{ {
if (!multiPartMessage) if (!multiPartMessage)
{
// Received a complete message and it's not multi part // Received a complete message and it's not multi part
log.Write(LogLevel.Trace, $"Socket {Id} received {receiveResult.Count} bytes in single message");
HandleMessage(buffer.Array, buffer.Offset, receiveResult.Count, receiveResult.MessageType); HandleMessage(buffer.Array, buffer.Offset, receiveResult.Count, receiveResult.MessageType);
}
else else
{
// Received the end of a multipart message, write to memory stream for reassembling // Received the end of a multipart message, write to memory stream for reassembling
log.Write(LogLevel.Trace, $"Socket {Id} received {receiveResult.Count} bytes in partial message");
await memoryStream!.WriteAsync(buffer.Array, buffer.Offset, receiveResult.Count).ConfigureAwait(false); await memoryStream!.WriteAsync(buffer.Array, buffer.Offset, receiveResult.Count).ConfigureAwait(false);
}
break; break;
} }
} }
lock (_receivedMessagesLock)
UpdateReceivedMessages();
if (receiveResult?.MessageType == WebSocketMessageType.Close) if (receiveResult?.MessageType == WebSocketMessageType.Close)
{ {
// Received close message // Received close message
@ -491,6 +529,7 @@ namespace CryptoExchange.Net.Sockets
if (multiPartMessage) if (multiPartMessage)
{ {
// Reassemble complete message from memory stream // Reassemble complete message from memory stream
log.Write(LogLevel.Trace, $"Socket {Id} reassembled message of {memoryStream!.Length} bytes");
HandleMessage(memoryStream!.ToArray(), 0, (int)memoryStream.Length, receiveResult.MessageType); HandleMessage(memoryStream!.ToArray(), 0, (int)memoryStream.Length, receiveResult.MessageType);
memoryStream.Dispose(); memoryStream.Dispose();
} }
@ -514,7 +553,9 @@ namespace CryptoExchange.Net.Sockets
try try
{ {
strData = DataInterpreterBytes(data); var relevantData = new byte[count];
Array.Copy(data, offset, relevantData, 0, count);
strData = DataInterpreterBytes(relevantData);
} }
catch(Exception e) catch(Exception e)
{ {
@ -619,8 +660,21 @@ namespace CryptoExchange.Net.Sockets
private int MessagesSentLastSecond() private int MessagesSentLastSecond()
{ {
var testTime = DateTime.UtcNow; var testTime = DateTime.UtcNow;
outgoingMessages.RemoveAll(r => testTime - r > TimeSpan.FromSeconds(1)); _outgoingMessages.RemoveAll(r => testTime - r > TimeSpan.FromSeconds(1));
return outgoingMessages.Count; return _outgoingMessages.Count;
}
protected void UpdateReceivedMessages()
{
var checkTime = DateTime.UtcNow;
if (checkTime - _lastReceivedMessagesUpdate > TimeSpan.FromSeconds(1))
{
foreach (var msgTime in _receivedMessages.Keys)
if (checkTime - msgTime > TimeSpan.FromSeconds(3))
_receivedMessages.Remove(msgTime);
_lastReceivedMessagesUpdate = checkTime;
}
} }
} }
} }

View File

@ -97,7 +97,7 @@ namespace CryptoExchange.Net.Sockets
if (pausedActivity != value) if (pausedActivity != value)
{ {
pausedActivity = value; pausedActivity = value;
log.Write(LogLevel.Debug, "Paused activity: " + value); log.Write(LogLevel.Debug, $"Socket {Socket.Id} Paused activity: " + value);
if(pausedActivity) ActivityPaused?.Invoke(); if(pausedActivity) ActivityPaused?.Invoke();
else ActivityUnpaused?.Invoke(); else ActivityUnpaused?.Invoke();
} }