From cad2825cd8bcd7a364dfc64d52d554012ac5f88d Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Tue, 1 Oct 2019 23:32:34 +0100 Subject: [PATCH 1/5] Updating to connection middleware for aspnet 3.0 --- .../CondenserDotNet.Middleware.csproj | 19 +-- .../ProtocolSwitcher/BackToBackStream.cs | 138 ------------------ .../ProtocolSwitchConnectionFilter.cs | 51 ------- .../ProtocolSwitcherExtensions.cs | 14 -- .../AuthenticationConnectionFilter.cs | 36 ----- .../AuthenticationConnectionMiddleware.cs | 29 ++++ .../WindowsAuthenticationExtensions.cs | 7 +- .../Condenser.Tests.Integration.csproj | 8 +- 8 files changed, 42 insertions(+), 260 deletions(-) delete mode 100644 src/CondenserDotNet.Middleware/ProtocolSwitcher/BackToBackStream.cs delete mode 100644 src/CondenserDotNet.Middleware/ProtocolSwitcher/ProtocolSwitchConnectionFilter.cs delete mode 100644 src/CondenserDotNet.Middleware/ProtocolSwitcher/ProtocolSwitcherExtensions.cs delete mode 100644 src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionFilter.cs create mode 100644 src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionMiddleware.cs diff --git a/src/CondenserDotNet.Middleware/CondenserDotNet.Middleware.csproj b/src/CondenserDotNet.Middleware/CondenserDotNet.Middleware.csproj index 46bfcae..d1a0fd4 100644 --- a/src/CondenserDotNet.Middleware/CondenserDotNet.Middleware.csproj +++ b/src/CondenserDotNet.Middleware/CondenserDotNet.Middleware.csproj @@ -1,27 +1,18 @@ - + - netstandard2.0 + netcoreapp3.0 CondenserDotNet.Middleware CondenserDotNet.Middleware true + + + - - - - - - - 2.0.1 - - - - - diff --git a/src/CondenserDotNet.Middleware/ProtocolSwitcher/BackToBackStream.cs b/src/CondenserDotNet.Middleware/ProtocolSwitcher/BackToBackStream.cs deleted file mode 100644 index 0df0fac..0000000 --- a/src/CondenserDotNet.Middleware/ProtocolSwitcher/BackToBackStream.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.IO; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; - -namespace CondenserDotNet.Middleware.ProtocolSwitcher -{ - public class BackToBackStream : Stream - { - private bool _usedFirstByte; - private readonly Stream _innerStream; - - public BackToBackStream(Stream innerStream) => _innerStream = innerStream; - - public byte FirstByte { get; set; } - public override bool CanRead => _innerStream.CanRead; - public override bool CanSeek => _innerStream.CanSeek; - public override bool CanWrite => _innerStream.CanWrite; - public override long Length => _innerStream.Length; - public override long Position { get => _innerStream.Position; set => _innerStream.Position = value; } - - public override void Flush() => _innerStream.Flush(); - - public override int Read(byte[] buffer, int offset, int count) - { - var returnCount = 0; - if (!_usedFirstByte) - { - buffer[offset] = FirstByte; - offset++; - count--; - returnCount++; - _usedFirstByte = true; - } - returnCount += _innerStream.Read(buffer, offset, count); - return returnCount; - } - - public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset,origin); - public override void SetLength(long value) => _innerStream.SetLength(value); - public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count); - public override Task FlushAsync(CancellationToken cancellationToken) => _innerStream.FlushAsync(cancellationToken); - - public async override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - var totalCount = 0; - if (!_usedFirstByte) - { - buffer[offset] = FirstByte; - offset++; - _usedFirstByte = true; - count--; - totalCount++; - } - totalCount += await _innerStream.ReadAsync(buffer, offset, count, cancellationToken); - return totalCount; - } - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => - _innerStream.WriteAsync(buffer, offset, count, cancellationToken); - - protected override void Dispose(bool disposing) => _innerStream.Dispose(); - -#if NET46 - // The below APM methods call the underlying Read/WriteAsync methods which will still be logged. - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - var task = ReadAsync(buffer, offset, count, default(CancellationToken), state); - if (callback != null) - { - task.ContinueWith(t => callback.Invoke(t)); - } - return task; - } - - public override int EndRead(IAsyncResult asyncResult) => ((Task)asyncResult).GetAwaiter().GetResult(); - - private Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state) - { - var tcs = new TaskCompletionSource(state); - var task = ReadAsync(buffer, offset, count, cancellationToken); - task.ContinueWith((task2, state2) => - { - var tcs2 = (TaskCompletionSource)state2; - if (task2.IsCanceled) - { - tcs2.SetCanceled(); - } - else if (task2.IsFaulted) - { - tcs2.SetException(task2.Exception); - } - else - { - tcs2.SetResult(task2.Result); - } - }, tcs, cancellationToken); - return tcs.Task; - } - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - var task = WriteAsync(buffer, offset, count, default(CancellationToken), state); - if (callback != null) - { - task.ContinueWith(t => callback.Invoke(t)); - } - return task; - } - - public override void EndWrite(IAsyncResult asyncResult) => ((Task)asyncResult).GetAwaiter().GetResult(); - - private Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state) - { - var tcs = new TaskCompletionSource(state); - var task = WriteAsync(buffer, offset, count, cancellationToken); - task.ContinueWith((task2, state2) => - { - var tcs2 = (TaskCompletionSource)state2; - if (task2.IsCanceled) - { - tcs2.SetCanceled(); - } - else if (task2.IsFaulted) - { - tcs2.SetException(task2.Exception); - } - else - { - tcs2.SetResult(null); - } - }, tcs, cancellationToken); - return tcs.Task; - } -#endif - } -} diff --git a/src/CondenserDotNet.Middleware/ProtocolSwitcher/ProtocolSwitchConnectionFilter.cs b/src/CondenserDotNet.Middleware/ProtocolSwitcher/ProtocolSwitchConnectionFilter.cs deleted file mode 100644 index 043e37f..0000000 --- a/src/CondenserDotNet.Middleware/ProtocolSwitcher/ProtocolSwitchConnectionFilter.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal; -using Microsoft.AspNetCore.Server.Kestrel; -using System.IO; -using Microsoft.AspNetCore.Http.Features; - -namespace CondenserDotNet.Middleware.ProtocolSwitcher -{ - public class ProtocolSwitchConnectionFilter : IConnectionAdapter - { - private bool _isHttp; - - public bool IsHttps => _isHttp; - - public async Task OnConnectionAsync(ConnectionAdapterContext context) - { - var connection = context.ConnectionStream; - var back2Back = new BackToBackStream(connection); - - var firstByte = new byte[1]; - var bytesRead = await connection.ReadAsync(firstByte, 0, 1); - back2Back.FirstByte = firstByte[0]; - if (firstByte[0] == 0x16) - { - context.Features.Set(new TlsConnectionFeature()); - _isHttp = true; - } - - - throw new NotImplementedException(); - //await _previous.OnConnectionAsync(context); - //var previousRequest = context.PrepareRequest; - //context.PrepareRequest = features => - //{ - // previousRequest?.Invoke(features); - //}; - } - - public class ProtocolSwitcherAdaptedConnection : IAdaptedConnection - { - private readonly Stream _adaptedConnection; - - public Stream ConnectionStream => _adaptedConnection; - - public ProtocolSwitcherAdaptedConnection(Stream adaptedConnection) => _adaptedConnection = adaptedConnection; - - public void Dispose() => throw new NotImplementedException(); - } - } -} diff --git a/src/CondenserDotNet.Middleware/ProtocolSwitcher/ProtocolSwitcherExtensions.cs b/src/CondenserDotNet.Middleware/ProtocolSwitcher/ProtocolSwitcherExtensions.cs deleted file mode 100644 index ed77d8d..0000000 --- a/src/CondenserDotNet.Middleware/ProtocolSwitcher/ProtocolSwitcherExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.AspNetCore.Server.Kestrel; -using Microsoft.AspNetCore.Server.Kestrel.Core; - -namespace CondenserDotNet.Middleware.ProtocolSwitcher -{ - public static class ProtocolSwitcherExtensions - { - public static ListenOptions Switcheroo(this ListenOptions options) - { - options.ConnectionAdapters.Add(new ProtocolSwitchConnectionFilter()); - return options; - } - } -} diff --git a/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionFilter.cs b/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionFilter.cs deleted file mode 100644 index ce745c2..0000000 --- a/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionFilter.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal; - -namespace CondenserDotNet.Middleware.WindowsAuthentication -{ - public class AuthenticationConnectionFilter : IConnectionAdapter - { - public bool IsHttps => false; - - public Task OnConnectionAsync(ConnectionAdapterContext context) - { - var authFeature = new WindowsAuthFeature(); - context.Features.Set(authFeature); - var adapted = new AuthenticationAdaptedConnection(context.ConnectionStream, authFeature); - return Task.FromResult(adapted); - } - - public class AuthenticationAdaptedConnection : IAdaptedConnection - { - private readonly Stream _connectionStream; - private WindowsAuthFeature _windowsAuth; - - public AuthenticationAdaptedConnection(Stream stream, WindowsAuthFeature authFeature) - { - _connectionStream = stream; - _windowsAuth = authFeature; - } - - public Stream ConnectionStream => _connectionStream; - - public void Dispose() => _windowsAuth.Dispose(); - } - } -} diff --git a/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionMiddleware.cs b/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionMiddleware.cs new file mode 100644 index 0000000..17ef9c9 --- /dev/null +++ b/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionMiddleware.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Connections; + +namespace CondenserDotNet.Middleware.WindowsAuthentication +{ + public class AuthenticationConnectionFilter : ConnectionHandler + { + private ConnectionDelegate _next; + + public AuthenticationConnectionFilter(ConnectionDelegate next) => _next = next; + + public override async Task OnConnectedAsync(ConnectionContext connection) + { + var authFeature = new WindowsAuthFeature(); + connection.Features.Set(authFeature); + + try + { + await _next(connection); + } + finally + { + authFeature.Dispose(); + } + } + } +} diff --git a/src/CondenserDotNet.Middleware/WindowsAuthentication/WindowsAuthenticationExtensions.cs b/src/CondenserDotNet.Middleware/WindowsAuthentication/WindowsAuthenticationExtensions.cs index 57d7877..3f9578e 100644 --- a/src/CondenserDotNet.Middleware/WindowsAuthentication/WindowsAuthenticationExtensions.cs +++ b/src/CondenserDotNet.Middleware/WindowsAuthentication/WindowsAuthenticationExtensions.cs @@ -8,8 +8,11 @@ public static class WindowsAuthenticationExtensions { public static ListenOptions UseWindowsAuthentication(this ListenOptions options) { - var adapter = new AuthenticationConnectionFilter(); - options.ConnectionAdapters.Add(adapter); + options.Use(next => + { + var middleware = new AuthenticationConnectionFilter(next); + return middleware.OnConnectedAsync; + }); return options; } diff --git a/test/Condenser.Tests.Integration/Condenser.Tests.Integration.csproj b/test/Condenser.Tests.Integration/Condenser.Tests.Integration.csproj index 41b3c80..b5c792e 100644 --- a/test/Condenser.Tests.Integration/Condenser.Tests.Integration.csproj +++ b/test/Condenser.Tests.Integration/Condenser.Tests.Integration.csproj @@ -1,7 +1,7 @@ - netcoreapp2.2 + netcoreapp3.0 Condenser.Tests.Integration Condenser.Tests.Integration true @@ -12,6 +12,7 @@ + @@ -25,15 +26,12 @@ - - + - - From 6d34a488c48778016bbfdc79b8e876d28d0ee3ad Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Tue, 1 Oct 2019 23:34:15 +0100 Subject: [PATCH 2/5] move to using --- .../AuthenticationConnectionMiddleware.cs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionMiddleware.cs b/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionMiddleware.cs index 17ef9c9..4bf11a2 100644 --- a/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionMiddleware.cs +++ b/src/CondenserDotNet.Middleware/WindowsAuthentication/AuthenticationConnectionMiddleware.cs @@ -5,25 +5,17 @@ namespace CondenserDotNet.Middleware.WindowsAuthentication { - public class AuthenticationConnectionFilter : ConnectionHandler + public class AuthenticationConnectionMiddleware : ConnectionHandler { private ConnectionDelegate _next; - public AuthenticationConnectionFilter(ConnectionDelegate next) => _next = next; + public AuthenticationConnectionMiddleware(ConnectionDelegate next) => _next = next; public override async Task OnConnectedAsync(ConnectionContext connection) { - var authFeature = new WindowsAuthFeature(); + using var authFeature = new WindowsAuthFeature(); connection.Features.Set(authFeature); - - try - { - await _next(connection); - } - finally - { - authFeature.Dispose(); - } + await _next(connection); } } } From b21e10276a1993511c4f46cf71b4314fe05db1f0 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Tue, 1 Oct 2019 23:50:07 +0100 Subject: [PATCH 3/5] Removed a lot of unused server code --- CondenserDotNet.sln | 30 --- releasenotes/5.0.0.props | 9 + .../CondenserDotNet.Client.csproj | 6 +- .../CondenserDotNet.Configuration.csproj | 1 - .../CondenserDotNet.Core.csproj | 5 +- .../WindowsAuthenticationExtensions.cs | 2 +- .../CondenserDotNet.Server.Extensions.csproj | 3 - .../Condenser.Tests.Integration.csproj | 2 - .../Routing/RouterApiFacts.cs | 45 ----- .../Routing/RouterStatisticsApiFacts.cs | 49 ----- .../Routing/RouterStrategyApiFacts.cs | 80 -------- .../Routing/RouterSumaryApiFacts.cs | 71 ------- .../Routing/RouterToServiceFacts.cs | 47 ----- .../Routing/RouterTreeApiFacts.cs | 41 ---- .../Routing/RoutingFacts.cs | 79 -------- .../Routing/RoutingFixture.cs | 183 ------------------ test/CondenserTests/CondenserTests.csproj | 3 +- test/CondenserTests/CustomRouterFacts.cs | 52 ----- test/CondenserTests/Fakes/FakeHealthRouter.cs | 18 -- test/CondenserTests/RadixTests.cs | 114 ----------- version.props | 2 +- 21 files changed, 16 insertions(+), 826 deletions(-) create mode 100644 releasenotes/5.0.0.props delete mode 100644 test/Condenser.Tests.Integration/Routing/RouterApiFacts.cs delete mode 100644 test/Condenser.Tests.Integration/Routing/RouterStatisticsApiFacts.cs delete mode 100644 test/Condenser.Tests.Integration/Routing/RouterStrategyApiFacts.cs delete mode 100644 test/Condenser.Tests.Integration/Routing/RouterSumaryApiFacts.cs delete mode 100644 test/Condenser.Tests.Integration/Routing/RouterToServiceFacts.cs delete mode 100644 test/Condenser.Tests.Integration/Routing/RouterTreeApiFacts.cs delete mode 100644 test/Condenser.Tests.Integration/Routing/RoutingFacts.cs delete mode 100644 test/Condenser.Tests.Integration/Routing/RoutingFixture.cs delete mode 100644 test/CondenserTests/CustomRouterFacts.cs delete mode 100644 test/CondenserTests/Fakes/FakeHealthRouter.cs delete mode 100644 test/CondenserTests/RadixTests.cs diff --git a/CondenserDotNet.sln b/CondenserDotNet.sln index 8903f4b..c681a21 100644 --- a/CondenserDotNet.sln +++ b/CondenserDotNet.sln @@ -26,8 +26,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CondenserTests", "test\Cond EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Condenser.Tests.Integration", "test\Condenser.Tests.Integration\Condenser.Tests.Integration.csproj", "{A7E55927-04D3-4EDB-B598-6754611DE8C6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CondenserDotNet.Server", "src\CondenserDotNet.Server\CondenserDotNet.Server.csproj", "{F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CondenserDotNet.Core", "src\CondenserDotNet.Core\CondenserDotNet.Core.csproj", "{25408E8E-979D-4A36-84EC-F778FEE284CF}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "script", "script", "{09EDB6E2-E430-462F-BFE8-F38681ABCAD5}" @@ -38,8 +36,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "script", "script", "{09EDB6 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CondenserDotNet.Configuration", "src\CondenserDotNet.Configuration\CondenserDotNet.Configuration.csproj", "{6850B566-5210-4234-B9F6-6F543B73ED05}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CondenserDotNet.Server.Extensions", "src\CondenserDotNet.Server.Extensions\CondenserDotNet.Server.Extensions.csproj", "{99180374-30F2-43A2-B040-3EAA36B59227}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Release Notes", "Release Notes", "{06591E48-DAE7-4EEE-81C8-2469894B9EAF}" ProjectSection(SolutionItems) = preProject releasenotes\2.1.1.props = releasenotes\2.1.1.props @@ -143,18 +139,6 @@ Global {A7E55927-04D3-4EDB-B598-6754611DE8C6}.Release|x64.Build.0 = Release|Any CPU {A7E55927-04D3-4EDB-B598-6754611DE8C6}.Release|x86.ActiveCfg = Release|Any CPU {A7E55927-04D3-4EDB-B598-6754611DE8C6}.Release|x86.Build.0 = Release|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Debug|x64.ActiveCfg = Debug|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Debug|x64.Build.0 = Debug|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Debug|x86.ActiveCfg = Debug|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Debug|x86.Build.0 = Debug|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Release|Any CPU.Build.0 = Release|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Release|x64.ActiveCfg = Release|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Release|x64.Build.0 = Release|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Release|x86.ActiveCfg = Release|Any CPU - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78}.Release|x86.Build.0 = Release|Any CPU {25408E8E-979D-4A36-84EC-F778FEE284CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {25408E8E-979D-4A36-84EC-F778FEE284CF}.Debug|Any CPU.Build.0 = Debug|Any CPU {25408E8E-979D-4A36-84EC-F778FEE284CF}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -179,18 +163,6 @@ Global {6850B566-5210-4234-B9F6-6F543B73ED05}.Release|x64.Build.0 = Release|Any CPU {6850B566-5210-4234-B9F6-6F543B73ED05}.Release|x86.ActiveCfg = Release|Any CPU {6850B566-5210-4234-B9F6-6F543B73ED05}.Release|x86.Build.0 = Release|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Debug|Any CPU.Build.0 = Debug|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Debug|x64.ActiveCfg = Debug|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Debug|x64.Build.0 = Debug|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Debug|x86.ActiveCfg = Debug|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Debug|x86.Build.0 = Debug|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Release|Any CPU.ActiveCfg = Release|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Release|Any CPU.Build.0 = Release|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Release|x64.ActiveCfg = Release|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Release|x64.Build.0 = Release|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Release|x86.ActiveCfg = Release|Any CPU - {99180374-30F2-43A2-B040-3EAA36B59227}.Release|x86.Build.0 = Release|Any CPU {5DC8FA9E-4CB9-4F80-8AA9-7F4ABF8375B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5DC8FA9E-4CB9-4F80-8AA9-7F4ABF8375B3}.Debug|Any CPU.Build.0 = Debug|Any CPU {5DC8FA9E-4CB9-4F80-8AA9-7F4ABF8375B3}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -223,10 +195,8 @@ Global {941378DD-52CC-48CD-8CB5-CE9039721DF8} = {CB18CD55-85E2-46FC-A55B-7DE23EABFAE5} {17E329C7-CAC6-4D6A-8D83-A4C68476DD04} = {6C110226-F12E-423E-A358-D680889C6CD7} {A7E55927-04D3-4EDB-B598-6754611DE8C6} = {6C110226-F12E-423E-A358-D680889C6CD7} - {F8A84ABC-60CD-4EF4-B55D-CB27996B1F78} = {CB18CD55-85E2-46FC-A55B-7DE23EABFAE5} {25408E8E-979D-4A36-84EC-F778FEE284CF} = {CB18CD55-85E2-46FC-A55B-7DE23EABFAE5} {6850B566-5210-4234-B9F6-6F543B73ED05} = {CB18CD55-85E2-46FC-A55B-7DE23EABFAE5} - {99180374-30F2-43A2-B040-3EAA36B59227} = {CB18CD55-85E2-46FC-A55B-7DE23EABFAE5} {5DC8FA9E-4CB9-4F80-8AA9-7F4ABF8375B3} = {CB18CD55-85E2-46FC-A55B-7DE23EABFAE5} {BC05CC41-9F65-4D0C-A1CD-C6BAED37B0AB} = {CB18CD55-85E2-46FC-A55B-7DE23EABFAE5} EndGlobalSection diff --git a/releasenotes/5.0.0.props b/releasenotes/5.0.0.props new file mode 100644 index 0000000..7129d1f --- /dev/null +++ b/releasenotes/5.0.0.props @@ -0,0 +1,9 @@ + + + +* Upgraded middleware package to Aspnet Core 3.0 +* Moved project to .net standard 2.1 and upgraded librarys +* Removed unneeded package references + + + diff --git a/src/CondenserDotNet.Client/CondenserDotNet.Client.csproj b/src/CondenserDotNet.Client/CondenserDotNet.Client.csproj index 7f8c57a..8dd8b00 100644 --- a/src/CondenserDotNet.Client/CondenserDotNet.Client.csproj +++ b/src/CondenserDotNet.Client/CondenserDotNet.Client.csproj @@ -14,10 +14,8 @@ - - - - + + diff --git a/src/CondenserDotNet.Configuration/CondenserDotNet.Configuration.csproj b/src/CondenserDotNet.Configuration/CondenserDotNet.Configuration.csproj index bd8040e..6ad2025 100644 --- a/src/CondenserDotNet.Configuration/CondenserDotNet.Configuration.csproj +++ b/src/CondenserDotNet.Configuration/CondenserDotNet.Configuration.csproj @@ -7,7 +7,6 @@ latest - diff --git a/src/CondenserDotNet.Core/CondenserDotNet.Core.csproj b/src/CondenserDotNet.Core/CondenserDotNet.Core.csproj index f5b99b9..9302d3b 100644 --- a/src/CondenserDotNet.Core/CondenserDotNet.Core.csproj +++ b/src/CondenserDotNet.Core/CondenserDotNet.Core.csproj @@ -10,8 +10,7 @@ - - - + + diff --git a/src/CondenserDotNet.Middleware/WindowsAuthentication/WindowsAuthenticationExtensions.cs b/src/CondenserDotNet.Middleware/WindowsAuthentication/WindowsAuthenticationExtensions.cs index 3f9578e..a3defa5 100644 --- a/src/CondenserDotNet.Middleware/WindowsAuthentication/WindowsAuthenticationExtensions.cs +++ b/src/CondenserDotNet.Middleware/WindowsAuthentication/WindowsAuthenticationExtensions.cs @@ -10,7 +10,7 @@ public static ListenOptions UseWindowsAuthentication(this ListenOptions options) { options.Use(next => { - var middleware = new AuthenticationConnectionFilter(next); + var middleware = new AuthenticationConnectionMiddleware(next); return middleware.OnConnectedAsync; }); return options; diff --git a/src/CondenserDotNet.Server.Extensions/CondenserDotNet.Server.Extensions.csproj b/src/CondenserDotNet.Server.Extensions/CondenserDotNet.Server.Extensions.csproj index 6268535..bca4245 100644 --- a/src/CondenserDotNet.Server.Extensions/CondenserDotNet.Server.Extensions.csproj +++ b/src/CondenserDotNet.Server.Extensions/CondenserDotNet.Server.Extensions.csproj @@ -8,7 +8,4 @@ latest - - - \ No newline at end of file diff --git a/test/Condenser.Tests.Integration/Condenser.Tests.Integration.csproj b/test/Condenser.Tests.Integration/Condenser.Tests.Integration.csproj index b5c792e..f3f369e 100644 --- a/test/Condenser.Tests.Integration/Condenser.Tests.Integration.csproj +++ b/test/Condenser.Tests.Integration/Condenser.Tests.Integration.csproj @@ -21,8 +21,6 @@ - - diff --git a/test/Condenser.Tests.Integration/Routing/RouterApiFacts.cs b/test/Condenser.Tests.Integration/Routing/RouterApiFacts.cs deleted file mode 100644 index ba63f90..0000000 --- a/test/Condenser.Tests.Integration/Routing/RouterApiFacts.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CondenserDotNet.Server.Routes; -using Newtonsoft.Json; -using System.Net; -using System.Threading.Tasks; -using Xunit; - -namespace Condenser.Tests.Integration.Routing -{ - - [Collection("RoutingTests")] - public class RouterApiFacts - { - [Fact] - public async Task CanCallRouterHealthCheck() - { - using (var fixture = new RoutingFixture()) - { - var serviceName1 = fixture.GetNewServiceName(); - var route1 = "/myservice3"; - - fixture.AddService(serviceName1, route1); - fixture.AddRouter(); - - fixture.StartAll(); - - await fixture.WaitForRegistrationAsync(); - - var responseService = await fixture.CallRouterAsync("/myservice3"); - Assert.Equal(HttpStatusCode.OK, responseService.StatusCode); - - var routerResponse = await fixture.CallRouterAsync("/admin/condenser/health"); - - Assert.Equal(HttpStatusCode.OK, routerResponse.StatusCode); - - routerResponse = await fixture.CallRouterAsync("/admin/condenser/healthstats"); - - Assert.Equal(HttpStatusCode.OK, routerResponse.StatusCode); - var content = await routerResponse.Content.ReadAsStringAsync(); - - var health = JsonConvert.DeserializeObject(content); - Assert.Equal(1, health.Stats.Http200Responses); - } - } - } -} diff --git a/test/Condenser.Tests.Integration/Routing/RouterStatisticsApiFacts.cs b/test/Condenser.Tests.Integration/Routing/RouterStatisticsApiFacts.cs deleted file mode 100644 index 9fafc6e..0000000 --- a/test/Condenser.Tests.Integration/Routing/RouterStatisticsApiFacts.cs +++ /dev/null @@ -1,49 +0,0 @@ -using CondenserDotNet.Core; -using CondenserDotNet.Server.DataContracts; -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using Xunit; -using static Condenser.Tests.Integration.Routing.RouterSumaryApiFacts; - -namespace Condenser.Tests.Integration.Routing -{ - [Collection("RoutingTests")] - public class RouterStatisticsApiFacts - { - [Fact] - public async Task CanCallRouterStatisticsForRegisteredService() - { - using (var fixture = new RoutingFixture()) - { - var serviceName1 = fixture.GetNewServiceName(); - var route1 = "/customer"; - - fixture.AddService(serviceName1, route1); - fixture.AddRouter(); - - fixture.StartAll(); - - await fixture.WaitForRegistrationAsync(); - var responseService = await fixture.CallRouterAsync(route1); - Assert.Equal(HttpStatusCode.OK, responseService.StatusCode); - - var routerResponse = await fixture.CallRouterAsync("/admin/condenser/server/"+serviceName1); - - Assert.Equal(HttpStatusCode.OK, routerResponse.StatusCode); - - var content = await routerResponse.Content.GetObject(); - - var server = content[0]; - Assert.Equal(1, server.Calls); - Assert.Equal(1, server.Summary.Http200Responses); - Assert.Equal(DateTime.UtcNow.Date, server.LastRequest.Date); - Assert.True(server.LastRequestTime > 0, "last request time not recorded"); - Assert.True(server.AverageRequestTime > 0, "average request time not recorded"); - } - } - } -} diff --git a/test/Condenser.Tests.Integration/Routing/RouterStrategyApiFacts.cs b/test/Condenser.Tests.Integration/Routing/RouterStrategyApiFacts.cs deleted file mode 100644 index 0eae45e..0000000 --- a/test/Condenser.Tests.Integration/Routing/RouterStrategyApiFacts.cs +++ /dev/null @@ -1,80 +0,0 @@ -using CondenserDotNet.Core; -using CondenserDotNet.Core.Routing; -using CondenserDotNet.Server; -using CondenserDotNet.Server.DataContracts; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using Xunit; - -namespace Condenser.Tests.Integration.Routing -{ - [Collection("RoutingTests")] - public class RouterStrategyApiFacts - { - - [Fact] - public async Task CanCallRouterWithDifferentRouterStrategies() - { - using (var fixture = new RoutingFixture()) - { - var serviceName1 = fixture.GetNewServiceName(); - var route1 = "/data"; - - var strategyOne = new StrategyOne(); - var strategyTwo = new StrategyTwo(); - - fixture.AddService(serviceName1, route1); - - fixture.AddRouter(strategyOne, strategyTwo); - - fixture.StartAll(); - - await fixture.WaitForRegistrationAsync(); - - var routerResponse = await fixture.CallRouterAsync("/admin/condenser/router/replace?strategy=One"); - Assert.Equal(HttpStatusCode.OK, routerResponse.StatusCode); - - var responseService = await fixture.CallRouterAsync(route1); - Assert.Equal(HttpStatusCode.OK, responseService.StatusCode); - Assert.True(strategyOne.Called, "strategy one was not called"); - - routerResponse = await fixture.CallRouterAsync("/admin/condenser/router/replace?strategy=Two"); - Assert.Equal(HttpStatusCode.OK, routerResponse.StatusCode); - - responseService = await fixture.CallRouterAsync(route1); - Assert.Equal(HttpStatusCode.OK, responseService.StatusCode); - Assert.True(strategyTwo.Called, "strategy two was not called"); - } - } - - public class StrategyOne : IRoutingStrategy - { - public string Name => "One"; - - public bool Called { get; set; } - - public IService RouteTo(List services) - { - Called = true; - return services[0]; - } - } - - public class StrategyTwo : IRoutingStrategy - { - public string Name => "Two"; - - public bool Called { get; set; } - - public IService RouteTo(List services) - { - Called = true; - return services[0]; - } - } - } -} diff --git a/test/Condenser.Tests.Integration/Routing/RouterSumaryApiFacts.cs b/test/Condenser.Tests.Integration/Routing/RouterSumaryApiFacts.cs deleted file mode 100644 index f85ae6f..0000000 --- a/test/Condenser.Tests.Integration/Routing/RouterSumaryApiFacts.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Xunit; - -namespace Condenser.Tests.Integration.Routing -{ - [Collection("RoutingTests")] - public class RouterSumaryApiFacts - { - [Fact] - public async Task CanCallRouterSummaryForRegisteredService() - { - using (var fixture = new RoutingFixture()) - { - var serviceName1 = fixture.GetNewServiceName(); - var route1 = "/otherroute"; - - fixture.AddService(serviceName1, route1); - fixture.AddRouter(); - - fixture.StartAll(); - - await fixture.WaitForRegistrationAsync(); - - var responseService = await fixture.CallRouterAsync(route1); - Assert.Equal(HttpStatusCode.OK, responseService.StatusCode); - - var routerResponse = await fixture.CallRouterAsync("/admin/condenser/routes/summmary"); - - Assert.Equal(HttpStatusCode.OK, routerResponse.StatusCode); - var content = await routerResponse.Content.ReadAsStringAsync(); - - /*Error on travis at the moment on deserialise - * var items = JsonConvert.DeserializeObject>(content); - - var registration = items.SingleOrDefault(x => x.Service == serviceName1); - - Assert.NotNull(registration); - - Assert.Equal(1, registration.Nodes.Length); - - Assert.Equal(Environment.MachineName.ToLower(), registration.Nodes[0].NodeId.ToLower()); - Assert.Equal((serviceName1 + ":" + Environment.MachineName).ToLower(), - registration.Nodes[0].ServiceId.ToLower()); - Assert.Equal(new[] { route1 }, registration.Nodes[0].Routes); - Assert.Equal(new[] { "urlprefix-" + route1 }, registration.Nodes[0].Tags);*/ - - - } - } - - public class Summary - { - public string Service { get; set; } - public Node[] Nodes { get; set; } - } - - public class Node - { - public string NodeId { get; set; } - public string ServiceId { get; set; } - public string[] Routes { get; set; } - public string[] Tags { get; set; } - } - - } -} diff --git a/test/Condenser.Tests.Integration/Routing/RouterToServiceFacts.cs b/test/Condenser.Tests.Integration/Routing/RouterToServiceFacts.cs deleted file mode 100644 index 49de1f0..0000000 --- a/test/Condenser.Tests.Integration/Routing/RouterToServiceFacts.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Net; -using System.Threading.Tasks; -using Xunit; - -namespace Condenser.Tests.Integration.Routing -{ - [Collection("RoutingTests")] - public class RouterToServiceFacts - { - [Fact] - public async Task CanWeRunRegisteredServicesThroughRouter() - { - using (var fixture = new RoutingFixture()) - { - - var serviceName1 = fixture.GetNewServiceName(); - var route1 = "/test1"; - var serviceName2 = fixture.GetNewServiceName(); - var route2 = "/test2"; - - fixture.AddService(serviceName1, route1) - .AddService(serviceName2, route2); - - fixture.AddRouter(); - - fixture.StartAll(); - - if (!fixture.AreAllRegistered()) - { - await fixture.WaitForRegistrationAsync(); - } - - var response = await fixture.CallRouterAsync(route1); - - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - var content = await response.Content.ReadAsStringAsync(); - Assert.Equal("Called me " + serviceName1, content); - - response = await fixture.CallRouterAsync(route2); - - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - content = await response.Content.ReadAsStringAsync(); - Assert.Equal("Called me " + serviceName2, content); - } - } - } -} diff --git a/test/Condenser.Tests.Integration/Routing/RouterTreeApiFacts.cs b/test/Condenser.Tests.Integration/Routing/RouterTreeApiFacts.cs deleted file mode 100644 index f018d27..0000000 --- a/test/Condenser.Tests.Integration/Routing/RouterTreeApiFacts.cs +++ /dev/null @@ -1,41 +0,0 @@ -using CondenserDotNet.Server.DataContracts; -using Newtonsoft.Json; -using System.Net; -using System.Threading.Tasks; -using Xunit; - -namespace Condenser.Tests.Integration.Routing -{ - [Collection("RoutingTests")] - public class RouterTreeApiFacts - { - [Fact] - public async Task CanCallRouterTreeForRegisteredService() - { - using (var fixture = new RoutingFixture()) - { - var serviceName1 = fixture.GetNewServiceName(); - var route1 = "/myservice2"; - - fixture.AddService(serviceName1, route1); - fixture.AddRouter(); - - fixture.StartAll(); - - await fixture.WaitForRegistrationAsync(); - - var responseService = await fixture.CallRouterAsync("/myservice2"); - Assert.Equal(HttpStatusCode.OK, responseService.StatusCode); - - var routerResponse = await fixture.CallRouterAsync("/admin/condenser/tree"); - - Assert.Equal(HttpStatusCode.OK, routerResponse.StatusCode); - var content = await routerResponse.Content.ReadAsStringAsync(); - - var node = JsonConvert.DeserializeObject(content); - - Assert.NotNull(node); - } - } - } -} diff --git a/test/Condenser.Tests.Integration/Routing/RoutingFacts.cs b/test/Condenser.Tests.Integration/Routing/RoutingFacts.cs deleted file mode 100644 index 5a8cd34..0000000 --- a/test/Condenser.Tests.Integration/Routing/RoutingFacts.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Threading.Tasks; -using CondenserDotNet.Core.DataContracts; -using CondenserDotNet.Core.Routing; -using CondenserDotNet.Server; -using CondenserDotNet.Server.RoutingTrie; -using Microsoft.AspNetCore.Http; -using Xunit; - -namespace Condenser.Tests.Integration.Routing -{ - [Collection("RoutingTests")] - public class RoutingFacts - { - private const string UrlPrefix = "urlprefix-"; - - [Fact] - public async Task CanWeFindARouteAndGetAPage() - { - var informationService = new InformationService - { - Address = "www.google.com", - Port = 80 - }; - - var router = BuildRouter(); - var routingData = new RoutingData(null); - var service = new Service(null, null, routingData); - await service.Initialise("service1", "node1", new[] { UrlPrefix + "/search" }, "www.google.com", 80); - router.AddNewService(service); - - var context = new DefaultHttpContext(); - context.Request.Method = "GET"; - context.Request.Path = "/search"; - - var routedService = router.GetServiceFromRoute(context.Request.Path, out var matchedPath); - await routedService.CallService(context); - - Assert.Equal(200, context.Response.StatusCode); - } - - [Fact] - public async Task CanWeFindARouteAndGetAPageHttps() - { - var informationService = new InformationService - { - Address = "www.google.com", - Port = 80 - }; - - var router = BuildRouter(); - var routerData = new RoutingData(null); - var service = new Service(null, null, routerData); - await service.Initialise("service1", "node1", new[] { UrlPrefix + "/search", "protocolScheme-https" }, "www.google.com", 443); - router.AddNewService(service); - - var context = new DefaultHttpContext(); - context.Request.Method = "GET"; - context.Request.Path = "/search"; - - var routedService = router.GetServiceFromRoute(context.Request.Path, out var matchedPath); - await routedService.CallService(context); - Assert.Equal(200, context.Response.StatusCode); - } - - private CustomRouter BuildRouter() - { - ChildContainer createNode() - { - var randomRoutingStrategy = new RandomRoutingStrategy(); - return new ChildContainer(new DefaultRouting(new[] { randomRoutingStrategy }, - null)); - } - var data = new RoutingData(new RadixTree(createNode)); - return new CustomRouter(null, data, new IService[0]); - } - - } -} diff --git a/test/Condenser.Tests.Integration/Routing/RoutingFixture.cs b/test/Condenser.Tests.Integration/Routing/RoutingFixture.cs deleted file mode 100644 index e09d802..0000000 --- a/test/Condenser.Tests.Integration/Routing/RoutingFixture.cs +++ /dev/null @@ -1,183 +0,0 @@ -using CondenserDotNet.Client; -using CondenserDotNet.Core; -using CondenserDotNet.Server; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.DependencyInjection; -using CondenserDotNet.Core.Routing; - -namespace Condenser.Tests.Integration.Routing -{ - public class RoutingFixture : IDisposable - { - private Dictionary _hosts = new Dictionary(); - private const string HealthRoute = "/health"; - private volatile string[] _currentRegistrations; - private int routerPort; - private AsyncManualResetEvent _wait = new AsyncManualResetEvent(); - //private RoutingHost _host; - private IWebHost _routerHost; - private HttpClient _client = new HttpClient(); - - public RoutingFixture() => Console.WriteLine("Created Routing Fixture"); - public void SetServiceHealth(string name, bool isHealthy) => _hosts[name].IsHealthy = isHealthy; - public string GetNewServiceName() => Guid.NewGuid().ToString("N").Substring(0, 10); - public Task CallRouterAsync(string route) => _client.GetAsync($"http://localhost:{routerPort}" + route); - public Task WaitForRegistrationAsync() => Task.WhenAny(new[] { _wait.WaitAsync(), Task.Delay(30 * 1000) }); - private bool AllRegistered(string[] data) => _hosts.All(h => data.Contains(h.Key, StringComparer.OrdinalIgnoreCase)); - - private void RegisterService(string name, int port, string route) - { - var options = Options.Create(new ServiceManagerConfig - { - ServiceName = name, - ServicePort = port - - }); - - var serviceManager = new ServiceManager(options); - - var ignore = serviceManager - .AddHttpHealthCheck(HealthRoute, 3) - .AddApiUrl(route) - .RegisterServiceAsync(); - } - - public RoutingFixture AddService(string name, string route) - { - var hostPort = ServiceManagerConfig.GetNextAvailablePort(); - - var host = new WebHostBuilder() - .UseKestrel() - .UseUrls($"http://*:{hostPort}") - .Configure(app => - { - var appLifetime = app.ApplicationServices.GetService(); - appLifetime.ApplicationStarted.Register(() => RegisterService(name, hostPort, route)); - - app.Run(async message => - { - HttpStatusCode status; - string content = null; - var path = message.Request.Path; - - var instance = _hosts[name]; - - if (path == HealthRoute) - { - if (instance.IsHealthy) - { - status = HttpStatusCode.OK; - content = "Healthy"; - } - else - { - status = HttpStatusCode.InternalServerError; - content = "Not healthy"; - } - } - else if (path == route) - { - status = HttpStatusCode.OK; - content = "Called me " + name; - } - else - { - status = HttpStatusCode.NotFound; - content = ""; - } - - message.Response.StatusCode = (int)status; - await message.Response.WriteAsync(content); - - }); - }) - .Build(); - - _hosts.Add(name, new ServiceInstance(host)); - - return this; - } - - public void AddRouter(params IRoutingStrategy[] strategies) - { - routerPort = ServiceManagerConfig.GetNextAvailablePort(); - - _routerHost = new WebHostBuilder() - .UseKestrel() - .UseUrls($"http://*:{routerPort}") - .ConfigureServices(x => - { - x.AddCondenserWithBuilder() - .WithRoutesBuiltCallback(SignalWhenAllRegistered) - .WithRoutingStrategies(strategies) - .Build(); - - }) - .Configure(app => - { - app.UseCondenser(); - }) - .Build(); - } - - public bool AreAllRegistered() - { - if (_currentRegistrations == null) return false; - - return AllRegistered(_currentRegistrations); - } - - private void SignalWhenAllRegistered(string[] data) - { - Interlocked.Exchange(ref _currentRegistrations, data); - - if (AllRegistered(data)) - { - _wait.Set(true); - } - } - - public void StartAll() - { - foreach (var host in _hosts) - { - host.Value.Host.Start(); - } - - _routerHost?.Start(); - } - - public void Dispose() - { - foreach (var host in _hosts) - { - host.Value.Host.Dispose(); - } - - _routerHost?.Dispose(); - } - - public class ServiceInstance - { - public IWebHost Host { get; } - - public bool IsHealthy { get; set; } - public ServiceInstance(IWebHost host) - { - Host = host; - IsHealthy = true; - } - } - } -} diff --git a/test/CondenserTests/CondenserTests.csproj b/test/CondenserTests/CondenserTests.csproj index 07bc4d3..444f06a 100644 --- a/test/CondenserTests/CondenserTests.csproj +++ b/test/CondenserTests/CondenserTests.csproj @@ -13,7 +13,6 @@ - @@ -26,7 +25,7 @@ - + diff --git a/test/CondenserTests/CustomRouterFacts.cs b/test/CondenserTests/CustomRouterFacts.cs deleted file mode 100644 index abda873..0000000 --- a/test/CondenserTests/CustomRouterFacts.cs +++ /dev/null @@ -1,52 +0,0 @@ -using CondenserDotNet.Server; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; -using Xunit; - -namespace CondenserTests -{ - public class CustomRouterFacts - { - private const string UrlPrefix = "urlprefix-"; - - [Fact] - public async void SetupCustomRouterAndRouteToService() - { - var router = BuildRouter(); - var routerData = new RoutingData(null); - var service = new Service(null, null, routerData); - await service.Initialise("Service1Test", "node1", new string[] { UrlPrefix + "/test1/test2/test3/test4/test5" }, "Address1Test", 10000); - router.AddNewService(service); - - var context = new DefaultHttpContext(); - context.Request.Method = "GET"; - context.Request.Path = "/test1/test2/test3/test4/test5/test6"; - - var routedService = router.GetServiceFromRoute(context.Request.Path, out var matchedPath); - - Assert.Equal(service, routedService); - } - - [Fact] - public async void SetupCustomRouterAndLookForbadRoute() - { - var router = BuildRouter(); - - var routerData = new RoutingData(null); - var service = new Service(null, null, routerData); - await service.Initialise("Service1Test", "node1", new string[] { UrlPrefix + "/test1/test2/test3/test4/test5" }, "Address1Test", 10000); - router.AddNewService(service); - - var context = new DefaultHttpContext(); - context.Request.Method = "GET"; - context.Request.Path = "/test2/test2/test3/test4/test5/test6"; - var routeContext = new RouteContext(context); - - //await router.RouteAsync(routeContext); - - Assert.Null(routeContext.Handler); - } - - private CustomRouter BuildRouter() => new CustomRouter(null, RoutingData.BuildDefault(), new IService[0]); - } -} diff --git a/test/CondenserTests/Fakes/FakeHealthRouter.cs b/test/CondenserTests/Fakes/FakeHealthRouter.cs deleted file mode 100644 index dc33f42..0000000 --- a/test/CondenserTests/Fakes/FakeHealthRouter.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using CondenserDotNet.Server; -using Microsoft.AspNetCore.Http; - -namespace CondenserTests.Fakes -{ - public class FakeHealthRouter : ServiceBase - { - public FakeHealthRouter(string route) => Routes = new[] { route }; - - public override string[] Routes { get; } - public override IPEndPoint IpEndPoint => throw new NotImplementedException(); - - public override Task CallService(HttpContext context) => Task.FromResult(0); - } -} diff --git a/test/CondenserTests/RadixTests.cs b/test/CondenserTests/RadixTests.cs deleted file mode 100644 index 50d0027..0000000 --- a/test/CondenserTests/RadixTests.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using CondenserDotNet.Core.Routing; -using CondenserDotNet.Server; -using CondenserDotNet.Server.RoutingTrie; -using Xunit; - -namespace CondenserTests -{ - public class RadixTests - { - [Fact(Skip ="Ignore while compression in flux")] - public void TestSplitting() - { - var tree = CreateDefault(); - - var routingData = new RoutingData(null); - var service = new Service(null, null, routingData); - service.Initialise("Service1Test", "node1", new string[0], "Adress1Test", 10000).Wait(); - var service2 = new Service(null, null, routingData); - service2.Initialise("Service1Test", "node1", new string[0], "Address2Test", 10000).Wait(); - tree.AddServiceToRoute("/test1/test2/test3/test4/test5", service); - tree.AddServiceToRoute("/test1/test2/test3/test4/test5/test6", service); - - tree.Compress(); - - ////Time to split the tree it should be 5 long at the moment but this should make it 2 long and then split - tree.AddServiceToRoute("/test1/test2/test10/test6/test4/test6", service); - - var topNode = tree.GetTopNode(); - - //Check the first node is two long - Assert.Equal(2, topNode.ChildrenNodes.KeyLength); - - //find the root common node - var commonNode = topNode.ChildrenNodes[new string[] { "TEST1", "TEST2" }]; - - //check the keys are consistant - foreach (var kv in commonNode.ChildrenNodes) - { - Assert.Equal(kv.Item1.Length, commonNode.ChildrenNodes.KeyLength); - } - } - - [Fact(Skip = "Ignore while compression in flux")] - public void TestCompression() - { - var tree = CreateDefault(); - - var routingData = new RoutingData(null); - var service = new Service(null, null, routingData); - service.Initialise("Service1Test", "node1", new string[0], "Address1Test", 10000).Wait(); - var service2 = new Service(null, null, routingData); - service2.Initialise("Service1Test", "node1", new string[0], "Address2Test", 10000).Wait(); - - tree.AddServiceToRoute("/test1/test2/test3/test4/test5", service); - tree.AddServiceToRoute("/test1/test2/test3/test4/test5/test6", service2); - - Assert.Equal(1, tree.GetTopNode().ChildrenNodes.Count); - - tree.Compress(); - - //We should have 1 node in the tree - Assert.Equal(1, tree.GetTopNode().ChildrenNodes.Count); - - //The key length should be 5 long - Assert.Equal(5, tree.GetTopNode().ChildrenNodes.KeyLength); - - var returnservice = tree.GetServiceFromRoute("/test1/test2/test3/test4/test5/test7", out var matchedpath); - Assert.Equal("/test1/test2/test3/test4/test5".ToUpperInvariant(), matchedpath); - //Assert.Equal(returnservice.ServiceId, service.ServiceId); - } - - [Fact] - public void TestRemovingAService() - { - var tree = CreateDefault(); - - var routingData = new RoutingData(null); - var service = new Service(null, null, routingData); - service.Initialise("Service1Test", "node1", new string[0], "Address1Test", 10000).Wait(); - var service2 = new Service(null, null, routingData); - service2.Initialise("Service1Test", "node1", new string[0], "Address2Test", 10000).Wait(); - - tree.AddServiceToRoute("/test1/test2/test3/test4/test5", service); - tree.AddServiceToRoute("/test1/test2/test3/test4/test5/test6", service2); - - var returnservice = tree.GetServiceFromRoute("/test1/test2/test3/test4/test5/test7", out var matchedpath); - Assert.Equal("/test1/test2/test3/test4/test5".ToUpperInvariant(), matchedpath); - - ////now remove the service - tree.RemoveService(service); - - //Now we should get no match - returnservice = tree.GetServiceFromRoute("/test1/test2/test3/test4/test5/test7", out matchedpath); - Assert.Null(returnservice); - - } - - public static RadixTree CreateDefault() => - new RadixTree(() => - { - var randomRoutingStrategy = new RandomRoutingStrategy(); - return new ChildContainer(new DefaultRouting - (new[] { randomRoutingStrategy }, new FakeRouteConfig())); - }); - } - - public class FakeRouteConfig : IRoutingConfig - { - public string DefaultRouteStrategy { get; } = RouteStrategy.Random.ToString(); - - public Action OnRoutesBuilt => null; - } -} diff --git a/version.props b/version.props index 4f7bccf..d3678ba 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@ - 4.1.13 + 5.0.0 beta From 4c46b9e98b0f24bd951ac6aeb8402b5e68a04e77 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Tue, 1 Oct 2019 23:56:40 +0100 Subject: [PATCH 4/5] Removed more code --- ...ondenserDotNet.Middleware.Pipelines.csproj | 25 --- .../HttpConsts.cs | 16 -- .../HttpRequestHelper.cs | 99 --------- .../HttpResponseHelper.cs | 175 ---------------- .../ServiceWithCustomClient.cs | 134 ------------ .../WebSocketMiddleware.cs | 117 ----------- .../ApplicationBuilderExtensions.cs | 21 -- .../CondenserDotNet.Server.Extensions.csproj | 11 - .../ConfigurationBuilder.cs | 88 -------- .../IConfigurationBuilder.cs | 27 --- .../ServiceCollectionExtensions.cs | 73 ------- .../Builder/IHealthConfig.cs | 13 -- .../CondenserConfiguration.cs | 8 - .../CondenserDotNet.Server.csproj | 26 --- .../ConsulRouteSource.cs | 62 ------ src/CondenserDotNet.Server/CurrentState.cs | 76 ------- src/CondenserDotNet.Server/CustomRouter.cs | 55 ----- .../DataContracts/HealthCheck.cs | 14 -- .../DataContracts/HealthCheckStatus.cs | 9 - .../DataContracts/Node.cs | 12 -- .../DataContracts/ServerStatistics.cs | 16 -- .../DataContracts/ServiceInstance.cs | 12 -- .../DataContracts/StatsSummary.cs | 18 -- .../Extensions/HttpResponseExtensions.cs | 11 - .../GetHealthCheckResult.cs | 13 -- src/CondenserDotNet.Server/IConsulService.cs | 9 - src/CondenserDotNet.Server/ICurrentState.cs | 12 -- .../IHttpClientConfig.cs | 9 - src/CondenserDotNet.Server/IRouteSource.cs | 12 -- src/CondenserDotNet.Server/IRouteStore.cs | 19 -- src/CondenserDotNet.Server/IService.cs | 23 --- src/CondenserDotNet.Server/IUsageInfo.cs | 13 -- src/CondenserDotNet.Server/RouteStore.cs | 49 ----- .../Routes/ChangeRoutingStrategy.cs | 74 ------- .../Routes/CondenserRoutes.cs | 12 -- .../Routes/HealthResponse.cs | 10 - .../Routes/HealthRouter.cs | 23 --- .../Routes/HealthStatsRouter.cs | 77 ------- .../Routes/RouteSummary.cs | 47 ----- .../Routes/ServerStatisticsRoute.cs | 73 ------- .../Routes/TreeRouter.cs | 53 ----- src/CondenserDotNet.Server/RoutingData.cs | 49 ----- src/CondenserDotNet.Server/RoutingHost.cs | 195 ------------------ .../RoutingMiddleware.cs | 40 ---- .../RoutingTrie/ChildContainer.cs | 57 ----- .../RoutingTrie/Node.cs | 193 ----------------- .../RoutingTrie/NodeComparer.cs | 41 ---- .../RoutingTrie/NodeContainer.cs | 116 ----------- .../RoutingTrie/RadixTree.cs | 68 ------ src/CondenserDotNet.Server/Service.cs | 183 ---------------- src/CondenserDotNet.Server/ServiceBase.cs | 25 --- .../ServiceCallMiddleware.cs | 26 --- 52 files changed, 2639 deletions(-) delete mode 100644 src/CondenserDotNet.Middleware.Pipelines/CondenserDotNet.Middleware.Pipelines.csproj delete mode 100644 src/CondenserDotNet.Middleware.Pipelines/HttpConsts.cs delete mode 100644 src/CondenserDotNet.Middleware.Pipelines/HttpRequestHelper.cs delete mode 100644 src/CondenserDotNet.Middleware.Pipelines/HttpResponseHelper.cs delete mode 100644 src/CondenserDotNet.Middleware.Pipelines/ServiceWithCustomClient.cs delete mode 100644 src/CondenserDotNet.Middleware.Pipelines/WebSocketMiddleware.cs delete mode 100644 src/CondenserDotNet.Server.Extensions/ApplicationBuilderExtensions.cs delete mode 100644 src/CondenserDotNet.Server.Extensions/CondenserDotNet.Server.Extensions.csproj delete mode 100644 src/CondenserDotNet.Server.Extensions/ConfigurationBuilder.cs delete mode 100644 src/CondenserDotNet.Server.Extensions/IConfigurationBuilder.cs delete mode 100644 src/CondenserDotNet.Server.Extensions/ServiceCollectionExtensions.cs delete mode 100644 src/CondenserDotNet.Server/Builder/IHealthConfig.cs delete mode 100644 src/CondenserDotNet.Server/CondenserConfiguration.cs delete mode 100644 src/CondenserDotNet.Server/CondenserDotNet.Server.csproj delete mode 100644 src/CondenserDotNet.Server/ConsulRouteSource.cs delete mode 100644 src/CondenserDotNet.Server/CurrentState.cs delete mode 100644 src/CondenserDotNet.Server/CustomRouter.cs delete mode 100644 src/CondenserDotNet.Server/DataContracts/HealthCheck.cs delete mode 100644 src/CondenserDotNet.Server/DataContracts/HealthCheckStatus.cs delete mode 100644 src/CondenserDotNet.Server/DataContracts/Node.cs delete mode 100644 src/CondenserDotNet.Server/DataContracts/ServerStatistics.cs delete mode 100644 src/CondenserDotNet.Server/DataContracts/ServiceInstance.cs delete mode 100644 src/CondenserDotNet.Server/DataContracts/StatsSummary.cs delete mode 100644 src/CondenserDotNet.Server/Extensions/HttpResponseExtensions.cs delete mode 100644 src/CondenserDotNet.Server/GetHealthCheckResult.cs delete mode 100644 src/CondenserDotNet.Server/IConsulService.cs delete mode 100644 src/CondenserDotNet.Server/ICurrentState.cs delete mode 100644 src/CondenserDotNet.Server/IHttpClientConfig.cs delete mode 100644 src/CondenserDotNet.Server/IRouteSource.cs delete mode 100644 src/CondenserDotNet.Server/IRouteStore.cs delete mode 100644 src/CondenserDotNet.Server/IService.cs delete mode 100644 src/CondenserDotNet.Server/IUsageInfo.cs delete mode 100644 src/CondenserDotNet.Server/RouteStore.cs delete mode 100644 src/CondenserDotNet.Server/Routes/ChangeRoutingStrategy.cs delete mode 100644 src/CondenserDotNet.Server/Routes/CondenserRoutes.cs delete mode 100644 src/CondenserDotNet.Server/Routes/HealthResponse.cs delete mode 100644 src/CondenserDotNet.Server/Routes/HealthRouter.cs delete mode 100644 src/CondenserDotNet.Server/Routes/HealthStatsRouter.cs delete mode 100644 src/CondenserDotNet.Server/Routes/RouteSummary.cs delete mode 100644 src/CondenserDotNet.Server/Routes/ServerStatisticsRoute.cs delete mode 100644 src/CondenserDotNet.Server/Routes/TreeRouter.cs delete mode 100644 src/CondenserDotNet.Server/RoutingData.cs delete mode 100644 src/CondenserDotNet.Server/RoutingHost.cs delete mode 100644 src/CondenserDotNet.Server/RoutingMiddleware.cs delete mode 100644 src/CondenserDotNet.Server/RoutingTrie/ChildContainer.cs delete mode 100644 src/CondenserDotNet.Server/RoutingTrie/Node.cs delete mode 100644 src/CondenserDotNet.Server/RoutingTrie/NodeComparer.cs delete mode 100644 src/CondenserDotNet.Server/RoutingTrie/NodeContainer.cs delete mode 100644 src/CondenserDotNet.Server/RoutingTrie/RadixTree.cs delete mode 100644 src/CondenserDotNet.Server/Service.cs delete mode 100644 src/CondenserDotNet.Server/ServiceBase.cs delete mode 100644 src/CondenserDotNet.Server/ServiceCallMiddleware.cs diff --git a/src/CondenserDotNet.Middleware.Pipelines/CondenserDotNet.Middleware.Pipelines.csproj b/src/CondenserDotNet.Middleware.Pipelines/CondenserDotNet.Middleware.Pipelines.csproj deleted file mode 100644 index b7f0f70..0000000 --- a/src/CondenserDotNet.Middleware.Pipelines/CondenserDotNet.Middleware.Pipelines.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - netstandard2.0 - true - CondenserDotNet.Middleware.Pipelines - CondenserDotNet.Middleware.Pipelines - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/CondenserDotNet.Middleware.Pipelines/HttpConsts.cs b/src/CondenserDotNet.Middleware.Pipelines/HttpConsts.cs deleted file mode 100644 index b4d6316..0000000 --- a/src/CondenserDotNet.Middleware.Pipelines/HttpConsts.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Text; - -namespace CondenserDotNet.Middleware.Pipelines -{ - public static class HttpConsts - { - public static readonly byte[] Space = Encoding.UTF8.GetBytes(" "); - public static readonly byte[] EndOfLine = Encoding.UTF8.GetBytes("\r\n"); - public static readonly byte[] HeadersEnd = Encoding.UTF8.GetBytes("\r\n\r\n"); - public static readonly byte[] HeaderSplit = Encoding.UTF8.GetBytes(": "); - public static readonly byte[] ConnectionHeaderBytes = Encoding.UTF8.GetBytes("Connection: keep-alive\r\n\r\n"); - public static readonly string ContentLengthHeader = "Content-Length"; - public static readonly string ChunkedContentType = "chunked"; - public static readonly string TransferEncodingHeader = "Transfer-Encoding"; - } -} diff --git a/src/CondenserDotNet.Middleware.Pipelines/HttpRequestHelper.cs b/src/CondenserDotNet.Middleware.Pipelines/HttpRequestHelper.cs deleted file mode 100644 index 0fb251a..0000000 --- a/src/CondenserDotNet.Middleware.Pipelines/HttpRequestHelper.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.IO.Pipelines; -using System.Text; -using System.Text.Formatting; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; - -namespace CondenserDotNet.Middleware.Pipelines -{ - public static class HttpRequestHelper - { - private static readonly Task _cachedTask = Task.FromResult(0); - - public static WritableBufferAwaitable WriteHeadersAsync(this IPipeConnection connection, HttpContext context, byte[] host) - { - var writer = connection.Output.Alloc(); - writer.Append(context.Request.Method, TextEncoder.Utf8); - writer.Write(HttpConsts.Space); - writer.Append(context.Request.Path.Value, TextEncoder.Utf8); - writer.Write(HttpConsts.Space); - writer.Append(context.Request.Protocol, TextEncoder.Utf8); - writer.Write(HttpConsts.EndOfLine); - foreach (var header in context.Request.Headers) - { - if (header.Key == "Host" || header.Key == "Connection") { } - writer.Append(header.Key, TextEncoder.Utf8); - writer.Write(HttpConsts.HeaderSplit); - writer.Append(string.Join(", ", header.Value), TextEncoder.Utf8); - writer.Write(HttpConsts.EndOfLine); - } - writer.Write(host); - writer.Write(HttpConsts.ConnectionHeaderBytes); - return writer.FlushAsync(); - } - - public static Task WriteBodyAsync(this IPipeConnection connection, HttpContext context) - { - if (context.Request.Headers["Transfer-Encoding"] == "chunked") - { - return connection.WriteChunkedBody(context); - } - if (context.Request.ContentLength > 0) - { - return connection.WriteBody(context); - } - return _cachedTask; - } - - private static async Task WriteBody(this IPipeConnection connection, HttpContext context) - { - var bytesToWrite = context.Request.ContentLength.Value; - while (bytesToWrite > 0) - { - var buffer = connection.Output.Alloc(1024); - if (!buffer.Memory.TryGetArray(out ArraySegment byteArray)) - { - throw new NotImplementedException(); - } - var byteCount = await context.Request.Body.ReadAsync(byteArray.Array, byteArray.Offset, byteArray.Count); - buffer.Advance(byteCount); - bytesToWrite -= byteCount; - await buffer.FlushAsync(); - } - } - - private static async Task WriteChunkedBody(this IPipeConnection connection, HttpContext context) - { - while (true) - { - var buffer = connection.Output.Alloc(); - try - { - buffer.Ensure(1024); - var bookMark = buffer.Memory; - buffer.Advance(3); - buffer.Write(HttpConsts.EndOfLine); - if (!buffer.Memory.TryGetArray(out ArraySegment byteArray)) - { - throw new NotImplementedException(); - } - var bytesWritten = await context.Request.Body.ReadAsync(byteArray.Array, byteArray.Offset, byteArray.Count); - if (bytesWritten == 0) - { - Encoding.ASCII.GetBytes("000").CopyTo(bookMark.Span); - buffer.Write(HttpConsts.EndOfLine); - return; - } - Encoding.ASCII.GetBytes($"{bytesWritten:XXX}").CopyTo(bookMark.Span); - buffer.Advance(bytesWritten); - buffer.Write(HttpConsts.EndOfLine); - } - finally - { - await buffer.FlushAsync(); - } - } - } - } -} diff --git a/src/CondenserDotNet.Middleware.Pipelines/HttpResponseHelper.cs b/src/CondenserDotNet.Middleware.Pipelines/HttpResponseHelper.cs deleted file mode 100644 index f758e4d..0000000 --- a/src/CondenserDotNet.Middleware.Pipelines/HttpResponseHelper.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using System.IO.Pipelines; -using System.IO.Pipelines.Text.Primitives; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; - -namespace CondenserDotNet.Middleware.Pipelines -{ - public static class HttpResponseHelper - { - private static readonly Task _cachedTask = Task.FromResult(false); - - public static async Task ReceiveHeaderAsync(this IPipeConnection connection, HttpContext context) - { - var finished = false; - while (true) - { - var reader = await connection.Input.ReadAsync(); - var buffer = reader.Buffer; - try - { - if (!buffer.TrySliceTo(HttpConsts.HeadersEnd, out ReadableBuffer currentSlice, out ReadCursor cursor)) - { - continue; - } - buffer = buffer.Slice(cursor).Slice(HttpConsts.HeadersEnd.Length); - //first line - if (!currentSlice.TrySliceTo(HttpConsts.EndOfLine, out ReadableBuffer currentLine, out cursor)) - { - throw new InvalidOperationException(); - } - context.Response.StatusCode = int.Parse(currentLine.Split(HttpConsts.Space[0]).Skip(1).First().GetAsciiString()); - currentSlice = currentSlice.Slice(cursor).Slice(HttpConsts.EndOfLine.Length); - - while (currentSlice.Length > 0) - { - cursor = ProcessHeader(context, ref currentSlice); - } - finished = true; - return; - } - finally - { - if (finished) - { - connection.Input.Advance(buffer.Start, buffer.Start); - } - else - { - connection.Input.Advance(buffer.Start, buffer.End); - } - } - } - } - - private static ReadCursor ProcessHeader(HttpContext context, ref ReadableBuffer currentSlice) - { - if (!currentSlice.TrySliceTo(HttpConsts.EndOfLine, out ReadableBuffer headerLine, out ReadCursor cursor)) - { - headerLine = currentSlice; - currentSlice = currentSlice.Slice(currentSlice.Length); - } - else - { - currentSlice = currentSlice.Slice(cursor).Slice(HttpConsts.EndOfLine.Length); - } - if (!headerLine.TrySliceTo(HttpConsts.HeaderSplit, out ReadableBuffer key, out cursor)) - { - throw new NotImplementedException(); - } - var keyString = key.GetUtf8String(); - var values = headerLine.Slice(cursor).Slice(HttpConsts.HeaderSplit.Length).GetUtf8String().Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries); - if (keyString == HttpConsts.ContentLengthHeader) - { - context.Response.ContentLength = int.Parse(values[0]); - } - context.Response.Headers[keyString] = new Microsoft.Extensions.Primitives.StringValues(values); - return cursor; - } - - public static Task ReceiveBodyAsync(this IPipeConnection connection, HttpContext context, ILogger logger) - { - if (context.Response.Headers[HttpConsts.TransferEncodingHeader] == HttpConsts.ChunkedContentType) - { - return connection.ReceiveChunkedBody(context, logger); - } - if (context.Response.ContentLength > 0) - { - return connection.ReceiveContentLengthBody(context); - } - return _cachedTask; - } - - private static async Task ReceiveContentLengthBody(this IPipeConnection connection, HttpContext context) - { - var contentSize = (int)context.Response.ContentLength.Value; - while (true) - { - var reader = await connection.Input.ReadAsync(); - var buffer = reader.Buffer; - try - { - var amountTowrite = Math.Min(contentSize, buffer.Length); - await buffer.Slice(0, amountTowrite).CopyToAsync(context.Response.Body); - contentSize -= amountTowrite; - buffer = buffer.Slice(amountTowrite); - if (contentSize == 0) - { - return !reader.IsCompleted; - } - } - finally - { - connection.Input.Advance(buffer.Start, buffer.End); - } - } - } - - private static async Task ReceiveChunkedBody(this IPipeConnection connection, HttpContext context, ILogger logger) - { - var nextChunkSize = 0; - var lastChunk = false; - while (true) - { - var reader = await connection.Input.ReadAsync(); - var buffer = reader.Buffer; - try - { - while (true) - { - if (nextChunkSize == 0) - { - //looking for a length, slice a line - if (!buffer.TrySliceTo(HttpConsts.EndOfLine, out ReadableBuffer lengthLine, out ReadCursor cursor)) - { - break; - } - //We have the first line - await buffer.Slice(0, lengthLine.Length + HttpConsts.EndOfLine.Length).CopyToAsync(context.Response.Body); - buffer = buffer.Slice(cursor).Slice(HttpConsts.EndOfLine.Length); - nextChunkSize = int.Parse(lengthLine.GetAsciiString(), System.Globalization.NumberStyles.HexNumber); - if (nextChunkSize == 0) - { - lastChunk = true; - } - nextChunkSize += 2; - } - if (buffer.Length > 0) - { - var dataToSend = Math.Min(nextChunkSize, buffer.Length); - await buffer.Slice(0, dataToSend).CopyToAsync(context.Response.Body); - buffer = buffer.Slice(dataToSend); - nextChunkSize -= dataToSend; - if (nextChunkSize == 0 && lastChunk) - { - logger?.LogInformation("Finished sending chunked data remaining buffer size {bufferSize}", buffer.Length); - return !reader.IsCompleted; - } - if (buffer.Length == 0) - { - break; - } - } - } - } - finally - { - connection.Input.Advance(buffer.Start, buffer.End); - } - } - } - } -} diff --git a/src/CondenserDotNet.Middleware.Pipelines/ServiceWithCustomClient.cs b/src/CondenserDotNet.Middleware.Pipelines/ServiceWithCustomClient.cs deleted file mode 100644 index 49836b5..0000000 --- a/src/CondenserDotNet.Middleware.Pipelines/ServiceWithCustomClient.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.IO.Pipelines; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using CondenserDotNet.Core; -using CondenserDotNet.Server; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using System.Diagnostics; -using CondenserDotNet.Server.DataContracts; - -namespace CondenserDotNet.Middleware.Pipelines -{ - public class ServiceWithCustomClient : IConsulService, IDisposable - { - private readonly System.Threading.CountdownEvent _waitUntilRequestsAreFinished = new System.Threading.CountdownEvent(1); - private string _address; - private int _port; - private byte[] _hostHeader; - private ICurrentState _stats; - private IPEndPoint _ipEndPoint; - private Version[] _supportedVersions; - private string[] _tags; - private string _serviceId; - private readonly ILogger _logger; - private int _calls; - private long _totalRequestTime; - private readonly ConcurrentQueue _pooledConnections = new ConcurrentQueue(); - private readonly PipeFactory _factory; - private readonly RoutingData _routingData; - - public ServiceWithCustomClient(ILoggerFactory loggingFactory, PipeFactory factory, RoutingData routingData) - { - _routingData = routingData; - _logger = loggingFactory?.CreateLogger(); - _pooledConnections = new ConcurrentQueue(); - _factory = factory; - } - - public Version[] SupportedVersions => _supportedVersions; - public string[] Tags => _tags; - public string[] Routes { get; private set; } - public string ServiceId => _serviceId; - public string NodeId { get; private set; } - public int Calls => _calls; - public double TotalRequestTime => _totalRequestTime; - public IPEndPoint IpEndPoint => _ipEndPoint; - - public async Task CallService(HttpContext context) - { - System.Threading.Interlocked.Increment(ref _calls); - var sw = Stopwatch.StartNew(); - try - { - if (!_pooledConnections.TryDequeue(out IPipeConnection socket)) - { - socket = await System.IO.Pipelines.Networking.Sockets.SocketConnection.ConnectAsync(IpEndPoint); - _logger?.LogInformation("Created new socket"); - } - else - { - _logger?.LogInformation("Got a connection from the pool, current pool size {poolSize}", _pooledConnections.Count); - } - await socket.WriteHeadersAsync(context, _hostHeader); - await socket.WriteBodyAsync(context); - await socket.ReceiveHeaderAsync(context); - await socket.ReceiveBodyAsync(context, _logger); - _pooledConnections.Enqueue(socket); - } - catch - { - throw new NotImplementedException(); - } - sw.Stop(); - System.Threading.Interlocked.Add(ref _totalRequestTime, sw.ElapsedMilliseconds); - } - - public override int GetHashCode() => ServiceId.GetHashCode(); - - public override bool Equals(object obj) - { - if (obj is ServiceWithCustomClient otherService) - { - if (otherService.ServiceId != ServiceId) - { - return false; - } - if (!Tags.SequenceEqual(otherService.Tags)) - { - return false; - } - return true; - } - return false; - } - - public void UpdateRoutes(string[] routes) => Routes = routes; - - public async Task Initialise(string serviceId, string nodeId, string[] tags, string address, int port) - { - _stats = _routingData.GetStats(serviceId); - _stats.ResetUptime(); - _address = address; - _port = port; - _tags = tags; - Routes = ServiceUtils.RoutesFromTags(tags); - _serviceId = serviceId; - NodeId = nodeId; - _hostHeader = Encoding.UTF8.GetBytes($"Host: {_address}:{_port}\r\n"); - try - { - var result = await Dns.GetHostAddressesAsync(address); - _ipEndPoint = new IPEndPoint(result[0], port); - } - catch - { - _logger.LogError("Unable to get an ip address for {serverAddress}", address); - } - _supportedVersions = tags.Where(t => t.StartsWith("version=")).Select(t => new Version(t.Substring(8))).ToArray(); - } - - public void Dispose() - { - _waitUntilRequestsAreFinished.Signal(); - _waitUntilRequestsAreFinished.Wait(5000); - _waitUntilRequestsAreFinished.Dispose(); - } - - public StatsSummary GetSummary() => _stats.GetSummary(); - } -} diff --git a/src/CondenserDotNet.Middleware.Pipelines/WebSocketMiddleware.cs b/src/CondenserDotNet.Middleware.Pipelines/WebSocketMiddleware.cs deleted file mode 100644 index bb626fb..0000000 --- a/src/CondenserDotNet.Middleware.Pipelines/WebSocketMiddleware.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO.Pipelines; -using System.IO.Pipelines.Text.Primitives; -using System.Text; -using System.Text.Formatting; -using System.Threading.Tasks; -using CondenserDotNet.Server; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.Extensions.Logging; - -namespace CondenserDotNet.Middleware.Pipelines -{ - public class WebsocketMiddleware - { - private readonly RequestDelegate _next; - private readonly ILogger _logger; - private readonly PipeFactory _factory; - private static readonly byte[] _space = Encoding.UTF8.GetBytes(" "); - private static readonly byte[] _endOfLine = Encoding.UTF8.GetBytes("\r\n"); - private static readonly byte[] _headersEnd = Encoding.UTF8.GetBytes("\r\n\r\n"); - private static readonly byte[] _headerSplit = Encoding.UTF8.GetBytes(": "); - - public WebsocketMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, PipeFactory factory) - { - _next = next; - _factory = factory; - _logger = loggerFactory?.CreateLogger(); - } - - public Task Invoke(HttpContext context) - { - var upgradeFeature = context.Features.Get(); - if (upgradeFeature != null && context.Request.Headers["Upgrade"].Count > 0) - { - return DoWebSocket(context, upgradeFeature); - } - return _next.Invoke(context); - } - - private async Task DoWebSocket(HttpContext context, IHttpUpgradeFeature upgrade) - { - var service = context.Features.Get(); - var endPoint = service.IpEndPoint; - var socket = await System.IO.Pipelines.Networking.Sockets.SocketConnection.ConnectAsync(endPoint, _factory); - try - { - var writer = socket.Output.Alloc(); - - writer.Append(context.Request.Method, TextEncoder.Utf8); - writer.Write(_space); - writer.Append(context.Request.Path.Value, TextEncoder.Utf8); - writer.Write(_space); - writer.Append(context.Request.Protocol, TextEncoder.Utf8); - writer.Write(_endOfLine); - foreach (var header in context.Request.Headers) - { - writer.Append(header.Key, TextEncoder.Utf8); - writer.Write(_headerSplit); - writer.Append(string.Join(", ", (IEnumerable)header.Value), TextEncoder.Utf8); - writer.Write(_endOfLine); - } - writer.Write(_endOfLine); - await writer.FlushAsync(); - while (true) - { - var reader = await socket.Input.ReadAsync(); - var buffer = reader.Buffer; - try - { - if (!buffer.TrySliceTo(_headersEnd, out ReadableBuffer headers, out ReadCursor cursor)) - { - continue; - } - buffer = buffer.Slice(cursor).Slice(_headersEnd.Length); - if (!headers.TrySliceTo(_endOfLine, out ReadableBuffer line, out cursor)) - { - throw new InvalidOperationException(); - } - headers = headers.Slice(cursor).Slice(_endOfLine.Length); - while (headers.Length > 0) - { - if (!headers.TrySliceTo(_endOfLine, out ReadableBuffer headerLine, out cursor)) - { - headerLine = headers; - headers = headers.Slice(headers.Length); - } - else - { - headers = headers.Slice(cursor).Slice(_endOfLine.Length); - } - if (!headerLine.TrySliceTo(_headerSplit, out ReadableBuffer key, out cursor)) - { - throw new NotImplementedException(); - } - var values = headerLine.Slice(cursor).Slice(_headerSplit.Length).GetUtf8String().Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries); - context.Response.Headers[key.GetUtf8String()] = new Microsoft.Extensions.Primitives.StringValues(values); - } - break; - } - finally - { - socket.Input.Advance(buffer.Start, buffer.End); - } - } - var upgradedStream = await upgrade.UpgradeAsync(); - await Task.WhenAll(upgradedStream.CopyToEndAsync(socket.Output), socket.Input.CopyToEndAsync(upgradedStream)); - upgradedStream.Dispose(); - } - finally - { - await socket.DisposeAsync(); - } - } - } -} diff --git a/src/CondenserDotNet.Server.Extensions/ApplicationBuilderExtensions.cs b/src/CondenserDotNet.Server.Extensions/ApplicationBuilderExtensions.cs deleted file mode 100644 index 5d4c3a9..0000000 --- a/src/CondenserDotNet.Server.Extensions/ApplicationBuilderExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using System.Threading.Tasks; - -namespace CondenserDotNet.Server -{ - public static class ApplicationBuilderExtensions - { - public static IApplicationBuilder UseCondenser(this IApplicationBuilder self) - { - self.UseMiddleware(); - //self.UseMiddleware(); - self.UseMiddleware(); - - //Resolve to start building routes - self.ApplicationServices.GetServices(); - - return self; - } - } -} diff --git a/src/CondenserDotNet.Server.Extensions/CondenserDotNet.Server.Extensions.csproj b/src/CondenserDotNet.Server.Extensions/CondenserDotNet.Server.Extensions.csproj deleted file mode 100644 index bca4245..0000000 --- a/src/CondenserDotNet.Server.Extensions/CondenserDotNet.Server.Extensions.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - netstandard2.0 - CondenserDotNet.Server.Extensions - CondenserDotNet.Server.Extensions - - - latest - - \ No newline at end of file diff --git a/src/CondenserDotNet.Server.Extensions/ConfigurationBuilder.cs b/src/CondenserDotNet.Server.Extensions/ConfigurationBuilder.cs deleted file mode 100644 index bfc3b6e..0000000 --- a/src/CondenserDotNet.Server.Extensions/ConfigurationBuilder.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using CondenserDotNet.Core.Routing; -using CondenserDotNet.Server.Builder; -using CondenserDotNet.Server.DataContracts; -using CondenserDotNet.Server.Routes; -using Microsoft.Extensions.DependencyInjection; - -namespace CondenserDotNet.Server -{ - public class ConfigurationBuilder : IHealthConfig, IConfigurationBuilder, IRoutingConfig, IHttpClientConfig - { - private readonly IServiceCollection _collection; - private string _agentAddress = "localhost"; - private int _agentPort = 8500; - private Func _clientFactory; - - public ConfigurationBuilder(IServiceCollection collection) => _collection = collection; - - public List>> Checks { get; } = new List>>(); - public string Route { get; private set; } = CondenserRoutes.HealthStats; - public string DefaultRouteStrategy { get; private set; } = RouteStrategy.Random.ToString(); - - private readonly List> _strategies = new List>(); - - public Action OnRoutesBuilt { get; private set; } - - public IConfigurationBuilder WithAgentAddress(string agentAdress) - { - _agentAddress = agentAdress; - return this; - } - - public IConfigurationBuilder WithRoutesBuiltCallback(Action onRoutesBuilt) - { - OnRoutesBuilt = onRoutesBuilt; - return this; - } - - public IConfigurationBuilder WithAgentPort(int agentPort) - { - _agentPort = agentPort; - return this; - } - - public IConfigurationBuilder WithHealthRoute(string route) - { - Route = route; - return this; - } - - public IConfigurationBuilder WithHealthCheck(Func> check) - { - Checks.Add(check); - return this; - } - - public IConfigurationBuilder WithHealthCheck(Func check) - { - Checks.Add(() => Task.FromResult(check())); - return this; - } - - public IServiceCollection Build() => _collection.AddCondenser(_agentAddress, _agentPort, this, this, this, _strategies); - - public IConfigurationBuilder WithRoutingStrategy(RouteStrategy name) - { - DefaultRouteStrategy = name.ToString(); - return this; - } - - public IConfigurationBuilder WithHttpClient(Func clientFactory) - { - _clientFactory = clientFactory; - return this; - } - - public IConfigurationBuilder WithRoutingStrategies(IEnumerable> strategies) - { - _strategies.AddRange(strategies); - return this; - } - - public HttpClient Create(string serviceId) => _clientFactory?.Invoke(serviceId); - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server.Extensions/IConfigurationBuilder.cs b/src/CondenserDotNet.Server.Extensions/IConfigurationBuilder.cs deleted file mode 100644 index 0f79b41..0000000 --- a/src/CondenserDotNet.Server.Extensions/IConfigurationBuilder.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading.Tasks; -using CondenserDotNet.Core.Routing; -using CondenserDotNet.Server.DataContracts; -using Microsoft.Extensions.DependencyInjection; -using System.Collections.Generic; - -namespace CondenserDotNet.Server -{ - public interface IConfigurationBuilder - { - IConfigurationBuilder WithAgentAddress(string agentAdress); - IConfigurationBuilder WithAgentPort(int agentPort); - IConfigurationBuilder WithHealthRoute(string route); - IConfigurationBuilder WithHealthCheck(Func> check); - IConfigurationBuilder WithHealthCheck(Func check); - IConfigurationBuilder WithRoutingStrategy(RouteStrategy name); - IConfigurationBuilder WithHttpClient(Func clientFactory); - - IConfigurationBuilder WithRoutesBuiltCallback(Action onRoutesBuilt); - - IConfigurationBuilder WithRoutingStrategies(IEnumerable> strategies); - - IServiceCollection Build(); - } -} diff --git a/src/CondenserDotNet.Server.Extensions/ServiceCollectionExtensions.cs b/src/CondenserDotNet.Server.Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 7086fae..0000000 --- a/src/CondenserDotNet.Server.Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Net.Http; -using CondenserDotNet.Core.Routing; -using CondenserDotNet.Server.Builder; -using CondenserDotNet.Server.Routes; -using CondenserDotNet.Server.RoutingTrie; -using Microsoft.Extensions.DependencyInjection; -using CondenserDotNet.Server; -using System.Collections.Generic; - -namespace CondenserDotNet.Server -{ - public static class ServiceCollectionExtensions - { - public static IServiceCollection AddCondenser(this IServiceCollection self) => AddCondenser(self, "localhost", 8500); - - private static IServiceCollection AddCondenser(this IServiceCollection self, string agentAddress, int agentPort) => - self.AddCondenserWithBuilder() - .WithAgentAddress(agentAddress) - .WithAgentPort(agentPort) - .WithHttpClient(s => new HttpClient()) - .Build(); - - public static IServiceCollection AddCondenser(this IServiceCollection self, string agentAddress, int agentPort, - IHealthConfig health, IRoutingConfig routingConfig, IHttpClientConfig httpClientConfig, - IEnumerable> strategies) - { - var config = new CondenserConfiguration - { - AgentPort = agentPort, - AgentAddress = agentAddress - }; - - self.AddSingleton(config); - self.AddSingleton(health); - self.AddSingleton(routingConfig); - self.AddSingleton>(httpClientConfig.Create); - - self.AddSingleton(); - self.AddSingleton(); - self.AddSingleton(); - self.AddSingleton(); - self.AddSingleton(); - self.AddSingleton(); - self.AddSingleton(); - self.AddSingleton(); - self.AddSingleton(); - self.AddTransient, RandomRoutingStrategy>(); - self.AddTransient, RoundRobinRoutingStrategy>(); - self.AddSingleton, DefaultRouting>(); - - foreach(var service in strategies) - { - self.AddSingleton(service); - } - - self.AddTransient>(); - self.AddTransient(); - self.AddSingleton(); - self.AddSingleton(); - self.AddSingleton>(); - - self.AddTransient(); - self.AddSingleton>(x => x.GetService); - self.AddSingleton>(x => x.GetService); - self.AddSingleton>>(x => x.GetService>); - - return self; - } - - public static IConfigurationBuilder AddCondenserWithBuilder(this IServiceCollection self) => new ConfigurationBuilder(self); - } -} diff --git a/src/CondenserDotNet.Server/Builder/IHealthConfig.cs b/src/CondenserDotNet.Server/Builder/IHealthConfig.cs deleted file mode 100644 index 487d89f..0000000 --- a/src/CondenserDotNet.Server/Builder/IHealthConfig.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using CondenserDotNet.Server.DataContracts; - -namespace CondenserDotNet.Server.Builder -{ - public interface IHealthConfig - { - List>> Checks { get; } - string Route { get; } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/CondenserConfiguration.cs b/src/CondenserDotNet.Server/CondenserConfiguration.cs deleted file mode 100644 index 77786dd..0000000 --- a/src/CondenserDotNet.Server/CondenserConfiguration.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace CondenserDotNet.Server -{ - public class CondenserConfiguration - { - public string AgentAddress { get; set; } = "localhost"; - public int AgentPort { get; set; } = 8500; - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/CondenserDotNet.Server.csproj b/src/CondenserDotNet.Server/CondenserDotNet.Server.csproj deleted file mode 100644 index f736ffa..0000000 --- a/src/CondenserDotNet.Server/CondenserDotNet.Server.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - netstandard2.0 - true - CondenserDotNet.Server - CondenserDotNet.Server - - - latest - - - - - - - - - - - - - - - - diff --git a/src/CondenserDotNet.Server/ConsulRouteSource.cs b/src/CondenserDotNet.Server/ConsulRouteSource.cs deleted file mode 100644 index b1c7203..0000000 --- a/src/CondenserDotNet.Server/ConsulRouteSource.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using CondenserDotNet.Core; -using CondenserDotNet.Core.Consul; -using CondenserDotNet.Server.DataContracts; -using Microsoft.Extensions.Logging; - -namespace CondenserDotNet.Server -{ - public class ConsulRouteSource : IRouteSource - { - private readonly HttpClient _client; - private readonly CancellationTokenSource _cancel = new CancellationTokenSource(); - private readonly string _healthCheckUri; - private readonly string _serviceLookupUri; - private string _lastConsulIndex = string.Empty; - private readonly ILogger _logger; - static readonly HealthCheck[] EmptyChecks = new HealthCheck[0]; - - public ConsulRouteSource(CondenserConfiguration config, - ILoggerFactory logger, IConsulAclProvider aclProvider = null) - { - _client = HttpUtils.CreateClient(aclProvider, config.AgentAddress, config.AgentPort); - _healthCheckUri = $"{HttpUtils.HealthAnyUrl}?index="; - _serviceLookupUri = $"{HttpUtils.SingleServiceCatalogUrl}"; - - _logger = logger?.CreateLogger(); - } - - public bool CanRequestRoute() => !_cancel.IsCancellationRequested; - - public async Task TryGetHealthChecksAsync() - { - _logger?.LogInformation("Looking for health changes with index {index}", _lastConsulIndex); - using (var result = await _client.GetAsync(_healthCheckUri + _lastConsulIndex.ToString(), _cancel.Token)) - { - if (!result.IsSuccessStatusCode) - { - _logger?.LogWarning("Retrieved a response that was not success when getting the health status code was {code}", result.StatusCode); - return new GetHealthCheckResult() { Checks = EmptyChecks, Success = false }; - } - var newConsulIndex = result.GetConsulIndex(); - - if (newConsulIndex == _lastConsulIndex) - { - return new GetHealthCheckResult() { Success = false, Checks = EmptyChecks }; - } - - _lastConsulIndex = newConsulIndex; - - _logger?.LogInformation("Got new set of health information new index is {index}", _lastConsulIndex); - - var checks = await result.Content.GetObject(); - return new GetHealthCheckResult() { Success = true, Checks = checks }; - } - } - - public Task GetServiceInstancesAsync(string serviceName) => _client.GetAsync(_serviceLookupUri + serviceName); - } -} diff --git a/src/CondenserDotNet.Server/CurrentState.cs b/src/CondenserDotNet.Server/CurrentState.cs deleted file mode 100644 index 277ef0c..0000000 --- a/src/CondenserDotNet.Server/CurrentState.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using Microsoft.Extensions.Logging; -using CondenserDotNet.Server.DataContracts; - -namespace CondenserDotNet.Server -{ - public class CurrentState : ICurrentState - { - private DateTime _startedTime; - - public CurrentState() => _startedTime = DateTime.UtcNow; - - public StatsSummary GetSummary() - { - var stats = new StatsSummary(); - - lock (_lock) - { - UpTime = DateTime.UtcNow - _startedTime; - - stats.Http100Responses = Http100Responses; - stats.Http200Responses = Http200Responses; - stats.Http300Responses = Http300Responses; - stats.Http400Responses = Http400Responses; - stats.Http500Responses = Http500Responses; - stats.HttpUnknownResponse = HttpUnknownResponse; - stats.UpTime = UpTime; - } - return stats; - } - - public int Http100Responses { get; private set; } - public int Http200Responses { get; private set; } - public int Http300Responses { get; private set; } - public int Http400Responses { get; private set; } - public int Http500Responses { get; private set; } - public TimeSpan UpTime { get; private set; } - public int HttpUnknownResponse { get; private set; } - - private readonly object _lock = new object(); - - public void RecordResponse(int responseCode) - { - lock (_lock) - { - responseCode /= 100; - switch (responseCode) - { - case 5: - Http500Responses++; - break; - case 4: - Http400Responses++; - break; - case 3: - Http300Responses++; - break; - case 2: - Http200Responses++; - break; - case 1: - Http100Responses++; - break; - default: - HttpUnknownResponse++; - break; - } - } - - } - - public void ResetUptime() => _startedTime = DateTime.UtcNow; - } -} diff --git a/src/CondenserDotNet.Server/CustomRouter.cs b/src/CondenserDotNet.Server/CustomRouter.cs deleted file mode 100644 index da352dc..0000000 --- a/src/CondenserDotNet.Server/CustomRouter.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using System.Collections.Generic; - -namespace CondenserDotNet.Server -{ - public class CustomRouter - { - private readonly RoutingData _routingData; - private readonly ILogger _log; - - public CustomRouter(ILoggerFactory factory, RoutingData routingData, IEnumerable customRoutes) - { - _routingData = routingData; - _log = factory?.CreateLogger(); - - foreach (var customRoute in customRoutes) - { - AddNewService(customRoute); - } - } - - public IService GetServiceFromRoute(PathString path, out string matchedPath) - { - var service = _routingData.Tree.GetServiceFromRoute(path, out matchedPath); - _log?.LogTrace("Looked for a service for the path {path} and got {service}", path, service); - return service; - } - - public void AddServiceToRoute(string route, IService serviceToAdd) => _routingData.Tree.AddServiceToRoute(route, serviceToAdd); - - public void AddNewService(IService serviceToAdd) - { - foreach (var r in serviceToAdd.Routes) - { - _routingData.Tree.AddServiceToRoute(r, serviceToAdd); - } - } - - public void RemoveService(IService serviceToRemove) => _routingData.Tree.RemoveService(serviceToRemove); - - public void RemoveServiceFromRoute(string route, IService serviceToRemove) - { - _log?.LogTrace("Removing {service} from {route}", serviceToRemove, route); - _routingData.Tree.RemoveServiceFromRoute(route, serviceToRemove); - } - - internal void CleanUpRoutes() - { - _log?.LogTrace("Compressing Trie Current Depth {maxDepth}", _routingData.Tree.MaxDepth()); - _routingData.Tree.Compress(); - _log?.LogTrace("Compressing Trie Finished New Depth {maxDepth}", _routingData.Tree.MaxDepth()); - } - } -} diff --git a/src/CondenserDotNet.Server/DataContracts/HealthCheck.cs b/src/CondenserDotNet.Server/DataContracts/HealthCheck.cs deleted file mode 100644 index 77bc562..0000000 --- a/src/CondenserDotNet.Server/DataContracts/HealthCheck.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace CondenserDotNet.Server.DataContracts -{ - public class HealthCheck - { - public bool Ok { get; set; } - public string Name { get; set; } - public string Message { get; set; } - public string CheckID { get; set; } - public string ServiceID { get; set; } - public string ServiceName { get; set; } - public string Node { get; set; } - public HealthCheckStatus Status { get; set; } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/DataContracts/HealthCheckStatus.cs b/src/CondenserDotNet.Server/DataContracts/HealthCheckStatus.cs deleted file mode 100644 index 8f21c5e..0000000 --- a/src/CondenserDotNet.Server/DataContracts/HealthCheckStatus.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace CondenserDotNet.Server.DataContracts -{ - public enum HealthCheckStatus - { - Passing, - Warning, - Critical - } -} diff --git a/src/CondenserDotNet.Server/DataContracts/Node.cs b/src/CondenserDotNet.Server/DataContracts/Node.cs deleted file mode 100644 index a3ca2a7..0000000 --- a/src/CondenserDotNet.Server/DataContracts/Node.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; - -namespace CondenserDotNet.Server.DataContracts -{ - public class Node - { - public string Path { get; set; } - public string Services { get; set; } - public string[] Prefix { get; set; } - public Dictionary Nodes { get; set; } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/DataContracts/ServerStatistics.cs b/src/CondenserDotNet.Server/DataContracts/ServerStatistics.cs deleted file mode 100644 index 588cdae..0000000 --- a/src/CondenserDotNet.Server/DataContracts/ServerStatistics.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace CondenserDotNet.Server.DataContracts -{ - public class ServerStats - { - public string ServiceId { get; set; } - public string NodeId { get; set; } - public int Calls { get; set; } - public double AverageRequestTime { get; set; } - - public double LastRequestTime { get; set; } - public DateTime LastRequest { get; set; } - public StatsSummary Summary { get; set; } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/DataContracts/ServiceInstance.cs b/src/CondenserDotNet.Server/DataContracts/ServiceInstance.cs deleted file mode 100644 index 8744cf0..0000000 --- a/src/CondenserDotNet.Server/DataContracts/ServiceInstance.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace CondenserDotNet.Server.DataContracts -{ - public class ServiceInstance - { - public string Address { get; set; } - public string ServiceID { get; set; } - public string[] ServiceTags { get; set; } - public string ServiceAddress { get; set; } - public int ServicePort { get; set; } - public string Node { get; set; } - } -} diff --git a/src/CondenserDotNet.Server/DataContracts/StatsSummary.cs b/src/CondenserDotNet.Server/DataContracts/StatsSummary.cs deleted file mode 100644 index 9cfaf23..0000000 --- a/src/CondenserDotNet.Server/DataContracts/StatsSummary.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using CondenserDotNet.Server; - -namespace CondenserDotNet.Server.DataContracts -{ - public struct StatsSummary - { - public int Http100Responses { get; set; } - public int Http200Responses { get; set; } - public int Http300Responses { get; set; } - public int Http400Responses { get; set; } - public int Http500Responses { get; set; } - public TimeSpan UpTime { get; set; } - public int HttpUnknownResponse { get; set; } - } -} diff --git a/src/CondenserDotNet.Server/Extensions/HttpResponseExtensions.cs b/src/CondenserDotNet.Server/Extensions/HttpResponseExtensions.cs deleted file mode 100644 index c2c314f..0000000 --- a/src/CondenserDotNet.Server/Extensions/HttpResponseExtensions.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; - -namespace CondenserDotNet.Server.Extensions -{ - public static class HttpResponseExtensions - { - public static Task WriteJsonAsync(this HttpResponse self, T item) => self.WriteAsync(JsonConvert.SerializeObject(item)); - } -} diff --git a/src/CondenserDotNet.Server/GetHealthCheckResult.cs b/src/CondenserDotNet.Server/GetHealthCheckResult.cs deleted file mode 100644 index 2548e39..0000000 --- a/src/CondenserDotNet.Server/GetHealthCheckResult.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using CondenserDotNet.Server.DataContracts; - -namespace CondenserDotNet.Server -{ - public struct GetHealthCheckResult - { - public bool Success; - public HealthCheck[] Checks; - } -} diff --git a/src/CondenserDotNet.Server/IConsulService.cs b/src/CondenserDotNet.Server/IConsulService.cs deleted file mode 100644 index e74e6c1..0000000 --- a/src/CondenserDotNet.Server/IConsulService.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Threading.Tasks; - -namespace CondenserDotNet.Server -{ - public interface IConsulService : IService - { - Task Initialise(string serviceId, string nodeId, string[] tags, string address, int port); - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/ICurrentState.cs b/src/CondenserDotNet.Server/ICurrentState.cs deleted file mode 100644 index e509c6f..0000000 --- a/src/CondenserDotNet.Server/ICurrentState.cs +++ /dev/null @@ -1,12 +0,0 @@ -using CondenserDotNet.Server.DataContracts; -using System; - -namespace CondenserDotNet.Server -{ - public interface ICurrentState - { - void RecordResponse(int responseCode); - StatsSummary GetSummary(); - void ResetUptime(); - } -} diff --git a/src/CondenserDotNet.Server/IHttpClientConfig.cs b/src/CondenserDotNet.Server/IHttpClientConfig.cs deleted file mode 100644 index ac69185..0000000 --- a/src/CondenserDotNet.Server/IHttpClientConfig.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Net.Http; - -namespace CondenserDotNet.Server -{ - public interface IHttpClientConfig - { - HttpClient Create(string serviceId); - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/IRouteSource.cs b/src/CondenserDotNet.Server/IRouteSource.cs deleted file mode 100644 index 6481411..0000000 --- a/src/CondenserDotNet.Server/IRouteSource.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Threading.Tasks; -using CondenserDotNet.Server.DataContracts; - -namespace CondenserDotNet.Server -{ - public interface IRouteSource - { - bool CanRequestRoute(); - Task GetServiceInstancesAsync(string serviceName); - Task TryGetHealthChecksAsync(); - } -} diff --git a/src/CondenserDotNet.Server/IRouteStore.cs b/src/CondenserDotNet.Server/IRouteStore.cs deleted file mode 100644 index c65a72e..0000000 --- a/src/CondenserDotNet.Server/IRouteStore.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using CondenserDotNet.Server.DataContracts; -using CondenserDotNet.Server.RoutingTrie; - -namespace CondenserDotNet.Server -{ - public interface IRouteStore - { - void AddService(string serviceName); - Task CreateServiceInstanceAsync(ServiceInstance info); - Dictionary> GetServices(); - bool HasService(string serviceName); - void RemoveService(string serviceName); - ICurrentState[] GetStats(); - RadixTree GetTree(); - List GetServiceInstances(string serviceName); - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/IService.cs b/src/CondenserDotNet.Server/IService.cs deleted file mode 100644 index 5a8eb85..0000000 --- a/src/CondenserDotNet.Server/IService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using CondenserDotNet.Server.DataContracts; - -namespace CondenserDotNet.Server -{ - public interface IService - { - Version[] SupportedVersions { get; } - string[] Tags { get; } - string[] Routes { get; } - string ServiceId { get; } - string NodeId { get; } - Task CallService(HttpContext context); - IPEndPoint IpEndPoint { get; } - - void UpdateRoutes(string[] routes); - - StatsSummary GetSummary(); - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/IUsageInfo.cs b/src/CondenserDotNet.Server/IUsageInfo.cs deleted file mode 100644 index f1f7d0c..0000000 --- a/src/CondenserDotNet.Server/IUsageInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace CondenserDotNet.Server -{ - public interface IUsageInfo - { - int Calls { get; } - double TotalRequestTime { get; } - - double LastRequestTime { get; } - DateTime LastRequest { get; } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/RouteStore.cs b/src/CondenserDotNet.Server/RouteStore.cs deleted file mode 100644 index ef20063..0000000 --- a/src/CondenserDotNet.Server/RouteStore.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using CondenserDotNet.Server.DataContracts; -using System.Linq; -using CondenserDotNet.Server.RoutingTrie; - -namespace CondenserDotNet.Server -{ - public class RouteStore : IRouteStore - { - private readonly RoutingData _routingData; - private readonly Func _serviceFactory; - private readonly Func _statsFactory; - readonly static List Empty = new List(); - - public RouteStore(RoutingData routingData, Func serviceFactory, - Func statsFactory) - { - _routingData = routingData; - _serviceFactory = serviceFactory; - _statsFactory = statsFactory; - } - - public void RemoveService(string serviceName) => _routingData.ServicesWithHealthChecks.Remove(serviceName); - public bool HasService(string serviceName) => _routingData.ServicesWithHealthChecks.ContainsKey(serviceName); - public void AddService(string serviceName) => _routingData.ServicesWithHealthChecks[serviceName] = new List(); - public Dictionary> GetServices() => _routingData.ServicesWithHealthChecks; - public ICurrentState[] GetStats() => _routingData.GetAllStats(); - public RadixTree GetTree() => _routingData.Tree; - - public List GetServiceInstances(string serviceName) - { - if (!_routingData.ServicesWithHealthChecks.TryGetValue(serviceName, out var services)) - { - services = Empty; - } - - return services; - } - - public Task CreateServiceInstanceAsync(ServiceInstance info) - { - var instance = _serviceFactory(); - return instance.Initialise(info.ServiceID, info.Node, info.ServiceTags, info.ServiceAddress, info.ServicePort) - .ContinueWith(t => (IService)instance); - } - } -} diff --git a/src/CondenserDotNet.Server/Routes/ChangeRoutingStrategy.cs b/src/CondenserDotNet.Server/Routes/ChangeRoutingStrategy.cs deleted file mode 100644 index 623f113..0000000 --- a/src/CondenserDotNet.Server/Routes/ChangeRoutingStrategy.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using CondenserDotNet.Core.Routing; -using CondenserDotNet.Server.RoutingTrie; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.WebUtilities; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Primitives; -using System.Collections.Generic; - -namespace CondenserDotNet.Server.Routes -{ - public sealed class ChangeRoutingStrategy : ServiceBase - { - private readonly IDefaultRouting _defaultRouting; - private readonly IServiceProvider _provider; - private readonly IRouteStore _store; - static readonly Func, bool> _externalServicesOnly = services => services.Any(s => s is IConsulService); - - public ChangeRoutingStrategy(IRouteStore store, - IServiceProvider provider, - IDefaultRouting defaultRouting) - { - _store = store; - _provider = provider; - _defaultRouting = defaultRouting; - } - - public override string[] Routes => new string[]{ CondenserRoutes.Router }; - public override IPEndPoint IpEndPoint => throw new NotImplementedException(); - - public override async Task CallService(HttpContext context) - { - var query = context.Request.QueryString; - - if (!query.HasValue) - { - await context.Response.WriteAsync("No query string args"); - context.Response.StatusCode = (int) HttpStatusCode.BadRequest; - return; - } - var queryDictionary = QueryHelpers.ParseQuery(query.Value); - - if (queryDictionary.TryGetValue("strategy", out var values)) - { - var router = _provider.GetServices>() - .SingleOrDefault(x => x.Name.Equals(values[0], StringComparison.OrdinalIgnoreCase)); - - if (router != null) - { - _defaultRouting.SetDefault(router); - ReplaceStrategy(_store.GetTree().TopNode, router); - await context.Response.WriteAsync("Routing strategy has been replaced"); - } - } - else - { - await context.Response.WriteAsync("No query string args"); - context.Response.StatusCode = (int)HttpStatusCode.BadRequest; - } - } - - private void ReplaceStrategy(Node node, IRoutingStrategy strategy) - { - foreach (var child in node.ChildrenNodes) - { - child.Item2.Services.SetRoutingStrategy(strategy, _externalServicesOnly); - ReplaceStrategy(child.Item2, strategy); - } - } - } -} diff --git a/src/CondenserDotNet.Server/Routes/CondenserRoutes.cs b/src/CondenserDotNet.Server/Routes/CondenserRoutes.cs deleted file mode 100644 index 21532a2..0000000 --- a/src/CondenserDotNet.Server/Routes/CondenserRoutes.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace CondenserDotNet.Server.Routes -{ - public static class CondenserRoutes - { - public const string Tree = "/admin/condenser/tree"; - public const string Summary = "/admin/condenser/routes/summmary"; - public const string HealthStats = "/admin/condenser/healthstats"; - public const string Health = "/admin/condenser/health"; - public const string Router = "/admin/condenser/router/replace"; - public const string Statistics = "/admin/condenser/server"; - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/Routes/HealthResponse.cs b/src/CondenserDotNet.Server/Routes/HealthResponse.cs deleted file mode 100644 index 18ca27c..0000000 --- a/src/CondenserDotNet.Server/Routes/HealthResponse.cs +++ /dev/null @@ -1,10 +0,0 @@ -using CondenserDotNet.Server.DataContracts; - -namespace CondenserDotNet.Server.Routes -{ - public class HealthResponse - { - public StatsSummary Stats { get; set; } - public HealthCheck[] HealthChecks { get; set; } - } -} diff --git a/src/CondenserDotNet.Server/Routes/HealthRouter.cs b/src/CondenserDotNet.Server/Routes/HealthRouter.cs deleted file mode 100644 index 196f4b6..0000000 --- a/src/CondenserDotNet.Server/Routes/HealthRouter.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using CondenserDotNet.Server.Extensions; -using Microsoft.AspNetCore.Http; - -namespace CondenserDotNet.Server.Routes -{ - - public sealed class HealthRouter : ServiceBase - { - public HealthRouter() => Routes = new[] { CondenserRoutes.Health }; - - public override string[] Routes { get; } - public override IPEndPoint IpEndPoint => throw new NotImplementedException(); - - public override async Task CallService(HttpContext context) - { - context.Response.StatusCode = (int)HttpStatusCode.OK; - await context.Response.WriteJsonAsync("Ok"); - } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/Routes/HealthStatsRouter.cs b/src/CondenserDotNet.Server/Routes/HealthStatsRouter.cs deleted file mode 100644 index edec8e7..0000000 --- a/src/CondenserDotNet.Server/Routes/HealthStatsRouter.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using CondenserDotNet.Server.Builder; -using CondenserDotNet.Server.DataContracts; -using CondenserDotNet.Server.Extensions; -using Microsoft.AspNetCore.Http; -using System.Linq; - -namespace CondenserDotNet.Server.Routes -{ - public sealed class HealthStatsRouter : ServiceBase - { - private readonly IHealthConfig _config; - private readonly IRouteStore _store; - - public HealthStatsRouter(IHealthConfig config, IRouteStore store) - { - _config = config; - Routes = new[] { _config.Route }; - _store = store; - } - - public override string[] Routes { get; } - public override IPEndPoint IpEndPoint => throw new NotImplementedException(); - - public override async Task CallService(HttpContext context) - { - var summary = GetAggregatedSummary(); - var response = new HealthResponse { Stats = summary }; - - if (_config.Checks?.Count > 0) - { - var checks = new Task[_config.Checks.Count]; - for (var i = 0; i < checks.Length; i++) - checks[i] = _config.Checks[i](); - await Task.WhenAll(checks); - var results = new HealthCheck[_config.Checks.Count]; - var code = HttpStatusCode.OK; - for (var i = 0; i < checks.Length; i++) - { - results[i] = checks[i].Result; - if (!results[i].Ok) - code = HttpStatusCode.InternalServerError; - } - response.HealthChecks = results; - context.Response.StatusCode = (int)code; - } - else - { - context.Response.StatusCode = (int)HttpStatusCode.OK; - } - await context.Response.WriteJsonAsync(response); - } - - private StatsSummary GetAggregatedSummary() - { - var statistics = _store.GetStats(); - - var summary = new StatsSummary(); - - foreach(var service in statistics) - { - var stats = service.GetSummary(); - - summary.Http100Responses += stats.Http100Responses; - summary.Http200Responses += stats.Http200Responses; - summary.Http300Responses += stats.Http300Responses; - summary.Http400Responses += stats.Http400Responses; - summary.Http500Responses += stats.Http500Responses; - summary.HttpUnknownResponse += stats.HttpUnknownResponse; - } - - return summary; - } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/Routes/RouteSummary.cs b/src/CondenserDotNet.Server/Routes/RouteSummary.cs deleted file mode 100644 index b2c1744..0000000 --- a/src/CondenserDotNet.Server/Routes/RouteSummary.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using CondenserDotNet.Server.Extensions; -using Microsoft.AspNetCore.Http; -using Newtonsoft.Json; - -namespace CondenserDotNet.Server.Routes -{ - public sealed class RouteSummary : ServiceBase - { - private readonly IRouteStore _routeStore; - - public RouteSummary(IRouteStore routeStore) - { - _routeStore = routeStore; - Routes = new[] { CondenserRoutes.Summary }; - } - - public override string[] Routes { get; } - - public override IPEndPoint IpEndPoint => throw new NotImplementedException(); - - public override Task CallService(HttpContext context) - { - context.Response.StatusCode = (int)HttpStatusCode.OK; - - var response = _routeStore.GetServices() - .Select(s => new - { - Service = s.Key, - Nodes = s.Value - .Select(n => new - { - n.NodeId, - n.ServiceId, - n.SupportedVersions, - n.Routes, - n.Tags - }).ToList() - }).ToList(); - - return context.Response.WriteAsync(JsonConvert.SerializeObject(response)); - } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/Routes/ServerStatisticsRoute.cs b/src/CondenserDotNet.Server/Routes/ServerStatisticsRoute.cs deleted file mode 100644 index 78737f8..0000000 --- a/src/CondenserDotNet.Server/Routes/ServerStatisticsRoute.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; -using CondenserDotNet.Server.DataContracts; -using CondenserDotNet.Server.Extensions; -using Microsoft.AspNetCore.Http; -using System.Linq; - -namespace CondenserDotNet.Server.Routes -{ - public class ServerStatsRoute : ServiceBase - { - private readonly IRouteStore _store; - - public ServerStatsRoute(IRouteStore store) => _store = store; - - public override string[] Routes { get; } = { CondenserRoutes.Statistics }; - - public override IPEndPoint IpEndPoint => throw new NotImplementedException(); - - public override async Task CallService(HttpContext context) - { - var index = context.Request.Path.Value.LastIndexOf('/'); - if (index > 0) - { - var serviceName = context.Request.Path.Value.Substring(index + 1); - var services = _store.GetServiceInstances(serviceName).ToArray(); - if (services.Any()) - { - var response = new ServerStats[services.Length]; - - for (var i = 0; i < services.Length; i++) - { - var service = services[i]; - - if (!(service is IUsageInfo usage)) continue; - - double averageRequestTime = 0; - if (usage.Calls > 0) - { - averageRequestTime = usage.TotalRequestTime / usage.Calls; - } - response[i] = new ServerStats - { - ServiceId = service.ServiceId, - NodeId = service.NodeId, - Calls = usage.Calls, - AverageRequestTime = averageRequestTime, - LastRequest = usage.LastRequest, - LastRequestTime = usage.LastRequestTime, - Summary = service.GetSummary() - }; - } - - context.Response.StatusCode = (int)HttpStatusCode.OK; - await context.Response.WriteJsonAsync(response); - - } - else - { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; - await context.Response.WriteAsync("Unknown server " + serviceName); - - } - } - else - { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; - } - } - } -} diff --git a/src/CondenserDotNet.Server/Routes/TreeRouter.cs b/src/CondenserDotNet.Server/Routes/TreeRouter.cs deleted file mode 100644 index d6b4b75..0000000 --- a/src/CondenserDotNet.Server/Routes/TreeRouter.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using CondenserDotNet.Server.DataContracts; -using CondenserDotNet.Server.Extensions; -using CondenserDotNet.Server.RoutingTrie; -using Microsoft.AspNetCore.Http; - -namespace CondenserDotNet.Server.Routes -{ - public sealed class TreeRouter : ServiceBase - { - private readonly RoutingData _routingData; - - public TreeRouter(RoutingData routingData) - { - _routingData = routingData; - Routes = new[] { CondenserRoutes.Tree }; - } - - public override string[] Routes { get; } - public override IPEndPoint IpEndPoint => throw new NotImplementedException(); - - public override Task CallService(HttpContext context) - { - context.Response.StatusCode = (int)HttpStatusCode.OK; - - var nodeDto = new Node(); - MapTo(_routingData.Tree.TopNode, nodeDto); - return context.Response.WriteJsonAsync(nodeDto); - } - - private void MapTo(Node node, Node dto) - { - dto.Path = node.Path; - dto.Prefix = node.Prefix; - dto.Services = node.Services.ToString(); - - var children = new Dictionary(node.ChildrenNodes.Count); - dto.Nodes = children; - - for (var i = 0; i < node.ChildrenNodes.Count; i++) - { - var nodeDto = new Node(); - var key = string.Join(",", node.ChildrenNodes.ElementAt(i).Item1); - children.Add(key, nodeDto); - MapTo(node.ChildrenNodes.ElementAt(i).Item2, nodeDto); - } - } - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/RoutingData.cs b/src/CondenserDotNet.Server/RoutingData.cs deleted file mode 100644 index 905339b..0000000 --- a/src/CondenserDotNet.Server/RoutingData.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Collections.Generic; -using CondenserDotNet.Core.Routing; -using CondenserDotNet.Server.RoutingTrie; -using System.Linq; - -namespace CondenserDotNet.Server -{ - public class RoutingData - { - private readonly Dictionary _stats = new Dictionary(); - - public RoutingData(RadixTree tree) => Tree = tree; - - public Dictionary> ServicesWithHealthChecks { get; } = new Dictionary>(); - public RadixTree Tree { get; } - - public static RoutingData BuildDefault() - { - ChildContainer factory() - { - var randomRoutingStrategy = new RandomRoutingStrategy(); - return new ChildContainer(new DefaultRouting(new[] { randomRoutingStrategy }, null)); - } - return new RoutingData(new RadixTree(factory)); - } - - public ICurrentState GetStats(string serviceId) - { - lock(_stats) - { - if(!_stats.TryGetValue(serviceId,out var value)) - { - value = new CurrentState(); - _stats.Add(serviceId, value); - } - return value; - } - } - - public ICurrentState[] GetAllStats() - { - lock(_stats) - { - return _stats.Values.ToArray(); - } - } - } -} diff --git a/src/CondenserDotNet.Server/RoutingHost.cs b/src/CondenserDotNet.Server/RoutingHost.cs deleted file mode 100644 index 57e44a5..0000000 --- a/src/CondenserDotNet.Server/RoutingHost.cs +++ /dev/null @@ -1,195 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using CondenserDotNet.Core; -using CondenserDotNet.Core.DataContracts; -using CondenserDotNet.Server.DataContracts; -using Microsoft.Extensions.Logging; -using CondenserDotNet.Core.Routing; - -namespace CondenserDotNet.Server -{ - public class RoutingHost - { - private readonly CustomRouter _router; - private readonly ILogger _logger; - private readonly IRouteStore _store; - private readonly IRouteSource _source; - private readonly IRoutingConfig _config; - - public RoutingHost(ILoggerFactory logger, - CustomRouter router, IRouteStore store, IRouteSource source, - IRoutingConfig config) - { - _router = router; - _logger = logger?.CreateLogger(); - _store = store; - _source = source; - _config = config; - - var ignore = WatchLoop(); - } - - public CustomRouter Router => _router; - - private async Task WatchLoop() - { - while (_source.CanRequestRoute()) - { - try - { - var result = await _source.TryGetHealthChecksAsync(); - if (!result.Success) - { - await Task.Delay(TimeSpan.FromSeconds(1)); - continue; - } - - await ProcessHealthChecksAsync(result.Checks); - } - catch (Exception ex) - { - _logger?.LogError(1000, ex, "There was an error getting available services from consul"); - await Task.Delay(TimeSpan.FromSeconds(1)); - } - } - } - - private async Task ProcessHealthChecksAsync(HealthCheck[] healthChecks) - { - _logger?.LogInformation("Total number of health checks returned was {healthCheckCount}", healthChecks.Length); - var infoList = BuildListOfHealthyServiceInstances(healthChecks); - RemoveDeadInstances(infoList); - var services = _store.GetServices(); - foreach (var service in services) - { - var infoService = await _source.GetServiceInstancesAsync(service.Key); - foreach (var info in infoService) - { - var instance = GetInstance(info, service.Value); - if (instance == null) - { - await CreateNewServiceInstanceAsync(service, info); - } - else - { - UpdateExistingRoutes(instance, info); - } - } - } - _router.CleanUpRoutes(); - _config.OnRoutesBuilt?.Invoke(services.Keys.ToArray()); - } - - private async Task CreateNewServiceInstanceAsync(KeyValuePair> service, ServiceInstance info) - { - var instance = await _store.CreateServiceInstanceAsync(info); - service.Value.Add(instance); - _logger?.LogInformation("Adding a new service instance {serviceId} that is running the service {service} mapped to {routes}", instance.ServiceId, service.Key, instance.Routes); - _router.AddNewService(instance); - } - - private void UpdateExistingRoutes(IService instance, ServiceInstance info) - { - var routes = ServiceUtils.RoutesFromTags(info.ServiceTags); - if (instance.Routes.SequenceEqual(routes)) - { - return; - } - foreach (var newTag in routes.Except(instance.Routes)) - { - _router.AddServiceToRoute(newTag, instance); - } - foreach (var oldTag in instance.Routes.Except(routes)) - { - _router.RemoveServiceFromRoute(oldTag, instance); - } - instance.UpdateRoutes(routes); - } - - private IService GetInstance(ServiceInstance service, List instanceList) - { - for (var i = 0; i < instanceList.Count; i++) - { - if (instanceList[i].ServiceId == service.ServiceID) - { - return instanceList[i]; - } - } - return null; - } - - private void RemoveDeadInstances(List infoList) - { - //All services that are removed - foreach (var service in _store.GetServices().ToArray()) - { - foreach (var instance in service.Value.ToArray()) - { - if (!HasInstance(instance.ServiceId, infoList)) - { - //Service is dead remove it - service.Value.Remove(instance); - _logger?.LogInformation("The service instance {serviceId} for service {serviceName} was removed due to failing health", instance.ServiceId, service.Key); - _router.RemoveService(instance); - } - } - if (service.Value.Count == 0) - { - _store.RemoveService(service.Key); - } - } - foreach (var i in infoList) - { - if (!_store.HasService(i.Service)) - { - _logger?.LogInformation("New service {serviceName} added because we have found instances of it", i.Service); - _store.AddService(i.Service); - } - } - } - - private List BuildListOfHealthyServiceInstances(HealthCheck[] healthChecks) - { - var downNodes = new HashSet(); - //Now we get all service instances that are working - var infoList = new List(); - foreach (var check in healthChecks) - { - if ((check.CheckID == "serfHealth" || check.CheckID == "_node_maintenance") && check.Status != HealthCheckStatus.Passing) - { - downNodes.Add(check.Node); - } - } - _logger?.LogInformation("List of nodes that are currently down is {downNodes}", downNodes); - foreach (var check in healthChecks) - { - if (!string.IsNullOrEmpty(check.ServiceID) && check.Status == HealthCheckStatus.Passing && !downNodes.Contains(check.Node)) - { - infoList.Add(new InformationService() - { - Service = check.ServiceName, - ID = check.ServiceID - }); - } - } - _logger?.LogInformation("Total number of instances with passing health checks is {passingHealthChecks}", infoList.Count); - return infoList; - } - - private bool HasInstance(string serviceID, List infoList) - { - for (var i = 0; i < infoList.Count; i++) - { - if (infoList[i].ID == serviceID) - { - return true; - } - } - return false; - } - } -} diff --git a/src/CondenserDotNet.Server/RoutingMiddleware.cs b/src/CondenserDotNet.Server/RoutingMiddleware.cs deleted file mode 100644 index 5e757bb..0000000 --- a/src/CondenserDotNet.Server/RoutingMiddleware.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Net; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; - -namespace CondenserDotNet.Server -{ - public class RoutingMiddleware - { - private readonly RequestDelegate _next; - private readonly ILogger _logger; - private readonly RoutingHost _routeData; - private static readonly Task _completedTask = Task.FromResult(0); - - public RoutingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, RoutingHost routeData) - { - _next = next; - _logger = loggerFactory?.CreateLogger(); - _routeData = routeData; - } - - public Task Invoke(HttpContext httpContext) - { - using (var scope = _logger?.BeginScope("Started request scope {path}", httpContext.Request.Path)) - { - var service = _routeData.Router.GetServiceFromRoute(httpContext.Request.Path, out var matchedPath); - if (service == null) - { - _logger?.LogInformation("No matching route for {path}", httpContext.Request.Path); - httpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; - return _completedTask; - } - _logger?.LogInformation("Found matching path {path} to service {serviceName}", httpContext.Request.Path, service.ServiceId); - httpContext.Features.Set(service); - httpContext.Items.Add("matchedPath", matchedPath); - return _next.Invoke(httpContext); - } - } - } -} diff --git a/src/CondenserDotNet.Server/RoutingTrie/ChildContainer.cs b/src/CondenserDotNet.Server/RoutingTrie/ChildContainer.cs deleted file mode 100644 index 7127477..0000000 --- a/src/CondenserDotNet.Server/RoutingTrie/ChildContainer.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using CondenserDotNet.Core.Routing; -using System; - -namespace CondenserDotNet.Server.RoutingTrie -{ - public class ChildContainer - { - private IRoutingStrategy _routingStrategy; - private List _services = new List(); - - public ChildContainer(IDefaultRouting defaultStrategy) => _routingStrategy = defaultStrategy.Default; - - public int Count => Volatile.Read(ref _services).Count; - - public void SetRoutingStrategy(IRoutingStrategy routingStrategy, Func, bool> applies) - { - var services = Volatile.Read(ref _services); - - if (applies(services)) - { - Interlocked.Exchange(ref _routingStrategy, routingStrategy); - } - - } - public override string ToString() => $"Total Services Registered {_services.Count}"; - - public void AddService(T service) - { - var newServices = new List(Volatile.Read(ref _services)) - { - service - }; - Volatile.Write(ref _services, newServices); - } - - public bool RemoveService(T service) - { - var newServices = new List(Volatile.Read(ref _services)); - var result = newServices.Remove(service); - Volatile.Write(ref _services, newServices); - return result; - } - - public T GetService() - { - var services = Volatile.Read(ref _services); - if (services.Count > 0) - { - //Simple random selector - return _routingStrategy.RouteTo(services); - } - return default; - } - } -} diff --git a/src/CondenserDotNet.Server/RoutingTrie/Node.cs b/src/CondenserDotNet.Server/RoutingTrie/Node.cs deleted file mode 100644 index f822652..0000000 --- a/src/CondenserDotNet.Server/RoutingTrie/Node.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using System.Linq; - -namespace CondenserDotNet.Server.RoutingTrie -{ - public class Node - { - private readonly Func> _factory; - private NodeContainer _childrenNodes; - - public Node(string[] prefix, string pathToHere, Func> factory) - : this(prefix, pathToHere, 1, factory) - { - } - - public Node(string[] prefix, string pathToHere, int initialKeySize, Func> factory) - { - _factory = factory; - Services = factory(); - Prefix = prefix; - _childrenNodes = new NodeContainer(initialKeySize, _factory); - Path = pathToHere + "/" + string.Join("/", Prefix); - if (Path == "/") - { - Path = ""; - } - } - - public string Path { get; private set; } - public ChildContainer Services { get; private set; } - public NodeContainer ChildrenNodes => _childrenNodes; - public string[] Prefix { get; private set; } - - public Node CloneWithNewPrefix(string[] newPrefix, string newPath) - { - var newNode = new Node(newPrefix, newPath, _factory) - { - _childrenNodes = _childrenNodes, - Services = Services - }; - return newNode; - } - - public void AddRoute(string[] route, T service) - { - if (route.Length == 0) - { - Services.AddService(service); - return; - } - var children = System.Threading.Volatile.Read(ref _childrenNodes); - - for (var i = Math.Min(children.KeyLength, route.Length); i > 0; i--) - { - //We need to first see if the first part of the route matches any of the current nodes - var matche = children.FindFirstNodeThatMatches(route, i); - if (matche != null) - { - //we found something that matched our prefix, if the key length is a match then just pass down the service to the next node - if (children.KeyLength == i) - { - matche.AddRoute(route.Skip(i).ToArray(), service); - return; - } - else - { - var newChildren = children.SplitContainer(i, Path); - newChildren[route].AddRoute(route.Skip(i).ToArray(), service); - System.Threading.Volatile.Write(ref _childrenNodes, newChildren); - return; - } - } - } - //Nothing matched, if we have a key >= current prefix length we can just add it, otherwise we need a split - if (route.Length >= children.KeyLength) - { - //Create a new node and add it - var n = new Node(route.Take(children.KeyLength).ToArray(), Path, _factory); - n.AddRoute(route.Skip(children.KeyLength).ToArray(), service); - - var newChildren = children.Clone(); - newChildren.Add(n.Prefix, n); - System.Threading.Volatile.Write(ref _childrenNodes, newChildren); - return; - } - else - { - //The key is smaller than the current key length so we are going to have to split before we add - var newChildren = ChildrenNodes.SplitContainer(route.Length, Path); - var n = new Node(route, Path, _factory); - n.AddRoute(new string[0], service); - newChildren.Add(n.Prefix, n); - - System.Threading.Volatile.Write(ref _childrenNodes, newChildren); - return; - } - } - - public int MaxDepth() => _childrenNodes.MaxNodeDepth() + 1; - - internal bool RemoveServiceFromRoute(string[] route, T service) - { - var container = System.Threading.Volatile.Read(ref _childrenNodes); - if (route.Length == 0) - { - return Services.RemoveService(service); - } - if (container.TryGetValue(route, out var child)) - { - return child.RemoveServiceFromRoute(route.Skip(container.KeyLength).ToArray(), service); - } - return false; - } - - internal void RemoveService(T service) - { - var children = System.Threading.Volatile.Read(ref _childrenNodes); - Services.RemoveService(service); - foreach (var kv in children) - { - kv.Item2.RemoveService(service); - } - } - - public T GetService(string[] route, out string matchedPath) - { - var container = System.Threading.Volatile.Read(ref _childrenNodes); - if (route.Length == 0) - { - matchedPath = Path; - return Services.GetService(); - } - if (container.TryGetValue(route, out var child)) - { - var returnService = child.GetService(route.Skip(container.KeyLength).ToArray(), out matchedPath); - if (returnService != null) - { - return returnService; - } - } - matchedPath = Path; - return Services.GetService(); - } - - private bool CanCompress(NodeContainer children) - { - foreach (var kv in children) - { - if (kv.Item2.Services.Count > 0) - { - return false; - } - } - return true; - } - - public void Compress() - { - - /* - var children = System.Threading.Volatile.Read(ref _childrenNodes); - if (children.Count == 0) return; - var canCompress = CanCompress(children); - if (!canCompress) - { - foreach (var kv in children) - { - kv.Item2.Compress(); - } - return; - } - var newMerged = new NodeContainer(children.KeyLength + 1, _factory); - foreach (var kv in children) - { - foreach (var childkv in kv.Item2.ChildrenNodes) - { - //This will prune out orphaned trees - if (childkv.Item2.Services.Count > 0 || childkv.Item2.ChildrenNodes.Count > 0) - { - var mergedKey = Enumerable.Concat(kv.Item1, childkv.Item1).ToArray(); - var newNode = childkv.Item2.CloneWithNewPrefix(mergedKey, Path); - newMerged.Add(newNode.Prefix, newNode); - } - } - } - System.Threading.Volatile.Write(ref _childrenNodes, newMerged); - Compress(); - */ - } - - public override string ToString() => $"Path {string.Join("/", Prefix)} Services {Services.Count}"; - } -} diff --git a/src/CondenserDotNet.Server/RoutingTrie/NodeComparer.cs b/src/CondenserDotNet.Server/RoutingTrie/NodeComparer.cs deleted file mode 100644 index 8cac159..0000000 --- a/src/CondenserDotNet.Server/RoutingTrie/NodeComparer.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace CondenserDotNet.Server.RoutingTrie -{ - public class NodeComparer : IEqualityComparer - { - private readonly int _compareLength; - - public NodeComparer(int compareLength) => _compareLength = compareLength; - - public int CompareLength => _compareLength; - - public bool Equals(string[] x, string[] y) - { - if (y.Length < _compareLength || x.Length < _compareLength) - { - return false; - } - - for (var i = 0; i < _compareLength; i++) - { - if (x[i] != y[i]) return false; - } - return true; - } - - public int GetHashCode(string[] obj) - { - unchecked // Overflow is fine, just wrap - { - var hash = 17; - for (var i = 0; i < Math.Min(_compareLength, obj.Length); i++) - { - hash = hash * 23 + obj[i].GetHashCode(); - } - return hash; - } - } - } -} diff --git a/src/CondenserDotNet.Server/RoutingTrie/NodeContainer.cs b/src/CondenserDotNet.Server/RoutingTrie/NodeContainer.cs deleted file mode 100644 index 798385c..0000000 --- a/src/CondenserDotNet.Server/RoutingTrie/NodeContainer.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; - -namespace CondenserDotNet.Server.RoutingTrie -{ - public class NodeContainer : IEnumerable>> - { - private readonly int _keylength; - private readonly Func> _factory; - private readonly NodeComparer _comparer; - private List>> _children; - - public NodeContainer(int keyLength, Func> factory) - { - _keylength = keyLength; - _comparer = new NodeComparer(_keylength); - _factory = factory; - _children = new List>>(5); - } - - public int Count => _children.Count; - public int KeyLength => _keylength; - - public Node FindFirstNodeThatMatches(string[] route, int compareLength) - { - NodeComparer compare; - if (compareLength != _keylength) - { - compare = new NodeComparer(compareLength); - } - else - { - compare = _comparer; - } - foreach (var child in _children) - { - if (compare.Equals(child.Item1, route)) - { - return child.Item2; - } - } - return null; - } - - public void Add(string[] route, Node node) => _children.Add(Tuple.Create(route, node)); - - public NodeContainer SplitContainer(int newKeyLength, string currentPath) - { - var newContainer = new NodeContainer(newKeyLength, _factory); - foreach (var kv in _children) - { - var newPrefix = kv.Item1.Take(newKeyLength).ToArray(); - var newTailPrefix = kv.Item1.Skip(newKeyLength).ToArray(); - if (!newContainer.TryGetValue(newPrefix, out var newHeadNode)) - { - newHeadNode = new Node(newPrefix, currentPath, KeyLength - newKeyLength, _factory); - newContainer.Add(newPrefix, newHeadNode); - } - var oldNode = kv.Item2.CloneWithNewPrefix(newTailPrefix, newHeadNode.Path); - newHeadNode.ChildrenNodes.Add(newTailPrefix, oldNode); - } - return newContainer; - } - - public bool TryGetValue(string[] searchValue, out Node node) - { - foreach (var child in _children) - { - if (_comparer.Equals(child.Item1, searchValue)) - { - node = child.Item2; - return true; - } - } - node = null; - return false; - } - - public IEnumerator>> GetEnumerator() => _children.GetEnumerator(); - - public Node this[string[] key] - { - get - { - if (TryGetValue(key, out var node)) - { - return node; - } - throw new ArgumentOutOfRangeException(); - } - } - - public int MaxNodeDepth() - { - var nodeDepth = 0; - foreach (var n in _children) - { - nodeDepth = Math.Max(n.Item2.MaxDepth(), nodeDepth); - } - return nodeDepth; - } - - internal NodeContainer Clone() - { - var container = new NodeContainer(KeyLength, _factory) - { - _children = _children.ToList() - }; - return container; - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } -} diff --git a/src/CondenserDotNet.Server/RoutingTrie/RadixTree.cs b/src/CondenserDotNet.Server/RoutingTrie/RadixTree.cs deleted file mode 100644 index 056230c..0000000 --- a/src/CondenserDotNet.Server/RoutingTrie/RadixTree.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; - -namespace CondenserDotNet.Server.RoutingTrie -{ - public class RadixTree - { - private readonly Node _topNode; - private readonly object _writeLock = new object(); - private static readonly char[] _routeSplit = new char[] { '/' }; - private readonly bool _killCase = true; - - public RadixTree(Func> factory) => _topNode = new Node(new string[0], "", factory); - - public Node TopNode => _topNode; - - public void AddServiceToRoute(string route, T service) - { - if (_killCase) - { - route = route.ToUpperInvariant(); - } - lock (_writeLock) - { - _topNode.AddRoute(route.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries), service); - } - } - - public T GetServiceFromRoute(string route, out string matchedPath) - { - if (_killCase) - { - route = route.ToUpperInvariant(); - } - return _topNode.GetService(route.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries), out matchedPath); - } - - public void Compress() - { - lock (_writeLock) - { - _topNode.Compress(); - } - } - - public void RemoveService(T service) - { - lock (_writeLock) - { - _topNode.RemoveService(service); - } - } - - public void RemoveServiceFromRoute(string route, T service) - { - if (_killCase) - { - route = route.ToUpperInvariant(); - } - lock (_writeLock) - { - _topNode.RemoveServiceFromRoute(route.Split(_routeSplit, StringSplitOptions.RemoveEmptyEntries), service); - } - } - - public Node GetTopNode() => _topNode; - public int MaxDepth() => _topNode.MaxDepth() + 1; - } -} \ No newline at end of file diff --git a/src/CondenserDotNet.Server/Service.cs b/src/CondenserDotNet.Server/Service.cs deleted file mode 100644 index 783353a..0000000 --- a/src/CondenserDotNet.Server/Service.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System; -using System.Diagnostics; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using CondenserDotNet.Core; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using CondenserDotNet.Server.DataContracts; - -namespace CondenserDotNet.Server -{ - public class Service : IDisposable, IConsulService, IUsageInfo - { - private HttpClient _httpClient; - private readonly System.Threading.CountdownEvent _waitUntilRequestsAreFinished = new System.Threading.CountdownEvent(1); - private string _address; - private int _port; - private ICurrentState _stats; - private readonly Func _clientFactory; - private IPEndPoint _ipEndPoint; - private Version[] _supportedVersions; - private string[] _tags; - private string _serviceId; - private int _calls; - private int _totalRequestTime; - private DateTime _lastRequest; - private double _lastRequestTime; - private string _hostString; - private readonly ILogger _logger; - private string _protocolScheme; - private RoutingData _routingData; - - public Service(Func clientFactory, ILoggerFactory logger, RoutingData routingData) - { - _logger = logger?.CreateLogger(); - _clientFactory = clientFactory; - _routingData = routingData; - } - - public Version[] SupportedVersions => _supportedVersions; - public string[] Tags => _tags; - public string[] Routes { get; private set; } - public string ServiceId => _serviceId; - public string NodeId { get; private set; } - public int Calls => _calls; - public double TotalRequestTime => _totalRequestTime; - public double LastRequestTime => _lastRequestTime; - public DateTime LastRequest => _lastRequest; - public IPEndPoint IpEndPoint => _ipEndPoint; - - public async Task CallService(HttpContext context) - { - var sw = new Stopwatch(); - _waitUntilRequestsAreFinished.AddCount(); - try - { - sw.Start(); - var uriString = $"{_protocolScheme}://{_hostString}{context.Request.Path.Value}{context.Request.QueryString}"; - - var uri = new Uri(uriString); - - var requestMessage = new HttpRequestMessage(); - if (!string.Equals(context.Request.Method, "GET", StringComparison.OrdinalIgnoreCase) && - !string.Equals(context.Request.Method, "HEAD", StringComparison.OrdinalIgnoreCase) && - !string.Equals(context.Request.Method, "DELETE", StringComparison.OrdinalIgnoreCase) && - !string.Equals(context.Request.Method, "TRACE", StringComparison.OrdinalIgnoreCase)) - { - var streamContent = new StreamContent(context.Request.Body); - requestMessage.Content = streamContent; - } - requestMessage.RequestUri = uri; - requestMessage.Method = new HttpMethod(context.Request.Method); - // Copy the request headers - foreach (var header in context.Request.Headers) - { - if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null) - { - requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); - } - } - - requestMessage.Headers.Host = _hostString; - - requestMessage.Method = new HttpMethod(context.Request.Method); - - using (var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted)) - { - context.Response.StatusCode = (int)responseMessage.StatusCode; - _stats?.RecordResponse(context.Response.StatusCode); - foreach (var header in responseMessage.Headers) - { - context.Response.Headers[header.Key] = header.Value?.ToArray(); - } - - foreach (var header in responseMessage.Content.Headers) - { - context.Response.Headers[header.Key] = header.Value?.ToArray(); - } - - // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response. - context.Response.Headers.Remove("transfer-encoding"); - await responseMessage.Content.CopyToAsync(context.Response.Body); - } - } - finally - { - sw.Stop(); - - var time = (int)sw.Elapsed.TotalMilliseconds; - - - System.Threading.Interlocked.Add(ref _totalRequestTime, time); - System.Threading.Interlocked.Increment(ref _calls); - System.Threading.Interlocked.Exchange(ref _lastRequestTime, time); - _lastRequest = DateTime.UtcNow; - - _waitUntilRequestsAreFinished.Signal(); - } - } - - public override int GetHashCode() => ServiceId.GetHashCode(); - - public override bool Equals(object obj) - { - if (obj is Service otherService) - { - if (otherService.ServiceId != ServiceId) - { - return false; - } - if (!Tags.SequenceEqual(otherService.Tags)) - { - return false; - } - return true; - } - return false; - } - - public void UpdateRoutes(string[] routes) => Routes = routes; - - public async Task Initialise(string serviceId, string nodeId, string[] tags, string address, int port) - { - _stats = _routingData.GetStats(serviceId); - _address = address; - _port = port; - _tags = tags; - Routes = ServiceUtils.RoutesFromTags(tags); - _serviceId = serviceId; - - NodeId = nodeId; - try - { - var result = await Dns.GetHostAddressesAsync(address); - _ipEndPoint = new IPEndPoint(result[0], port); - } - catch - { - _logger?.LogWarning("Unable to resolve the host address for {address} when adding the service", address); - } - _supportedVersions = tags.Where(t => t.StartsWith("version=")).Select(t => new Version(t.Substring(8))).ToArray(); - _protocolScheme = tags.Where(t => t.StartsWith("protocolScheme-")) - .Select(t => t.Substring("protocolScheme-".Length)).FirstOrDefault() ?? "http"; - - _hostString = $"{_address}:{_port}"; - _httpClient = _clientFactory?.Invoke(ServiceId) ?? new HttpClient(); - } - - public override string ToString() => _serviceId; - - public void Dispose() - { - _waitUntilRequestsAreFinished.Signal(); - _waitUntilRequestsAreFinished.Wait(5000); - _httpClient.Dispose(); - _waitUntilRequestsAreFinished.Dispose(); - } - - public StatsSummary GetSummary() => _stats.GetSummary(); - } -} diff --git a/src/CondenserDotNet.Server/ServiceBase.cs b/src/CondenserDotNet.Server/ServiceBase.cs deleted file mode 100644 index bac5ae6..0000000 --- a/src/CondenserDotNet.Server/ServiceBase.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using CondenserDotNet.Server.DataContracts; -using Microsoft.AspNetCore.Http; - -namespace CondenserDotNet.Server -{ - public abstract class ServiceBase : IService - { - public Version[] SupportedVersions { get; } - public string[] Tags { get; } - public abstract string[] Routes { get; } - public string ServiceId { get; } - public string NodeId { get; } - public abstract Task CallService(HttpContext context); - public abstract IPEndPoint IpEndPoint { get; } - - public virtual void UpdateRoutes(string[] routes) - { - } - - public StatsSummary GetSummary() => default; - } -} diff --git a/src/CondenserDotNet.Server/ServiceCallMiddleware.cs b/src/CondenserDotNet.Server/ServiceCallMiddleware.cs deleted file mode 100644 index 20c3611..0000000 --- a/src/CondenserDotNet.Server/ServiceCallMiddleware.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; - -namespace CondenserDotNet.Server -{ - public class ServiceCallMiddleware - { - private readonly RequestDelegate _next; - private readonly ILogger _logger; - private readonly RoutingHost _routeData; - - public ServiceCallMiddleware(RequestDelegate next, ILoggerFactory loggerFactory, RoutingHost routeData) - { - _next = next; - _logger = loggerFactory?.CreateLogger(); - _routeData = routeData; - } - - public Task Invoke(HttpContext context) - { - var service = context.Features.Get(); - return service.CallService(context); - } - } -} From 77f5170600ac1921155941cdb5452590014f0748 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Wed, 2 Oct 2019 00:11:59 +0100 Subject: [PATCH 5/5] fix appveyor --- appveyor.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8969eb8..c5706b4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,18 +25,16 @@ test_script: after_test: # Build and pack source - - ps: iex ((Get-ChildItem ($env:USERPROFILE + '\.nuget\packages\OpenCover'))[0].FullName + '\tools\OpenCover.Console.exe' + ' -register:user -target:".\script\runtests.bat" -searchdirs:"..\test\Condenser.Tests.Integration\bin\Debug\netcoreapp1.1;..\test\CondenserTests\bin\debug\netcoreapp1.1" -oldstyle -output:coverage.xml -skipautoprops -hideskipped:All -returntargetcode -filter:"+[Condenser*]* -[*Test*]*"') + - ps: iex ((Get-ChildItem ($env:USERPROFILE + '\.nuget\packages\OpenCover'))[0].FullName + '\tools\OpenCover.Console.exe' + ' -register:user -target:".\script\runtests.bat" -searchdirs:"..\test\Condenser.Tests.Integration\bin\Debug\netcoreapp3.10;..\test\CondenserTests\bin\debug\netcoreapp3.0" -oldstyle -output:coverage.xml -skipautoprops -hideskipped:All -returntargetcode -filter:"+[Condenser*]* -[*Test*]*"') - ps: iex ((Get-ChildItem ($env:USERPROFILE + '\.nuget\packages\coveralls.io'))[0].FullName + '\tools\coveralls.net.exe' + ' --opencover coverage.xml') - "SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH%" - pip install codecov - codecov -f "coverage.xml" - dotnet build -c Release - dotnet pack -c Release src/CondenserDotNet.Client - - dotnet pack -c Release src/CondenserDotNet.Server - dotnet pack -c Release src/CondenserDotNet.Core - dotnet pack -c Release src/CondenserDotNet.Configuration - dotnet pack -c Release src/CondenserDotNet.Middleware - - dotnet pack -c Release src/CondenserDotNet.Server.Extensions artifacts: