From 212d987f8cc0d68880685f143caa0cbc17ad4468 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 14 Feb 2024 15:43:40 -0600 Subject: [PATCH 1/3] feat: Add Async WebRequest handler In order to allow async/await operations to work, we need to treat the tasks differently. If the `ProcessRequest` method completes before whatever async/await operations are running complete, then the underlying connection is closed and nothing can be written to the requestor. --- .../WebApiBaseRequestAsyncHandler.cs | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs diff --git a/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs b/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs new file mode 100644 index 0000000..04a13a9 --- /dev/null +++ b/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs @@ -0,0 +1,164 @@ +using Crestron.SimplSharp.WebScripting; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace PepperDash.Core.Web.RequestHandlers +{ + public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler + { + private readonly Dictionary> _handlers; + protected readonly bool EnableCors; + + /// + /// Constructor + /// + protected WebApiBaseRequestAsyncHandler(bool enableCors) + { + EnableCors = enableCors; + + _handlers = new Dictionary> + { + {"CONNECT", HandleConnect}, + {"DELETE", HandleDelete}, + {"GET", HandleGet}, + {"HEAD", HandleHead}, + {"OPTIONS", HandleOptions}, + {"PATCH", HandlePatch}, + {"POST", HandlePost}, + {"PUT", HandlePut}, + {"TRACE", HandleTrace} + }; + } + + /// + /// Constructor + /// + protected WebApiBaseRequestAsyncHandler() + : this(false) + { + } + + /// + /// Handles CONNECT method requests + /// + /// + protected virtual async Task HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected virtual async Task HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected virtual async Task HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected virtual async Task HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected virtual async Task HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected virtual async Task HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected virtual async Task HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected virtual async Task HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected virtual async Task HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Process request + /// + /// + public void ProcessRequest(HttpCwsContext context) + { + if (!_handlers.TryGetValue(context.Request.HttpMethod, out Func handler)) + { + return; + } + + if (EnableCors) + { + context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); + context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); + } + + var handlerTask = handler(context); + + handlerTask.Wait(); + } + } +} +} From 0b178ca264981ef4e1f753259a625cc5e333633b Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 14 Feb 2024 15:46:27 -0600 Subject: [PATCH 2/3] chore: remove extraneous curly brace --- .../Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs b/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs index 04a13a9..dd177bc 100644 --- a/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs +++ b/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs @@ -161,4 +161,3 @@ namespace PepperDash.Core.Web.RequestHandlers } } } -} From eeb1e22e608f738be44fae9000d13ce8eb30b0ee Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 15 Feb 2024 08:39:40 -0600 Subject: [PATCH 3/3] refactor: use 1GetAwaiter().GetResult()` instead of `Wait()` --- .../Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs b/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs index dd177bc..b117003 100644 --- a/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs +++ b/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs @@ -157,7 +157,7 @@ namespace PepperDash.Core.Web.RequestHandlers var handlerTask = handler(context); - handlerTask.Wait(); + handlerTask.GetAwaiter().GetResult(); } } }