mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-08 08:26:20 +00:00
Added DateTimeConverter as replacement for individual converters, fix for not closing socket when auth fails
This commit is contained in:
parent
7ac7a11dfe
commit
8b619e82f2
58
CryptoExchange.Net.UnitTests/ConverterTests.cs
Normal file
58
CryptoExchange.Net.UnitTests/ConverterTests.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using CryptoExchange.Net.Converters;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.UnitTests
|
||||||
|
{
|
||||||
|
[TestFixture()]
|
||||||
|
public class ConverterTests
|
||||||
|
{
|
||||||
|
[TestCase("2021-05-12")]
|
||||||
|
[TestCase("20210512")]
|
||||||
|
[TestCase("210512")]
|
||||||
|
[TestCase("1620777600.000")]
|
||||||
|
[TestCase("1620777600000")]
|
||||||
|
[TestCase("2021-05-12T00:00:00.000Z")]
|
||||||
|
public void TestDateTimeConverterString(string input)
|
||||||
|
{
|
||||||
|
var output = JsonConvert.DeserializeObject<TimeObject>($"{{ \"time\": \"{input}\" }}");
|
||||||
|
Assert.AreEqual(output.Time, new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(1620777600.000)]
|
||||||
|
[TestCase(1620777600000d)]
|
||||||
|
public void TestDateTimeConverterDouble(double input)
|
||||||
|
{
|
||||||
|
var output = JsonConvert.DeserializeObject<TimeObject>($"{{ \"time\": {input} }}");
|
||||||
|
Assert.AreEqual(output.Time, new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(1620777600)]
|
||||||
|
[TestCase(1620777600000)]
|
||||||
|
[TestCase(1620777600000000)]
|
||||||
|
[TestCase(1620777600000000000)]
|
||||||
|
public void TestDateTimeConverterLong(long input)
|
||||||
|
{
|
||||||
|
var output = JsonConvert.DeserializeObject<TimeObject>($"{{ \"time\": {input} }}");
|
||||||
|
Assert.AreEqual(output.Time, new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDateTimeConverterNull()
|
||||||
|
{
|
||||||
|
var output = JsonConvert.DeserializeObject<TimeObject>($"{{ \"time\": null }}");
|
||||||
|
Assert.AreEqual(output.Time, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TimeObject
|
||||||
|
{
|
||||||
|
[JsonConverter(typeof(DateTimeConverter))]
|
||||||
|
public DateTime? Time { get; set; }
|
||||||
|
}
|
||||||
|
}
|
132
CryptoExchange.Net/Converters/DateTimeConverter.cs
Normal file
132
CryptoExchange.Net/Converters/DateTimeConverter.cs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.Converters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Datetime converter
|
||||||
|
/// </summary>
|
||||||
|
public class DateTimeConverter: JsonConverter
|
||||||
|
{
|
||||||
|
private static DateTime _epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
private const decimal ticksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000;
|
||||||
|
private const decimal ticksPerNanosecond = TimeSpan.TicksPerMillisecond / 1000m / 1000;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return objectType == typeof(DateTime) || objectType == typeof(DateTime?);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.Value == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if(reader.TokenType is JsonToken.Integer)
|
||||||
|
{
|
||||||
|
var longValue = (long)reader.Value;
|
||||||
|
if (longValue < 1999999999)
|
||||||
|
return ConvertFromSeconds(longValue);
|
||||||
|
if (longValue < 1999999999999)
|
||||||
|
return ConvertFromMilliseconds(longValue);
|
||||||
|
if (longValue < 1999999999999999)
|
||||||
|
return ConvertFromMicroseconds(longValue);
|
||||||
|
|
||||||
|
return ConvertFromNanoseconds(longValue);
|
||||||
|
}
|
||||||
|
else if (reader.TokenType is JsonToken.Float)
|
||||||
|
{
|
||||||
|
var doubleValue = (double)reader.Value;
|
||||||
|
if (doubleValue < 1999999999)
|
||||||
|
return ConvertFromSeconds(doubleValue);
|
||||||
|
|
||||||
|
return ConvertFromMilliseconds(doubleValue);
|
||||||
|
}
|
||||||
|
else if(reader.TokenType is JsonToken.String)
|
||||||
|
{
|
||||||
|
var stringValue = (string)reader.Value;
|
||||||
|
if (stringValue.Length == 8)
|
||||||
|
{
|
||||||
|
// Parse 20211103 format
|
||||||
|
if (!int.TryParse(stringValue.Substring(0, 4), out var year)
|
||||||
|
|| !int.TryParse(stringValue.Substring(4, 2), out var month)
|
||||||
|
|| !int.TryParse(stringValue.Substring(6, 2), out var day))
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Unknown DateTime format: " + reader.Value);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
return new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stringValue.Length == 6)
|
||||||
|
{
|
||||||
|
// Parse 211103 format
|
||||||
|
if (!int.TryParse(stringValue.Substring(0, 2), out var year)
|
||||||
|
|| !int.TryParse(stringValue.Substring(2, 2), out var month)
|
||||||
|
|| !int.TryParse(stringValue.Substring(4, 2), out var day))
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Unknown DateTime format: " + reader.Value);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
return new DateTime(year + 2000, month, day, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (double.TryParse(stringValue, out var doubleValue))
|
||||||
|
{
|
||||||
|
// Parse 1637745563.000 format
|
||||||
|
if (doubleValue < 1999999999)
|
||||||
|
return ConvertFromSeconds(doubleValue);
|
||||||
|
return ConvertFromMilliseconds(doubleValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stringValue.Length == 10)
|
||||||
|
{
|
||||||
|
// Parse 2021-11-03 format
|
||||||
|
var values = stringValue.Split('-');
|
||||||
|
if(!int.TryParse(values[0], out var year)
|
||||||
|
|| !int.TryParse(values[1], out var month)
|
||||||
|
|| !int.TryParse(values[2], out var day))
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Unknown DateTime format: " + reader.Value);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DateTime(year, month, day, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonConvert.DeserializeObject(stringValue);
|
||||||
|
}
|
||||||
|
else if(reader.TokenType == JsonToken.Date)
|
||||||
|
{
|
||||||
|
return (DateTime)reader.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.WriteLine("Unknown DateTime format: " + reader.Value);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime ConvertFromSeconds(double seconds) => _epoch.AddSeconds(seconds);
|
||||||
|
public static DateTime ConvertFromMilliseconds(double milliseconds) => _epoch.AddMilliseconds(milliseconds);
|
||||||
|
public static DateTime ConvertFromMicroseconds(long microseconds) => _epoch.AddTicks((long)Math.Round(microseconds * ticksPerMicrosecond));
|
||||||
|
public static DateTime ConvertFromNanoseconds(long nanoseconds) => _epoch.AddTicks((long)Math.Round(nanoseconds * ticksPerNanosecond));
|
||||||
|
public static long ConvertToSeconds(DateTime time) => (long)Math.Round((time - _epoch).TotalSeconds);
|
||||||
|
public static long ConvertToMilliseconds(DateTime time) => (long)Math.Round((time - _epoch).TotalMilliseconds);
|
||||||
|
public static long ConvertToMicroseconds(DateTime time) => (long)Math.Round((time - _epoch).Ticks / ticksPerMicrosecond);
|
||||||
|
public static long ConvertToNanoseconds(DateTime time) => (long)Math.Round((time - _epoch).Ticks / ticksPerNanosecond);
|
||||||
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
writer.WriteValue((DateTime?)null);
|
||||||
|
else
|
||||||
|
writer.WriteValue((long)Math.Round(((DateTime)value - new DateTime(1970, 1, 1)).TotalMilliseconds));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.Converters
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converter for nanoseconds to datetime
|
||||||
|
/// </summary>
|
||||||
|
public class TimestampMicroSecondsConverter : JsonConverter
|
||||||
|
{
|
||||||
|
private const decimal ticksPerMicrosecond = TimeSpan.TicksPerMillisecond / 1000;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return objectType == typeof(DateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
if (reader.Value == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var nanoSeconds = long.Parse(reader.Value.ToString());
|
||||||
|
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddTicks((long)Math.Round(nanoSeconds * ticksPerMicrosecond));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
writer.WriteValue((long)Math.Round(((DateTime)value! - new DateTime(1970, 1, 1)).Ticks / ticksPerMicrosecond));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -78,10 +78,15 @@ namespace CryptoExchange.Net.Objects
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var newValue = value;
|
// TODO addresses can't always be forced to end with '/', bybit websocket doesn't work with it.
|
||||||
if (!newValue.EndsWith("/"))
|
// Should be fixed in the GetUrl methods?
|
||||||
newValue += "/";
|
|
||||||
_baseAddress = newValue;
|
//var newValue = value;
|
||||||
|
//if (!newValue.EndsWith("/"))
|
||||||
|
// newValue += "/";
|
||||||
|
//_baseAddress = newValue;
|
||||||
|
|
||||||
|
_baseAddress = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,6 +346,7 @@ namespace CryptoExchange.Net
|
|||||||
var result = await AuthenticateSocketAsync(socket).ConfigureAwait(false);
|
var result = await AuthenticateSocketAsync(socket).ConfigureAwait(false);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
|
await socket.CloseAsync().ConfigureAwait(false);
|
||||||
log.Write(LogLevel.Warning, $"Socket {socket.Socket.Id} 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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user