add server status & capabilities

This commit is contained in:
Pilzinsel64
2025-06-13 09:21:04 +02:00
parent 00bd2e62e8
commit 6f44ab32f0
7 changed files with 108 additions and 18 deletions

View File

@@ -8,11 +8,11 @@ public record class ApiResult(
{
public static ApiResult Ok() => new(HttpStatusCode.OK);
public static ApiResult Ok(ApiMessage message) => new(HttpStatusCode.OK, message);
public static ApiResult Ok(ApiMessage? message) => new(HttpStatusCode.OK, message);
public static ApiResult Created() => new(HttpStatusCode.Created);
public static ApiResult Created(ApiMessage message) => new(HttpStatusCode.Created, message);
public static ApiResult Created(ApiMessage? message) => new(HttpStatusCode.Created, message);
public static ApiResult Unauthorized() => new(HttpStatusCode.Unauthorized);

View File

@@ -20,7 +20,7 @@ public class ApiServer : IApiServer
protected readonly Dictionary<Type, IApiMessageSerializer> serializers = [];
protected readonly Dictionary<ThreadHolder, IDataManager> managers = [];
protected HttpListener httpListener;
protected int restartAttempts = 0;
protected uint restartAttempts = 0;
protected DateTime lastRestartAttempt;
protected SemaphoreSlim? semaphore;
protected bool doListen;
@@ -36,6 +36,10 @@ public class ApiServer : IApiServer
protected record PrivateMessageHandler(string Url, bool UseRegEx, Delegate Handler, PrivateParameterInfo[] Parameters, ApiMessageHandlerAttribute Attribute);
protected record PrivateApiResult(ApiResult Original, object? ResultContent);
public int HandlersCount => handlers.Count;
public int ManagersCount => managers.Count;
public uint RestartAttempts => restartAttempts;
public string ApiUrl { get; }
public uint ApiVersion { get; set; } = 1;
public virtual bool EnableAuth { get; set; }
@@ -112,11 +116,6 @@ public class ApiServer : IApiServer
Receive();
}
public virtual void Stop()
{
Stop(true);
}
public virtual void Stop(bool graceful)
{
Log.Info("Stopping listener");
@@ -184,6 +183,15 @@ public class ApiServer : IApiServer
semaphore.Release();
}
public virtual IEnumerable<string> GetEndpoints()
{
return handlers.SelectMany(n => n.Attribute.Methods.Select(m => new
{
n.Attribute.Route,
Method = m,
})).OrderBy(n => n.Route).ThenBy(n => n.Method).Select(n => $"{n.Method} {n.Route}");
}
public virtual void RegisterHandler<T>(T instance) where T : class
{
// Initialize

View File

@@ -16,24 +16,18 @@ public interface IApiServer
event DataManagerEventHandler? OnResetDataManager;
IDataManager Manager { get; }
string ApiUrl { get; }
bool EnableAuth { get; set; }
IApiMessageSerializer Serializer { get; }
ILogger Log { get; set; }
void Start();
void Stop();
void Stop() => Stop(true);
void RegisterHandler<T>(T instance) where T : class;
void RegisterHandler(Delegate handler);
void RegisterHandler(Delegate handler, bool throwOnError);
void RegisterHandler(Delegate handler, ApiMessageHandlerAttribute attribute, bool throwOnError);
IEnumerable<string> GetEndpoints();
void Stop(bool graceful);
void Restart(bool graceful);
}

View File

@@ -0,0 +1,6 @@
namespace Pilz.Net.Api.Messages;
public class ServerCapabilitiesMessage : ApiMessage
{
public List<string> Endpoints { get; } = [];
}

View File

@@ -0,0 +1,10 @@
namespace Pilz.Net.Api.Messages;
public class ServerStatusMessage : ApiMessage
{
public AppVersion? AppVersion { get; set; }
public uint ApiVersion { get; set; }
public int EndpointsCount { get; set; }
public int DataManagersCount { get; set; }
public uint RestartAttempts { get; set; }
}

View File

@@ -0,0 +1,31 @@
using Pilz.Extensions.Reflection;
using Pilz.Net.Api.Messages;
using System.Diagnostics;
namespace Pilz.Net.Api.Server;
public class ServerCapabilitiesHandler : IApiHandlerInitializer
{
protected IApiServer? server;
public string Route { get; set; } = "/capabilities";
public virtual void Initialize(IApiServer server)
{
this.server = server;
server.RegisterHandler(GetType().GetMethod(nameof(GetCapabilities))!.CreateDelegate(this), new(Route, "GET"), Debugger.IsAttached);
}
public virtual ApiResult GetCapabilities(ApiRequestInfo req)
{
var msg = BuildMessage(req);
if (server is ServerCapabilitiesMessage message)
message.Endpoints.AddRange(server.GetEndpoints());
return ApiResult.Ok(msg);
}
protected virtual ApiMessage? BuildMessage(ApiRequestInfo req)
{
return new ServerCapabilitiesMessage();
}
}

View File

@@ -0,0 +1,41 @@
using Pilz.Extensions;
using Pilz.Extensions.Reflection;
using Pilz.Net.Api.Messages;
using System.Diagnostics;
using System.Reflection;
namespace Pilz.Net.Api.Server;
public class ServerStatusHandler : IApiHandlerInitializer
{
protected IApiServer? server;
public string Route { get; set; } = "/status";
public virtual void Initialize(IApiServer server)
{
this.server = server;
server.RegisterHandler(GetType().GetMethod(nameof(GetStatus))!.CreateDelegate(this), new(Route, "GET"), Debugger.IsAttached);
}
public virtual ApiResult GetStatus(ApiRequestInfo req)
{
var msg = BuildMessage(req);
if (server is ApiServer apiServer && msg is ServerStatusMessage message)
{
message.AppVersion ??= Assembly.GetEntryAssembly()?.GetAppVersion();
message.ApiVersion = apiServer.ApiVersion;
message.EndpointsCount = apiServer.HandlersCount;
message.DataManagersCount = apiServer.ManagersCount;
message.RestartAttempts = apiServer.RestartAttempts;
}
return ApiResult.Ok(msg);
}
protected virtual ApiMessage? BuildMessage(ApiRequestInfo req)
{
return new ServerStatusMessage();
}
}