mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-06-07 16:06:15 +00:00
Updated tests
This commit is contained in:
parent
66ac2972d6
commit
3365837338
@ -16,7 +16,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var logger = new TestStringLogger();
|
var logger = new TestStringLogger();
|
||||||
var client = new TestBaseClient(new BaseRestClientOptions()
|
var client = new TestBaseClient(new TestOptions()
|
||||||
{
|
{
|
||||||
LogWriters = new List<ILogger> { logger }
|
LogWriters = new List<ILogger> { logger }
|
||||||
});
|
});
|
||||||
@ -56,7 +56,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var logger = new TestStringLogger();
|
var logger = new TestStringLogger();
|
||||||
var options = new BaseRestClientOptions()
|
var options = new TestOptions()
|
||||||
{
|
{
|
||||||
LogWriters = new List<ILogger> { logger }
|
LogWriters = new List<ILogger> { logger }
|
||||||
};
|
};
|
||||||
@ -78,7 +78,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
var client = new TestBaseClient();
|
var client = new TestBaseClient();
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var result = client.Deserialize<object>("{\"testProperty\": 123}");
|
var result = client.SubClient.Deserialize<object>("{\"testProperty\": 123}");
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsTrue(result.Success);
|
Assert.IsTrue(result.Success);
|
||||||
@ -91,7 +91,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
var client = new TestBaseClient();
|
var client = new TestBaseClient();
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var result = client.Deserialize<object>("{\"testProperty\": 123");
|
var result = client.SubClient.Deserialize<object>("{\"testProperty\": 123");
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsFalse(result.Success);
|
Assert.IsFalse(result.Success);
|
||||||
|
@ -248,7 +248,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestClientOptions: BaseRestClientOptions
|
public class TestClientOptions: ClientOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default options for the futures client
|
/// Default options for the futures client
|
||||||
|
@ -28,7 +28,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
client.SetResponse(JsonConvert.SerializeObject(expected), out _);
|
client.SetResponse(JsonConvert.SerializeObject(expected), out _);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var result = client.Request<TestObject>().Result;
|
var result = client.Api1.Request<TestObject>().Result;
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsTrue(result.Success);
|
Assert.IsTrue(result.Success);
|
||||||
@ -43,7 +43,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
client.SetResponse("{\"property\": 123", out _);
|
client.SetResponse("{\"property\": 123", out _);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var result = client.Request<TestObject>().Result;
|
var result = client.Api1.Request<TestObject>().Result;
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsFalse(result.Success);
|
Assert.IsFalse(result.Success);
|
||||||
@ -58,7 +58,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
client.SetErrorWithoutResponse(System.Net.HttpStatusCode.BadRequest, "Invalid request");
|
client.SetErrorWithoutResponse(System.Net.HttpStatusCode.BadRequest, "Invalid request");
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var result = await client.Request<TestObject>();
|
var result = await client.Api1.Request<TestObject>();
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsFalse(result.Success);
|
Assert.IsFalse(result.Success);
|
||||||
@ -73,7 +73,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
client.SetErrorWithResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest);
|
client.SetErrorWithResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var result = await client.Request<TestObject>();
|
var result = await client.Api1.Request<TestObject>();
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsFalse(result.Success);
|
Assert.IsFalse(result.Success);
|
||||||
@ -91,7 +91,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
client.SetErrorWithResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest);
|
client.SetErrorWithResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var result = await client.Request<TestObject>();
|
var result = await client.Api2.Request<TestObject>();
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsFalse(result.Success);
|
Assert.IsFalse(result.Success);
|
||||||
@ -112,9 +112,9 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
BaseAddress = "http://test.address.com",
|
BaseAddress = "http://test.address.com",
|
||||||
RateLimiters = new List<IRateLimiter> { new RateLimiter() },
|
RateLimiters = new List<IRateLimiter> { new RateLimiter() },
|
||||||
RateLimitingBehaviour = RateLimitingBehaviour.Fail
|
RateLimitingBehaviour = RateLimitingBehaviour.Fail,
|
||||||
},
|
RequestTimeout = TimeSpan.FromMinutes(1)
|
||||||
RequestTimeout = TimeSpan.FromMinutes(1)
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
Assert.IsTrue(((TestClientOptions)client.ClientOptions).Api1Options.BaseAddress == "http://test.address.com");
|
Assert.IsTrue(((TestClientOptions)client.ClientOptions).Api1Options.BaseAddress == "http://test.address.com");
|
||||||
Assert.IsTrue(((TestClientOptions)client.ClientOptions).Api1Options.RateLimiters.Count == 1);
|
Assert.IsTrue(((TestClientOptions)client.ClientOptions).Api1Options.RateLimiters.Count == 1);
|
||||||
Assert.IsTrue(((TestClientOptions)client.ClientOptions).Api1Options.RateLimitingBehaviour == RateLimitingBehaviour.Fail);
|
Assert.IsTrue(((TestClientOptions)client.ClientOptions).Api1Options.RateLimitingBehaviour == RateLimitingBehaviour.Fail);
|
||||||
Assert.IsTrue(client.ClientOptions.RequestTimeout == TimeSpan.FromMinutes(1));
|
Assert.IsTrue(((TestClientOptions)client.ClientOptions).Api1Options.RequestTimeout == TimeSpan.FromMinutes(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("GET", HttpMethodParameterPosition.InUri)] // No need to test InBody for GET since thats not valid
|
[TestCase("GET", HttpMethodParameterPosition.InUri)] // No need to test InBody for GET since thats not valid
|
||||||
@ -148,7 +148,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
|
|
||||||
client.SetResponse("{}", out var request);
|
client.SetResponse("{}", out var request);
|
||||||
|
|
||||||
await client.RequestWithParams<TestObject>(new HttpMethod(method), new Dictionary<string, object>
|
await client.Api1.RequestWithParams<TestObject>(new HttpMethod(method), new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ "TestParam1", "Value1" },
|
{ "TestParam1", "Value1" },
|
||||||
{ "TestParam2", 2 },
|
{ "TestParam2", 2 },
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using CryptoExchange.Net.Logging;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Sockets;
|
using CryptoExchange.Net.Sockets;
|
||||||
using CryptoExchange.Net.UnitTests.TestImplementations;
|
using CryptoExchange.Net.UnitTests.TestImplementations;
|
||||||
@ -19,17 +20,17 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
//act
|
//act
|
||||||
var client = new TestSocketClient(new TestOptions()
|
var client = new TestSocketClient(new TestOptions()
|
||||||
{
|
{
|
||||||
SubOptions = new RestApiClientOptions
|
SubOptions = new SocketApiClientOptions
|
||||||
{
|
{
|
||||||
BaseAddress = "http://test.address.com"
|
BaseAddress = "http://test.address.com",
|
||||||
},
|
ReconnectInterval = TimeSpan.FromSeconds(6)
|
||||||
ReconnectInterval = TimeSpan.FromSeconds(6)
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.IsTrue(client.SubClient.Options.BaseAddress == "http://test.address.com");
|
Assert.IsTrue(client.SubClient.Options.BaseAddress == "http://test.address.com");
|
||||||
Assert.IsTrue(client.ClientOptions.ReconnectInterval.TotalSeconds == 6);
|
Assert.IsTrue(client.SubClient.Options.ReconnectInterval.TotalSeconds == 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
@ -42,7 +43,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
socket.CanConnect = canConnect;
|
socket.CanConnect = canConnect;
|
||||||
|
|
||||||
//act
|
//act
|
||||||
var connectResult = client.ConnectSocketSub(new SocketConnection(client, null, socket, null));
|
var connectResult = client.SubClient.ConnectSocketSub(new SocketConnection(new Log(""), client.SubClient, socket, null));
|
||||||
|
|
||||||
//assert
|
//assert
|
||||||
Assert.IsTrue(connectResult.Success == canConnect);
|
Assert.IsTrue(connectResult.Success == canConnect);
|
||||||
@ -52,12 +53,18 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void SocketMessages_Should_BeProcessedInDataHandlers()
|
public void SocketMessages_Should_BeProcessedInDataHandlers()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new TestOptions() { ReconnectInterval = TimeSpan.Zero, LogLevel = LogLevel.Debug });
|
var client = new TestSocketClient(new TestOptions() {
|
||||||
|
SubOptions = new SocketApiClientOptions
|
||||||
|
{
|
||||||
|
ReconnectInterval = TimeSpan.Zero,
|
||||||
|
},
|
||||||
|
LogLevel = LogLevel.Debug
|
||||||
|
});
|
||||||
var socket = client.CreateSocket();
|
var socket = client.CreateSocket();
|
||||||
socket.ShouldReconnect = true;
|
socket.ShouldReconnect = true;
|
||||||
socket.CanConnect = true;
|
socket.CanConnect = true;
|
||||||
socket.DisconnectTime = DateTime.UtcNow;
|
socket.DisconnectTime = DateTime.UtcNow;
|
||||||
var sub = new SocketConnection(client, null, socket, null);
|
var sub = new SocketConnection(new Log(""), client.SubClient, socket, null);
|
||||||
var rstEvent = new ManualResetEvent(false);
|
var rstEvent = new ManualResetEvent(false);
|
||||||
JToken result = null;
|
JToken result = null;
|
||||||
sub.AddSubscription(SocketSubscription.CreateForIdentifier(10, "TestHandler", true, false, (messageEvent) =>
|
sub.AddSubscription(SocketSubscription.CreateForIdentifier(10, "TestHandler", true, false, (messageEvent) =>
|
||||||
@ -65,7 +72,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
result = messageEvent.JsonData;
|
result = messageEvent.JsonData;
|
||||||
rstEvent.Set();
|
rstEvent.Set();
|
||||||
}));
|
}));
|
||||||
client.ConnectSocketSub(sub);
|
client.SubClient.ConnectSocketSub(sub);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
socket.InvokeMessage("{\"property\": 123}");
|
socket.InvokeMessage("{\"property\": 123}");
|
||||||
@ -80,12 +87,19 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void SocketMessages_Should_ContainOriginalDataIfEnabled(bool enabled)
|
public void SocketMessages_Should_ContainOriginalDataIfEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new TestOptions() { ReconnectInterval = TimeSpan.Zero, LogLevel = LogLevel.Debug, OutputOriginalData = enabled });
|
var client = new TestSocketClient(new TestOptions() {
|
||||||
|
SubOptions = new SocketApiClientOptions
|
||||||
|
{
|
||||||
|
ReconnectInterval = TimeSpan.Zero,
|
||||||
|
OutputOriginalData = enabled
|
||||||
|
},
|
||||||
|
LogLevel = LogLevel.Debug,
|
||||||
|
});
|
||||||
var socket = client.CreateSocket();
|
var socket = client.CreateSocket();
|
||||||
socket.ShouldReconnect = true;
|
socket.ShouldReconnect = true;
|
||||||
socket.CanConnect = true;
|
socket.CanConnect = true;
|
||||||
socket.DisconnectTime = DateTime.UtcNow;
|
socket.DisconnectTime = DateTime.UtcNow;
|
||||||
var sub = new SocketConnection(client, null, socket, null);
|
var sub = new SocketConnection(new Log(""), client.SubClient, socket, null);
|
||||||
var rstEvent = new ManualResetEvent(false);
|
var rstEvent = new ManualResetEvent(false);
|
||||||
string original = null;
|
string original = null;
|
||||||
sub.AddSubscription(SocketSubscription.CreateForIdentifier(10, "TestHandler", true, false, (messageEvent) =>
|
sub.AddSubscription(SocketSubscription.CreateForIdentifier(10, "TestHandler", true, false, (messageEvent) =>
|
||||||
@ -93,7 +107,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
original = messageEvent.OriginalData;
|
original = messageEvent.OriginalData;
|
||||||
rstEvent.Set();
|
rstEvent.Set();
|
||||||
}));
|
}));
|
||||||
client.ConnectSocketSub(sub);
|
client.SubClient.ConnectSocketSub(sub);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
socket.InvokeMessage("{\"property\": 123}");
|
socket.InvokeMessage("{\"property\": 123}");
|
||||||
@ -107,11 +121,18 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void UnsubscribingStream_Should_CloseTheSocket()
|
public void UnsubscribingStream_Should_CloseTheSocket()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new TestOptions() { ReconnectInterval = TimeSpan.Zero, LogLevel = LogLevel.Debug });
|
var client = new TestSocketClient(new TestOptions()
|
||||||
|
{
|
||||||
|
SubOptions = new SocketApiClientOptions
|
||||||
|
{
|
||||||
|
ReconnectInterval = TimeSpan.Zero,
|
||||||
|
},
|
||||||
|
LogLevel = LogLevel.Debug
|
||||||
|
});
|
||||||
var socket = client.CreateSocket();
|
var socket = client.CreateSocket();
|
||||||
socket.CanConnect = true;
|
socket.CanConnect = true;
|
||||||
var sub = new SocketConnection(client, null, socket, null);
|
var sub = new SocketConnection(new Log(""), client.SubClient, socket, null);
|
||||||
client.ConnectSocketSub(sub);
|
client.SubClient.ConnectSocketSub(sub);
|
||||||
var us = SocketSubscription.CreateForIdentifier(10, "Test", true, false, (e) => { });
|
var us = SocketSubscription.CreateForIdentifier(10, "Test", true, false, (e) => { });
|
||||||
var ups = new UpdateSubscription(sub, us);
|
var ups = new UpdateSubscription(sub, us);
|
||||||
sub.AddSubscription(us);
|
sub.AddSubscription(us);
|
||||||
@ -127,15 +148,22 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void UnsubscribingAll_Should_CloseAllSockets()
|
public void UnsubscribingAll_Should_CloseAllSockets()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new TestOptions() { ReconnectInterval = TimeSpan.Zero, LogLevel = LogLevel.Debug });
|
var client = new TestSocketClient(new TestOptions()
|
||||||
|
{
|
||||||
|
SubOptions = new SocketApiClientOptions
|
||||||
|
{
|
||||||
|
ReconnectInterval = TimeSpan.Zero,
|
||||||
|
},
|
||||||
|
LogLevel = LogLevel.Debug
|
||||||
|
});
|
||||||
var socket1 = client.CreateSocket();
|
var socket1 = client.CreateSocket();
|
||||||
var socket2 = client.CreateSocket();
|
var socket2 = client.CreateSocket();
|
||||||
socket1.CanConnect = true;
|
socket1.CanConnect = true;
|
||||||
socket2.CanConnect = true;
|
socket2.CanConnect = true;
|
||||||
var sub1 = new SocketConnection(client, null, socket1, null);
|
var sub1 = new SocketConnection(new Log(""), client.SubClient, socket1, null);
|
||||||
var sub2 = new SocketConnection(client, null, socket2, null);
|
var sub2 = new SocketConnection(new Log(""), client.SubClient, socket2, null);
|
||||||
client.ConnectSocketSub(sub1);
|
client.SubClient.ConnectSocketSub(sub1);
|
||||||
client.ConnectSocketSub(sub2);
|
client.SubClient.ConnectSocketSub(sub2);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
client.UnsubscribeAllAsync().Wait();
|
client.UnsubscribeAllAsync().Wait();
|
||||||
@ -149,13 +177,20 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
public void FailingToConnectSocket_Should_ReturnError()
|
public void FailingToConnectSocket_Should_ReturnError()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var client = new TestSocketClient(new TestOptions() { ReconnectInterval = TimeSpan.Zero, LogLevel = LogLevel.Debug });
|
var client = new TestSocketClient(new TestOptions()
|
||||||
|
{
|
||||||
|
SubOptions = new SocketApiClientOptions
|
||||||
|
{
|
||||||
|
ReconnectInterval = TimeSpan.Zero,
|
||||||
|
},
|
||||||
|
LogLevel = LogLevel.Debug
|
||||||
|
});
|
||||||
var socket = client.CreateSocket();
|
var socket = client.CreateSocket();
|
||||||
socket.CanConnect = false;
|
socket.CanConnect = false;
|
||||||
var sub = new SocketConnection(client, null, socket, null);
|
var sub1 = new SocketConnection(new Log(""), client.SubClient, socket, null);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
var connectResult = client.ConnectSocketSub(sub);
|
var connectResult = client.SubClient.ConnectSocketSub(sub1);
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.IsFalse(connectResult.Success);
|
Assert.IsFalse(connectResult.Success);
|
||||||
|
@ -1,19 +1,25 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
|
using CryptoExchange.Net.Logging;
|
||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
|
using CryptoExchange.Net.UnitTests.TestImplementations;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.UnitTests
|
namespace CryptoExchange.Net.UnitTests
|
||||||
{
|
{
|
||||||
public class TestBaseClient: BaseClient
|
public class TestBaseClient: BaseClient
|
||||||
{
|
{
|
||||||
public TestBaseClient(): base("Test", new BaseClientOptions())
|
public TestSubClient SubClient { get; }
|
||||||
|
|
||||||
|
public TestBaseClient(): base("Test", new TestOptions())
|
||||||
{
|
{
|
||||||
|
SubClient = AddApiClient(new TestSubClient(new TestOptions(), new RestApiClientOptions()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestBaseClient(BaseRestClientOptions exchangeOptions) : base("Test", exchangeOptions)
|
public TestBaseClient(ClientOptions exchangeOptions) : base("Test", exchangeOptions)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,11 +27,20 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
{
|
{
|
||||||
log.Write(verbosity, data);
|
log.Write(verbosity, data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CallResult<T> Deserialize<T>(string data)
|
public class TestSubClient : RestApiClient
|
||||||
|
{
|
||||||
|
public TestSubClient(ClientOptions options, RestApiClientOptions apiOptions) : base(new Log(""), options, apiOptions)
|
||||||
{
|
{
|
||||||
return Deserialize<T>(data, null, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CallResult<T> Deserialize<T>(string data) => Deserialize<T>(data, null, null);
|
||||||
|
|
||||||
|
public override TimeSpan GetTimeOffset() => throw new NotImplementedException();
|
||||||
|
public override TimeSyncInfo GetTimeSyncInfo() => throw new NotImplementedException();
|
||||||
|
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) => throw new NotImplementedException();
|
||||||
|
protected override Task<WebCallResult<DateTime>> GetServerTimestampAsync() => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestAuthProvider : AuthenticationProvider
|
public class TestAuthProvider : AuthenticationProvider
|
||||||
|
@ -12,6 +12,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CryptoExchange.Net.Authentication;
|
using CryptoExchange.Net.Authentication;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using CryptoExchange.Net.Logging;
|
||||||
|
|
||||||
namespace CryptoExchange.Net.UnitTests.TestImplementations
|
namespace CryptoExchange.Net.UnitTests.TestImplementations
|
||||||
{
|
{
|
||||||
@ -28,7 +29,6 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
{
|
{
|
||||||
Api1 = new TestRestApi1Client(exchangeOptions);
|
Api1 = new TestRestApi1Client(exchangeOptions);
|
||||||
Api2 = new TestRestApi2Client(exchangeOptions);
|
Api2 = new TestRestApi2Client(exchangeOptions);
|
||||||
RequestFactory = new Mock<IRequestFactory>().Object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetResponse(string responseData, out IRequest requestObj)
|
public void SetResponse(string responseData, out IRequest requestObj)
|
||||||
@ -50,7 +50,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
request.Setup(c => c.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((key, val) => headers.Add(key, new List<string> { val }));
|
request.Setup(c => c.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((key, val) => headers.Add(key, new List<string> { val }));
|
||||||
request.Setup(c => c.GetHeaders()).Returns(() => headers);
|
request.Setup(c => c.GetHeaders()).Returns(() => headers);
|
||||||
|
|
||||||
var factory = Mock.Get(RequestFactory);
|
var factory = Mock.Get(Api1.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Callback<HttpMethod, Uri, int>((method, uri, id) =>
|
.Callback<HttpMethod, Uri, int>((method, uri, id) =>
|
||||||
{
|
{
|
||||||
@ -58,6 +58,15 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
request.Setup(a => a.Method).Returns(method);
|
request.Setup(a => a.Method).Returns(method);
|
||||||
})
|
})
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
|
|
||||||
|
factory = Mock.Get(Api2.RequestFactory);
|
||||||
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
|
.Callback<HttpMethod, Uri, int>((method, uri, id) =>
|
||||||
|
{
|
||||||
|
request.Setup(a => a.Uri).Returns(uri);
|
||||||
|
request.Setup(a => a.Method).Returns(method);
|
||||||
|
})
|
||||||
|
.Returns(request.Object);
|
||||||
requestObj = request.Object;
|
requestObj = request.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +80,12 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
request.Setup(c => c.GetHeaders()).Returns(new Dictionary<string, IEnumerable<string>>());
|
request.Setup(c => c.GetHeaders()).Returns(new Dictionary<string, IEnumerable<string>>());
|
||||||
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Throws(we);
|
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Throws(we);
|
||||||
|
|
||||||
var factory = Mock.Get(RequestFactory);
|
var factory = Mock.Get(Api1.RequestFactory);
|
||||||
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
|
.Returns(request.Object);
|
||||||
|
|
||||||
|
|
||||||
|
factory = Mock.Get(Api2.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
}
|
}
|
||||||
@ -94,27 +108,33 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
request.Setup(c => c.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((key, val) => headers.Add(key, new List<string> { val }));
|
request.Setup(c => c.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback<string, string>((key, val) => headers.Add(key, new List<string> { val }));
|
||||||
request.Setup(c => c.GetHeaders()).Returns(headers);
|
request.Setup(c => c.GetHeaders()).Returns(headers);
|
||||||
|
|
||||||
var factory = Mock.Get(RequestFactory);
|
var factory = Mock.Get(Api1.RequestFactory);
|
||||||
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
.Callback<HttpMethod, Uri, int>((method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
.Callback<HttpMethod, Uri, int>((method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
||||||
.Returns(request.Object);
|
.Returns(request.Object);
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<CallResult<T>> Request<T>(CancellationToken ct = default) where T:class
|
factory = Mock.Get(Api2.RequestFactory);
|
||||||
{
|
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
|
||||||
return await SendRequestAsync<T>(Api1, new Uri("http://www.test.com"), HttpMethod.Get, ct);
|
.Callback<HttpMethod, Uri, int>((method, uri, id) => request.Setup(a => a.Uri).Returns(uri))
|
||||||
}
|
.Returns(request.Object);
|
||||||
|
|
||||||
public async Task<CallResult<T>> RequestWithParams<T>(HttpMethod method, Dictionary<string, object> parameters, Dictionary<string, string> headers) where T : class
|
|
||||||
{
|
|
||||||
return await SendRequestAsync<T>(Api1, new Uri("http://www.test.com"), method, default, parameters, additionalHeaders: headers);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestRestApi1Client : RestApiClient
|
public class TestRestApi1Client : RestApiClient
|
||||||
{
|
{
|
||||||
public TestRestApi1Client(TestClientOptions options): base(options, options.Api1Options)
|
public TestRestApi1Client(TestClientOptions options): base(new Log(""), options, options.Api1Options)
|
||||||
{
|
{
|
||||||
|
RequestFactory = new Mock<IRequestFactory>().Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CallResult<T>> Request<T>(CancellationToken ct = default) where T : class
|
||||||
|
{
|
||||||
|
return await SendRequestAsync<T>(new Uri("http://www.test.com"), HttpMethod.Get, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CallResult<T>> RequestWithParams<T>(HttpMethod method, Dictionary<string, object> parameters, Dictionary<string, string> headers) where T : class
|
||||||
|
{
|
||||||
|
return await SendRequestAsync<T>(new Uri("http://www.test.com"), method, default, parameters, additionalHeaders: headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetParameterPosition(HttpMethod method, HttpMethodParameterPosition position)
|
public void SetParameterPosition(HttpMethod method, HttpMethodParameterPosition position)
|
||||||
@ -143,9 +163,19 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
|
|
||||||
public class TestRestApi2Client : RestApiClient
|
public class TestRestApi2Client : RestApiClient
|
||||||
{
|
{
|
||||||
public TestRestApi2Client(TestClientOptions options) : base(options, options.Api2Options)
|
public TestRestApi2Client(TestClientOptions options) : base(new Log(""), options, options.Api2Options)
|
||||||
{
|
{
|
||||||
|
RequestFactory = new Mock<IRequestFactory>().Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<CallResult<T>> Request<T>(CancellationToken ct = default) where T : class
|
||||||
|
{
|
||||||
|
return await SendRequestAsync<T>(new Uri("http://www.test.com"), HttpMethod.Get, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Error ParseErrorResponse(JToken error)
|
||||||
|
{
|
||||||
|
return new ServerError((int)error["errorCode"], (string)error["errorMessage"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override TimeSpan GetTimeOffset()
|
public override TimeSpan GetTimeOffset()
|
||||||
@ -186,9 +216,5 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
public ParseErrorTestRestClient() { }
|
public ParseErrorTestRestClient() { }
|
||||||
public ParseErrorTestRestClient(TestClientOptions exchangeOptions) : base(exchangeOptions) { }
|
public ParseErrorTestRestClient(TestClientOptions exchangeOptions) : base(exchangeOptions) { }
|
||||||
|
|
||||||
protected override Error ParseErrorResponse(JToken error)
|
|
||||||
{
|
|
||||||
return new ServerError((int)error["errorCode"], (string)error["errorMessage"]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,16 +20,39 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
|
|
||||||
public TestSocketClient(TestOptions exchangeOptions) : base("test", exchangeOptions)
|
public TestSocketClient(TestOptions exchangeOptions) : base("test", exchangeOptions)
|
||||||
{
|
{
|
||||||
SubClient = new TestSubSocketClient(exchangeOptions, exchangeOptions.SubOptions);
|
SubClient = AddApiClient(new TestSubSocketClient(exchangeOptions, exchangeOptions.SubOptions));
|
||||||
SocketFactory = new Mock<IWebsocketFactory>().Object;
|
SubClient.SocketFactory = new Mock<IWebsocketFactory>().Object;
|
||||||
Mock.Get(SocketFactory).Setup(f => f.CreateWebsocket(It.IsAny<Log>(), It.IsAny<WebSocketParameters>())).Returns(new TestSocket());
|
Mock.Get(SubClient.SocketFactory).Setup(f => f.CreateWebsocket(It.IsAny<Log>(), It.IsAny<WebSocketParameters>())).Returns(new TestSocket());
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestSocket CreateSocket()
|
public TestSocket CreateSocket()
|
||||||
{
|
{
|
||||||
Mock.Get(SocketFactory).Setup(f => f.CreateWebsocket(It.IsAny<Log>(), It.IsAny<WebSocketParameters>())).Returns(new TestSocket());
|
Mock.Get(SubClient.SocketFactory).Setup(f => f.CreateWebsocket(It.IsAny<Log>(), It.IsAny<WebSocketParameters>())).Returns(new TestSocket());
|
||||||
return (TestSocket)CreateSocket("https://localhost:123/");
|
return (TestSocket)SubClient.CreateSocketInternal("https://localhost:123/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestOptions: ClientOptions
|
||||||
|
{
|
||||||
|
public SocketApiClientOptions SubOptions { get; set; } = new SocketApiClientOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestSubSocketClient : SocketApiClient
|
||||||
|
{
|
||||||
|
|
||||||
|
public TestSubSocketClient(ClientOptions options, SocketApiClientOptions apiOptions): base(new Log(""), options, apiOptions)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IWebsocket CreateSocketInternal(string address)
|
||||||
|
{
|
||||||
|
return CreateSocket(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials)
|
||||||
|
=> new TestAuthProvider(credentials);
|
||||||
|
|
||||||
public CallResult<bool> ConnectSocketSub(SocketConnection sub)
|
public CallResult<bool> ConnectSocketSub(SocketConnection sub)
|
||||||
{
|
{
|
||||||
@ -67,21 +90,4 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestOptions: BaseSocketClientOptions
|
|
||||||
{
|
|
||||||
public ApiClientOptions SubOptions { get; set; } = new ApiClientOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TestSubSocketClient : SocketApiClient
|
|
||||||
{
|
|
||||||
|
|
||||||
public TestSubSocketClient(BaseClientOptions options, ApiClientOptions apiOptions): base(options, apiOptions)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials)
|
|
||||||
=> new TestAuthProvider(credentials);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -113,12 +113,13 @@ namespace CryptoExchange.Net
|
|||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="log">Logger</param>
|
/// <param name="log">Logger</param>
|
||||||
|
/// <param name="clientOptions">Client options</param>
|
||||||
/// <param name="apiOptions">Api client options</param>
|
/// <param name="apiOptions">Api client options</param>
|
||||||
protected BaseApiClient(Log log, ApiClientOptions apiOptions)
|
protected BaseApiClient(Log log, ClientOptions clientOptions, ApiClientOptions apiOptions)
|
||||||
{
|
{
|
||||||
Options = apiOptions;
|
Options = apiOptions;
|
||||||
_log = log;
|
_log = log;
|
||||||
_apiCredentials = apiOptions.ApiCredentials?.Copy();
|
_apiCredentials = apiOptions.ApiCredentials?.Copy() ?? clientOptions.ApiCredentials?.Copy();
|
||||||
BaseAddress = apiOptions.BaseAddress;
|
BaseAddress = apiOptions.BaseAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="log">Logger</param>
|
/// <param name="log">Logger</param>
|
||||||
/// <param name="options">The base client options</param>
|
/// <param name="options">The base client options</param>
|
||||||
/// <param name="apiOptions">The Api client options</param>
|
/// <param name="apiOptions">The Api client options</param>
|
||||||
public RestApiClient(Log log, ClientOptions options, RestApiClientOptions apiOptions): base(log, apiOptions)
|
public RestApiClient(Log log, ClientOptions options, RestApiClientOptions apiOptions): base(log, options, apiOptions)
|
||||||
{
|
{
|
||||||
var rateLimiters = new List<IRateLimiter>();
|
var rateLimiters = new List<IRateLimiter>();
|
||||||
foreach (var rateLimiter in apiOptions.RateLimiters)
|
foreach (var rateLimiter in apiOptions.RateLimiters)
|
||||||
|
@ -117,7 +117,7 @@ namespace CryptoExchange.Net
|
|||||||
/// <param name="log">log</param>
|
/// <param name="log">log</param>
|
||||||
/// <param name="options">Client options</param>
|
/// <param name="options">Client options</param>
|
||||||
/// <param name="apiOptions">The Api client options</param>
|
/// <param name="apiOptions">The Api client options</param>
|
||||||
public SocketApiClient(Log log, ClientOptions options, SocketApiClientOptions apiOptions): base(log, apiOptions)
|
public SocketApiClient(Log log, ClientOptions options, SocketApiClientOptions apiOptions): base(log, options, apiOptions)
|
||||||
{
|
{
|
||||||
ClientOptions = options;
|
ClientOptions = options;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,10 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace CryptoExchange.Net.Objects
|
namespace CryptoExchange.Net.Objects
|
||||||
{
|
{
|
||||||
public class ClientOptions
|
/// <summary>
|
||||||
|
/// Client options
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ClientOptions
|
||||||
{
|
{
|
||||||
internal event Action? OnLoggingChanged;
|
internal event Action? OnLoggingChanged;
|
||||||
|
|
||||||
@ -46,16 +49,44 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ApiProxy? Proxy { get; set; }
|
public ApiProxy? Proxy { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The api credentials used for signing requests to this API.
|
||||||
|
/// </summary>
|
||||||
|
public ApiCredentials? ApiCredentials { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
public ClientOptions()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ctor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clientOptions">Copy values for the provided options</param>
|
||||||
|
public ClientOptions(ClientOptions? clientOptions)
|
||||||
|
{
|
||||||
|
if (clientOptions == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LogLevel = clientOptions.LogLevel;
|
||||||
|
LogWriters = clientOptions.LogWriters.ToList();
|
||||||
|
Proxy = clientOptions.Proxy;
|
||||||
|
ApiCredentials = clientOptions.ApiCredentials?.Copy();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ctor
|
/// ctor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="baseOptions">Copy values for the provided options</param>
|
/// <param name="baseOptions">Copy values for the provided options</param>
|
||||||
/// <param name="newValues">Copy values for the provided options</param>
|
/// <param name="newValues">Copy values for the provided options</param>
|
||||||
public ClientOptions(ClientOptions baseOptions, ClientOptions? newValues)
|
internal ClientOptions(ClientOptions baseOptions, ClientOptions? newValues)
|
||||||
{
|
{
|
||||||
Proxy = newValues?.Proxy ?? baseOptions.Proxy;
|
Proxy = newValues?.Proxy ?? baseOptions.Proxy;
|
||||||
LogLevel = baseOptions.LogLevel;
|
LogLevel = baseOptions.LogLevel;
|
||||||
LogWriters = baseOptions.LogWriters.ToList();
|
LogWriters = baseOptions.LogWriters.ToList();
|
||||||
|
ApiCredentials = newValues?.ApiCredentials?.Copy() ?? baseOptions.ApiCredentials?.Copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -112,7 +143,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
{
|
{
|
||||||
BaseAddress = newValues?.BaseAddress ?? baseOptions.BaseAddress;
|
BaseAddress = newValues?.BaseAddress ?? baseOptions.BaseAddress;
|
||||||
ApiCredentials = newValues?.ApiCredentials?.Copy() ?? baseOptions.ApiCredentials?.Copy();
|
ApiCredentials = newValues?.ApiCredentials?.Copy() ?? baseOptions.ApiCredentials?.Copy();
|
||||||
OutputOriginalData = baseOptions.OutputOriginalData;
|
OutputOriginalData = newValues?.OutputOriginalData ?? baseOptions.OutputOriginalData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -281,7 +312,7 @@ namespace CryptoExchange.Net.Objects
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base for order book options
|
/// Base for order book options
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OrderBookOptions : ApiClientOptions
|
public class OrderBookOptions : ClientOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether or not checksum validation is enabled. Default is true, disabling will ignore checksum messages.
|
/// Whether or not checksum validation is enabled. Default is true, disabling will ignore checksum messages.
|
||||||
|
@ -40,7 +40,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
set { } }
|
set { } }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ISymbolOrderBookEntry emptySymbolOrderBookEntry = new EmptySymbolOrderBookEntry();
|
private static readonly ISymbolOrderBookEntry _emptySymbolOrderBookEntry = new EmptySymbolOrderBookEntry();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -167,7 +167,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock (_bookLock)
|
lock (_bookLock)
|
||||||
return bids.FirstOrDefault().Value ?? emptySymbolOrderBookEntry;
|
return bids.FirstOrDefault().Value ?? _emptySymbolOrderBookEntry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock (_bookLock)
|
lock (_bookLock)
|
||||||
return asks.FirstOrDefault().Value ?? emptySymbolOrderBookEntry;
|
return asks.FirstOrDefault().Value ?? _emptySymbolOrderBookEntry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,7 +581,9 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
var (bestBid, bestAsk) = BestOffers;
|
var (bestBid, bestAsk) = BestOffers;
|
||||||
if (bestBid.Price != prevBestBid.Price || bestBid.Quantity != prevBestBid.Quantity ||
|
if (bestBid.Price != prevBestBid.Price || bestBid.Quantity != prevBestBid.Quantity ||
|
||||||
bestAsk.Price != prevBestAsk.Price || bestAsk.Quantity != prevBestAsk.Quantity)
|
bestAsk.Price != prevBestAsk.Price || bestAsk.Quantity != prevBestAsk.Quantity)
|
||||||
|
{
|
||||||
OnBestOffersChanged?.Invoke((bestBid, bestAsk));
|
OnBestOffersChanged?.Invoke((bestBid, bestAsk));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Reset()
|
private void Reset()
|
||||||
@ -752,7 +754,9 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
_ = _subscription!.ReconnectAsync();
|
_ = _subscription!.ReconnectAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
await ResyncAsync().ConfigureAwait(false);
|
await ResyncAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +53,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int SubscriptionCount
|
public int SubscriptionCount
|
||||||
{
|
{
|
||||||
get { lock (subscriptionLock)
|
get { lock (_subscriptionLock)
|
||||||
return subscriptions.Count(h => h.UserSubscription); }
|
return _subscriptions.Count(h => h.UserSubscription); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -64,8 +64,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
return subscriptions.Where(h => h.UserSubscription).ToArray();
|
return _subscriptions.Where(h => h.UserSubscription).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,14 +114,14 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool PausedActivity
|
public bool PausedActivity
|
||||||
{
|
{
|
||||||
get => pausedActivity;
|
get => _pausedActivity;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (pausedActivity != value)
|
if (_pausedActivity != value)
|
||||||
{
|
{
|
||||||
pausedActivity = value;
|
_pausedActivity = value;
|
||||||
log.Write(LogLevel.Information, $"Socket {SocketId} Paused activity: " + value);
|
_log.Write(LogLevel.Information, $"Socket {SocketId} Paused activity: " + value);
|
||||||
if(pausedActivity) _ = Task.Run(() => ActivityPaused?.Invoke());
|
if(_pausedActivity) _ = Task.Run(() => ActivityPaused?.Invoke());
|
||||||
else _ = Task.Run(() => ActivityUnpaused?.Invoke());
|
else _ = Task.Run(() => ActivityUnpaused?.Invoke());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,17 +140,17 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
var oldStatus = _status;
|
var oldStatus = _status;
|
||||||
_status = value;
|
_status = value;
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} status changed from {oldStatus} to {_status}");
|
_log.Write(LogLevel.Debug, $"Socket {SocketId} status changed from {oldStatus} to {_status}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool pausedActivity;
|
private bool _pausedActivity;
|
||||||
private readonly List<SocketSubscription> subscriptions;
|
private readonly List<SocketSubscription> _subscriptions;
|
||||||
private readonly object subscriptionLock = new();
|
private readonly object _subscriptionLock = new();
|
||||||
|
|
||||||
private readonly Log log;
|
private readonly Log _log;
|
||||||
|
|
||||||
private readonly List<PendingRequest> pendingRequests;
|
private readonly List<PendingRequest> _pendingRequests;
|
||||||
|
|
||||||
private SocketStatus _status;
|
private SocketStatus _status;
|
||||||
|
|
||||||
@ -168,12 +168,12 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <param name="tag"></param>
|
/// <param name="tag"></param>
|
||||||
public SocketConnection(Log log, SocketApiClient apiClient, IWebsocket socket, string tag)
|
public SocketConnection(Log log, SocketApiClient apiClient, IWebsocket socket, string tag)
|
||||||
{
|
{
|
||||||
this.log = log;
|
this._log = log;
|
||||||
ApiClient = apiClient;
|
ApiClient = apiClient;
|
||||||
Tag = tag;
|
Tag = tag;
|
||||||
|
|
||||||
pendingRequests = new List<PendingRequest>();
|
_pendingRequests = new List<PendingRequest>();
|
||||||
subscriptions = new List<SocketSubscription>();
|
_subscriptions = new List<SocketSubscription>();
|
||||||
|
|
||||||
_socket = socket;
|
_socket = socket;
|
||||||
_socket.OnMessage += HandleMessage;
|
_socket.OnMessage += HandleMessage;
|
||||||
@ -201,9 +201,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
{
|
{
|
||||||
Status = SocketStatus.Closed;
|
Status = SocketStatus.Closed;
|
||||||
Authenticated = false;
|
Authenticated = false;
|
||||||
lock(subscriptionLock)
|
lock(_subscriptionLock)
|
||||||
{
|
{
|
||||||
foreach (var sub in subscriptions)
|
foreach (var sub in _subscriptions)
|
||||||
sub.Confirmed = false;
|
sub.Confirmed = false;
|
||||||
}
|
}
|
||||||
Task.Run(() => ConnectionClosed?.Invoke());
|
Task.Run(() => ConnectionClosed?.Invoke());
|
||||||
@ -217,9 +217,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
Status = SocketStatus.Reconnecting;
|
Status = SocketStatus.Reconnecting;
|
||||||
DisconnectTime = DateTime.UtcNow;
|
DisconnectTime = DateTime.UtcNow;
|
||||||
Authenticated = false;
|
Authenticated = false;
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
{
|
{
|
||||||
foreach (var sub in subscriptions)
|
foreach (var sub in _subscriptions)
|
||||||
sub.Confirmed = false;
|
sub.Confirmed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual async Task<Uri?> GetReconnectionUrlAsync()
|
protected virtual async Task<Uri?> GetReconnectionUrlAsync()
|
||||||
{
|
{
|
||||||
return await ApiClient.GetReconnectUriAsync(ApiClient, this).ConfigureAwait(false);
|
return await ApiClient.GetReconnectUriAsync(this).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -241,18 +241,20 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
protected virtual async void HandleReconnected()
|
protected virtual async void HandleReconnected()
|
||||||
{
|
{
|
||||||
Status = SocketStatus.Resubscribing;
|
Status = SocketStatus.Resubscribing;
|
||||||
lock (pendingRequests)
|
lock (_pendingRequests)
|
||||||
{
|
{
|
||||||
foreach (var pendingRequest in pendingRequests.ToList())
|
foreach (var pendingRequest in _pendingRequests.ToList())
|
||||||
{
|
{
|
||||||
pendingRequest.Fail();
|
pendingRequest.Fail();
|
||||||
pendingRequests.Remove(pendingRequest);
|
_pendingRequests.Remove(pendingRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var reconnectSuccessful = await ProcessReconnectAsync().ConfigureAwait(false);
|
var reconnectSuccessful = await ProcessReconnectAsync().ConfigureAwait(false);
|
||||||
if (!reconnectSuccessful)
|
if (!reconnectSuccessful)
|
||||||
|
{
|
||||||
await _socket.ReconnectAsync().ConfigureAwait(false);
|
await _socket.ReconnectAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Status = SocketStatus.Connected;
|
Status = SocketStatus.Connected;
|
||||||
@ -271,9 +273,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
protected virtual void HandleError(Exception e)
|
protected virtual void HandleError(Exception e)
|
||||||
{
|
{
|
||||||
if (e is WebSocketException wse)
|
if (e is WebSocketException wse)
|
||||||
log.Write(LogLevel.Warning, $"Socket {SocketId} error: Websocket error code {wse.WebSocketErrorCode}, details: " + e.ToLogString());
|
_log.Write(LogLevel.Warning, $"Socket {SocketId} error: Websocket error code {wse.WebSocketErrorCode}, details: " + e.ToLogString());
|
||||||
else
|
else
|
||||||
log.Write(LogLevel.Warning, $"Socket {SocketId} error: " + e.ToLogString());
|
_log.Write(LogLevel.Warning, $"Socket {SocketId} error: " + e.ToLogString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -283,14 +285,14 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
protected virtual void HandleMessage(string data)
|
protected virtual void HandleMessage(string data)
|
||||||
{
|
{
|
||||||
var timestamp = DateTime.UtcNow;
|
var timestamp = DateTime.UtcNow;
|
||||||
log.Write(LogLevel.Trace, $"Socket {SocketId} received data: " + data);
|
_log.Write(LogLevel.Trace, $"Socket {SocketId} received data: " + data);
|
||||||
if (string.IsNullOrEmpty(data)) return;
|
if (string.IsNullOrEmpty(data)) return;
|
||||||
|
|
||||||
var tokenData = data.ToJToken(log);
|
var tokenData = data.ToJToken(_log);
|
||||||
if (tokenData == null)
|
if (tokenData == null)
|
||||||
{
|
{
|
||||||
data = $"\"{data}\"";
|
data = $"\"{data}\"";
|
||||||
tokenData = data.ToJToken(log);
|
tokenData = data.ToJToken(_log);
|
||||||
if (tokenData == null)
|
if (tokenData == null)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -299,10 +301,10 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
// Remove any timed out requests
|
// Remove any timed out requests
|
||||||
PendingRequest[] requests;
|
PendingRequest[] requests;
|
||||||
lock (pendingRequests)
|
lock (_pendingRequests)
|
||||||
{
|
{
|
||||||
pendingRequests.RemoveAll(r => r.Completed);
|
_pendingRequests.RemoveAll(r => r.Completed);
|
||||||
requests = pendingRequests.ToArray();
|
requests = _pendingRequests.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this message is an answer on any pending requests
|
// Check if this message is an answer on any pending requests
|
||||||
@ -310,8 +312,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
{
|
{
|
||||||
if (pendingRequest.CheckData(tokenData))
|
if (pendingRequest.CheckData(tokenData))
|
||||||
{
|
{
|
||||||
lock (pendingRequests)
|
lock (_pendingRequests)
|
||||||
pendingRequests.Remove(pendingRequest);
|
_pendingRequests.Remove(pendingRequest);
|
||||||
|
|
||||||
if (!ApiClient.ContinueOnQueryResponse)
|
if (!ApiClient.ContinueOnQueryResponse)
|
||||||
return;
|
return;
|
||||||
@ -327,16 +329,18 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (!handled && !handledResponse)
|
if (!handled && !handledResponse)
|
||||||
{
|
{
|
||||||
if (!ApiClient.UnhandledMessageExpected)
|
if (!ApiClient.UnhandledMessageExpected)
|
||||||
log.Write(LogLevel.Warning, $"Socket {SocketId} Message not handled: " + tokenData);
|
_log.Write(LogLevel.Warning, $"Socket {SocketId} Message not handled: " + tokenData);
|
||||||
UnhandledMessage?.Invoke(tokenData);
|
UnhandledMessage?.Invoke(tokenData);
|
||||||
}
|
}
|
||||||
|
|
||||||
var total = DateTime.UtcNow - timestamp;
|
var total = DateTime.UtcNow - timestamp;
|
||||||
if (userProcessTime.TotalMilliseconds > 500)
|
if (userProcessTime.TotalMilliseconds > 500)
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId}{(subscription == null ? "" : " subscription " + subscription!.Id)} message processing slow ({(int)total.TotalMilliseconds}ms, {(int)userProcessTime.TotalMilliseconds}ms user code), consider offloading data handling to another thread. " +
|
{
|
||||||
|
_log.Write(LogLevel.Debug, $"Socket {SocketId}{(subscription == null ? "" : " subscription " + subscription!.Id)} message processing slow ({(int)total.TotalMilliseconds}ms, {(int)userProcessTime.TotalMilliseconds}ms user code), consider offloading data handling to another thread. " +
|
||||||
"Data from this socket may arrive late or not at all if message processing is continuously slow.");
|
"Data from this socket may arrive late or not at all if message processing is continuously slow.");
|
||||||
|
}
|
||||||
|
|
||||||
log.Write(LogLevel.Trace, $"Socket {SocketId}{(subscription == null ? "" : " subscription " + subscription!.Id)} message processed in {(int)total.TotalMilliseconds}ms, ({(int)userProcessTime.TotalMilliseconds}ms user code)");
|
_log.Write(LogLevel.Trace, $"Socket {SocketId}{(subscription == null ? "" : " subscription " + subscription!.Id)} message processed in {(int)total.TotalMilliseconds}ms, ({(int)userProcessTime.TotalMilliseconds}ms user code)");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -369,9 +373,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (ApiClient.socketConnections.ContainsKey(SocketId))
|
if (ApiClient.socketConnections.ContainsKey(SocketId))
|
||||||
ApiClient.socketConnections.TryRemove(SocketId, out _);
|
ApiClient.socketConnections.TryRemove(SocketId, out _);
|
||||||
|
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
{
|
{
|
||||||
foreach (var subscription in subscriptions)
|
foreach (var subscription in _subscriptions)
|
||||||
{
|
{
|
||||||
if (subscription.CancellationTokenRegistration.HasValue)
|
if (subscription.CancellationTokenRegistration.HasValue)
|
||||||
subscription.CancellationTokenRegistration.Value.Dispose();
|
subscription.CancellationTokenRegistration.Value.Dispose();
|
||||||
@ -389,9 +393,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task CloseAsync(SocketSubscription subscription)
|
public async Task CloseAsync(SocketSubscription subscription)
|
||||||
{
|
{
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
{
|
{
|
||||||
if (!subscriptions.Contains(subscription))
|
if (!_subscriptions.Contains(subscription))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
subscription.Closed = true;
|
subscription.Closed = true;
|
||||||
@ -400,7 +404,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (Status == SocketStatus.Closing || Status == SocketStatus.Closed || Status == SocketStatus.Disposed)
|
if (Status == SocketStatus.Closing || Status == SocketStatus.Closed || Status == SocketStatus.Disposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} closing subscription {subscription.Id}");
|
_log.Write(LogLevel.Debug, $"Socket {SocketId} closing subscription {subscription.Id}");
|
||||||
if (subscription.CancellationTokenRegistration.HasValue)
|
if (subscription.CancellationTokenRegistration.HasValue)
|
||||||
subscription.CancellationTokenRegistration.Value.Dispose();
|
subscription.CancellationTokenRegistration.Value.Dispose();
|
||||||
|
|
||||||
@ -408,27 +412,27 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
await ApiClient.UnsubscribeAsync(this, subscription).ConfigureAwait(false);
|
await ApiClient.UnsubscribeAsync(this, subscription).ConfigureAwait(false);
|
||||||
|
|
||||||
bool shouldCloseConnection;
|
bool shouldCloseConnection;
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
{
|
{
|
||||||
if (Status == SocketStatus.Closing)
|
if (Status == SocketStatus.Closing)
|
||||||
{
|
{
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} already closing");
|
_log.Write(LogLevel.Debug, $"Socket {SocketId} already closing");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldCloseConnection = subscriptions.All(r => !r.UserSubscription || r.Closed);
|
shouldCloseConnection = _subscriptions.All(r => !r.UserSubscription || r.Closed);
|
||||||
if (shouldCloseConnection)
|
if (shouldCloseConnection)
|
||||||
Status = SocketStatus.Closing;
|
Status = SocketStatus.Closing;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldCloseConnection)
|
if (shouldCloseConnection)
|
||||||
{
|
{
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} closing as there are no more subscriptions");
|
_log.Write(LogLevel.Debug, $"Socket {SocketId} closing as there are no more subscriptions");
|
||||||
await CloseAsync().ConfigureAwait(false);
|
await CloseAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
subscriptions.Remove(subscription);
|
_subscriptions.Remove(subscription);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -446,14 +450,14 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <param name="subscription"></param>
|
/// <param name="subscription"></param>
|
||||||
public bool AddSubscription(SocketSubscription subscription)
|
public bool AddSubscription(SocketSubscription subscription)
|
||||||
{
|
{
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
{
|
{
|
||||||
if (Status != SocketStatus.None && Status != SocketStatus.Connected)
|
if (Status != SocketStatus.None && Status != SocketStatus.Connected)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
subscriptions.Add(subscription);
|
_subscriptions.Add(subscription);
|
||||||
if(subscription.UserSubscription)
|
if(subscription.UserSubscription)
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} adding new subscription with id {subscription.Id}, total subscriptions on connection: {subscriptions.Count(s => s.UserSubscription)}");
|
_log.Write(LogLevel.Debug, $"Socket {SocketId} adding new subscription with id {subscription.Id}, total subscriptions on connection: {_subscriptions.Count(s => s.UserSubscription)}");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,8 +468,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <param name="id"></param>
|
/// <param name="id"></param>
|
||||||
public SocketSubscription? GetSubscription(int id)
|
public SocketSubscription? GetSubscription(int id)
|
||||||
{
|
{
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
return subscriptions.SingleOrDefault(s => s.Id == id);
|
return _subscriptions.SingleOrDefault(s => s.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -475,8 +479,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public SocketSubscription? GetSubscriptionByRequest(Func<object?, bool> predicate)
|
public SocketSubscription? GetSubscriptionByRequest(Func<object?, bool> predicate)
|
||||||
{
|
{
|
||||||
lock(subscriptionLock)
|
lock(_subscriptionLock)
|
||||||
return subscriptions.SingleOrDefault(s => predicate(s.Request));
|
return _subscriptions.SingleOrDefault(s => predicate(s.Request));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -494,8 +498,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
// Loop the subscriptions to check if any of them signal us that the message is for them
|
// Loop the subscriptions to check if any of them signal us that the message is for them
|
||||||
List<SocketSubscription> subscriptionsCopy;
|
List<SocketSubscription> subscriptionsCopy;
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
subscriptionsCopy = subscriptions.ToList();
|
subscriptionsCopy = _subscriptions.ToList();
|
||||||
|
|
||||||
foreach (var subscription in subscriptionsCopy)
|
foreach (var subscription in subscriptionsCopy)
|
||||||
{
|
{
|
||||||
@ -529,7 +533,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
log.Write(LogLevel.Error, $"Socket {SocketId} Exception during message processing\r\nException: {ex.ToLogString()}\r\nData: {messageEvent.JsonData}");
|
_log.Write(LogLevel.Error, $"Socket {SocketId} Exception during message processing\r\nException: {ex.ToLogString()}\r\nData: {messageEvent.JsonData}");
|
||||||
currentSubscription?.InvokeExceptionHandler(ex);
|
currentSubscription?.InvokeExceptionHandler(ex);
|
||||||
return (false, TimeSpan.Zero, null);
|
return (false, TimeSpan.Zero, null);
|
||||||
}
|
}
|
||||||
@ -546,9 +550,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
public virtual Task SendAndWaitAsync<T>(T obj, TimeSpan timeout, Func<JToken, bool> handler)
|
public virtual Task SendAndWaitAsync<T>(T obj, TimeSpan timeout, Func<JToken, bool> handler)
|
||||||
{
|
{
|
||||||
var pending = new PendingRequest(handler, timeout);
|
var pending = new PendingRequest(handler, timeout);
|
||||||
lock (pendingRequests)
|
lock (_pendingRequests)
|
||||||
{
|
{
|
||||||
pendingRequests.Add(pending);
|
_pendingRequests.Add(pending);
|
||||||
}
|
}
|
||||||
var sendOk = Send(obj);
|
var sendOk = Send(obj);
|
||||||
if(!sendOk)
|
if(!sendOk)
|
||||||
@ -577,7 +581,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <param name="data">The data to send</param>
|
/// <param name="data">The data to send</param>
|
||||||
public virtual bool Send(string data)
|
public virtual bool Send(string data)
|
||||||
{
|
{
|
||||||
log.Write(LogLevel.Trace, $"Socket {SocketId} sending data: {data}");
|
_log.Write(LogLevel.Trace, $"Socket {SocketId} sending data: {data}");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_socket.Send(data);
|
_socket.Send(data);
|
||||||
@ -595,36 +599,36 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
return new CallResult<bool>(new WebError("Socket not connected"));
|
return new CallResult<bool>(new WebError("Socket not connected"));
|
||||||
|
|
||||||
bool anySubscriptions = false;
|
bool anySubscriptions = false;
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
anySubscriptions = subscriptions.Any(s => s.UserSubscription);
|
anySubscriptions = _subscriptions.Any(s => s.UserSubscription);
|
||||||
|
|
||||||
if (!anySubscriptions)
|
if (!anySubscriptions)
|
||||||
{
|
{
|
||||||
// No need to resubscribe anything
|
// No need to resubscribe anything
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} Nothing to resubscribe, closing connection");
|
_log.Write(LogLevel.Debug, $"Socket {SocketId} Nothing to resubscribe, closing connection");
|
||||||
_ = _socket.CloseAsync();
|
_ = _socket.CloseAsync();
|
||||||
return new CallResult<bool>(true);
|
return new CallResult<bool>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subscriptions.Any(s => s.Authenticated))
|
if (_subscriptions.Any(s => s.Authenticated))
|
||||||
{
|
{
|
||||||
// If we reconnected a authenticated connection we need to re-authenticate
|
// If we reconnected a authenticated connection we need to re-authenticate
|
||||||
var authResult = await ApiClient.AuthenticateSocketAsync(this).ConfigureAwait(false);
|
var authResult = await ApiClient.AuthenticateSocketAsync(this).ConfigureAwait(false);
|
||||||
if (!authResult)
|
if (!authResult)
|
||||||
{
|
{
|
||||||
log.Write(LogLevel.Warning, $"Socket {SocketId} authentication failed on reconnected socket. Disconnecting and reconnecting.");
|
_log.Write(LogLevel.Warning, $"Socket {SocketId} authentication failed on reconnected socket. Disconnecting and reconnecting.");
|
||||||
return authResult;
|
return authResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
Authenticated = true;
|
Authenticated = true;
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} authentication succeeded on reconnected socket.");
|
_log.Write(LogLevel.Debug, $"Socket {SocketId} authentication succeeded on reconnected socket.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of all subscriptions on the socket
|
// Get a list of all subscriptions on the socket
|
||||||
List<SocketSubscription> subscriptionList = new List<SocketSubscription>();
|
List<SocketSubscription> subscriptionList = new List<SocketSubscription>();
|
||||||
lock (subscriptionLock)
|
lock (_subscriptionLock)
|
||||||
{
|
{
|
||||||
foreach (var subscription in subscriptions)
|
foreach (var subscription in _subscriptions)
|
||||||
{
|
{
|
||||||
if (subscription.Request != null)
|
if (subscription.Request != null)
|
||||||
subscriptionList.Add(subscription);
|
subscriptionList.Add(subscription);
|
||||||
@ -654,7 +658,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (!_socket.IsOpen)
|
if (!_socket.IsOpen)
|
||||||
return new CallResult<bool>(new WebError("Socket not connected"));
|
return new CallResult<bool>(new WebError("Socket not connected"));
|
||||||
|
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} all subscription successfully resubscribed on reconnected socket.");
|
_log.Write(LogLevel.Debug, $"Socket {SocketId} all subscription successfully resubscribed on reconnected socket.");
|
||||||
return new CallResult<bool>(true);
|
return new CallResult<bool>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user