Skip to content
This repository was archived by the owner on Jan 13, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions LiteHttp.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
<Folder Name="/src/Server/Features/Limits/src/">
<Project Path="src/Server/Features/Limits/src/LiteHttp.Limits.csproj" />
</Folder>
<Folder Name="/src/Server/Features/Limits/tests/">
<Project Path="src/Server/Features/Limits/tests/LiteHttp.Limits.Tests.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/" />
<Folder Name="/src/Server/Infrastructure/ConnectionManager/" />
<Folder Name="/src/Server/Infrastructure/ConnectionManager/src/">
Expand All @@ -51,6 +54,13 @@
<Folder Name="/src/Server/Infrastructure/Events/src/">
<Project Path="src/Server/Infrastructure/Events/src/LiteHttp.Infrastructure.Events.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/Events/tests/">
<Project Path="src/Server/Infrastructure/Events/tests/LiteHttp.Infrastructure.Events.Tests.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/Heartbeat/" />
<Folder Name="/src/Server/Infrastructure/Heartbeat/src/">
<Project Path="src/Server/Infrastructure/Heartbeat/src/LiteHttp.Heartbeat.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/Helpers/" />
<Folder Name="/src/Server/Infrastructure/Helpers/src/">
<Project Path="src/Server/Infrastructure/Helpers/src/LiteHttp.Helpers.csproj" />
Expand All @@ -74,10 +84,16 @@
<Folder Name="/src/Server/Infrastructure/RequestProcessors/src/">
<Project Path="src/Server/Infrastructure/RequestProcessors/src/LiteHttp.RequestProcessors.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/RequestProcessors/tests/">
<Project Path="src/Server/Infrastructure/RequestProcessors/tests/LiteHttp.RequestProcessors.Tests.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/Routing/" />
<Folder Name="/src/Server/Infrastructure/Routing/src/">
<Project Path="src/Server/Infrastructure/Routing/src/LiteHttp.Routing.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/Routing/tests/">
<Project Path="src/Server/Infrastructure/Routing/tests/LiteHttp.Routing.Tests.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/Server/" />
<Folder Name="/src/Server/Infrastructure/Server/src/">
<Project Path="src/Server/Infrastructure/Server/src/LiteHttp.Server.csproj" />
Expand All @@ -90,18 +106,6 @@
<Folder Name="/src/Server/LiteHttp/src/">
<Project Path="src/Server/LiteHttp/src/LiteHttp.csproj" />
</Folder>
<Folder Name="/src/Server/Features/Limits/tests/">
<Project Path="src/Server/Features/Limits/tests/LiteHttp.Limits.Tests.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/Events/tests/">
<Project Path="src/Server/Infrastructure/Events/tests/LiteHttp.Infrastructure.Events.Tests.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/RequestProcessors/tests/">
<Project Path="src/Server/Infrastructure/RequestProcessors/tests/LiteHttp.RequestProcessors.Tests.csproj" />
</Folder>
<Folder Name="/src/Server/Infrastructure/Routing/tests/">
<Project Path="src/Server/Infrastructure/Routing/tests/LiteHttp.Routing.Tests.csproj" />
</Folder>
<Folder Name="/src/Server/LiteHttp/tests/">
<Project Path="src/Server/LiteHttp/tests/LiteHttp.Tests.csproj" />
</Folder>
Expand Down
75 changes: 75 additions & 0 deletions src/Server/Infrastructure/Heartbeat/src/Heartbeat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Based on: ASP.NET Core Kestrel Heartbeat
// Source: https://github.com/dotnet/aspnetcore/blob/main/src/Servers/Kestrel/Core/src/Internal/Infrastrutcure/Heartbeat.cs
// Retrieved: 2026-01-06
// License: MIT license

using System.Diagnostics;

using LiteHttp.Logging.Abstractions;

namespace LiteHttp.Heartbeat;

public sealed class Heartbeat : IDisposable
{
private static readonly TimeSpan Interval = TimeSpan.FromSeconds(1);
private const string NoHandlersExceptionString = "Heartbeat not needed to be initialized if here is no handlers in app";

private readonly Action[] _callbacks;
private readonly ManualResetEventSlim _timer = new ManualResetEventSlim(false, 0);
private readonly Thread _heartbeatThread;
private readonly ILogger<Heartbeat> _logger;

public Heartbeat(IHeartbeatHandler[] heartbeatHandlers, ILogger<Heartbeat> logger)
{
Debug.Assert(heartbeatHandlers.Length > 0, NoHandlersExceptionString);

ArgumentException.ThrowIfNullOrEmpty(NoHandlersExceptionString);

_logger = logger;

_callbacks = new Action[heartbeatHandlers.Length];

for (int i = 0; i < heartbeatHandlers.Length; i++)
_callbacks[i] = heartbeatHandlers[i].OnHeartbeat;

_heartbeatThread = new Thread(Loop)
{
IsBackground = true,
Name = "Heartbeat"
};

_heartbeatThread.Start();
}

private void OnHeartbeat()
{
foreach (var callback in _callbacks)
{
try
{
callback();
// optional: detect long heartbeat
}
catch (Exception ex)

Check warning on line 53 in src/Server/Infrastructure/Heartbeat/src/Heartbeat.cs

View workflow job for this annotation

GitHub Actions / build

The variable 'ex' is declared but never used

Check warning on line 53 in src/Server/Infrastructure/Heartbeat/src/Heartbeat.cs

View workflow job for this annotation

GitHub Actions / build

The variable 'ex' is declared but never used
{
_logger.LogTrace($"Exception thrown in heartbeat handler");
}
}
}

private void Loop()
{
while (!_timer.Wait(Interval))
OnHeartbeat();
}

public void Dispose()
{
_timer.Set();

if (_heartbeatThread.IsAlive)
_heartbeatThread.Join();

_timer.Dispose();
}
}
6 changes: 6 additions & 0 deletions src/Server/Infrastructure/Heartbeat/src/IHeartbeatHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace LiteHttp.Heartbeat;

