diff --git a/CryptoExchange.Net/ExchangeClient.cs b/CryptoExchange.Net/ExchangeClient.cs index f83aa94..ef547a1 100644 --- a/CryptoExchange.Net/ExchangeClient.cs +++ b/CryptoExchange.Net/ExchangeClient.cs @@ -79,13 +79,17 @@ namespace CryptoExchange.Net protected virtual async Task> ExecuteRequest(Uri uri, string method = "GET", Dictionary parameters = null, bool signed = false) where T : class { - if(signed && authProvider == null) + log.Write(LogVerbosity.Debug, $"Creating request for " + uri); + if (signed && authProvider == null) return new CallResult(null, new NoApiCredentialsError()); var request = ConstructRequest(uri, method, parameters, signed); if (apiProxy != null) + { + log.Write(LogVerbosity.Debug, "Setting proxy"); request.SetProxy(apiProxy.Host, apiProxy.Port); + } foreach (var limiter in rateLimiters) { diff --git a/CryptoExchange.Net/Implementation/BaseSocket.cs b/CryptoExchange.Net/Implementation/BaseSocket.cs index 7ddc940..ac51e21 100644 --- a/CryptoExchange.Net/Implementation/BaseSocket.cs +++ b/CryptoExchange.Net/Implementation/BaseSocket.cs @@ -7,6 +7,7 @@ using System.Security.Authentication; using System.Threading; using System.Threading.Tasks; using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Logging; using SuperSocket.ClientEngine.Proxy; using WebSocket4Net; @@ -15,6 +16,7 @@ namespace CryptoExchange.Net.Implementation public class BaseSocket: IWebsocket { protected WebSocket socket; + protected Log log; protected object socketLock = new object(); protected readonly List> errorhandlers = new List>(); @@ -37,12 +39,13 @@ namespace CryptoExchange.Net.Implementation set => socket.AutoSendPingInterval = (int) Math.Round(value.TotalSeconds); } - public BaseSocket(string url):this(url, new Dictionary(), new Dictionary()) + public BaseSocket(Log log, string url):this(log, url, new Dictionary(), new Dictionary()) { } - public BaseSocket(string url, IDictionary cookies, IDictionary headers) + public BaseSocket(Log log, string url, IDictionary cookies, IDictionary headers) { + this.log = log; socket = new WebSocket(url, cookies: cookies.ToList(), customHeaderItems: headers.ToList()); socket.EnableAutoSendPing = true; socket.AutoSendPingInterval = 10; @@ -96,6 +99,7 @@ namespace CryptoExchange.Net.Implementation if (socket == null || IsClosed) return; + log.Write(LogVerbosity.Debug, "Closing websocket"); ManualResetEvent evnt = new ManualResetEvent(false); var handler = new EventHandler((o, a) => evnt.Set()); socket.Closed += handler; @@ -104,7 +108,9 @@ namespace CryptoExchange.Net.Implementation socket.Closed -= handler; if (!triggered) - Debug.WriteLine($"Not triggered, {socket.State}, Open: {IsOpen}, Closed: {IsClosed}"); + log.Write(LogVerbosity.Debug, "Websocket closed event did not trigger"); + else + log.Write(LogVerbosity.Debug, "Websocket closed"); } }).ConfigureAwait(false); } @@ -120,6 +126,7 @@ namespace CryptoExchange.Net.Implementation { lock (socketLock) { + log.Write(LogVerbosity.Debug, "Connecting websocket"); ManualResetEvent evnt = new ManualResetEvent(false); var handler = new EventHandler((o, a) => evnt.Set()); socket.Opened += handler; @@ -128,7 +135,12 @@ namespace CryptoExchange.Net.Implementation evnt.WaitOne(); socket.Opened -= handler; socket.Closed -= handler; - return socket.State == WebSocketState.Open; + var connected = socket.State == WebSocketState.Open; + if (connected) + log.Write(LogVerbosity.Debug, "Websocket connected"); + else + log.Write(LogVerbosity.Debug, "Websocket connection failed, state: " + socket.State); + return connected; } }).ConfigureAwait(false); } @@ -150,6 +162,9 @@ namespace CryptoExchange.Net.Implementation { lock (socketLock) { + if (socket != null) + log.Write(LogVerbosity.Debug, "Disposing websocket"); + socket?.Dispose(); socket = null; diff --git a/CryptoExchange.Net/Implementation/WebsocketFactory.cs b/CryptoExchange.Net/Implementation/WebsocketFactory.cs index ba5ac1e..c06a951 100644 --- a/CryptoExchange.Net/Implementation/WebsocketFactory.cs +++ b/CryptoExchange.Net/Implementation/WebsocketFactory.cs @@ -1,12 +1,13 @@ using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Logging; namespace CryptoExchange.Net.Implementation { public class WebsocketFactory : IWebsocketFactory { - public IWebsocket CreateWebsocket(string url) + public IWebsocket CreateWebsocket(Log log, string url) { - return new BaseSocket(url); + return new BaseSocket(log, url); } } } diff --git a/CryptoExchange.Net/Interfaces/IWebsocketFactory.cs b/CryptoExchange.Net/Interfaces/IWebsocketFactory.cs index 2858af7..bc265f0 100644 --- a/CryptoExchange.Net/Interfaces/IWebsocketFactory.cs +++ b/CryptoExchange.Net/Interfaces/IWebsocketFactory.cs @@ -1,7 +1,9 @@ -namespace CryptoExchange.Net.Interfaces +using CryptoExchange.Net.Logging; + +namespace CryptoExchange.Net.Interfaces { public interface IWebsocketFactory { - IWebsocket CreateWebsocket(string url); + IWebsocket CreateWebsocket(Log log, string url); } } diff --git a/CryptoExchange.Net/Logging/ThreadSafeFileWriter.cs b/CryptoExchange.Net/Logging/ThreadSafeFileWriter.cs new file mode 100644 index 0000000..950618a --- /dev/null +++ b/CryptoExchange.Net/Logging/ThreadSafeFileWriter.cs @@ -0,0 +1,33 @@ +using System.IO; +using System.Text; + +namespace CryptoExchange.Net.Logging +{ + public class ThreadSafeFileWriter: TextWriter + { + private StreamWriter logWriter; + private object writeLock; + + public override Encoding Encoding => Encoding.ASCII; + + public ThreadSafeFileWriter(string path) + { + writeLock = new object(); + logWriter = new StreamWriter(File.Open(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)); + logWriter.AutoFlush = true; + } + + + public override void WriteLine(string logMessage) + { + lock (writeLock) + logWriter.WriteLine(logMessage); + } + + protected override void Dispose(bool disposing) + { + logWriter.Close(); + logWriter = null; + } + } +} diff --git a/CryptoExchange.Net/Requests/Request.cs b/CryptoExchange.Net/Requests/Request.cs index 2085ef2..e2471a3 100644 --- a/CryptoExchange.Net/Requests/Request.cs +++ b/CryptoExchange.Net/Requests/Request.cs @@ -53,7 +53,7 @@ namespace CryptoExchange.Net.Requests public async Task GetRequestStream() { - return await request.GetRequestStreamAsync(); + return await request.GetRequestStreamAsync().ConfigureAwait(false); } public async Task GetResponse()