Skip to content

Commit

Permalink
Remove dependency to Serilog and use logging abstraction LibLog.
Browse files Browse the repository at this point in the history
Websocket - add Name property for better logging.
Release version 2.0
  • Loading branch information
Marfusios committed Feb 4, 2019
1 parent a1ed9bb commit 52179eb
Show file tree
Hide file tree
Showing 10 changed files with 76 additions and 56 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ deploy:
provider: script
skip_cleanup: true
script:
- cd src/Websocket.Client && dotnet pack /p:PackageVersion=1.0.$TRAVIS_BUILD_NUMBER -c Release && cd bin/Release && dotnet nuget push **/*.1.0.$TRAVIS_BUILD_NUMBER.nupkg -k $NUGET_API_KEY -s https://api.nuget.org/v3/index.json
- cd src/Websocket.Client && dotnet pack /p:PackageVersion=2.0.$TRAVIS_BUILD_NUMBER -c Release && cd bin/Release && dotnet nuget push **/*.2.0.$TRAVIS_BUILD_NUMBER.nupkg -k $NUGET_API_KEY -s https://api.nuget.org/v3/index.json
on:
branch: master
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This is a wrapper over native C# class `ClientWebSocket` with built-in reconnect
* installation via NuGet ([Websocket.Client](https://www.nuget.org/packages/Websocket.Client))
* targeting .NET Standard 2.0 (.NET Core, Linux/MacOS compatible)
* reactive extensions ([Rx.NET](https://github.com/Reactive-Extensions/Rx.NET))
* integrated logging ([Serilog](https://serilog.net/))
* integrated logging abstraction ([LibLog](https://github.com/damianh/LibLog))

### Usage

Expand Down
2 changes: 2 additions & 0 deletions Websocket.Client.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Bitmex/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
6 changes: 6 additions & 0 deletions src/Websocket.Client/IWebsocketClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public interface IWebsocketClient : IDisposable
/// </summary>
int ErrorReconnectTimeoutMs { get; set; }

/// <summary>
/// Get or set the name of the current websocket client instance.
/// For logging purpose (in case you use more parallel websocket clients and want to distinguish between them)
/// </summary>
string Name { get; set;}

/// <summary>
/// Returns true if Start() method was called at least once. False if not started or disposed
/// </summary>
Expand Down
13 changes: 8 additions & 5 deletions src/Websocket.Client/Websocket.Client.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageId>Websocket.Client</PackageId>
<Version>1.0.0</Version>
<Version>2.0.0</Version>
<Authors>Mariusz Kotas</Authors>
<Description>Client for websocket API with built-in reconnection and error handling</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageReleaseNotes>Initial release</PackageReleaseNotes>
<PackageReleaseNotes>Release of version 2.0</PackageReleaseNotes>
<Copyright>Copyright 2018 Mariusz Kotas. All rights reserved.</Copyright>
<PackageTags>websockets websocket client</PackageTags>
<PackageLicenseUrl>https://github.com/Marfusios/Websocket.Client/blob/master/LICENSE</PackageLicenseUrl>
Expand All @@ -17,12 +17,15 @@
<RepositoryType>Git</RepositoryType>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<FileVersion>2.0.0.0</FileVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Serilog" Version="2.7.1" />
<PackageReference Include="LibLog" Version="5.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Reactive" Version="4.0.0" />
</ItemGroup>

Expand Down
81 changes: 45 additions & 36 deletions src/Websocket.Client/WebsocketClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Serilog;
using Websocket.Client.Logging;

namespace Websocket.Client
{
Expand All @@ -15,6 +15,8 @@ namespace Websocket.Client
/// </summary>
public class WebsocketClient : IWebsocketClient
{
private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();

private readonly Uri _url;
private Timer _lastChanceTimer;
private readonly Func<ClientWebSocket> _clientFactory;
Expand All @@ -23,8 +25,8 @@ public class WebsocketClient : IWebsocketClient

private bool _disposing = false;
private ClientWebSocket _client;
private CancellationTokenSource _cancelation;
private CancellationTokenSource _cancelationTotal;
private CancellationTokenSource _cancellation;
private CancellationTokenSource _cancellationTotal;

private readonly Subject<string> _messageReceivedSubject = new Subject<string>();
private readonly Subject<ReconnectionType> _reconnectionSubject = new Subject<ReconnectionType>();
Expand All @@ -50,12 +52,12 @@ public WebsocketClient(Uri url, Func<ClientWebSocket> clientFactory = null)
public IObservable<string> MessageReceived => _messageReceivedSubject.AsObservable();

/// <summary>
/// Stream for reconnection event (trigerred after the new connection)
/// Stream for reconnection event (triggered after the new connection)
/// </summary>
public IObservable<ReconnectionType> ReconnectionHappened => _reconnectionSubject.AsObservable();

/// <summary>
/// Stream for disconnection event (trigerred after the connection was lost)
/// Stream for disconnection event (triggered after the connection was lost)
/// </summary>
public IObservable<DisconnectionType> DisconnectionHappened => _disconnectedSubject.AsObservable();

Expand All @@ -71,6 +73,12 @@ public WebsocketClient(Uri url, Func<ClientWebSocket> clientFactory = null)
/// </summary>
public int ErrorReconnectTimeoutMs { get; set; } = 60 * 1000;

/// <summary>
/// Get or set the name of the current websocket client instance.
/// For logging purpose (in case you use more parallel websocket clients and want to distinguish between them)
/// </summary>
public string Name { get; set;}

/// <summary>
/// Returns true if Start() method was called at least once. False if not started or disposed
/// </summary>
Expand All @@ -87,21 +95,21 @@ public WebsocketClient(Uri url, Func<ClientWebSocket> clientFactory = null)
public void Dispose()
{
_disposing = true;
Log.Debug(L("Disposing.."));
Logger.Debug(L("Disposing.."));
try
{
_lastChanceTimer?.Dispose();
_cancelation?.Cancel();
_cancelationTotal?.Cancel();
_cancellation?.Cancel();
_cancellationTotal?.Cancel();
_client?.Abort();
_client?.Dispose();
_cancelation?.Dispose();
_cancelationTotal?.Dispose();
_cancellation?.Dispose();
_cancellationTotal?.Dispose();
_messagesToSendQueue?.Dispose();
}
catch (Exception e)
{
Log.Error(e, L($"Failed to dispose client, error: {e.Message}"));
Logger.Error(e, L($"Failed to dispose client, error: {e.Message}"));
}

IsStarted = false;
Expand All @@ -115,16 +123,16 @@ public async Task Start()
{
if (IsStarted)
{
Log.Debug(L("Client already started, ignoring.."));
Logger.Debug(L("Client already started, ignoring.."));
return;
}
IsStarted = true;

Log.Debug(L("Starting.."));
_cancelation = new CancellationTokenSource();
_cancelationTotal = new CancellationTokenSource();
Logger.Debug(L("Starting.."));
_cancellation = new CancellationTokenSource();
_cancellationTotal = new CancellationTokenSource();

await StartClient(_url, _cancelation.Token, ReconnectionType.Initial).ConfigureAwait(false);
await StartClient(_url, _cancellation.Token, ReconnectionType.Initial).ConfigureAwait(false);

StartBackgroundThreadForSending();
}
Expand Down Expand Up @@ -164,7 +172,7 @@ public async Task Reconnect()
{
if (!IsStarted)
{
Log.Debug(L("Client not started, ignoring reconnection.."));
Logger.Debug(L("Client not started, ignoring reconnection.."));
return;
}
await Reconnect(ReconnectionType.ByUser).ConfigureAwait(false);
Expand All @@ -174,15 +182,15 @@ private async Task SendFromQueue()
{
try
{
foreach (var message in _messagesToSendQueue.GetConsumingEnumerable(_cancelationTotal.Token))
foreach (var message in _messagesToSendQueue.GetConsumingEnumerable(_cancellationTotal.Token))
{
try
{
await SendInternal(message).ConfigureAwait(false);
}
catch (Exception e)
{
Log.Error(L($"Failed to send message: '{message}'. Error: {e.Message}"));
Logger.Error(L($"Failed to send message: '{message}'. Error: {e.Message}"));
}
}
}
Expand All @@ -192,7 +200,7 @@ private async Task SendFromQueue()
}
catch (Exception e)
{
if (_cancelationTotal.IsCancellationRequested || _disposing)
if (_cancellationTotal.IsCancellationRequested || _disposing)
{
// disposing/canceling, do nothing and exit
return;
Expand All @@ -206,22 +214,22 @@ private async Task SendFromQueue()
private void StartBackgroundThreadForSending()
{
#pragma warning disable 4014
Task.Factory.StartNew(_ => SendFromQueue(), TaskCreationOptions.LongRunning, _cancelationTotal.Token);
Task.Factory.StartNew(_ => SendFromQueue(), TaskCreationOptions.LongRunning, _cancellationTotal.Token);
#pragma warning restore 4014
}

private async Task SendInternal(string message)
{
Log.Verbose(L($"Sending: {message}"));
Logger.Trace(L($"Sending: {message}"));
var buffer = Encoding.UTF8.GetBytes(message);
var messageSegment = new ArraySegment<byte>(buffer);
var client = await GetClient().ConfigureAwait(false);
await client.SendAsync(messageSegment, WebSocketMessageType.Text, true, _cancelation.Token).ConfigureAwait(false);
await client.SendAsync(messageSegment, WebSocketMessageType.Text, true, _cancellation.Token).ConfigureAwait(false);
}

private async Task StartClient(Uri uri, CancellationToken token, ReconnectionType type)
{
DeactiveLastChance();
DeactivateLastChance();
_client = _clientFactory();

try
Expand All @@ -237,7 +245,7 @@ private async Task StartClient(Uri uri, CancellationToken token, ReconnectionTyp
catch (Exception e)
{
_disconnectedSubject.OnNext(DisconnectionType.Error);
Log.Error(e, L("Exception while connecting. " +
Logger.Error(e, L("Exception while connecting. " +
$"Waiting {ErrorReconnectTimeoutMs/1000} sec before next reconnection try."));
await Task.Delay(ErrorReconnectTimeoutMs, token).ConfigureAwait(false);
await Reconnect(ReconnectionType.Error).ConfigureAwait(false);
Expand All @@ -261,12 +269,12 @@ private async Task Reconnect(ReconnectionType type)
if(type != ReconnectionType.Error)
_disconnectedSubject.OnNext(TranslateTypeToDisconnection(type));

Log.Debug(L("Reconnecting..."));
_cancelation.Cancel();
Logger.Debug(L("Reconnecting..."));
_cancellation.Cancel();
await Task.Delay(1000).ConfigureAwait(false);

_cancelation = new CancellationTokenSource();
await StartClient(_url, _cancelation.Token, type).ConfigureAwait(false);
_cancellation = new CancellationTokenSource();
await StartClient(_url, _cancellation.Token, type).ConfigureAwait(false);
}

private async Task Listen(ClientWebSocket client, CancellationToken token)
Expand All @@ -290,7 +298,7 @@ private async Task Listen(ClientWebSocket client, CancellationToken token)
} while (!result.EndOfMessage);

var received = resultMessage.ToString();
Log.Verbose(L($"Received: {received}"));
Logger.Trace(L($"Received: {received}"));
_lastReceivedMsg = DateTime.UtcNow;
_messageReceivedSubject.OnNext(received);

Expand All @@ -302,7 +310,7 @@ private async Task Listen(ClientWebSocket client, CancellationToken token)
}
catch (Exception e)
{
Log.Error(e, L("Error while listening to websocket stream"));
Logger.Error(e, L("Error while listening to websocket stream"));
}
}

Expand All @@ -312,7 +320,7 @@ private void ActivateLastChance()
_lastChanceTimer = new Timer(LastChance, null, timerMs, timerMs);
}

private void DeactiveLastChance()
private void DeactivateLastChance()
{
_lastChanceTimer?.Dispose();
_lastChanceTimer = null;
Expand All @@ -324,9 +332,9 @@ private void LastChance(object state)
var diffMs = Math.Abs(DateTime.UtcNow.Subtract(_lastReceivedMsg).TotalMilliseconds);
if (diffMs > timeoutMs)
{
Log.Debug(L($"Last message received more than {timeoutMs:F} ms ago. Hard restart.."));
Logger.Debug(L($"Last message received more than {timeoutMs:F} ms ago. Hard restart.."));

DeactiveLastChance();
DeactivateLastChance();
_client?.Abort();
_client?.Dispose();
#pragma warning disable 4014
Expand All @@ -337,12 +345,13 @@ private void LastChance(object state)

private string L(string msg)
{
return $"[WEBSOCKET CLIENT] {msg}";
var name = Name ?? "CLIENT";
return $"[WEBSOCKET {name}] {msg}";
}

private DisconnectionType TranslateTypeToDisconnection(ReconnectionType type)
{
// beaware enum indexes must correspond to each other
// beware enum indexes must correspond to each other
return (DisconnectionType) type;
}
}
Expand Down
13 changes: 5 additions & 8 deletions test_integration/Websocket.Client.Sample.NetFramework/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Threading;
using System.Threading.Tasks;
using Serilog;
Expand All @@ -18,7 +17,6 @@ static void Main(string[] args)
InitLogging();

AppDomain.CurrentDomain.ProcessExit += CurrentDomainOnProcessExit;
AssemblyLoadContext.Default.Unloading += DefaultOnUnloading;
Console.CancelKeyPress += ConsoleOnCancelKeyPress;

Console.WriteLine("|=======================|");
Expand All @@ -35,9 +33,14 @@ static void Main(string[] args)
var url = new Uri("wss://www.bitmex.com/realtime");
using (var client = new WebsocketClient(url))
{
client.Name = "Bitmex";
client.ReconnectTimeoutMs = (int)TimeSpan.FromSeconds(30).TotalMilliseconds;
client.ReconnectionHappened.Subscribe(type =>
Log.Information($"Reconnection happened, type: {type}"));
client.DisconnectionHappened.Subscribe(type =>
Log.Warning($"Disconnection happened, type: {type}"));

client.MessageReceived.Subscribe(msg => Log.Information($"Message received: {msg}"));

client.Start();

Expand Down Expand Up @@ -78,12 +81,6 @@ private static void CurrentDomainOnProcessExit(object sender, EventArgs eventArg
ExitEvent.Set();
}

private static void DefaultOnUnloading(AssemblyLoadContext assemblyLoadContext)
{
Log.Warning("Unloading process");
ExitEvent.Set();
}

private static void ConsoleOnCancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
Log.Warning("Canceling process");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{56642A4E-B8CE-4399-9879-3E89C7C1FA3D}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Bitmex.Client.Websocket.Sample.NetFramework</RootNamespace>
<AssemblyName>Bitmex.Client.Websocket.Sample.NetFramework</AssemblyName>
<RootNamespace>Websocket.Client.Sample.NetFramework</RootNamespace>
<AssemblyName>Websocket.Client.Sample.NetFramework</AssemblyName>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
Expand Down Expand Up @@ -36,7 +36,7 @@
<HintPath>..\..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Serilog, Version=2.0.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\packages\Serilog.2.5.0\lib\net46\Serilog.dll</HintPath>
<HintPath>..\..\packages\Serilog.2.8.0\lib\net46\Serilog.dll</HintPath>
</Reference>
<Reference Include="Serilog.Sinks.ColoredConsole, Version=3.0.1.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
<HintPath>..\..\packages\Serilog.Sinks.ColoredConsole.3.0.1\lib\net45\Serilog.Sinks.ColoredConsole.dll</HintPath>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="11.0.2" targetFramework="net471" />
<package id="Serilog" version="2.5.0" targetFramework="net471" />
<package id="Serilog" version="2.8.0" targetFramework="net471" />
<package id="Serilog.Sinks.ColoredConsole" version="3.0.1" targetFramework="net471" />
<package id="Serilog.Sinks.Console" version="3.1.1" targetFramework="net471" />
<package id="Serilog.Sinks.File" version="4.0.0" targetFramework="net471" />
Expand Down
Loading

0 comments on commit 52179eb

Please sign in to comment.