From f57aef5f4f55de0d47486f0dd5bcc9b5ddcd28a6 Mon Sep 17 00:00:00 2001 From: Pilzinsel64 Date: Thu, 15 Aug 2024 15:51:23 +0200 Subject: [PATCH] more work on api --- Pilz.Networking/Api/ApiClient.cs | 38 ++++++++++++- Pilz.Networking/Api/ApiResponse.cs | 13 +++++ Pilz.Networking/Api/ApiResponseT.cs | 15 +++++ Pilz.Networking/Api/ApiResult.cs | 3 +- Pilz.Networking/Api/ApiServer.cs | 87 +++++++++++++++-------------- Pilz.Networking/Api/IApiClient.cs | 3 +- 6 files changed, 112 insertions(+), 47 deletions(-) create mode 100644 Pilz.Networking/Api/ApiResponse.cs create mode 100644 Pilz.Networking/Api/ApiResponseT.cs diff --git a/Pilz.Networking/Api/ApiClient.cs b/Pilz.Networking/Api/ApiClient.cs index 392a95e..545c3b0 100644 --- a/Pilz.Networking/Api/ApiClient.cs +++ b/Pilz.Networking/Api/ApiClient.cs @@ -1,9 +1,41 @@ namespace Pilz.Networking.Api; -public class ApiClient : IApiClient +public class ApiClient(string apiUrl) : IApiClient { - public void MakeRequest(string url, T message) where T : ApiMessage + protected readonly HttpClient httpClient = new(); + + public string ApiUrl { get; } = apiUrl; + + public IMessageSerializer Serializer { get; set; } = new DefaultMessageSerializer(); + + public virtual async Task SendMessage(string url, ApiMessage message, IMessageSerializer? serializer) { - // ... + serializer ??= Serializer; + //message.AuthSecret = AuthSecret; + + var res = await Send(url, message, serializer); + + return new(res.StatusCode); + } + + public virtual async Task> SendRequest(string url, ApiMessage message, IMessageSerializer? serializer) where TResponse : ApiMessage + { + serializer ??= Serializer; + //message.AuthSecret = AuthSecret; + + var res = await Send(url, message, serializer); + TResponse? result = null; + + if (res.IsSuccessStatusCode) + result = serializer.Deserialize(await res.Content.ReadAsStringAsync(), typeof(TResponse)) as TResponse; + + return new(res.StatusCode, result); + } + + protected virtual async Task Send(string url, ApiMessage message, IMessageSerializer serializer) + { + var fullRequestUrl = ApiUrl + url; + var content = new StringContent(serializer.Serialize(message)!, null, "application/json"); + return await httpClient.PostAsync(fullRequestUrl, content); } } diff --git a/Pilz.Networking/Api/ApiResponse.cs b/Pilz.Networking/Api/ApiResponse.cs new file mode 100644 index 0000000..b95cc4d --- /dev/null +++ b/Pilz.Networking/Api/ApiResponse.cs @@ -0,0 +1,13 @@ +using System.Net; + +namespace Pilz.Networking.Api; + +public record class ApiResponse( + HttpStatusCode StatusCode) +{ + public void EnsureOk() + { + if (StatusCode != HttpStatusCode.OK) + throw new Exception("Api return is not ok!"); + } +} diff --git a/Pilz.Networking/Api/ApiResponseT.cs b/Pilz.Networking/Api/ApiResponseT.cs new file mode 100644 index 0000000..294ce3b --- /dev/null +++ b/Pilz.Networking/Api/ApiResponseT.cs @@ -0,0 +1,15 @@ +using System.Net; + +namespace Pilz.Networking.Api; + +public record class ApiResponse( + HttpStatusCode StatusCode, + T? Message) + where T : ApiMessage +{ + public void EnsureOk() + { + if (StatusCode != HttpStatusCode.OK) + throw new Exception("Api return is not ok!"); + } +} diff --git a/Pilz.Networking/Api/ApiResult.cs b/Pilz.Networking/Api/ApiResult.cs index 48e4257..1baed6c 100644 --- a/Pilz.Networking/Api/ApiResult.cs +++ b/Pilz.Networking/Api/ApiResult.cs @@ -4,8 +4,7 @@ namespace Pilz.Networking.Api; public record class ApiResult( HttpStatusCode StatusCode, - ApiMessage? Message = null, - string? StatusDescription = null) + ApiMessage? Message = null) { public static ApiResult Ok() { diff --git a/Pilz.Networking/Api/ApiServer.cs b/Pilz.Networking/Api/ApiServer.cs index 7d2b20c..7421a2b 100644 --- a/Pilz.Networking/Api/ApiServer.cs +++ b/Pilz.Networking/Api/ApiServer.cs @@ -50,50 +50,55 @@ public class ApiServer(string apiUrl) : ApiClient, IApiServer protected virtual void Listen() { while (httpListener.IsListening) + CheckContext(); + } + + protected virtual void CheckContext() + { + var context = httpListener.GetContext(); + void close() => context.Response.OutputStream.Close(); + + if (context.Request.HttpMethod != HttpMethod.Post.Method + || context.Request.ContentType is not string contentType + || !contentType.Contains("application/json")) { - var context = httpListener.GetContext(); - - if (context.Request.HttpMethod != HttpMethod.Post.Method - || context.Request.ContentType is not string contentType - || contentType.Contains("application/json") - || context.Request.AcceptTypes is null - || context.Request.AcceptTypes.Contains("application/json")) - { - close(); - continue; - } - - // Parse url - var path = context.Request.Url?.PathAndQuery.Replace(ApiUrl, string.Empty); - if (string.IsNullOrWhiteSpace(path) || context.Request.ContentLength64 <= 0) - { - close(); - continue; - } - - // Read input content - using StreamReader input = new(context.Request.InputStream); - var contentJson = input.ReadToEnd(); - - // Handle message - if (HandleMessage(path, contentJson) is not string resultJson) - { - close(); - continue; - } - - // Set response parameters - context.Response.StatusCode = (int)args.ResponseStatusCode; - context.Response.StatusDescription = args.ResponseStatusDescription; - - // Write response content - context.Response.ContentType = ContentTypes.CONTENT_TYPE_JSON; - using StreamWriter output = new(context.Response.OutputStream); - output.Write(resultJson); - close(); - void close() => context.Response.OutputStream.Close(); + return; } + + // Parse url + var path = context.Request.Url?.PathAndQuery.Replace(ApiUrl, string.Empty); + if (string.IsNullOrWhiteSpace(path) || context.Request.ContentLength64 <= 0) + { + close(); + return; + } + + // Read input content + using StreamReader input = new(context.Request.InputStream); + var contentJson = input.ReadToEnd(); + + // Handle message + if (HandleMessage(path, contentJson) is not PrivateApiResult result) + { + close(); + return; + } + + // Set response parameters + context.Response.StatusCode = (int)result.Original.StatusCode; + if (result.Original.StatusDescription is not null) + context.Response.StatusDescription = result.Original.StatusDescription; + + // Write response content + if (result.ResultJson is not null) + { + context.Response.ContentType = "application/json"; + using StreamWriter output = new(context.Response.OutputStream); + output.Write(result); + } + + close(); } protected virtual PrivateApiResult? HandleMessage(string url, string json) diff --git a/Pilz.Networking/Api/IApiClient.cs b/Pilz.Networking/Api/IApiClient.cs index 3204398..ec01c42 100644 --- a/Pilz.Networking/Api/IApiClient.cs +++ b/Pilz.Networking/Api/IApiClient.cs @@ -2,5 +2,6 @@ public interface IApiClient { - void MakeRequest(string url, T message) where T : ApiMessage; + Task SendMessage(string url, ApiMessage message, IMessageSerializer? serializer = null); + Task> SendRequest(string url, ApiMessage message, IMessageSerializer? serializer = null) where TResponse : ApiMessage; }