mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-11 18:06:27 +00:00
wip
This commit is contained in:
parent
8ec902951d
commit
b2b5b0fef0
@ -23,7 +23,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
// arrange
|
// arrange
|
||||||
// act
|
// act
|
||||||
// assert
|
// assert
|
||||||
Assert.Throws(typeof(ArgumentException), () => new TestBaseClient(new RestClientOptions() { ApiCredentials = new ApiCredentials(key, secret) }));
|
Assert.Throws(typeof(ArgumentException), () => new TestBaseClient(new RestClientOptions("") { ApiCredentials = new ApiCredentials(key, secret) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase]
|
[TestCase]
|
||||||
@ -31,7 +31,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var stringBuilder = new StringBuilder();
|
var stringBuilder = new StringBuilder();
|
||||||
var client = new TestBaseClient(new RestClientOptions()
|
var client = new TestBaseClient(new RestClientOptions("")
|
||||||
{
|
{
|
||||||
LogWriters = new List<TextWriter> { new StringWriter(stringBuilder) }
|
LogWriters = new List<TextWriter> { new StringWriter(stringBuilder) }
|
||||||
});
|
});
|
||||||
@ -67,7 +67,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var stringBuilder = new StringBuilder();
|
var stringBuilder = new StringBuilder();
|
||||||
var client = new TestBaseClient(new RestClientOptions()
|
var client = new TestBaseClient(new RestClientOptions("")
|
||||||
{
|
{
|
||||||
LogWriters = new List<TextWriter> { new StringWriter(stringBuilder) },
|
LogWriters = new List<TextWriter> { new StringWriter(stringBuilder) },
|
||||||
LogVerbosity = verbosity
|
LogVerbosity = verbosity
|
||||||
|
@ -9,6 +9,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using CryptoExchange.Net.Interfaces;
|
using CryptoExchange.Net.Interfaces;
|
||||||
using CryptoExchange.Net.RateLimiter;
|
using CryptoExchange.Net.RateLimiter;
|
||||||
@ -105,7 +106,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
// act
|
// act
|
||||||
var client = new TestRestClient(new RestClientOptions()
|
var client = new TestRestClient(new RestClientOptions("")
|
||||||
{
|
{
|
||||||
BaseAddress = "http://test.address.com",
|
BaseAddress = "http://test.address.com",
|
||||||
RateLimiters = new List<IRateLimiter>{new RateLimiterTotal(1, TimeSpan.FromSeconds(1))},
|
RateLimiters = new List<IRateLimiter>{new RateLimiterTotal(1, TimeSpan.FromSeconds(1))},
|
||||||
@ -123,7 +124,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void SettingRateLimitingBehaviourToFail_Should_FailLimitedRequests()
|
public void SettingRateLimitingBehaviourToFail_Should_FailLimitedRequests()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestRestClient(new RestClientOptions()
|
var client = new TestRestClient(new RestClientOptions("")
|
||||||
{
|
{
|
||||||
RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) },
|
RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) },
|
||||||
RateLimitingBehaviour = RateLimitingBehaviour.Fail
|
RateLimitingBehaviour = RateLimitingBehaviour.Fail
|
||||||
@ -146,7 +147,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void SettingRateLimitingBehaviourToWait_Should_DelayLimitedRequests()
|
public void SettingRateLimitingBehaviourToWait_Should_DelayLimitedRequests()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestRestClient(new RestClientOptions()
|
var client = new TestRestClient(new RestClientOptions("")
|
||||||
{
|
{
|
||||||
RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) },
|
RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) },
|
||||||
RateLimitingBehaviour = RateLimitingBehaviour.Wait
|
RateLimitingBehaviour = RateLimitingBehaviour.Wait
|
||||||
@ -171,7 +172,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void SettingApiKeyRateLimiter_Should_DelayRequestsFromSameKey()
|
public void SettingApiKeyRateLimiter_Should_DelayRequestsFromSameKey()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestRestClient(new RestClientOptions()
|
var client = new TestRestClient(new RestClientOptions("")
|
||||||
{
|
{
|
||||||
RateLimiters = new List<IRateLimiter> { new RateLimiterAPIKey(1, TimeSpan.FromSeconds(1)) },
|
RateLimiters = new List<IRateLimiter> { new RateLimiterAPIKey(1, TimeSpan.FromSeconds(1)) },
|
||||||
RateLimitingBehaviour = RateLimitingBehaviour.Wait,
|
RateLimitingBehaviour = RateLimitingBehaviour.Wait,
|
||||||
|
@ -19,7 +19,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
//arrange
|
//arrange
|
||||||
//act
|
//act
|
||||||
var client = new TestSocketClient(new SocketClientOptions()
|
var client = new TestSocketClient(new SocketClientOptions("")
|
||||||
{
|
{
|
||||||
BaseAddress = "http://test.address.com",
|
BaseAddress = "http://test.address.com",
|
||||||
ReconnectInterval = TimeSpan.FromSeconds(6)
|
ReconnectInterval = TimeSpan.FromSeconds(6)
|
||||||
@ -51,7 +51,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void SocketMessages_Should_BeProcessedInDataHandlers()
|
public void SocketMessages_Should_BeProcessedInDataHandlers()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new SocketClientOptions() { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
var client = new TestSocketClient(new SocketClientOptions("") { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
||||||
var socket = client.CreateSocket();
|
var socket = client.CreateSocket();
|
||||||
socket.ShouldReconnect = true;
|
socket.ShouldReconnect = true;
|
||||||
socket.CanConnect = true;
|
socket.CanConnect = true;
|
||||||
@ -59,11 +59,11 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
var sub = new SocketConnection(client, socket);
|
var sub = new SocketConnection(client, socket);
|
||||||
var rstEvent = new ManualResetEvent(false);
|
var rstEvent = new ManualResetEvent(false);
|
||||||
JToken result = null;
|
JToken result = null;
|
||||||
sub.AddHandler("TestHandler", true, (connection, data) =>
|
sub.AddHandler(SocketSubscription.CreateForIdentifier("TestHandler", true, (connection, data) =>
|
||||||
{
|
{
|
||||||
result = data;
|
result = data;
|
||||||
rstEvent.Set();
|
rstEvent.Set();
|
||||||
});
|
}));
|
||||||
client.ConnectSocketSub(sub);
|
client.ConnectSocketSub(sub);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
@ -79,7 +79,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
bool reconnected = false;
|
bool reconnected = false;
|
||||||
var client = new TestSocketClient(new SocketClientOptions() { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
var client = new TestSocketClient(new SocketClientOptions("") { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
||||||
var socket = client.CreateSocket();
|
var socket = client.CreateSocket();
|
||||||
socket.ShouldReconnect = true;
|
socket.ShouldReconnect = true;
|
||||||
socket.CanConnect = true;
|
socket.CanConnect = true;
|
||||||
@ -106,12 +106,12 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void UnsubscribingStream_Should_CloseTheSocket()
|
public void UnsubscribingStream_Should_CloseTheSocket()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new SocketClientOptions() { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
var client = new TestSocketClient(new SocketClientOptions("") { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
||||||
var socket = client.CreateSocket();
|
var socket = client.CreateSocket();
|
||||||
socket.CanConnect = true;
|
socket.CanConnect = true;
|
||||||
var sub = new SocketConnection(client, socket);
|
var sub = new SocketConnection(client, socket);
|
||||||
client.ConnectSocketSub(sub);
|
client.ConnectSocketSub(sub);
|
||||||
var ups = new UpdateSubscription(sub, new SocketSubscription("Test", null, true, (d, a) => {}));
|
var ups = new UpdateSubscription(sub, SocketSubscription.CreateForIdentifier("Test", true, (d, a) => {}));
|
||||||
|
|
||||||
// act
|
// act
|
||||||
client.Unsubscribe(ups).Wait();
|
client.Unsubscribe(ups).Wait();
|
||||||
@ -124,7 +124,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void UnsubscribingAll_Should_CloseAllSockets()
|
public void UnsubscribingAll_Should_CloseAllSockets()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new SocketClientOptions() { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
var client = new TestSocketClient(new SocketClientOptions("") { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
||||||
var socket1 = client.CreateSocket();
|
var socket1 = client.CreateSocket();
|
||||||
var socket2 = client.CreateSocket();
|
var socket2 = client.CreateSocket();
|
||||||
socket1.CanConnect = true;
|
socket1.CanConnect = true;
|
||||||
@ -146,7 +146,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void FailingToConnectSocket_Should_ReturnError()
|
public void FailingToConnectSocket_Should_ReturnError()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new SocketClientOptions() { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
var client = new TestSocketClient(new SocketClientOptions("") { ReconnectInterval = TimeSpan.Zero, LogVerbosity = LogVerbosity.Debug });
|
||||||
var socket = client.CreateSocket();
|
var socket = client.CreateSocket();
|
||||||
socket.CanConnect = false;
|
socket.CanConnect = false;
|
||||||
var sub = new SocketConnection(client, socket);
|
var sub = new SocketConnection(client, socket);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
using CryptoExchange.Net.Logging;
|
using CryptoExchange.Net.Logging;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
@ -7,7 +8,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
public class TestBaseClient: BaseClient
|
public class TestBaseClient: BaseClient
|
||||||
{
|
{
|
||||||
public TestBaseClient(): base(new RestClientOptions(), null)
|
public TestBaseClient(): base(new RestClientOptions("http://testurl.url"), null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,12 +38,12 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Dictionary<string, string> AddAuthenticationToHeaders(string uri, string method, Dictionary<string, object> parameters, bool signed)
|
public override Dictionary<string, string> AddAuthenticationToHeaders(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed)
|
||||||
{
|
{
|
||||||
return base.AddAuthenticationToHeaders(uri, method, parameters, signed);
|
return base.AddAuthenticationToHeaders(uri, method, parameters, signed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Dictionary<string, object> AddAuthenticationToParameters(string uri, string method, Dictionary<string, object> parameters, bool signed)
|
public override Dictionary<string, object> AddAuthenticationToParameters(string uri, HttpMethod method, Dictionary<string, object> parameters, bool signed)
|
||||||
{
|
{
|
||||||
return base.AddAuthenticationToParameters(uri, method, parameters, signed);
|
return base.AddAuthenticationToParameters(uri, method, parameters, signed);
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,10 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
|
|
||||||
@ -16,7 +18,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
{
|
{
|
||||||
public class TestRestClient: RestClient
|
public class TestRestClient: RestClient
|
||||||
{
|
{
|
||||||
public TestRestClient() : base(new RestClientOptions(), null)
|
public TestRestClient() : base(new RestClientOptions("http://testurl.url"), null)
|
||||||
{
|
{
|
||||||
RequestFactory = new Mock<IRequestFactory>().Object;
|
RequestFactory = new Mock<IRequestFactory>().Object;
|
||||||
}
|
}
|
||||||
@ -39,36 +41,28 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
responseStream.Seek(0, SeekOrigin.Begin);
|
responseStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
var response = new Mock<IResponse>();
|
var response = new Mock<IResponse>();
|
||||||
response.Setup(c => c.GetResponseStream()).Returns(responseStream);
|
response.Setup(c => c.IsSuccessStatusCode).Returns(true);
|
||||||
|
response.Setup(c => c.GetResponseStream()).Returns(Task.FromResult((Stream)responseStream));
|
||||||
|
|
||||||
var request = new Mock<IRequest>();
|
var request = new Mock<IRequest>();
|
||||||
request.Setup(c => c.Headers).Returns(new WebHeaderCollection());
|
|
||||||
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
|
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
|
||||||
request.Setup(c => c.GetRequestStream()).Returns(Task.FromResult(requestStream));
|
request.Setup(c => c.GetResponse(It.IsAny<CancellationToken>())).Returns(Task.FromResult(response.Object));
|
||||||
request.Setup(c => c.GetResponse()).Returns(Task.FromResult(response.Object));
|
|
||||||
|
|
||||||
var factory = Mock.Get(RequestFactory);
|
var factory = Mock.Get(RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<string>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<string>()))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetErrorWithoutResponse(HttpStatusCode code, string message)
|
public void SetErrorWithoutResponse(HttpStatusCode code, string message)
|
||||||
{
|
{
|
||||||
var we = new WebException();
|
var we = new HttpRequestException();
|
||||||
var r = new HttpWebResponse();
|
typeof(HttpRequestException).GetField("_message", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, message);
|
||||||
var re = new HttpResponseMessage();
|
|
||||||
|
|
||||||
typeof(HttpResponseMessage).GetField("_statusCode", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(re, code);
|
|
||||||
typeof(HttpWebResponse).GetField("_httpResponseMessage", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(r, re);
|
|
||||||
typeof(WebException).GetField("_message", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, message);
|
|
||||||
typeof(WebException).GetField("_response", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, r);
|
|
||||||
|
|
||||||
var request = new Mock<IRequest>();
|
var request = new Mock<IRequest>();
|
||||||
request.Setup(c => c.Headers).Returns(new WebHeaderCollection());
|
request.Setup(c => c.GetResponse(It.IsAny<CancellationToken>())).Throws(we);
|
||||||
request.Setup(c => c.GetResponse()).Throws(we);
|
|
||||||
|
|
||||||
var factory = Mock.Get(RequestFactory);
|
var factory = Mock.Get(RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<string>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<string>()))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,22 +73,22 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
responseStream.Write(expectedBytes, 0, expectedBytes.Length);
|
responseStream.Write(expectedBytes, 0, expectedBytes.Length);
|
||||||
responseStream.Seek(0, SeekOrigin.Begin);
|
responseStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
var r = new Mock<HttpWebResponse>();
|
var response = new Mock<IResponse>();
|
||||||
r.Setup(x => x.GetResponseStream()).Returns(responseStream);
|
response.Setup(c => c.IsSuccessStatusCode).Returns(false);
|
||||||
var we = new WebException("", null, WebExceptionStatus.Success, r.Object);
|
response.Setup(c => c.GetResponseStream()).Returns(Task.FromResult((Stream)responseStream));
|
||||||
|
|
||||||
var request = new Mock<IRequest>();
|
var request = new Mock<IRequest>();
|
||||||
request.Setup(c => c.Headers).Returns(new WebHeaderCollection());
|
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
|
||||||
request.Setup(c => c.GetResponse()).Throws(we);
|
request.Setup(c => c.GetResponse(It.IsAny<CancellationToken>())).Returns(Task.FromResult(response.Object));
|
||||||
|
|
||||||
var factory = Mock.Get(RequestFactory);
|
var factory = Mock.Get(RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<string>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<string>()))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CallResult<T>> Request<T>(string method = "GET") where T:class
|
public async Task<CallResult<T>> Request<T>(CancellationToken ct = default) where T:class
|
||||||
{
|
{
|
||||||
return await ExecuteRequest<T>(new Uri("http://www.test.com"), method);
|
return await SendRequest<T>(new Uri("http://www.test.com"), HttpMethod.Get, ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
{
|
{
|
||||||
public class TestSocketClient: SocketClient
|
public class TestSocketClient: SocketClient
|
||||||
{
|
{
|
||||||
public TestSocketClient() : this(new SocketClientOptions())
|
public TestSocketClient() : this(new SocketClientOptions("http://testurl.url"))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,32 +32,33 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
return ConnectSocket(sub).Result;
|
return ConnectSocket(sub).Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool HandleQueryResponse<T>(SocketConnection s, object request, JToken data, out CallResult<T> callResult)
|
protected internal override bool HandleQueryResponse<T>(SocketConnection s, object request, JToken data, out CallResult<T> callResult)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool HandleSubscriptionResponse(SocketConnection s, SocketSubscription subscription, object request, JToken message, out CallResult<object> callResult)
|
protected internal override bool HandleSubscriptionResponse(SocketConnection s, SocketSubscription subscription, object request, JToken message,
|
||||||
|
out CallResult<object> callResult)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool MessageMatchesHandler(JToken message, object request)
|
protected internal override bool MessageMatchesHandler(JToken message, object request)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool MessageMatchesHandler(JToken message, string identifier)
|
protected internal override bool MessageMatchesHandler(JToken message, string identifier)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task<CallResult<bool>> AuthenticateSocket(SocketConnection s)
|
protected internal override Task<CallResult<bool>> AuthenticateSocket(SocketConnection s)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task<bool> Unsubscribe(SocketConnection connection, SocketSubscription s)
|
protected internal override Task<bool> Unsubscribe(SocketConnection connection, SocketSubscription s)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
1
CryptoExchange.Net/AssemblyInfo.cs
Normal file
1
CryptoExchange.Net/AssemblyInfo.cs
Normal file
@ -0,0 +1 @@
|
|||||||
|
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("CryptoExchange.Net.UnitTests")]
|
210
CryptoExchange.Net/Attributes/NullableAttributes.cs
Normal file
210
CryptoExchange.Net/Attributes/NullableAttributes.cs
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#if !NETSTANDARD2_1
|
||||||
|
namespace System.Diagnostics.CodeAnalysis
|
||||||
|
{
|
||||||
|
using global::System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that <see langword="null"/> is allowed as an input even if the
|
||||||
|
/// corresponding type disallows it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(
|
||||||
|
AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property,
|
||||||
|
Inherited = false
|
||||||
|
)]
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class AllowNullAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AllowNullAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public AllowNullAttribute() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that <see langword="null"/> is disallowed as an input even if the
|
||||||
|
/// corresponding type allows it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(
|
||||||
|
AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property,
|
||||||
|
Inherited = false
|
||||||
|
)]
|
||||||
|
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class DisallowNullAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DisallowNullAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public DisallowNullAttribute() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that a method that will never return under any circumstance.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class DoesNotReturnAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DoesNotReturnAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public DoesNotReturnAttribute() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the method will not return if the associated <see cref="Boolean"/>
|
||||||
|
/// parameter is passed the specified value.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class DoesNotReturnIfAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <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>
|
||||||
|
public bool ParameterValue { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="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>
|
||||||
|
public DoesNotReturnIfAttribute(bool parameterValue)
|
||||||
|
{
|
||||||
|
ParameterValue = parameterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that an output may be <see langword="null"/> even if the
|
||||||
|
/// corresponding type disallows it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(
|
||||||
|
AttributeTargets.Field | AttributeTargets.Parameter |
|
||||||
|
AttributeTargets.Property | AttributeTargets.ReturnValue,
|
||||||
|
Inherited = false
|
||||||
|
)]
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class MaybeNullAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MaybeNullAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public MaybeNullAttribute() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that when a method returns <see cref="ReturnValue"/>,
|
||||||
|
/// the parameter may be <see langword="null"/> even if the corresponding type disallows it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class MaybeNullWhenAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the return value condition.
|
||||||
|
/// If the method returns this value, the associated parameter may be <see langword="null"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool ReturnValue { get; }
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
public MaybeNullWhenAttribute(bool returnValue)
|
||||||
|
{
|
||||||
|
ReturnValue = returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that an output is not <see langword="null"/> even if the
|
||||||
|
/// corresponding type allows it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(
|
||||||
|
AttributeTargets.Field | AttributeTargets.Parameter |
|
||||||
|
AttributeTargets.Property | AttributeTargets.ReturnValue,
|
||||||
|
Inherited = false
|
||||||
|
)]
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class NotNullAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="NotNullAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public NotNullAttribute() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that the output will be non-<see langword="null"/> if the
|
||||||
|
/// named parameter is non-<see langword="null"/>.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(
|
||||||
|
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue,
|
||||||
|
AllowMultiple = true,
|
||||||
|
Inherited = false
|
||||||
|
)]
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class NotNullIfNotNullAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <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>
|
||||||
|
public string ParameterName { get; }
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
public NotNullIfNotNullAttribute(string parameterName)
|
||||||
|
{
|
||||||
|
// .NET Core 3.0 doesn't throw an ArgumentNullException, even though this is
|
||||||
|
// tagged as non-null.
|
||||||
|
// Follow this behavior here.
|
||||||
|
ParameterName = parameterName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies that when a method returns <see cref="ReturnValue"/>,
|
||||||
|
/// the parameter will not be <see langword="null"/> even if the corresponding type allows it.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
|
||||||
|
[ExcludeFromCodeCoverage]
|
||||||
|
internal sealed class NotNullWhenAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the return value condition.
|
||||||
|
/// If the method returns this value, the associated parameter will not be <see langword="null"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool ReturnValue { get; }
|
||||||
|
|
||||||
|
/// <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>
|
||||||
|
public NotNullWhenAttribute(bool returnValue)
|
||||||
|
{
|
||||||
|
ReturnValue = returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
@ -10,6 +10,7 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CryptoExchange.Net
|
namespace CryptoExchange.Net
|
||||||
@ -22,7 +23,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The address of the client
|
/// The address of the client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BaseAddress { get; private set; }
|
public string BaseAddress { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The log object
|
/// The log object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -207,36 +208,39 @@ namespace CryptoExchange.Net
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var reader = new StreamReader(stream);
|
using var reader = new StreamReader(stream, Encoding.UTF8, false, 512, true);
|
||||||
using var jsonReader = new JsonTextReader(reader);
|
using var jsonReader = new JsonTextReader(reader);
|
||||||
return new CallResult<T>(serializer.Deserialize<T>(jsonReader), null);
|
return new CallResult<T>(serializer.Deserialize<T>(jsonReader), null);
|
||||||
}
|
}
|
||||||
catch (JsonReaderException jre)
|
catch (JsonReaderException jre)
|
||||||
{
|
{
|
||||||
|
if(stream.CanSeek)
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
var data = await ReadStream(stream).ConfigureAwait(false);
|
var data = await ReadStream(stream).ConfigureAwait(false);
|
||||||
var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}, data: {data}";
|
log.Write(LogVerbosity.Error, $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}, data: {data}");
|
||||||
log.Write(LogVerbosity.Error, info);
|
return new CallResult<T>(default, new DeserializeError(data));
|
||||||
return new CallResult<T>(default, new DeserializeError(info));
|
|
||||||
}
|
}
|
||||||
catch (JsonSerializationException jse)
|
catch (JsonSerializationException jse)
|
||||||
{
|
{
|
||||||
|
if (stream.CanSeek)
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
var data = await ReadStream(stream).ConfigureAwait(false);
|
var data = await ReadStream(stream).ConfigureAwait(false);
|
||||||
var info = $"Deserialize JsonSerializationException: {jse.Message}, data: {data}";
|
log.Write(LogVerbosity.Error, $"Deserialize JsonSerializationException: {jse.Message}, data: {data}");
|
||||||
log.Write(LogVerbosity.Error, info);
|
return new CallResult<T>(default, new DeserializeError(data));
|
||||||
return new CallResult<T>(default, new DeserializeError(info));
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
if (stream.CanSeek)
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
var data = await ReadStream(stream).ConfigureAwait(false);
|
var data = await ReadStream(stream).ConfigureAwait(false);
|
||||||
var info = $"Deserialize Unknown Exception: {ex.Message}, data: {data}";
|
log.Write(LogVerbosity.Error, $"Deserialize Unknown Exception: {ex.Message}, data: {data}");
|
||||||
log.Write(LogVerbosity.Error, info);
|
return new CallResult<T>(default, new DeserializeError(data));
|
||||||
return new CallResult<T>(default, new DeserializeError(info));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> ReadStream(Stream stream)
|
private async Task<string> ReadStream(Stream stream)
|
||||||
{
|
{
|
||||||
using var reader = new StreamReader(stream);
|
using var reader = new StreamReader(stream, Encoding.UTF8, false, 512, true);
|
||||||
return await reader.ReadToEndAsync().ConfigureAwait(false);
|
return await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
return objectType == typeof(T) || Nullable.GetUnderlyingType(objectType) == typeof(T);
|
return objectType == typeof(T) || Nullable.GetUnderlyingType(objectType) == typeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GetValue(string value, [NotNullWhen(false)]out T result)
|
private bool GetValue(string value, out T result)
|
||||||
{
|
{
|
||||||
var mapping = Mapping.FirstOrDefault(kv => kv.Value.Equals(value, StringComparison.InvariantCultureIgnoreCase));
|
var mapping = Mapping.FirstOrDefault(kv => kv.Value.Equals(value, StringComparison.InvariantCultureIgnoreCase));
|
||||||
if (!mapping.Equals(default(KeyValuePair<T, string>)))
|
if (!mapping.Equals(default(KeyValuePair<T, string>)))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PackageId>CryptoExchange.Net</PackageId>
|
<PackageId>CryptoExchange.Net</PackageId>
|
||||||
@ -8,12 +8,12 @@
|
|||||||
<PackageVersion>2.1.8</PackageVersion>
|
<PackageVersion>2.1.8</PackageVersion>
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
<PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl>
|
||||||
<PackageLicenseUrl>https://github.com/JKorf/CryptoExchange.Net/blob/master/LICENSE</PackageLicenseUrl>
|
|
||||||
<NeutralLanguage>en</NeutralLanguage>
|
<NeutralLanguage>en</NeutralLanguage>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<PackageReleaseNotes>2.1.8 - Added array serialization options for implementations</PackageReleaseNotes>
|
<PackageReleaseNotes>2.1.8 - Added array serialization options for implementations</PackageReleaseNotes>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<DocumentationFile>CryptoExchange.Net.xml</DocumentationFile>
|
<DocumentationFile>CryptoExchange.Net.xml</DocumentationFile>
|
||||||
|
@ -536,11 +536,6 @@
|
|||||||
Content
|
Content
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Headers">
|
|
||||||
<summary>
|
|
||||||
Headers
|
|
||||||
</summary>
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Method">
|
<member name="P:CryptoExchange.Net.Interfaces.IRequest.Method">
|
||||||
<summary>
|
<summary>
|
||||||
Method
|
Method
|
||||||
@ -564,6 +559,13 @@
|
|||||||
<param name="data"></param>
|
<param name="data"></param>
|
||||||
<param name="contentType"></param>
|
<param name="contentType"></param>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Interfaces.IRequest.AddHeader(System.String,System.String)">
|
||||||
|
<summary>
|
||||||
|
Add a header to the request
|
||||||
|
</summary>
|
||||||
|
<param name="key"></param>
|
||||||
|
<param name="value"></param>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IRequest.GetResponse(System.Threading.CancellationToken)">
|
<member name="M:CryptoExchange.Net.Interfaces.IRequest.GetResponse(System.Threading.CancellationToken)">
|
||||||
<summary>
|
<summary>
|
||||||
Get the response
|
Get the response
|
||||||
@ -663,13 +665,13 @@
|
|||||||
Removes all rate limiters from this client
|
Removes all rate limiters from this client
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IRestClient.Ping">
|
<member name="M:CryptoExchange.Net.Interfaces.IRestClient.Ping(System.Threading.CancellationToken)">
|
||||||
<summary>
|
<summary>
|
||||||
Ping to see if the server is reachable
|
Ping to see if the server is reachable
|
||||||
</summary>
|
</summary>
|
||||||
<returns>The roundtrip time of the ping request</returns>
|
<returns>The roundtrip time of the ping request</returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.IRestClient.PingAsync">
|
<member name="M:CryptoExchange.Net.Interfaces.IRestClient.PingAsync(System.Threading.CancellationToken)">
|
||||||
<summary>
|
<summary>
|
||||||
Ping to see if the server is reachable
|
Ping to see if the server is reachable
|
||||||
</summary>
|
</summary>
|
||||||
@ -700,6 +702,20 @@
|
|||||||
The base address of the API
|
The base address of the API
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Interfaces.ISocketClient.ResponseTimeout">
|
||||||
|
<inheritdoc cref="P:CryptoExchange.Net.Objects.SocketClientOptions.SocketResponseTimeout"/>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Interfaces.ISocketClient.SocketNoDataTimeout">
|
||||||
|
<inheritdoc cref="P:CryptoExchange.Net.Objects.SocketClientOptions.SocketNoDataTimeout"/>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Interfaces.ISocketClient.MaxSocketConnections">
|
||||||
|
<summary>
|
||||||
|
The max amount of concurrent socket connections
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Interfaces.ISocketClient.SocketCombineTarget">
|
||||||
|
<inheritdoc cref="P:CryptoExchange.Net.Objects.SocketClientOptions.SocketSubscriptionsCombineTarget"/>
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Interfaces.ISocketClient.Unsubscribe(CryptoExchange.Net.Sockets.UpdateSubscription)">
|
<member name="M:CryptoExchange.Net.Interfaces.ISocketClient.Unsubscribe(CryptoExchange.Net.Sockets.UpdateSubscription)">
|
||||||
<summary>
|
<summary>
|
||||||
Unsubscribe from a stream
|
Unsubscribe from a stream
|
||||||
@ -1135,6 +1151,12 @@
|
|||||||
<param name="data"></param>
|
<param name="data"></param>
|
||||||
<param name="error"></param>
|
<param name="error"></param>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.CallResult`1.op_Implicit(CryptoExchange.Net.Objects.CallResult{`0})~System.Boolean">
|
||||||
|
<summary>
|
||||||
|
Overwrite bool check so we can use if(callResult) instead of if(callResult.Success)
|
||||||
|
</summary>
|
||||||
|
<param name="obj"></param>
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.WebCallResult`1">
|
<member name="T:CryptoExchange.Net.Objects.WebCallResult`1">
|
||||||
<summary>
|
<summary>
|
||||||
The result of a request
|
The result of a request
|
||||||
@ -1306,12 +1328,18 @@
|
|||||||
The message for the error that occured
|
The message for the error that occured
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.Error.#ctor(System.Int32,System.String)">
|
<member name="P:CryptoExchange.Net.Objects.Error.Data">
|
||||||
|
<summary>
|
||||||
|
Optional data for the error
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Objects.Error.#ctor(System.Int32,System.String,System.Object)">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
</summary>
|
</summary>
|
||||||
<param name="code"></param>
|
<param name="code"></param>
|
||||||
<param name="message"></param>
|
<param name="message"></param>
|
||||||
|
<param name="data"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.Error.ToString">
|
<member name="M:CryptoExchange.Net.Objects.Error.ToString">
|
||||||
<summary>
|
<summary>
|
||||||
@ -1344,51 +1372,53 @@
|
|||||||
Error returned by the server
|
Error returned by the server
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.ServerError.#ctor(System.String)">
|
<member name="M:CryptoExchange.Net.Objects.ServerError.#ctor(System.String,System.Object)">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
</summary>
|
</summary>
|
||||||
<param name="message"></param>
|
<param name="message"></param>
|
||||||
|
<param name="data"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.ServerError.#ctor(System.Int32,System.String)">
|
<member name="M:CryptoExchange.Net.Objects.ServerError.#ctor(System.Int32,System.String,System.Object)">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
</summary>
|
</summary>
|
||||||
<param name="code"></param>
|
<param name="code"></param>
|
||||||
<param name="message"></param>
|
<param name="message"></param>
|
||||||
|
<param name="data"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.WebError">
|
<member name="T:CryptoExchange.Net.Objects.WebError">
|
||||||
<summary>
|
<summary>
|
||||||
Web error returned by the server
|
Web error returned by the server
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.WebError.#ctor(System.String)">
|
<member name="M:CryptoExchange.Net.Objects.WebError.#ctor(System.Object)">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
</summary>
|
</summary>
|
||||||
<param name="message"></param>
|
<param name="data"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.DeserializeError">
|
<member name="T:CryptoExchange.Net.Objects.DeserializeError">
|
||||||
<summary>
|
<summary>
|
||||||
Error while deserializing data
|
Error while deserializing data
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.DeserializeError.#ctor(System.String)">
|
<member name="M:CryptoExchange.Net.Objects.DeserializeError.#ctor(System.Object)">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
</summary>
|
</summary>
|
||||||
<param name="message"></param>
|
<param name="data">Deserializing data</param>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.UnknownError">
|
<member name="T:CryptoExchange.Net.Objects.UnknownError">
|
||||||
<summary>
|
<summary>
|
||||||
Unknown error
|
Unknown error
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Objects.UnknownError.#ctor(System.String)">
|
<member name="M:CryptoExchange.Net.Objects.UnknownError.#ctor(System.Object)">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
ctor
|
||||||
</summary>
|
</summary>
|
||||||
<param name="message"></param>
|
<param name="data">Error data</param>
|
||||||
</member>
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Objects.ArgumentError">
|
<member name="T:CryptoExchange.Net.Objects.ArgumentError">
|
||||||
<summary>
|
<summary>
|
||||||
@ -1665,6 +1695,11 @@
|
|||||||
The bid list
|
The bid list
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.OrderBook.SymbolOrderBook.Id">
|
||||||
|
<summary>
|
||||||
|
Order book implementation id
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="F:CryptoExchange.Net.OrderBook.SymbolOrderBook.log">
|
<member name="F:CryptoExchange.Net.OrderBook.SymbolOrderBook.log">
|
||||||
<summary>
|
<summary>
|
||||||
The log
|
The log
|
||||||
@ -1910,9 +1945,6 @@
|
|||||||
<param name="request"></param>
|
<param name="request"></param>
|
||||||
<param name="client"></param>
|
<param name="client"></param>
|
||||||
</member>
|
</member>
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.Headers">
|
|
||||||
<inheritdoc />
|
|
||||||
</member>
|
|
||||||
<member name="P:CryptoExchange.Net.Requests.Request.Content">
|
<member name="P:CryptoExchange.Net.Requests.Request.Content">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
@ -1928,6 +1960,9 @@
|
|||||||
<member name="M:CryptoExchange.Net.Requests.Request.SetContent(System.String,System.String)">
|
<member name="M:CryptoExchange.Net.Requests.Request.SetContent(System.String,System.String)">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Requests.Request.AddHeader(System.String,System.String)">
|
||||||
|
<inheritdoc />
|
||||||
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Requests.Request.SetContent(System.Byte[])">
|
<member name="M:CryptoExchange.Net.Requests.Request.SetContent(System.Byte[])">
|
||||||
<inheritdoc />
|
<inheritdoc />
|
||||||
</member>
|
</member>
|
||||||
@ -2034,13 +2069,13 @@
|
|||||||
Removes all rate limiters from this client
|
Removes all rate limiters from this client
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.Ping">
|
<member name="M:CryptoExchange.Net.RestClient.Ping(System.Threading.CancellationToken)">
|
||||||
<summary>
|
<summary>
|
||||||
Ping to see if the server is reachable
|
Ping to see if the server is reachable
|
||||||
</summary>
|
</summary>
|
||||||
<returns>The roundtrip time of the ping request</returns>
|
<returns>The roundtrip time of the ping request</returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.RestClient.PingAsync">
|
<member name="M:CryptoExchange.Net.RestClient.PingAsync(System.Threading.CancellationToken)">
|
||||||
<summary>
|
<summary>
|
||||||
Ping to see if the server is reachable
|
Ping to see if the server is reachable
|
||||||
</summary>
|
</summary>
|
||||||
@ -2380,6 +2415,187 @@
|
|||||||
Socket implementation
|
Socket implementation
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="F:CryptoExchange.Net.Sockets.BaseSocket.socket">
|
||||||
|
<summary>
|
||||||
|
Socket
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:CryptoExchange.Net.Sockets.BaseSocket.log">
|
||||||
|
<summary>
|
||||||
|
Log
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:CryptoExchange.Net.Sockets.BaseSocket.errorHandlers">
|
||||||
|
<summary>
|
||||||
|
Error handlers
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:CryptoExchange.Net.Sockets.BaseSocket.openHandlers">
|
||||||
|
<summary>
|
||||||
|
Open handlers
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:CryptoExchange.Net.Sockets.BaseSocket.closeHandlers">
|
||||||
|
<summary>
|
||||||
|
Close handlers
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="F:CryptoExchange.Net.Sockets.BaseSocket.messageHandlers">
|
||||||
|
<summary>
|
||||||
|
Message handlers
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.Id">
|
||||||
|
<summary>
|
||||||
|
Id
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.Reconnecting">
|
||||||
|
<summary>
|
||||||
|
If is reconnecting
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.Origin">
|
||||||
|
<summary>
|
||||||
|
Origin
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.Url">
|
||||||
|
<summary>
|
||||||
|
Url
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.IsClosed">
|
||||||
|
<summary>
|
||||||
|
Is closed
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.IsOpen">
|
||||||
|
<summary>
|
||||||
|
Is open
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.SSLProtocols">
|
||||||
|
<summary>
|
||||||
|
Protocols
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.DataInterpreterBytes">
|
||||||
|
<summary>
|
||||||
|
Interpreter for bytes
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.DataInterpreterString">
|
||||||
|
<summary>
|
||||||
|
Interpreter for strings
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.LastActionTime">
|
||||||
|
<summary>
|
||||||
|
Last action time
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.Timeout">
|
||||||
|
<summary>
|
||||||
|
Timeout
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="P:CryptoExchange.Net.Sockets.BaseSocket.SocketState">
|
||||||
|
<summary>
|
||||||
|
Socket state
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.#ctor(CryptoExchange.Net.Logging.Log,System.String)">
|
||||||
|
<summary>
|
||||||
|
ctor
|
||||||
|
</summary>
|
||||||
|
<param name="log"></param>
|
||||||
|
<param name="url"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.#ctor(CryptoExchange.Net.Logging.Log,System.String,System.Collections.Generic.IDictionary{System.String,System.String},System.Collections.Generic.IDictionary{System.String,System.String})">
|
||||||
|
<summary>
|
||||||
|
ctor
|
||||||
|
</summary>
|
||||||
|
<param name="log"></param>
|
||||||
|
<param name="url"></param>
|
||||||
|
<param name="cookies"></param>
|
||||||
|
<param name="headers"></param>
|
||||||
|
</member>
|
||||||
|
<member name="E:CryptoExchange.Net.Sockets.BaseSocket.OnClose">
|
||||||
|
<summary>
|
||||||
|
On close
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="E:CryptoExchange.Net.Sockets.BaseSocket.OnMessage">
|
||||||
|
<summary>
|
||||||
|
On message
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="E:CryptoExchange.Net.Sockets.BaseSocket.OnError">
|
||||||
|
<summary>
|
||||||
|
On error
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="E:CryptoExchange.Net.Sockets.BaseSocket.OnOpen">
|
||||||
|
<summary>
|
||||||
|
On open
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.Handle(System.Collections.Generic.List{System.Action})">
|
||||||
|
<summary>
|
||||||
|
Handle
|
||||||
|
</summary>
|
||||||
|
<param name="handlers"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.Handle``1(System.Collections.Generic.List{System.Action{``0}},``0)">
|
||||||
|
<summary>
|
||||||
|
Handle
|
||||||
|
</summary>
|
||||||
|
<typeparam name="T"></typeparam>
|
||||||
|
<param name="handlers"></param>
|
||||||
|
<param name="data"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.CheckTimeout">
|
||||||
|
<summary>
|
||||||
|
Checks if timed out
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.Close">
|
||||||
|
<summary>
|
||||||
|
Close socket
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.Reset">
|
||||||
|
<summary>
|
||||||
|
Reset socket
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.Send(System.String)">
|
||||||
|
<summary>
|
||||||
|
Send data
|
||||||
|
</summary>
|
||||||
|
<param name="data"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.Connect">
|
||||||
|
<summary>
|
||||||
|
Connect socket
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.SetProxy(System.String,System.Int32)">
|
||||||
|
<summary>
|
||||||
|
Set a proxy
|
||||||
|
</summary>
|
||||||
|
<param name="host"></param>
|
||||||
|
<param name="port"></param>
|
||||||
|
</member>
|
||||||
|
<member name="M:CryptoExchange.Net.Sockets.BaseSocket.Dispose">
|
||||||
|
<summary>
|
||||||
|
Dispose
|
||||||
|
</summary>
|
||||||
|
</member>
|
||||||
<member name="T:CryptoExchange.Net.Sockets.SocketConnection">
|
<member name="T:CryptoExchange.Net.Sockets.SocketConnection">
|
||||||
<summary>
|
<summary>
|
||||||
Socket connecting
|
Socket connecting
|
||||||
@ -2442,24 +2658,11 @@
|
|||||||
<param name="client">The socket client</param>
|
<param name="client">The socket client</param>
|
||||||
<param name="socket">The socket</param>
|
<param name="socket">The socket</param>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Sockets.SocketConnection.AddHandler(System.Object,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
<member name="M:CryptoExchange.Net.Sockets.SocketConnection.AddHandler(CryptoExchange.Net.Sockets.SocketSubscription)">
|
||||||
<summary>
|
<summary>
|
||||||
Add a handler
|
Add handler
|
||||||
</summary>
|
</summary>
|
||||||
<param name="request">The request object</param>
|
<param name="handler"></param>
|
||||||
<param name="userSubscription">If it is a user subscription or a generic handler</param>
|
|
||||||
<param name="dataHandler">The data handler</param>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
|
||||||
<member name="M:CryptoExchange.Net.Sockets.SocketConnection.AddHandler(System.String,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
|
||||||
<summary>
|
|
||||||
Add a handler
|
|
||||||
</summary>
|
|
||||||
<param name="identifier">The identifier of the handler</param>
|
|
||||||
<param name="userSubscription">If it is a user subscription or a generic handler</param>
|
|
||||||
<param name="dataHandler">The data handler</param>
|
|
||||||
<returns></returns>
|
|
||||||
<returns></returns>
|
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Sockets.SocketConnection.SendAndWait``1(``0,System.TimeSpan,System.Func{Newtonsoft.Json.Linq.JToken,System.Boolean})">
|
<member name="M:CryptoExchange.Net.Sockets.SocketConnection.SendAndWait``1(``0,System.TimeSpan,System.Func{Newtonsoft.Json.Linq.JToken,System.Boolean})">
|
||||||
<summary>
|
<summary>
|
||||||
@ -2538,21 +2741,23 @@
|
|||||||
If the subscription has been confirmed
|
If the subscription has been confirmed
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.#ctor(System.Object,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.CreateForRequest(System.Object,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
Create SocketSubscription for a request
|
||||||
</summary>
|
</summary>
|
||||||
<param name="request"></param>
|
<param name="request"></param>
|
||||||
<param name="userSubscription"></param>
|
<param name="userSubscription"></param>
|
||||||
<param name="dataHandler"></param>
|
<param name="dataHandler"></param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.#ctor(System.String,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.CreateForIdentifier(System.String,System.Boolean,System.Action{CryptoExchange.Net.Sockets.SocketConnection,Newtonsoft.Json.Linq.JToken})">
|
||||||
<summary>
|
<summary>
|
||||||
ctor
|
Create SocketSubscription for an identifier
|
||||||
</summary>
|
</summary>
|
||||||
<param name="identifier"></param>
|
<param name="identifier"></param>
|
||||||
<param name="userSubscription"></param>
|
<param name="userSubscription"></param>
|
||||||
<param name="dataHandler"></param>
|
<param name="dataHandler"></param>
|
||||||
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.InvokeExceptionHandler(System.Exception)">
|
<member name="M:CryptoExchange.Net.Sockets.SocketSubscription.InvokeExceptionHandler(System.Exception)">
|
||||||
<summary>
|
<summary>
|
||||||
|
@ -131,7 +131,7 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source"></param>
|
/// <param name="source"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static SecureString ToSecureString(this string source)
|
public static SecureString ToSecureString(this string source)
|
||||||
{
|
{
|
||||||
var secureString = new SecureString();
|
var secureString = new SecureString();
|
||||||
foreach (var c in source)
|
foreach (var c in source)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -20,10 +21,6 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
string? Content { get; }
|
string? Content { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Headers
|
|
||||||
/// </summary>
|
|
||||||
HttpRequestHeaders Headers { get; }
|
|
||||||
/// <summary>
|
|
||||||
/// Method
|
/// Method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
HttpMethod Method { get; set; }
|
HttpMethod Method { get; set; }
|
||||||
@ -42,6 +39,13 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
/// <param name="contentType"></param>
|
/// <param name="contentType"></param>
|
||||||
void SetContent(string data, string contentType);
|
void SetContent(string data, string contentType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a header to the request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
void AddHeader(string key, string value);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the response
|
/// Get the response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.RateLimiter;
|
using CryptoExchange.Net.RateLimiter;
|
||||||
@ -51,12 +52,12 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// Ping to see if the server is reachable
|
/// Ping to see if the server is reachable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The roundtrip time of the ping request</returns>
|
/// <returns>The roundtrip time of the ping request</returns>
|
||||||
CallResult<long> Ping();
|
CallResult<long> Ping(CancellationToken ct = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ping to see if the server is reachable
|
/// Ping to see if the server is reachable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The roundtrip time of the ping request</returns>
|
/// <returns>The roundtrip time of the ping request</returns>
|
||||||
Task<CallResult<long>> PingAsync();
|
Task<CallResult<long>> PingAsync(CancellationToken ct = default);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Sockets;
|
using CryptoExchange.Net.Sockets;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.Interfaces
|
namespace CryptoExchange.Net.Interfaces
|
||||||
@ -29,6 +30,20 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
string BaseAddress { get; }
|
string BaseAddress { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="SocketClientOptions.SocketResponseTimeout"/>
|
||||||
|
TimeSpan ResponseTimeout { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="SocketClientOptions.SocketNoDataTimeout"/>
|
||||||
|
TimeSpan SocketNoDataTimeout { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The max amount of concurrent socket connections
|
||||||
|
/// </summary>
|
||||||
|
int MaxSocketConnections { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="SocketClientOptions.SocketSubscriptionsCombineTarget"/>
|
||||||
|
int SocketCombineTarget { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unsubscribe from a stream
|
/// Unsubscribe from a stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -12,7 +12,7 @@ namespace CryptoExchange.Net.Logging
|
|||||||
private static readonly object openedFilesLock = new object();
|
private static readonly object openedFilesLock = new object();
|
||||||
private static readonly List<string> openedFiles = new List<string>();
|
private static readonly List<string> openedFiles = new List<string>();
|
||||||
|
|
||||||
private StreamWriter logWriter;
|
private readonly StreamWriter logWriter;
|
||||||
private readonly object writeLock;
|
private readonly object writeLock;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -40,7 +40,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
public static implicit operator bool(CallResult<T> obj)
|
public static implicit operator bool(CallResult<T> obj)
|
||||||
{
|
{
|
||||||
return !ReferenceEquals(obj, null) && obj.Success;
|
return obj?.Success == true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +67,9 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <param name="responseHeaders"></param>
|
/// <param name="responseHeaders"></param>
|
||||||
/// <param name="data"></param>
|
/// <param name="data"></param>
|
||||||
/// <param name="error"></param>
|
/// <param name="error"></param>
|
||||||
public WebCallResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, [AllowNull] T data, Error? error): base(data, error)
|
public WebCallResult(
|
||||||
|
HttpStatusCode? code,
|
||||||
|
IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, [AllowNull] T data, Error? error): base(data, error)
|
||||||
{
|
{
|
||||||
ResponseHeaders = responseHeaders;
|
ResponseHeaders = responseHeaders;
|
||||||
ResponseStatusCode = code;
|
ResponseStatusCode = code;
|
||||||
@ -80,7 +82,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static WebCallResult<T> CreateErrorResult(Error error)
|
public static WebCallResult<T> CreateErrorResult(Error error)
|
||||||
{
|
{
|
||||||
return new WebCallResult<T>(null, null, default, error);
|
return new WebCallResult<T>(null, null, default!, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -90,9 +92,9 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <param name="responseHeaders"></param>
|
/// <param name="responseHeaders"></param>
|
||||||
/// <param name="error"></param>
|
/// <param name="error"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static WebCallResult<T> CreateErrorResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>> responseHeaders, Error error)
|
public static WebCallResult<T> CreateErrorResult(HttpStatusCode? code, IEnumerable<KeyValuePair<string, IEnumerable<string>>>? responseHeaders, Error error)
|
||||||
{
|
{
|
||||||
return new WebCallResult<T>(code, responseHeaders, default, error);
|
return new WebCallResult<T>(code, responseHeaders, default!, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,15 +14,22 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Message { get; set; }
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optional data for the error
|
||||||
|
/// </summary>
|
||||||
|
public object? Data { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="code"></param>
|
/// <param name="code"></param>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
protected Error(int code, string message)
|
/// <param name="data"></param>
|
||||||
|
protected Error(int code, string message, object? data)
|
||||||
{
|
{
|
||||||
Code = code;
|
Code = code;
|
||||||
Message = message;
|
Message = message;
|
||||||
|
Data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -31,7 +38,7 @@
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{Code}: {Message}";
|
return $"{Code}: {Message} {Data}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +50,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CantConnectError() : base(1, "Can't connect to the server") { }
|
public CantConnectError() : base(1, "Can't connect to the server", null) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -54,7 +61,7 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public NoApiCredentialsError() : base(2, "No credentials provided for private endpoint") { }
|
public NoApiCredentialsError() : base(2, "No credentials provided for private endpoint", null) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -66,14 +73,16 @@
|
|||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
public ServerError(string message) : base(3, "Server error: " + message) { }
|
/// <param name="data"></param>
|
||||||
|
public ServerError(string message, object? data = null) : base(3, "Server error: " + message, data) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="code"></param>
|
/// <param name="code"></param>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
public ServerError(int code, string message) : base(code, message)
|
/// <param name="data"></param>
|
||||||
|
public ServerError(int code, string message, object? data = null) : base(code, message, data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,8 +95,8 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="data"></param>
|
||||||
public WebError(string message) : base(4, "Web error: " + message) { }
|
public WebError(object? data) : base(4, "Web error", data) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -98,8 +107,8 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="data">Deserializing data</param>
|
||||||
public DeserializeError(string message) : base(5, "Error deserializing data: " + message) { }
|
public DeserializeError(object? data) : base(5, "Error deserializing data", data) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -110,8 +119,8 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="data">Error data</param>
|
||||||
public UnknownError(string message) : base(6, "Unknown error occured " + message) { }
|
public UnknownError(object? data = null) : base(6, "Unknown error occured", data) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -123,7 +132,7 @@
|
|||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
public ArgumentError(string message) : base(7, "Invalid parameter: " + message) { }
|
public ArgumentError(string message) : base(7, "Invalid parameter: " + message, null) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -135,7 +144,7 @@
|
|||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
public RateLimitError(string message) : base(8, "Rate limit exceeded: " + message) { }
|
public RateLimitError(string message) : base(8, "Rate limit exceeded: " + message, null) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -146,6 +155,6 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CancellationRequestedError() : base(9, "Cancellation requested") { }
|
public CancellationRequestedError() : base(9, "Cancellation requested", null) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{base.ToString()}, RateLimitters: {RateLimiters.Count}, RateLimitBehaviour: {RateLimitingBehaviour}, RequestTimeout: {RequestTimeout.ToString("c")}";
|
return $"{base.ToString()}, RateLimiters: {RateLimiters.Count}, RateLimitBehaviour: {RateLimitingBehaviour}, RequestTimeout: {RequestTimeout:c}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{base.ToString()}, AutoReconnect: {AutoReconnect}, ReconnectInterval: {ReconnectInterval}, SocketResponseTimeout: {SocketResponseTimeout.ToString("c")}, SocketSubscriptionsCombineTarget: {SocketSubscriptionsCombineTarget}";
|
return $"{base.ToString()}, AutoReconnect: {AutoReconnect}, ReconnectInterval: {ReconnectInterval}, SocketResponseTimeout: {SocketResponseTimeout:c}, SocketSubscriptionsCombineTarget: {SocketSubscriptionsCombineTarget}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,11 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
private OrderBookStatus status;
|
private OrderBookStatus status;
|
||||||
private UpdateSubscription? subscription;
|
private UpdateSubscription? subscription;
|
||||||
private readonly bool sequencesAreConsecutive;
|
private readonly bool sequencesAreConsecutive;
|
||||||
private readonly string id;
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order book implementation id
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The log
|
/// The log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -54,7 +58,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
|
|
||||||
var old = status;
|
var old = status;
|
||||||
status = value;
|
status = value;
|
||||||
log.Write(LogVerbosity.Info, $"{id} order book {Symbol} status changed: {old} => {value}");
|
log.Write(LogVerbosity.Info, $"{Id} order book {Symbol} status changed: {old} => {value}");
|
||||||
OnStatusChange?.Invoke(old, status);
|
OnStatusChange?.Invoke(old, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,12 +150,12 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
protected SymbolOrderBook(string symbol, OrderBookOptions options)
|
protected SymbolOrderBook(string symbol, OrderBookOptions options)
|
||||||
{
|
{
|
||||||
if (symbol == null)
|
if (symbol == null)
|
||||||
throw new ArgumentNullException("symbol");
|
throw new ArgumentNullException(nameof(symbol));
|
||||||
|
|
||||||
if (options == null)
|
if (options == null)
|
||||||
throw new ArgumentNullException("options");
|
throw new ArgumentNullException(nameof(options));
|
||||||
|
|
||||||
id = options.OrderBookName;
|
Id = options.OrderBookName;
|
||||||
processBuffer = new List<ProcessBufferEntry>();
|
processBuffer = new List<ProcessBufferEntry>();
|
||||||
sequencesAreConsecutive = options.SequenceNumbersAreConsecutive;
|
sequencesAreConsecutive = options.SequenceNumbersAreConsecutive;
|
||||||
Symbol = symbol;
|
Symbol = symbol;
|
||||||
@ -191,7 +195,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
|
|
||||||
private void Reset()
|
private void Reset()
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Warning, $"{id} order book {Symbol} connection lost");
|
log.Write(LogVerbosity.Warning, $"{Id} order book {Symbol} connection lost");
|
||||||
Status = OrderBookStatus.Connecting;
|
Status = OrderBookStatus.Connecting;
|
||||||
processBuffer.Clear();
|
processBuffer.Clear();
|
||||||
bookSet = false;
|
bookSet = false;
|
||||||
@ -211,7 +215,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
success = resyncResult;
|
success = resyncResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Write(LogVerbosity.Info, $"{id} order book {Symbol} successfully resynchronized");
|
log.Write(LogVerbosity.Info, $"{Id} order book {Symbol} successfully resynchronized");
|
||||||
Status = OrderBookStatus.Synced;
|
Status = OrderBookStatus.Synced;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +282,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
bookSet = true;
|
bookSet = true;
|
||||||
LastOrderBookUpdate = DateTime.UtcNow;
|
LastOrderBookUpdate = DateTime.UtcNow;
|
||||||
OnOrderBookUpdate?.Invoke();
|
OnOrderBookUpdate?.Invoke();
|
||||||
log.Write(LogVerbosity.Debug, $"{id} order book {Symbol} data set: {BidCount} bids, {AskCount} asks");
|
log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} data set: {BidCount} bids, {AskCount} asks");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,12 +308,12 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
Entries = entries
|
Entries = entries
|
||||||
};
|
};
|
||||||
processBuffer.Add(entry);
|
processBuffer.Add(entry);
|
||||||
log.Write(LogVerbosity.Debug, $"{id} order book {Symbol} update before synced; buffering");
|
log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} update before synced; buffering");
|
||||||
}
|
}
|
||||||
else if (sequencesAreConsecutive && firstSequenceNumber > LastSequenceNumber + 1)
|
else if (sequencesAreConsecutive && firstSequenceNumber > LastSequenceNumber + 1)
|
||||||
{
|
{
|
||||||
// Out of sync
|
// Out of sync
|
||||||
log.Write(LogVerbosity.Warning, $"{id} order book {Symbol} out of sync, reconnecting");
|
log.Write(LogVerbosity.Warning, $"{Id} order book {Symbol} out of sync, reconnecting");
|
||||||
subscription!.Reconnect().Wait();
|
subscription!.Reconnect().Wait();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -320,7 +324,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
CheckProcessBuffer();
|
CheckProcessBuffer();
|
||||||
LastOrderBookUpdate = DateTime.UtcNow;
|
LastOrderBookUpdate = DateTime.UtcNow;
|
||||||
OnOrderBookUpdate?.Invoke();
|
OnOrderBookUpdate?.Invoke();
|
||||||
log.Write(LogVerbosity.Debug, $"{id} order book {Symbol} update: {entries.Count} entries processed");
|
log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} update: {entries.Count} entries processed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -11,7 +12,7 @@ namespace CryptoExchange.Net.Requests
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request object
|
/// Request object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class Request : IRequest
|
public class Request : IRequest
|
||||||
{
|
{
|
||||||
private readonly HttpRequestMessage request;
|
private readonly HttpRequestMessage request;
|
||||||
private readonly HttpClient httpClient;
|
private readonly HttpClient httpClient;
|
||||||
@ -26,10 +27,7 @@ namespace CryptoExchange.Net.Requests
|
|||||||
httpClient = client;
|
httpClient = client;
|
||||||
this.request = request;
|
this.request = request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public HttpRequestHeaders Headers => request.Headers;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? Content { get; private set; }
|
public string? Content { get; private set; }
|
||||||
|
|
||||||
@ -56,6 +54,12 @@ namespace CryptoExchange.Net.Requests
|
|||||||
request.Content = new StringContent(data, Encoding.UTF8, contentType);
|
request.Content = new StringContent(data, Encoding.UTF8, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void AddHeader(string key, string value)
|
||||||
|
{
|
||||||
|
request.Headers.Add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void SetContent(byte[] data)
|
public void SetContent(byte[] data)
|
||||||
{
|
{
|
||||||
|
@ -25,8 +25,7 @@ namespace CryptoExchange.Net.Requests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
httpClient = new HttpClient(handler);
|
httpClient = new HttpClient(handler) {Timeout = requestTimeout};
|
||||||
httpClient.Timeout = requestTimeout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
@ -46,11 +47,11 @@ namespace CryptoExchange.Net
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timeout for requests
|
/// Timeout for requests
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected TimeSpan RequestTimeout { get; private set; }
|
protected TimeSpan RequestTimeout { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rate limiting behaviour
|
/// Rate limiting behaviour
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RateLimitingBehaviour RateLimitBehaviour { get; private set; }
|
public RateLimitingBehaviour RateLimitBehaviour { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of ratelimitters
|
/// List of ratelimitters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -68,7 +69,7 @@ namespace CryptoExchange.Net
|
|||||||
protected RestClient(RestClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(exchangeOptions, authenticationProvider)
|
protected RestClient(RestClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(exchangeOptions, authenticationProvider)
|
||||||
{
|
{
|
||||||
if (exchangeOptions == null)
|
if (exchangeOptions == null)
|
||||||
throw new ArgumentNullException("Options");
|
throw new ArgumentNullException(nameof(exchangeOptions));
|
||||||
|
|
||||||
RequestTimeout = exchangeOptions.RequestTimeout;
|
RequestTimeout = exchangeOptions.RequestTimeout;
|
||||||
RequestFactory.Configure(exchangeOptions.RequestTimeout, exchangeOptions.Proxy);
|
RequestFactory.Configure(exchangeOptions.RequestTimeout, exchangeOptions.Proxy);
|
||||||
@ -86,7 +87,7 @@ namespace CryptoExchange.Net
|
|||||||
public void AddRateLimiter(IRateLimiter limiter)
|
public void AddRateLimiter(IRateLimiter limiter)
|
||||||
{
|
{
|
||||||
if (limiter == null)
|
if (limiter == null)
|
||||||
throw new ArgumentNullException("limiter");
|
throw new ArgumentNullException(nameof(limiter));
|
||||||
|
|
||||||
var rateLimiters = RateLimiters.ToList();
|
var rateLimiters = RateLimiters.ToList();
|
||||||
rateLimiters.Add(limiter);
|
rateLimiters.Add(limiter);
|
||||||
@ -105,17 +106,19 @@ namespace CryptoExchange.Net
|
|||||||
/// Ping to see if the server is reachable
|
/// Ping to see if the server is reachable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The roundtrip time of the ping request</returns>
|
/// <returns>The roundtrip time of the ping request</returns>
|
||||||
public virtual CallResult<long> Ping() => PingAsync().Result;
|
public virtual CallResult<long> Ping(CancellationToken ct = default) => PingAsync(ct).Result;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ping to see if the server is reachable
|
/// Ping to see if the server is reachable
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The roundtrip time of the ping request</returns>
|
/// <returns>The roundtrip time of the ping request</returns>
|
||||||
public virtual async Task<CallResult<long>> PingAsync()
|
public virtual async Task<CallResult<long>> PingAsync(CancellationToken ct = default)
|
||||||
{
|
{
|
||||||
var ping = new Ping();
|
var ping = new Ping();
|
||||||
var uri = new Uri(BaseAddress);
|
var uri = new Uri(BaseAddress);
|
||||||
PingReply reply;
|
PingReply reply;
|
||||||
|
|
||||||
|
var ctRegistration = ct.Register(() => ping.SendAsyncCancel());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
reply = await ping.SendPingAsync(uri.Host).ConfigureAwait(false);
|
reply = await ping.SendPingAsync(uri.Host).ConfigureAwait(false);
|
||||||
@ -131,9 +134,13 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
ctRegistration.Dispose();
|
||||||
ping.Dispose();
|
ping.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ct.IsCancellationRequested)
|
||||||
|
return new CallResult<long>(0, new CancellationRequestedError());
|
||||||
|
|
||||||
return reply.Status == IPStatus.Success ? new CallResult<long>(reply.RoundtripTime, null) : new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + reply.Status });
|
return reply.Status == IPStatus.Success ? new CallResult<long>(reply.RoundtripTime, null) : new CallResult<long>(0, new CantConnectError { Message = "Ping failed: " + reply.Status });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +155,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="signed">Whether or not the request should be authenticated</param>
|
/// <param name="signed">Whether or not the request should be authenticated</param>
|
||||||
/// <param name="checkResult">Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug)</param>
|
/// <param name="checkResult">Whether or not the resulting object should be checked for missing properties in the mapping (only outputs if log verbosity is Debug)</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
[return: NotNull]
|
||||||
protected virtual async Task<WebCallResult<T>> SendRequest<T>(Uri uri, HttpMethod method, CancellationToken cancellationToken,
|
protected virtual async Task<WebCallResult<T>> SendRequest<T>(Uri uri, HttpMethod method, CancellationToken cancellationToken,
|
||||||
Dictionary<string, object>? parameters = null, bool signed = false, bool checkResult = true) where T : class
|
Dictionary<string, object>? parameters = null, bool signed = false, bool checkResult = true) where T : class
|
||||||
{
|
{
|
||||||
@ -198,13 +206,17 @@ namespace CryptoExchange.Net
|
|||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
var desResult = await Deserialize<T>(responseStream).ConfigureAwait(false);
|
var desResult = await Deserialize<T>(responseStream).ConfigureAwait(false);
|
||||||
|
responseStream.Close();
|
||||||
response.Close();
|
response.Close();
|
||||||
|
|
||||||
|
|
||||||
return new WebCallResult<T>(statusCode, headers, desResult.Data, desResult.Error);
|
return new WebCallResult<T>(statusCode, headers, desResult.Data, desResult.Error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using var reader = new StreamReader(responseStream);
|
using var reader = new StreamReader(responseStream);
|
||||||
var data = await reader.ReadToEndAsync().ConfigureAwait(false);
|
var data = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
|
responseStream.Close();
|
||||||
response.Close();
|
response.Close();
|
||||||
var parseResult = ValidateJson(data);
|
var parseResult = ValidateJson(data);
|
||||||
return new WebCallResult<T>(statusCode, headers, default, parseResult.Success ? ParseErrorResponse(parseResult.Data) :new ServerError(data));
|
return new WebCallResult<T>(statusCode, headers, default, parseResult.Success ? ParseErrorResponse(parseResult.Data) :new ServerError(data));
|
||||||
@ -261,7 +273,7 @@ namespace CryptoExchange.Net
|
|||||||
headers = authProvider.AddAuthenticationToHeaders(uriString, method, parameters!, signed);
|
headers = authProvider.AddAuthenticationToHeaders(uriString, method, parameters!, signed);
|
||||||
|
|
||||||
foreach (var header in headers)
|
foreach (var header in headers)
|
||||||
request.Headers.Add(header.Key, header.Value);
|
request.AddHeader(header.Key, header.Value);
|
||||||
|
|
||||||
if ((method == HttpMethod.Post || method == HttpMethod.Put) && postParametersPosition != PostParameters.InUri)
|
if ((method == HttpMethod.Post || method == HttpMethod.Put) && postParametersPosition != PostParameters.InUri)
|
||||||
{
|
{
|
||||||
@ -286,7 +298,6 @@ namespace CryptoExchange.Net
|
|||||||
{
|
{
|
||||||
var stringData = JsonConvert.SerializeObject(parameters.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value));
|
var stringData = JsonConvert.SerializeObject(parameters.OrderBy(p => p.Key).ToDictionary(p => p.Key, p => p.Value));
|
||||||
request.SetContent(stringData, contentType);
|
request.SetContent(stringData, contentType);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(requestBodyFormat == RequestBodyFormat.FormData)
|
else if(requestBodyFormat == RequestBodyFormat.FormData)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -33,13 +34,13 @@ namespace CryptoExchange.Net
|
|||||||
protected internal readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
|
protected internal readonly SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1);
|
||||||
|
|
||||||
/// <inheritdoc cref="SocketClientOptions.ReconnectInterval"/>
|
/// <inheritdoc cref="SocketClientOptions.ReconnectInterval"/>
|
||||||
public TimeSpan ReconnectInterval { get; private set; }
|
public TimeSpan ReconnectInterval { get; }
|
||||||
/// <inheritdoc cref="SocketClientOptions.AutoReconnect"/>
|
/// <inheritdoc cref="SocketClientOptions.AutoReconnect"/>
|
||||||
public bool AutoReconnect { get; private set; }
|
public bool AutoReconnect { get; }
|
||||||
/// <inheritdoc cref="SocketClientOptions.SocketResponseTimeout"/>
|
/// <inheritdoc cref="SocketClientOptions.SocketResponseTimeout"/>
|
||||||
public TimeSpan ResponseTimeout { get; private set; }
|
public TimeSpan ResponseTimeout { get; }
|
||||||
/// <inheritdoc cref="SocketClientOptions.SocketNoDataTimeout"/>
|
/// <inheritdoc cref="SocketClientOptions.SocketNoDataTimeout"/>
|
||||||
public TimeSpan SocketNoDataTimeout { get; private set; }
|
public TimeSpan SocketNoDataTimeout { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The max amount of concurrent socket connections
|
/// The max amount of concurrent socket connections
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -87,7 +88,7 @@ namespace CryptoExchange.Net
|
|||||||
protected SocketClient(SocketClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(exchangeOptions, authenticationProvider)
|
protected SocketClient(SocketClientOptions exchangeOptions, AuthenticationProvider? authenticationProvider): base(exchangeOptions, authenticationProvider)
|
||||||
{
|
{
|
||||||
if (exchangeOptions == null)
|
if (exchangeOptions == null)
|
||||||
throw new ArgumentNullException("Options");
|
throw new ArgumentNullException(nameof(exchangeOptions));
|
||||||
|
|
||||||
AutoReconnect = exchangeOptions.AutoReconnect;
|
AutoReconnect = exchangeOptions.AutoReconnect;
|
||||||
ReconnectInterval = exchangeOptions.ReconnectInterval;
|
ReconnectInterval = exchangeOptions.ReconnectInterval;
|
||||||
@ -101,7 +102,7 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="byteHandler">Handler for byte data</param>
|
/// <param name="byteHandler">Handler for byte data</param>
|
||||||
/// <param name="stringHandler">Handler for string data</param>
|
/// <param name="stringHandler">Handler for string data</param>
|
||||||
protected void SetDataInterpreter(Func<byte[], string> byteHandler, Func<string, string> stringHandler)
|
protected void SetDataInterpreter(Func<byte[], string>? byteHandler, Func<string, string>? stringHandler)
|
||||||
{
|
{
|
||||||
dataInterpreterBytes = byteHandler;
|
dataInterpreterBytes = byteHandler;
|
||||||
dataInterpreterString = stringHandler;
|
dataInterpreterString = stringHandler;
|
||||||
@ -116,7 +117,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="authenticated">If the subscription should be authenticated</param>
|
/// <param name="authenticated">If the subscription should be authenticated</param>
|
||||||
/// <param name="dataHandler">The handler of update data</param>
|
/// <param name="dataHandler">The handler of update data</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual Task<CallResult<UpdateSubscription>> Subscribe<T>(object request, string identifier, bool authenticated, Action<T> dataHandler)
|
protected virtual Task<CallResult<UpdateSubscription>> Subscribe<T>(object? request, string? identifier, bool authenticated, Action<T> dataHandler)
|
||||||
{
|
{
|
||||||
return Subscribe(BaseAddress, request, identifier, authenticated, dataHandler);
|
return Subscribe(BaseAddress, request, identifier, authenticated, dataHandler);
|
||||||
}
|
}
|
||||||
@ -171,8 +172,10 @@ namespace CryptoExchange.Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
handler.Confirmed = true;
|
handler.Confirmed = true;
|
||||||
|
}
|
||||||
|
|
||||||
socket.ShouldReconnect = true;
|
socket.ShouldReconnect = true;
|
||||||
return new CallResult<UpdateSubscription>(new UpdateSubscription(socket, handler), null);
|
return new CallResult<UpdateSubscription>(new UpdateSubscription(socket, handler), null);
|
||||||
}
|
}
|
||||||
@ -187,7 +190,7 @@ namespace CryptoExchange.Net
|
|||||||
protected internal virtual async Task<CallResult<bool>> SubscribeAndWait(SocketConnection socket, object request, SocketSubscription subscription)
|
protected internal virtual async Task<CallResult<bool>> SubscribeAndWait(SocketConnection socket, object request, SocketSubscription subscription)
|
||||||
{
|
{
|
||||||
CallResult<object>? callResult = null;
|
CallResult<object>? callResult = null;
|
||||||
await socket.SendAndWait(request, ResponseTimeout, data => HandleSubscriptionResponse(socket, subscription, request, data, out var callResult)).ConfigureAwait(false);
|
await socket.SendAndWait(request, ResponseTimeout, data => HandleSubscriptionResponse(socket, subscription, request, data, out callResult)).ConfigureAwait(false);
|
||||||
|
|
||||||
if (callResult?.Success == true)
|
if (callResult?.Success == true)
|
||||||
subscription.Confirmed = true;
|
subscription.Confirmed = true;
|
||||||
@ -312,7 +315,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="data">The message</param>
|
/// <param name="data">The message</param>
|
||||||
/// <param name="callResult">The interpretation (null if message wasn't a response to the request)</param>
|
/// <param name="callResult">The interpretation (null if message wasn't a response to the request)</param>
|
||||||
/// <returns>True if the message was a response to the query</returns>
|
/// <returns>True if the message was a response to the query</returns>
|
||||||
protected internal abstract bool HandleQueryResponse<T>(SocketConnection s, object request, JToken data, out CallResult<T> callResult);
|
protected internal abstract bool HandleQueryResponse<T>(SocketConnection s, object request, JToken data, [NotNullWhen(true)]out CallResult<T>? callResult);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Needs to check if a received message was an answer to a subscription request (preferable by id) and set the callResult out to whatever the response is
|
/// Needs to check if a received message was an answer to a subscription request (preferable by id) and set the callResult out to whatever the response is
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -322,7 +325,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="message">The message</param>
|
/// <param name="message">The message</param>
|
||||||
/// <param name="callResult">The interpretation (null if message wasn't a response to the request)</param>
|
/// <param name="callResult">The interpretation (null if message wasn't a response to the request)</param>
|
||||||
/// <returns>True if the message was a response to the subscription request</returns>
|
/// <returns>True if the message was a response to the subscription request</returns>
|
||||||
protected internal abstract bool HandleSubscriptionResponse(SocketConnection s, SocketSubscription subscription, object request, JToken message, out CallResult<object> callResult);
|
protected internal abstract bool HandleSubscriptionResponse(SocketConnection s, SocketSubscription subscription, object request, JToken message, out CallResult<object>? callResult);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Needs to check if a received message matches a handler. Typically if an update message matches the request
|
/// Needs to check if a received message matches a handler. Typically if an update message matches the request
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -391,7 +394,11 @@ namespace CryptoExchange.Net
|
|||||||
dataHandler(desResult.Data);
|
dataHandler(desResult.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return connection.AddHandler(request ?? identifier!, userSubscription, InternalHandler);
|
var handler = request == null
|
||||||
|
? SocketSubscription.CreateForIdentifier(identifier!, userSubscription, InternalHandler)
|
||||||
|
: SocketSubscription.CreateForRequest(request, userSubscription, InternalHandler);
|
||||||
|
connection.AddHandler(handler);
|
||||||
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -399,11 +406,12 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="identifier">The name of the request handler. Needs to be unique</param>
|
/// <param name="identifier">The name of the request handler. Needs to be unique</param>
|
||||||
/// <param name="action">The action to execute when receiving a message for this handler (checked by <see cref="MessageMatchesHandler(Newtonsoft.Json.Linq.JToken,string)"/>)</param>
|
/// <param name="action">The action to execute when receiving a message for this handler (checked by <see cref="MessageMatchesHandler(Newtonsoft.Json.Linq.JToken,string)"/>)</param>
|
||||||
protected virtual void AddGenericHandler(string identifier, Action<SocketConnection, JToken> action)
|
protected void AddGenericHandler(string identifier, Action<SocketConnection, JToken> action)
|
||||||
{
|
{
|
||||||
genericHandlers.Add(identifier, action);
|
genericHandlers.Add(identifier, action);
|
||||||
|
var handler = SocketSubscription.CreateForIdentifier(identifier, false, action);
|
||||||
foreach (var connection in sockets.Values)
|
foreach (var connection in sockets.Values)
|
||||||
connection.AddHandler(identifier, false, action);
|
connection.AddHandler(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -429,7 +437,11 @@ namespace CryptoExchange.Net
|
|||||||
var socket = CreateSocket(address);
|
var socket = CreateSocket(address);
|
||||||
var socketWrapper = new SocketConnection(this, socket);
|
var socketWrapper = new SocketConnection(this, socket);
|
||||||
foreach (var kvp in genericHandlers)
|
foreach (var kvp in genericHandlers)
|
||||||
socketWrapper.AddHandler(kvp.Key, false, kvp.Value);
|
{
|
||||||
|
var handler = SocketSubscription.CreateForIdentifier(kvp.Key, false, kvp.Value);
|
||||||
|
socketWrapper.AddHandler(handler);
|
||||||
|
}
|
||||||
|
|
||||||
return socketWrapper;
|
return socketWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +480,7 @@ namespace CryptoExchange.Net
|
|||||||
socket.DataInterpreterString = dataInterpreterString;
|
socket.DataInterpreterString = dataInterpreterString;
|
||||||
socket.OnError += e =>
|
socket.OnError += e =>
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Info, $"Socket {socket.Id} error: " + e.ToString());
|
log.Write(LogVerbosity.Info, $"Socket {socket.Id} error: " + e);
|
||||||
};
|
};
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
@ -481,7 +493,7 @@ namespace CryptoExchange.Net
|
|||||||
public virtual void SendPeriodic(TimeSpan interval, Func<SocketConnection, object> objGetter)
|
public virtual void SendPeriodic(TimeSpan interval, Func<SocketConnection, object> objGetter)
|
||||||
{
|
{
|
||||||
if (objGetter == null)
|
if (objGetter == null)
|
||||||
throw new ArgumentNullException("objGetter");
|
throw new ArgumentNullException(nameof(objGetter));
|
||||||
|
|
||||||
periodicEvent = new AutoResetEvent(false);
|
periodicEvent = new AutoResetEvent(false);
|
||||||
periodicTask = Task.Run(async () =>
|
periodicTask = Task.Run(async () =>
|
||||||
@ -526,7 +538,7 @@ namespace CryptoExchange.Net
|
|||||||
public virtual async Task Unsubscribe(UpdateSubscription subscription)
|
public virtual async Task Unsubscribe(UpdateSubscription subscription)
|
||||||
{
|
{
|
||||||
if (subscription == null)
|
if (subscription == null)
|
||||||
throw new ArgumentNullException("subscription");
|
throw new ArgumentNullException(nameof(subscription));
|
||||||
|
|
||||||
log.Write(LogVerbosity.Info, "Closing subscription");
|
log.Write(LogVerbosity.Info, "Closing subscription");
|
||||||
await subscription.Close().ConfigureAwait(false);
|
await subscription.Close().ConfigureAwait(false);
|
||||||
@ -538,7 +550,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual async Task UnsubscribeAll()
|
public virtual async Task UnsubscribeAll()
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Debug, $"Closing all {sockets.Sum(s => s.Value.handlers.Count(h => h.UserSubscription))} subscriptions");
|
log.Write(LogVerbosity.Debug, $"Closing all {sockets.Sum(s => s.Value.HandlerCount)} subscriptions");
|
||||||
|
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
@ -16,45 +16,111 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Socket implementation
|
/// Socket implementation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class BaseSocket: IWebsocket
|
public class BaseSocket: IWebsocket
|
||||||
{
|
{
|
||||||
internal static int lastStreamId;
|
internal static int lastStreamId;
|
||||||
private static readonly object streamIdLock = new object();
|
private static readonly object streamIdLock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Socket
|
||||||
|
/// </summary>
|
||||||
protected WebSocket? socket;
|
protected WebSocket? socket;
|
||||||
|
/// <summary>
|
||||||
|
/// Log
|
||||||
|
/// </summary>
|
||||||
protected Log log;
|
protected Log log;
|
||||||
protected object socketLock = new object();
|
private readonly object socketLock = new object();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Error handlers
|
||||||
|
/// </summary>
|
||||||
protected readonly List<Action<Exception>> errorHandlers = new List<Action<Exception>>();
|
protected readonly List<Action<Exception>> errorHandlers = new List<Action<Exception>>();
|
||||||
|
/// <summary>
|
||||||
|
/// Open handlers
|
||||||
|
/// </summary>
|
||||||
protected readonly List<Action> openHandlers = new List<Action>();
|
protected readonly List<Action> openHandlers = new List<Action>();
|
||||||
|
/// <summary>
|
||||||
|
/// Close handlers
|
||||||
|
/// </summary>
|
||||||
protected readonly List<Action> closeHandlers = new List<Action>();
|
protected readonly List<Action> closeHandlers = new List<Action>();
|
||||||
|
/// <summary>
|
||||||
|
/// Message handlers
|
||||||
|
/// </summary>
|
||||||
protected readonly List<Action<string>> messageHandlers = new List<Action<string>>();
|
protected readonly List<Action<string>> messageHandlers = new List<Action<string>>();
|
||||||
|
|
||||||
protected IDictionary<string, string> cookies;
|
private readonly IDictionary<string, string> cookies;
|
||||||
protected IDictionary<string, string> headers;
|
private readonly IDictionary<string, string> headers;
|
||||||
protected HttpConnectProxy? proxy;
|
private HttpConnectProxy? proxy;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
public int Id { get; }
|
public int Id { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// If is reconnecting
|
||||||
|
/// </summary>
|
||||||
public bool Reconnecting { get; set; }
|
public bool Reconnecting { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Origin
|
||||||
|
/// </summary>
|
||||||
public string? Origin { get; set; }
|
public string? Origin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Url
|
||||||
|
/// </summary>
|
||||||
public string Url { get; }
|
public string Url { get; }
|
||||||
public bool IsClosed => socket?.State == null ? true: socket.State == WebSocketState.Closed;
|
/// <summary>
|
||||||
|
/// Is closed
|
||||||
|
/// </summary>
|
||||||
|
public bool IsClosed => socket?.State == null || socket.State == WebSocketState.Closed;
|
||||||
|
/// <summary>
|
||||||
|
/// Is open
|
||||||
|
/// </summary>
|
||||||
public bool IsOpen => socket?.State == WebSocketState.Open;
|
public bool IsOpen => socket?.State == WebSocketState.Open;
|
||||||
|
/// <summary>
|
||||||
|
/// Protocols
|
||||||
|
/// </summary>
|
||||||
public SslProtocols SSLProtocols { get; set; } = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
|
public SslProtocols SSLProtocols { get; set; } = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
|
||||||
|
/// <summary>
|
||||||
|
/// Interpreter for bytes
|
||||||
|
/// </summary>
|
||||||
public Func<byte[], string>? DataInterpreterBytes { get; set; }
|
public Func<byte[], string>? DataInterpreterBytes { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Interpreter for strings
|
||||||
|
/// </summary>
|
||||||
public Func<string, string>? DataInterpreterString { get; set; }
|
public Func<string, string>? DataInterpreterString { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Last action time
|
||||||
|
/// </summary>
|
||||||
public DateTime LastActionTime { get; private set; }
|
public DateTime LastActionTime { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Timeout
|
||||||
|
/// </summary>
|
||||||
public TimeSpan Timeout { get; set; }
|
public TimeSpan Timeout { get; set; }
|
||||||
private Task? timeoutTask;
|
private Task? timeoutTask;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Socket state
|
||||||
|
/// </summary>
|
||||||
public WebSocketState SocketState => socket?.State ?? WebSocketState.None;
|
public WebSocketState SocketState => socket?.State ?? WebSocketState.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="log"></param>
|
||||||
|
/// <param name="url"></param>
|
||||||
public BaseSocket(Log log, string url):this(log, url, new Dictionary<string, string>(), new Dictionary<string, string>())
|
public BaseSocket(Log log, string url):this(log, url, new Dictionary<string, string>(), new Dictionary<string, string>())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="log"></param>
|
||||||
|
/// <param name="url"></param>
|
||||||
|
/// <param name="cookies"></param>
|
||||||
|
/// <param name="headers"></param>
|
||||||
public BaseSocket(Log log, string url, IDictionary<string, string> cookies, IDictionary<string, string> headers)
|
public BaseSocket(Log log, string url, IDictionary<string, string> cookies, IDictionary<string, string> headers)
|
||||||
{
|
{
|
||||||
Id = NextStreamId();
|
Id = NextStreamId();
|
||||||
@ -94,27 +160,43 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// On close
|
||||||
|
/// </summary>
|
||||||
public event Action OnClose
|
public event Action OnClose
|
||||||
{
|
{
|
||||||
add => closeHandlers.Add(value);
|
add => closeHandlers.Add(value);
|
||||||
remove => closeHandlers.Remove(value);
|
remove => closeHandlers.Remove(value);
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// On message
|
||||||
|
/// </summary>
|
||||||
public event Action<string> OnMessage
|
public event Action<string> OnMessage
|
||||||
{
|
{
|
||||||
add => messageHandlers.Add(value);
|
add => messageHandlers.Add(value);
|
||||||
remove => messageHandlers.Remove(value);
|
remove => messageHandlers.Remove(value);
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// On error
|
||||||
|
/// </summary>
|
||||||
public event Action<Exception> OnError
|
public event Action<Exception> OnError
|
||||||
{
|
{
|
||||||
add => errorHandlers.Add(value);
|
add => errorHandlers.Add(value);
|
||||||
remove => errorHandlers.Remove(value);
|
remove => errorHandlers.Remove(value);
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// On open
|
||||||
|
/// </summary>
|
||||||
public event Action OnOpen
|
public event Action OnOpen
|
||||||
{
|
{
|
||||||
add => openHandlers.Add(value);
|
add => openHandlers.Add(value);
|
||||||
remove => openHandlers.Remove(value);
|
remove => openHandlers.Remove(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handlers"></param>
|
||||||
protected void Handle(List<Action> handlers)
|
protected void Handle(List<Action> handlers)
|
||||||
{
|
{
|
||||||
LastActionTime = DateTime.UtcNow;
|
LastActionTime = DateTime.UtcNow;
|
||||||
@ -122,6 +204,12 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
handle?.Invoke();
|
handle?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="handlers"></param>
|
||||||
|
/// <param name="data"></param>
|
||||||
protected void Handle<T>(List<Action<T>> handlers, T data)
|
protected void Handle<T>(List<Action<T>> handlers, T data)
|
||||||
{
|
{
|
||||||
LastActionTime = DateTime.UtcNow;
|
LastActionTime = DateTime.UtcNow;
|
||||||
@ -129,6 +217,10 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
handle?.Invoke(data);
|
handle?.Invoke(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if timed out
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
protected async Task CheckTimeout()
|
protected async Task CheckTimeout()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
@ -150,6 +242,10 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Close socket
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public virtual async Task Close()
|
public virtual async Task Close()
|
||||||
{
|
{
|
||||||
await Task.Run(() =>
|
await Task.Run(() =>
|
||||||
@ -184,6 +280,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reset socket
|
||||||
|
/// </summary>
|
||||||
public virtual void Reset()
|
public virtual void Reset()
|
||||||
{
|
{
|
||||||
lock (socketLock)
|
lock (socketLock)
|
||||||
@ -194,11 +293,19 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
public virtual void Send(string data)
|
public virtual void Send(string data)
|
||||||
{
|
{
|
||||||
socket?.Send(data);
|
socket?.Send(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Connect socket
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public virtual Task<bool> Connect()
|
public virtual Task<bool> Connect()
|
||||||
{
|
{
|
||||||
if (socket == null)
|
if (socket == null)
|
||||||
@ -259,7 +366,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
timeoutTask = Task.Run(CheckTimeout);
|
timeoutTask = Task.Run(CheckTimeout);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
log?.Write(LogVerbosity.Debug, $"Socket {Id} connection failed, state: " + socket.State);
|
log?.Write(LogVerbosity.Debug, $"Socket {Id} connection failed, state: " + socket.State);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socket.State == WebSocketState.Connecting)
|
if (socket.State == WebSocketState.Connecting)
|
||||||
@ -269,6 +378,11 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set a proxy
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host"></param>
|
||||||
|
/// <param name="port"></param>
|
||||||
public virtual void SetProxy(string host, int port)
|
public virtual void SetProxy(string host, int port)
|
||||||
{
|
{
|
||||||
proxy = IPAddress.TryParse(host, out var address)
|
proxy = IPAddress.TryParse(host, out var address)
|
||||||
@ -276,6 +390,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
: new HttpConnectProxy(new DnsEndPoint(host, port));
|
: new HttpConnectProxy(new DnsEndPoint(host, port));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispose
|
||||||
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
lock (socketLock)
|
lock (socketLock)
|
||||||
|
@ -65,7 +65,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PausedActivity { get; set; }
|
public bool PausedActivity { get; set; }
|
||||||
|
|
||||||
internal readonly List<SocketSubscription> handlers;
|
private readonly List<SocketSubscription> handlers;
|
||||||
private readonly object handlersLock = new object();
|
private readonly object handlersLock = new object();
|
||||||
|
|
||||||
private bool lostTriggered;
|
private bool lostTriggered;
|
||||||
@ -109,38 +109,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
Connected = true;
|
Connected = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add a handler
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">The request object</param>
|
|
||||||
/// <param name="userSubscription">If it is a user subscription or a generic handler</param>
|
|
||||||
/// <param name="dataHandler">The data handler</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public SocketSubscription AddHandler(object request, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
|
||||||
{
|
|
||||||
var handler = new SocketSubscription(request, userSubscription, dataHandler);
|
|
||||||
lock (handlersLock)
|
|
||||||
handlers.Add(handler);
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add a handler
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="identifier">The identifier of the handler</param>
|
|
||||||
/// <param name="userSubscription">If it is a user subscription or a generic handler</param>
|
|
||||||
/// <param name="dataHandler">The data handler</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <returns></returns>
|
|
||||||
public SocketSubscription AddHandler(string identifier, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
|
||||||
{
|
|
||||||
var handler = new SocketSubscription(identifier, userSubscription, dataHandler);
|
|
||||||
lock (handlersLock)
|
|
||||||
handlers.Add(handler);
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessMessage(string data)
|
private void ProcessMessage(string data)
|
||||||
{
|
{
|
||||||
log.Write(LogVerbosity.Debug, $"Socket {Socket.Id} received data: " + data);
|
log.Write(LogVerbosity.Debug, $"Socket {Socket.Id} received data: " + data);
|
||||||
@ -167,6 +136,16 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add handler
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handler"></param>
|
||||||
|
public void AddHandler(SocketSubscription handler)
|
||||||
|
{
|
||||||
|
lock(handlersLock)
|
||||||
|
handlers.Add(handler);
|
||||||
|
}
|
||||||
|
|
||||||
private bool HandleData(JToken tokenData)
|
private bool HandleData(JToken tokenData)
|
||||||
{
|
{
|
||||||
SocketSubscription? currentSubscription = null;
|
SocketSubscription? currentSubscription = null;
|
||||||
|
@ -36,30 +36,38 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Confirmed { get; set; }
|
public bool Confirmed { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
private SocketSubscription(object? request, string? identifier, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
||||||
/// ctor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request"></param>
|
|
||||||
/// <param name="userSubscription"></param>
|
|
||||||
/// <param name="dataHandler"></param>
|
|
||||||
public SocketSubscription(object request, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
|
||||||
{
|
{
|
||||||
UserSubscription = userSubscription;
|
UserSubscription = userSubscription;
|
||||||
MessageHandler = dataHandler;
|
MessageHandler = dataHandler;
|
||||||
Request = request;
|
Request = request;
|
||||||
|
Identifier = identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// Create SocketSubscription for a request
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="userSubscription"></param>
|
||||||
|
/// <param name="dataHandler"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static SocketSubscription CreateForRequest(object request, bool userSubscription,
|
||||||
|
Action<SocketConnection, JToken> dataHandler)
|
||||||
|
{
|
||||||
|
return new SocketSubscription(request, null, userSubscription, dataHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create SocketSubscription for an identifier
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="identifier"></param>
|
/// <param name="identifier"></param>
|
||||||
/// <param name="userSubscription"></param>
|
/// <param name="userSubscription"></param>
|
||||||
/// <param name="dataHandler"></param>
|
/// <param name="dataHandler"></param>
|
||||||
public SocketSubscription(string identifier, bool userSubscription, Action<SocketConnection, JToken> dataHandler)
|
/// <returns></returns>
|
||||||
|
public static SocketSubscription CreateForIdentifier(string identifier, bool userSubscription,
|
||||||
|
Action<SocketConnection, JToken> dataHandler)
|
||||||
{
|
{
|
||||||
UserSubscription = userSubscription;
|
return new SocketSubscription(null, identifier, userSubscription, dataHandler);
|
||||||
MessageHandler = dataHandler;
|
|
||||||
Identifier = identifier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user