public interface IHeartbeatHandler
{
void OnHeartbeat();
}
13 changes: 13 additions & 0 deletions src/Server/Infrastructure/Heartbeat/src/LiteHttp.Heartbeat.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Logging\src\LiteHttp.Logging.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace LiteHttp.RequestProcessors.Adapters;
using LiteHttp.Helpers;

namespace LiteHttp.RequestProcessors.Adapters;

public sealed class ParserEventAdapter
{
Expand All @@ -9,14 +11,24 @@
var buffer = connectionContext.SocketEventArgs.Buffer;
var result = _parser.Parse(buffer);

if (!result.Success) OnParsingError(connectionContext, InternalActionResults.BadRequest());

connectionContext.HttpContext = result.Value;

OnParsed(connectionContext);
}

private event Action<ConnectionContext> Parsed;

Check warning on line 21 in src/Server/Infrastructure/RequestProcessors/src/LiteHttp/RequestProcessors/Adapters/ParserEventAdapter.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable event 'Parsed' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the event as nullable.
private void OnParsed(ConnectionContext c) => Parsed?.Invoke(c);

public void SubscribeToParsed(Action<ConnectionContext> handler) => Parsed += handler;
public void UnsubscribeParsed(Action<ConnectionContext> handler) => Parsed += handler;


private event Action<ConnectionContext, IActionResult> ParsingError;
private void OnParsingError(ConnectionContext c, IActionResult result) => ParsingError?.Invoke(c, result);

public void SubscribeToParsingError(Action<ConnectionContext, IActionResult> handler) => ParsingError += handler;
public void UnsubscribParsingError(Action<ConnectionContext, IActionResult> handler) => ParsingError += handler;

}
3 changes: 2 additions & 1 deletion src/Server/Infrastructure/Routing/src/GlobalUsings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
global using System.Runtime.CompilerServices;

global using LiteHttp.Models;
global using LiteHttp.Constants;
global using LiteHttp.Helpers;
global using LiteHttp.Constants;
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<ItemGroup>
<ProjectReference Include="..\..\..\Core\Constants\src\LiteHttp.Constants.csproj" />
<ProjectReference Include="..\..\..\Core\Models\src\LiteHttp.Models.csproj" />
<ProjectReference Include="..\..\Helpers\src\LiteHttp.Helpers.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@ public sealed class RouterEventAdapter

public void Handle(ConnectionContext connectionContext)
{
var result = _router.GetAction(connectionContext.HttpContext);
var action = _router.GetAction(connectionContext.HttpContext);

OnCompleted(connectionContext, result);
if (action is null) OnRequestNotFound(connectionContext);

OnCompleted(connectionContext, action);
}

private event Action<ConnectionContext, Func<IActionResult>> Completed;
private void OnCompleted(ConnectionContext context, Func<IActionResult> action) => Completed?.Invoke(context, action);

public void SubscribeToCompleted(Action<ConnectionContext, Func<IActionResult>> handler) => Completed += handler;
public void UnsubscribeCompleted(Action<ConnectionContext, Func<IActionResult>> handler) => Completed -= handler;
public void UnsubscribeFromCompleted(Action<ConnectionContext, Func<IActionResult>> handler) => Completed -= handler;

private event Action<ConnectionContext, IActionResult> RequestNotFound;
private void OnRequestNotFound(ConnectionContext context) => RequestNotFound?.Invoke(context, InternalActionResults.NotFound());

public void SubscribeToRequestNotFound(Action<ConnectionContext, IActionResult> handler) => RequestNotFound += handler;
public void UnsubscribeFromRequestNotFound(Action<ConnectionContext, IActionResult> handler) => RequestNotFound -= handler;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace LiteHttp.Server.EventDriven;
using LiteHttp.RequestProcessors;

namespace LiteHttp.Server.EventDriven;

internal static class Binder
{
Expand All @@ -10,5 +12,9 @@ public static void Bind(InternalServer server)
server.RouterAdapter.SubscribeToCompleted(server.ExecutorAdapter.Handle);
server.ExecutorAdapter.SubscribeToExecuted(server.ResponseBuilderAdapter.Handle);
server.ResponseBuilderAdapter.SubscriveResponseBuilded(server.ConnectionManager.SendResponse);

server.ParserAdapter.SubscribeToParsingError(server.ResponseBuilderAdapter.Handle);

server.RouterAdapter.SubscribeToRequestNotFound(server.ResponseBuilderAdapter.Handle);
}
}
Loading