add logging & plish up
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
namespace Pilz.Net.Api;
|
using Castle.Core.Logging;
|
||||||
|
|
||||||
|
namespace Pilz.Net.Api;
|
||||||
|
|
||||||
public class ApiClient(string apiUrl) : IApiClient
|
public class ApiClient(string apiUrl) : IApiClient
|
||||||
{
|
{
|
||||||
@@ -10,10 +12,14 @@ public class ApiClient(string apiUrl) : IApiClient
|
|||||||
|
|
||||||
public virtual IMessageSerializer Serializer { get; set; } = new DefaultMessageSerializer();
|
public virtual IMessageSerializer Serializer { get; set; } = new DefaultMessageSerializer();
|
||||||
|
|
||||||
|
public ILogger Log { get; set; } = NullLogger.Instance;
|
||||||
|
|
||||||
public virtual async Task<ApiResponse> SendMessage<TResponse>(string url, ApiMessage message, IMessageSerializer? serializer)
|
public virtual async Task<ApiResponse> SendMessage<TResponse>(string url, ApiMessage message, IMessageSerializer? serializer)
|
||||||
{
|
{
|
||||||
serializer ??= Serializer;
|
serializer ??= Serializer;
|
||||||
|
|
||||||
|
Log.InfoFormat("Send message to {0}", url);
|
||||||
|
|
||||||
var res = await Send(url, message, serializer);
|
var res = await Send(url, message, serializer);
|
||||||
|
|
||||||
return new(res.StatusCode);
|
return new(res.StatusCode);
|
||||||
@@ -23,6 +29,8 @@ public class ApiClient(string apiUrl) : IApiClient
|
|||||||
{
|
{
|
||||||
serializer ??= Serializer;
|
serializer ??= Serializer;
|
||||||
|
|
||||||
|
Log.InfoFormat("Send request to {0}", url);
|
||||||
|
|
||||||
var res = await Send(url, message, serializer);
|
var res = await Send(url, message, serializer);
|
||||||
TResponse? result = null;
|
TResponse? result = null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Pilz.Extensions.Reflection;
|
using Castle.Core.Logging;
|
||||||
|
using Pilz.Extensions.Reflection;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using static Pilz.Net.Api.IApiServer;
|
using static Pilz.Net.Api.IApiServer;
|
||||||
@@ -21,8 +22,11 @@ public class ApiServer(string apiUrl) : IApiServer
|
|||||||
|
|
||||||
public IMessageSerializer Serializer { get; set; } = new DefaultMessageSerializer();
|
public IMessageSerializer Serializer { get; set; } = new DefaultMessageSerializer();
|
||||||
|
|
||||||
|
public ILogger Log { get; set; } = NullLogger.Instance;
|
||||||
|
|
||||||
public virtual void Start()
|
public virtual void Start()
|
||||||
{
|
{
|
||||||
|
Log.Info("Start listening");
|
||||||
httpListener.Start();
|
httpListener.Start();
|
||||||
Listen();
|
Listen();
|
||||||
}
|
}
|
||||||
@@ -30,6 +34,7 @@ public class ApiServer(string apiUrl) : IApiServer
|
|||||||
public virtual void Stop()
|
public virtual void Stop()
|
||||||
{
|
{
|
||||||
httpListener.Stop();
|
httpListener.Stop();
|
||||||
|
Log.Info("Stopped listening");
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void RegisterHandler<T>(T instance) where T : class
|
public virtual void RegisterHandler<T>(T instance) where T : class
|
||||||
@@ -54,7 +59,9 @@ public class ApiServer(string apiUrl) : IApiServer
|
|||||||
throw new NotSupportedException("The first parameter needs to be of type ApiMessage and must return an ApiResult object and the method must have the MessageHandlerAttribute.");
|
throw new NotSupportedException("The first parameter needs to be of type ApiMessage and must return an ApiResult object and the method must have the MessageHandlerAttribute.");
|
||||||
|
|
||||||
// Add handler
|
// Add handler
|
||||||
handlers.Add(ApiUrl + attribute.Route, handler);
|
var fullUrl = ApiUrl + attribute.Route;
|
||||||
|
Log.InfoFormat("Added handler for {0}", fullUrl);
|
||||||
|
handlers.Add(fullUrl, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Listen()
|
protected virtual void Listen()
|
||||||
@@ -66,85 +73,109 @@ public class ApiServer(string apiUrl) : IApiServer
|
|||||||
protected virtual void CheckContext()
|
protected virtual void CheckContext()
|
||||||
{
|
{
|
||||||
var context = httpListener.GetContext();
|
var context = httpListener.GetContext();
|
||||||
void close() => context.Response.OutputStream.Close();
|
void close()
|
||||||
|
{
|
||||||
|
Log.Info("End handling request.");
|
||||||
|
context.Response.OutputStream.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Debug("Sanity checks");
|
||||||
if (context.Request.HttpMethod != HttpMethod.Post.Method
|
if (context.Request.HttpMethod != HttpMethod.Post.Method
|
||||||
|| context.Request.ContentType is not string contentType
|
|| context.Request.ContentType is not string contentType
|
||||||
|| !contentType.Contains("application/json"))
|
|| !contentType.Contains("application/json"))
|
||||||
{
|
{
|
||||||
|
Log.Info("Request has no json content");
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse url
|
// Parse url
|
||||||
|
Log.Debug("Parse url");
|
||||||
var path = context.Request.Url?.PathAndQuery.Replace(ApiUrl, string.Empty);
|
var path = context.Request.Url?.PathAndQuery.Replace(ApiUrl, string.Empty);
|
||||||
if (string.IsNullOrWhiteSpace(path) || context.Request.ContentLength64 <= 0)
|
if (string.IsNullOrWhiteSpace(path) || context.Request.ContentLength64 <= 0)
|
||||||
{
|
{
|
||||||
|
Log.Info("Request has no content");
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read input content
|
// Read input content
|
||||||
|
Log.Debug("Read input content");
|
||||||
using StreamReader input = new(context.Request.InputStream);
|
using StreamReader input = new(context.Request.InputStream);
|
||||||
var contentJson = input.ReadToEnd();
|
var contentJson = input.ReadToEnd();
|
||||||
|
|
||||||
// Get auth key
|
// Get auth key
|
||||||
|
Log.Debug("Get auth key");
|
||||||
if (context.Request.Headers.Get("API-AUTH-KEY") is not string authKey)
|
if (context.Request.Headers.Get("API-AUTH-KEY") is not string authKey)
|
||||||
authKey = null!;
|
authKey = null!;
|
||||||
|
|
||||||
// Handle message
|
// Handle message
|
||||||
|
Log.Debug("Handle mssage");
|
||||||
if (HandleMessage(path, contentJson, authKey) is not PrivateApiResult result)
|
if (HandleMessage(path, contentJson, authKey) is not PrivateApiResult result)
|
||||||
{
|
{
|
||||||
|
Log.Warn("Request couldn't be handled");
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set response parameters
|
// Set response parameters
|
||||||
|
Log.Debug("Set response parameters");
|
||||||
context.Response.StatusCode = (int)result.Original.StatusCode;
|
context.Response.StatusCode = (int)result.Original.StatusCode;
|
||||||
|
|
||||||
// Write response content
|
// Write response content
|
||||||
|
Log.Debug("Write response");
|
||||||
if (result.ResultJson is not null)
|
if (result.ResultJson is not null)
|
||||||
{
|
{
|
||||||
|
Log.Info("Write response");
|
||||||
context.Response.ContentType = "application/json";
|
context.Response.ContentType = "application/json";
|
||||||
using StreamWriter output = new(context.Response.OutputStream);
|
using StreamWriter output = new(context.Response.OutputStream);
|
||||||
output.Write(result);
|
output.Write(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.Debug("Finish response");
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual PrivateApiResult? HandleMessage(string url, string json, string? authKey)
|
protected virtual PrivateApiResult? HandleMessage(string url, string json, string? authKey)
|
||||||
{
|
{
|
||||||
// Get handler
|
// Get handler
|
||||||
|
Log.Debug("Find handler");
|
||||||
if (!handlers.TryGetValue(url, out var handler)
|
if (!handlers.TryGetValue(url, out var handler)
|
||||||
|| handler.Method.GetCustomAttribute<MessageHandlerAttribute>() is not MessageHandlerAttribute attribute)
|
|| handler.Method.GetCustomAttribute<MessageHandlerAttribute>() is not MessageHandlerAttribute attribute)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Check authentication
|
// Check authentication
|
||||||
|
Log.Debug("Check authentication");
|
||||||
if (attribute.RequiesAuth && (string.IsNullOrWhiteSpace(authKey) || !CheckAuthentication(authKey)))
|
if (attribute.RequiesAuth && (string.IsNullOrWhiteSpace(authKey) || !CheckAuthentication(authKey)))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Get required infos
|
// Get required infos
|
||||||
|
Log.Debug("Find other infos");
|
||||||
var targetType = handler.Method.GetParameters().First().ParameterType;
|
var targetType = handler.Method.GetParameters().First().ParameterType;
|
||||||
var serializer = GetSerializer(attribute.Serializer);
|
var serializer = GetSerializer(attribute.Serializer);
|
||||||
|
|
||||||
// Deserialize
|
// Deserialize
|
||||||
|
Log.Debug("Deserialize message");
|
||||||
if (serializer.Deserialize(json, targetType) is not ApiMessage message)
|
if (serializer.Deserialize(json, targetType) is not ApiMessage message)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Invoke handler
|
// Invoke handler
|
||||||
|
Log.Debug("Invoke handler");
|
||||||
if (handler.DynamicInvoke(message) is not ApiResult result)
|
if (handler.DynamicInvoke(message) is not ApiResult result)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Return result without message
|
// Return result without message
|
||||||
|
Log.Debug("Check message");
|
||||||
if (result.Message is null)
|
if (result.Message is null)
|
||||||
return new(result, null);
|
return new(result, null);
|
||||||
|
|
||||||
// Serializer
|
// Serializer
|
||||||
|
Log.Debug("Serialize message");
|
||||||
if (serializer.Serialize(result.Message) is not string resultStr)
|
if (serializer.Serialize(result.Message) is not string resultStr)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Return result with message
|
// Return result with message
|
||||||
|
Log.Debug("Finish result");
|
||||||
return new(result, resultStr);
|
return new(result, resultStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace Pilz.Net.Api;
|
using Castle.Core.Logging;
|
||||||
|
|
||||||
|
namespace Pilz.Net.Api;
|
||||||
|
|
||||||
public interface IApiClient
|
public interface IApiClient
|
||||||
{
|
{
|
||||||
@@ -8,6 +10,8 @@ public interface IApiClient
|
|||||||
|
|
||||||
IMessageSerializer Serializer { get; }
|
IMessageSerializer Serializer { get; }
|
||||||
|
|
||||||
|
ILogger Log { get; set; }
|
||||||
|
|
||||||
Task<ApiResponse> SendMessage<TResponse>(string url, ApiMessage message, IMessageSerializer? serializer = null);
|
Task<ApiResponse> SendMessage<TResponse>(string url, ApiMessage message, IMessageSerializer? serializer = null);
|
||||||
|
|
||||||
Task<ApiResponse<TResponse>> SendRequest<TResponse>(string url, ApiMessage message, IMessageSerializer? serializer = null) where TResponse : ApiMessage;
|
Task<ApiResponse<TResponse>> SendRequest<TResponse>(string url, ApiMessage message, IMessageSerializer? serializer = null) where TResponse : ApiMessage;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace Pilz.Net.Api;
|
using Castle.Core.Logging;
|
||||||
|
|
||||||
|
namespace Pilz.Net.Api;
|
||||||
|
|
||||||
public interface IApiServer
|
public interface IApiServer
|
||||||
{
|
{
|
||||||
@@ -12,6 +14,8 @@ public interface IApiServer
|
|||||||
|
|
||||||
IMessageSerializer Serializer { get; }
|
IMessageSerializer Serializer { get; }
|
||||||
|
|
||||||
|
ILogger Log { get; set; }
|
||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Castle.Core" Version="5.1.1" />
|
||||||
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" />
|
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" />
|
||||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
|
|||||||
Reference in New Issue
Block a user