mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-07 16:06:15 +00:00
Performance improvements
This commit is contained in:
parent
db9fba4cf2
commit
e86713e949
@ -46,7 +46,7 @@ namespace CryptoExchange.Net.UnitTests
|
||||
{
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(data));
|
||||
var accessor = CreateAccessor();
|
||||
var valid = accessor.Read(stream, true);
|
||||
var valid = accessor.Read(stream, true).Result;
|
||||
if (!valid)
|
||||
return new CallResult<T>(new ServerError(data));
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace CryptoExchange.Net.Authentication
|
||||
public ApiCredentials(Stream inputStream, string? identifierKey = null, string? identifierSecret = null)
|
||||
{
|
||||
var accessor = new SystemTextJsonStreamMessageAccessor();
|
||||
if (!accessor.Read(inputStream, false))
|
||||
if (!accessor.Read(inputStream, false).Result)
|
||||
throw new ArgumentException("Input stream not valid json data");
|
||||
|
||||
var key = accessor.GetValue<string>(MessagePath.Get().Property(identifierKey ?? "apiKey"));
|
||||
|
@ -248,7 +248,7 @@ namespace CryptoExchange.Net.Authentication
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HMACSHA512 sign the data and return the hash
|
||||
/// HMACSHA256 sign the data and return the hash
|
||||
/// </summary>
|
||||
/// <param name="data">Data to sign</param>
|
||||
/// <param name="outputType">String type</param>
|
||||
@ -270,7 +270,7 @@ namespace CryptoExchange.Net.Authentication
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HMACSHA512 sign the data and return the hash
|
||||
/// HMACSHA384 sign the data and return the hash
|
||||
/// </summary>
|
||||
/// <param name="data">Data to sign</param>
|
||||
/// <param name="outputType">String type</param>
|
||||
|
@ -323,7 +323,7 @@ namespace CryptoExchange.Net.Clients
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
// Error response
|
||||
accessor.Read(responseStream, true);
|
||||
await accessor.Read(responseStream, true).ConfigureAwait(false);
|
||||
|
||||
Error error;
|
||||
if (response.StatusCode == (HttpStatusCode)418 || response.StatusCode == (HttpStatusCode)429)
|
||||
@ -341,7 +341,7 @@ namespace CryptoExchange.Net.Clients
|
||||
// Success status code and expected empty response, assume it's correct
|
||||
return new WebCallResult<T>(statusCode, headers, sw.Elapsed, 0, null, request.RequestId, request.Uri.ToString(), request.Content, request.Method, request.GetHeaders(), default, null);
|
||||
|
||||
var valid = accessor.Read(responseStream, outputOriginalData);
|
||||
var valid = await accessor.Read(responseStream, outputOriginalData).ConfigureAwait(false);
|
||||
if (!valid)
|
||||
{
|
||||
// Invalid json
|
||||
|
@ -7,7 +7,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.Converters.JsonNet
|
||||
{
|
||||
@ -222,26 +224,32 @@ namespace CryptoExchange.Net.Converters.JsonNet
|
||||
public override bool OriginalDataAvailable => _stream?.CanSeek == true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Read(Stream stream, bool bufferStream)
|
||||
public async Task<bool> Read(Stream stream, bool bufferStream)
|
||||
{
|
||||
if (bufferStream && stream is not MemoryStream)
|
||||
{
|
||||
// We need to be buffer the stream, and it's not currently a seekable stream, so copy it to a new memory stream
|
||||
_stream = new MemoryStream();
|
||||
stream.CopyTo(_stream);
|
||||
_stream.Position = 0;
|
||||
}
|
||||
else
|
||||
else if (bufferStream)
|
||||
{
|
||||
// We need to buffer the stream, and the current stream is seekable, store as is
|
||||
_stream = stream;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't need to buffer the stream, so don't bother keeping the reference
|
||||
}
|
||||
|
||||
var length = _stream.CanSeek ? _stream.Length : 4096;
|
||||
using var reader = new StreamReader(_stream, Encoding.UTF8, false, (int)Math.Max(2, length), true);
|
||||
var length = stream.CanSeek ? stream.Length : 4096;
|
||||
using var reader = new StreamReader(stream, Encoding.UTF8, false, (int)Math.Max(2, length), true);
|
||||
using var jsonTextReader = new JsonTextReader(reader);
|
||||
|
||||
try
|
||||
{
|
||||
_token = JToken.Load(jsonTextReader);
|
||||
_token = await JToken.LoadAsync(jsonTextReader).ConfigureAwait(false);
|
||||
IsJson = true;
|
||||
}
|
||||
catch (Exception)
|
||||
@ -284,8 +292,12 @@ namespace CryptoExchange.Net.Converters.JsonNet
|
||||
public bool Read(ReadOnlyMemory<byte> data)
|
||||
{
|
||||
_bytes = data;
|
||||
using var stream = new MemoryStream(data.ToArray());
|
||||
using var reader = new StreamReader(stream, Encoding.UTF8, false, (int)Math.Max(2, data.Length), true);
|
||||
|
||||
// Try getting the underlying byte[] instead of the ToArray to prevent creating a copy
|
||||
using var stream = MemoryMarshal.TryGetArray(data, out var arraySegment)
|
||||
? new MemoryStream(arraySegment.Array, arraySegment.Offset, arraySegment.Count)
|
||||
: new MemoryStream(data.ToArray());
|
||||
using var reader = new StreamReader(stream, Encoding.UTF8, false, Math.Max(2, data.Length), true);
|
||||
using var jsonTextReader = new JsonTextReader(reader);
|
||||
|
||||
try
|
||||
@ -303,7 +315,13 @@ namespace CryptoExchange.Net.Converters.JsonNet
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string GetOriginalString() => Encoding.UTF8.GetString(_bytes.ToArray());
|
||||
public override string GetOriginalString() =>
|
||||
// Netstandard 2.0 doesn't support GetString from a ReadonlySpan<byte>, so use ToArray there instead
|
||||
#if NETSTANDARD2_0
|
||||
Encoding.UTF8.GetString(_bytes.ToArray());
|
||||
#else
|
||||
Encoding.UTF8.GetString(_bytes.Span);
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OriginalDataAvailable => true;
|
||||
|
@ -192,9 +192,14 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
[return: NotNullIfNotNull("enumValue")]
|
||||
public static string? GetString<T>(T enumValue) => GetString(typeof(T), enumValue);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the string value for an enum value using the MapAttribute mapping. When multiple values are mapped for a enum entry the first value will be returned
|
||||
/// </summary>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="enumValue"></param>
|
||||
/// <returns></returns>
|
||||
[return: NotNullIfNotNull("enumValue")]
|
||||
private static string? GetString(Type objectType, object? enumValue)
|
||||
public static string? GetString(Type objectType, object? enumValue)
|
||||
{
|
||||
objectType = Nullable.GetUnderlyingType(objectType) ?? objectType;
|
||||
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
{
|
||||
@ -197,22 +198,28 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
public override bool OriginalDataAvailable => _stream?.CanSeek == true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Read(Stream stream, bool bufferStream)
|
||||
public async Task<bool> Read(Stream stream, bool bufferStream)
|
||||
{
|
||||
if (bufferStream && stream is not MemoryStream)
|
||||
{
|
||||
// We need to be buffer the stream, and it's not currently a seekable stream, so copy it to a new memory stream
|
||||
_stream = new MemoryStream();
|
||||
stream.CopyTo(_stream);
|
||||
_stream.Position = 0;
|
||||
}
|
||||
else if (bufferStream)
|
||||
{
|
||||
// We need to buffer the stream, and the current stream is seekable, store as is
|
||||
_stream = stream;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stream = stream;
|
||||
// We don't need to buffer the stream, so don't bother keeping the reference
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_document = JsonDocument.Parse(_stream);
|
||||
_document = await JsonDocument.ParseAsync(stream).ConfigureAwait(false);
|
||||
IsJson = true;
|
||||
}
|
||||
catch (Exception)
|
||||
@ -271,7 +278,13 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string GetOriginalString() => Encoding.UTF8.GetString(_bytes.ToArray());
|
||||
public override string GetOriginalString() =>
|
||||
// Netstandard 2.0 doesn't support GetString from a ReadonlySpan<byte>, so use ToArray there instead
|
||||
#if NETSTANDARD2_0
|
||||
Encoding.UTF8.GetString(_bytes.ToArray());
|
||||
#else
|
||||
Encoding.UTF8.GetString(_bytes.Span);
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OriginalDataAvailable => true;
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
@ -411,6 +413,22 @@ namespace CryptoExchange.Net
|
||||
|
||||
return ub.Uri;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decompress using Gzip
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static ReadOnlyMemory<byte> DecompressGzip(this ReadOnlyMemory<byte> data)
|
||||
{
|
||||
using var decompressedStream = new MemoryStream();
|
||||
using var dataStream = MemoryMarshal.TryGetArray(data, out var arraySegment)
|
||||
? new MemoryStream(arraySegment.Array, arraySegment.Offset, arraySegment.Count)
|
||||
: new MemoryStream(data.ToArray());
|
||||
using var deflateStream = new GZipStream(new MemoryStream(data.ToArray()), CompressionMode.Decompress);
|
||||
deflateStream.CopyTo(decompressedStream);
|
||||
return new ReadOnlyMemory<byte>(decompressedStream.GetBuffer(), 0, (int)decompressedStream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ using CryptoExchange.Net.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CryptoExchange.Net.Interfaces
|
||||
{
|
||||
@ -83,7 +84,7 @@ namespace CryptoExchange.Net.Interfaces
|
||||
/// </summary>
|
||||
/// <param name="stream"></param>
|
||||
/// <param name="bufferStream"></param>
|
||||
bool Read(Stream stream, bool bufferStream);
|
||||
Task<bool> Read(Stream stream, bool bufferStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -377,7 +377,8 @@ namespace CryptoExchange.Net.Sockets
|
||||
|
||||
// 2. Read data into accessor
|
||||
_accessor.Read(data);
|
||||
try {
|
||||
try
|
||||
{
|
||||
if (ApiClient.ApiOptions.OutputOriginalData ?? ApiClient.ClientOptions.OutputOriginalData)
|
||||
{
|
||||
originalData = _accessor.GetOriginalString();
|
||||
@ -400,7 +401,7 @@ namespace CryptoExchange.Net.Sockets
|
||||
lock (_listenersLock)
|
||||
processors = _listeners.Where(s => s.ListenerIdentifiers.Contains(listenId) && s.CanHandleData).ToList();
|
||||
|
||||
if (!processors.Any())
|
||||
if (processors.Count == 0)
|
||||
{
|
||||
if (!ApiClient.UnhandledMessageExpected)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user