From eb4a6ceafb60b3f8192c1c92f4f48a171696c0ef Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 13 Feb 2025 21:35:35 +0100 Subject: [PATCH] Finish implementing GenHTTP --- src/Artemis.Core/Artemis.Core.csproj | 2 +- .../EndPoints/DataModelJsonPluginEndPoint.cs | 84 ------------------- .../WebServer/EndPoints/JsonPluginEndPoint.cs | 10 +-- .../WebServer/EndPoints/PluginEndPoint.cs | 25 ++++-- .../WebServer/EndPoints/RawPluginEndPoint.cs | 6 +- .../EndPoints/StringPluginEndPoint.cs | 10 +-- .../WebServer/Interfaces/IWebServerService.cs | 14 +--- .../{PluginsModule.cs => PluginsHandler.cs} | 28 +++++-- .../Services/WebServer/StatusHandler.cs | 27 ++++++ .../Services/WebServer/WebServerService.cs | 78 ++++++++--------- .../Controllers/RemoteController.cs | 20 +---- src/Directory.Packages.props | 2 +- 12 files changed, 122 insertions(+), 184 deletions(-) delete mode 100644 src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs rename src/Artemis.Core/Services/WebServer/{PluginsModule.cs => PluginsHandler.cs} (76%) create mode 100644 src/Artemis.Core/Services/WebServer/StatusHandler.cs diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index efb61529e..ffea2cad6 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -38,7 +38,7 @@ - + diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs deleted file mode 100644 index b66c27d1b..000000000 --- a/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Artemis.Core.Modules; -using GenHTTP.Api.Protocol; - -namespace Artemis.Core.Services; - -/// -/// Represents a plugin web endpoint receiving an object of type and returning any -/// or . -/// Note: Both will be deserialized and serialized respectively using JSON. -/// -public class DataModelJsonPluginEndPoint : PluginEndPoint where T : DataModel, new() -{ - private readonly Module _module; - private readonly Action _update; - - internal DataModelJsonPluginEndPoint(Module module, string name, PluginsModule pluginsModule) : base(module, name, pluginsModule) - { - _module = module ?? throw new ArgumentNullException(nameof(module)); - _update = CreateUpdateAction(); - - ThrowOnFail = true; - Accepts = ContentType.ApplicationJson; - } - - /// - /// Whether or not the end point should throw an exception if deserializing the received JSON fails. - /// If set to malformed JSON is silently ignored; if set to malformed - /// JSON throws a . - /// - public bool ThrowOnFail { get; set; } - - /// - protected override async Task ProcessRequest(IRequest request) - { - if (request.Method != RequestMethod.Post && request.Method != RequestMethod.Put) - return request.Respond().Status(ResponseStatus.MethodNotAllowed).Build(); - if (request.Content == null) - return request.Respond().Status(ResponseStatus.BadRequest).Build(); - - try - { - T? dataModel = await JsonSerializer.DeserializeAsync(request.Content, WebServerService.JsonOptions); - if (dataModel != null) - _update(dataModel, _module.DataModel); - } - catch (JsonException) - { - if (ThrowOnFail) - throw; - } - - return request.Respond().Status(ResponseStatus.NoContent).Build(); - } - - private Action CreateUpdateAction() - { - ParameterExpression sourceParameter = Expression.Parameter(typeof(T), "source"); - ParameterExpression targetParameter = Expression.Parameter(typeof(T), "target"); - - IEnumerable assignments = typeof(T) - .GetProperties() - .Where(prop => prop.CanWrite && prop.GetSetMethod() != null && - prop.GetSetMethod()!.IsPublic && - !prop.IsDefined(typeof(JsonIgnoreAttribute), false) && - !prop.PropertyType.IsAssignableTo(typeof(IDataModelEvent))) - .Select(prop => - { - MemberExpression sourceProperty = Expression.Property(sourceParameter, prop); - MemberExpression targetProperty = Expression.Property(targetParameter, prop); - return Expression.Assign(targetProperty, sourceProperty); - }); - - BlockExpression body = Expression.Block(assignments); - - return Expression.Lambda>(body, sourceParameter, targetParameter).Compile(); - } -} \ No newline at end of file diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/JsonPluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/JsonPluginEndPoint.cs index 76cd74fc6..eee990829 100644 --- a/src/Artemis.Core/Services/WebServer/EndPoints/JsonPluginEndPoint.cs +++ b/src/Artemis.Core/Services/WebServer/EndPoints/JsonPluginEndPoint.cs @@ -17,19 +17,19 @@ public class JsonPluginEndPoint : PluginEndPoint private readonly Action? _requestHandler; private readonly Func? _responseRequestHandler; - internal JsonPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Action requestHandler) : base(pluginFeature, name, pluginsModule) + internal JsonPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Action requestHandler) : base(pluginFeature, name, pluginsHandler) { _requestHandler = requestHandler; ThrowOnFail = true; - Accepts = ContentType.ApplicationJson; + Accepts = FlexibleContentType.Get(ContentType.ApplicationJson); } - internal JsonPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Func responseRequestHandler) : base(pluginFeature, name, pluginsModule) + internal JsonPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Func responseRequestHandler) : base(pluginFeature, name, pluginsHandler) { _responseRequestHandler = responseRequestHandler; ThrowOnFail = true; - Accepts = ContentType.ApplicationJson; - Returns = ContentType.ApplicationJson; + Accepts = FlexibleContentType.Get(ContentType.ApplicationJson); + Returns = FlexibleContentType.Get(ContentType.ApplicationJson); } /// diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/PluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/PluginEndPoint.cs index 3048f53c7..ccea68640 100644 --- a/src/Artemis.Core/Services/WebServer/EndPoints/PluginEndPoint.cs +++ b/src/Artemis.Core/Services/WebServer/EndPoints/PluginEndPoint.cs @@ -10,15 +10,15 @@ using StringContent = GenHTTP.Modules.IO.Strings.StringContent; namespace Artemis.Core.Services; /// -/// Represents a base type for plugin end points to be targeted by the +/// Represents a base type for plugin end points to be targeted by the /// public abstract class PluginEndPoint { - private readonly PluginsModule _pluginsModule; + private readonly PluginsHandler _pluginsHandler; - internal PluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule) + internal PluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler) { - _pluginsModule = pluginsModule; + _pluginsHandler = pluginsHandler; PluginFeature = pluginFeature; Name = name; @@ -33,7 +33,7 @@ public abstract class PluginEndPoint /// /// Gets the full URL of the end point /// - public string Url => $"{_pluginsModule.ServerUrl?.TrimEnd('/')}{_pluginsModule.BaseRoute}{PluginFeature.Plugin.Guid}/{Name}"; + public string Url => $"{_pluginsHandler.ServerUrl}{_pluginsHandler.BaseRoute}/{PluginFeature.Plugin.Guid}/{Name}"; /// /// Gets the plugin the end point is associated with @@ -46,15 +46,15 @@ public abstract class PluginEndPoint /// public PluginInfo PluginInfo => PluginFeature.Plugin.Info; - /// + /// /// Gets the mime type of the input this end point accepts /// - public ContentType Accepts { get; protected set; } + public FlexibleContentType Accepts { get; protected set; } /// /// Gets the mime type of the output this end point returns /// - public ContentType Returns { get; protected set; } + public FlexibleContentType Returns { get; protected set; } /// /// Occurs whenever a request threw an unhandled exception @@ -107,6 +107,13 @@ public abstract class PluginEndPoint try { OnProcessingRequest(context); + + if (!Equals(context.ContentType, Accepts)) + { + OnRequestException(new Exception("Unsupported media type")); + return context.Respond().Status(ResponseStatus.UnsupportedMediaType).Build(); + } + IResponse response = await ProcessRequest(context); OnProcessedRequest(context); return response; @@ -125,6 +132,6 @@ public abstract class PluginEndPoint private void OnDisabled(object? sender, EventArgs e) { PluginFeature.Disabled -= OnDisabled; - _pluginsModule.RemovePluginEndPoint(this); + _pluginsHandler.RemovePluginEndPoint(this); } } \ No newline at end of file diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/RawPluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/RawPluginEndPoint.cs index 4c11ae899..91baffc17 100644 --- a/src/Artemis.Core/Services/WebServer/EndPoints/RawPluginEndPoint.cs +++ b/src/Artemis.Core/Services/WebServer/EndPoints/RawPluginEndPoint.cs @@ -14,7 +14,7 @@ namespace Artemis.Core.Services; public class RawPluginEndPoint : PluginEndPoint { /// - internal RawPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Func> requestHandler) : base(pluginFeature, name, pluginsModule) + internal RawPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Func> requestHandler) : base(pluginFeature, name, pluginsHandler) { RequestHandler = requestHandler; } @@ -29,7 +29,7 @@ public class RawPluginEndPoint : PluginEndPoint /// public void SetAcceptType(ContentType type) { - Accepts = type; + Accepts = FlexibleContentType.Get(type); } /// @@ -37,7 +37,7 @@ public class RawPluginEndPoint : PluginEndPoint /// public void SetReturnType(ContentType type) { - Returns = type; + Returns = FlexibleContentType.Get(type); } #region Overrides of PluginEndPoint diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/StringPluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/StringPluginEndPoint.cs index 12e0054c7..83230e8c1 100644 --- a/src/Artemis.Core/Services/WebServer/EndPoints/StringPluginEndPoint.cs +++ b/src/Artemis.Core/Services/WebServer/EndPoints/StringPluginEndPoint.cs @@ -16,17 +16,17 @@ public class StringPluginEndPoint : PluginEndPoint private readonly Action? _requestHandler; private readonly Func? _responseRequestHandler; - internal StringPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Action requestHandler) : base(pluginFeature, name, pluginsModule) + internal StringPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Action requestHandler) : base(pluginFeature, name, pluginsHandler) { _requestHandler = requestHandler; - Accepts = ContentType.TextPlain; + Accepts = FlexibleContentType.Get(ContentType.TextPlain); } - internal StringPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Func requestHandler) : base(pluginFeature, name, pluginsModule) + internal StringPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Func requestHandler) : base(pluginFeature, name, pluginsHandler) { _responseRequestHandler = requestHandler; - Accepts = ContentType.TextPlain; - Returns = ContentType.TextPlain; + Accepts = FlexibleContentType.Get(ContentType.TextPlain); + Returns = FlexibleContentType.Get(ContentType.TextPlain); } #region Overrides of PluginEndPoint diff --git a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs index b2ae3e0fa..01a41d1dd 100644 --- a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs +++ b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs @@ -19,7 +19,7 @@ public interface IWebServerService : IArtemisService /// /// Gets the plugins module containing all plugin end points /// - PluginsModule PluginsModule { get; } + PluginsHandler PluginsHandler { get; } /// /// Adds a new endpoint for the given plugin feature receiving an object of type @@ -44,16 +44,6 @@ public interface IWebServerService : IArtemisService /// The resulting end point JsonPluginEndPoint AddResponsiveJsonEndPoint(PluginFeature feature, string endPointName, Func requestHandler); - /// - /// Adds a new endpoint that directly maps received JSON to the data model of the provided . - /// - /// The data model type of the module - /// The module whose datamodel to apply the received JSON to - /// The name of the end point, must be unique - /// The resulting end point - [Obsolete("This way of updating is too unpredictable in combination with nested events, use AddJsonEndPoint to update manually instead")] - DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(Module module, string endPointName) where T : DataModel, new(); - /// /// Adds a new endpoint for the given plugin feature receiving an a . /// @@ -95,7 +85,7 @@ public interface IWebServerService : IArtemisService /// /// Adds a new Web API controller and restarts the web server /// - /// The type of Web API controller to remove + /// The type of Web API controller to add WebApiControllerRegistration AddController(PluginFeature feature, string path) where T : class; /// diff --git a/src/Artemis.Core/Services/WebServer/PluginsModule.cs b/src/Artemis.Core/Services/WebServer/PluginsHandler.cs similarity index 76% rename from src/Artemis.Core/Services/WebServer/PluginsModule.cs rename to src/Artemis.Core/Services/WebServer/PluginsHandler.cs index 0f1703fef..7327948d6 100644 --- a/src/Artemis.Core/Services/WebServer/PluginsModule.cs +++ b/src/Artemis.Core/Services/WebServer/PluginsHandler.cs @@ -12,14 +12,14 @@ using GenHTTP.Modules.IO.Strings; namespace Artemis.Core.Services; /// -/// Represents an EmbedIO web module used to process web requests and forward them to the right +/// Represents an GenHTTP handler used to process web requests and forward them to the right /// . /// -public class PluginsModule : IHandler +public class PluginsHandler : IHandler { private readonly Dictionary> _pluginEndPoints; - internal PluginsModule(string baseRoute) + internal PluginsHandler(string baseRoute) { BaseRoute = baseRoute; _pluginEndPoints = new Dictionary>(comparer: StringComparer.InvariantCultureIgnoreCase); @@ -63,20 +63,30 @@ public class PluginsModule : IHandler /// public async ValueTask HandleAsync(IRequest request) { - // Expect a plugin ID and an endpoint - if (request.Target.Path.Parts.Count != 2) + // Used to be part of the RemoteController but moved here to avoid the /remote/ prefix enforced by GenHTTP + if (request.Target.Current?.Value != "plugins") + return null; + + request.Target.Advance(); + string? pluginId = request.Target.Current?.Value; + if (pluginId == null) return null; // Find a matching plugin, if none found let another handler have a go :) - if (!_pluginEndPoints.TryGetValue(request.Target.Path.Parts[0].Value, out Dictionary? endPoints)) + if (!_pluginEndPoints.TryGetValue(pluginId, out Dictionary? endPoints)) return null; - + + request.Target.Advance(); + string? endPointName = request.Target.Current?.Value; + if (endPointName == null) + return null; + // Find a matching endpoint - if (!endPoints.TryGetValue(request.Target.Path.Parts[1].Value, out PluginEndPoint? endPoint)) + if (!endPoints.TryGetValue(endPointName, out PluginEndPoint? endPoint)) { return request.Respond() .Status(ResponseStatus.NotFound) - .Content(new StringContent($"Found no endpoint called {request.Target.Path.Parts[1].Value} for plugin with ID {request.Target.Path.Parts[0].Value}.")) + .Content(new StringContent($"Found no endpoint called {endPointName} for plugin with ID {pluginId}.")) .Type(ContentType.TextPlain) .Build(); } diff --git a/src/Artemis.Core/Services/WebServer/StatusHandler.cs b/src/Artemis.Core/Services/WebServer/StatusHandler.cs new file mode 100644 index 000000000..fbd6d83da --- /dev/null +++ b/src/Artemis.Core/Services/WebServer/StatusHandler.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using GenHTTP.Api.Content; +using GenHTTP.Api.Protocol; + +namespace Artemis.Core.Services; + +/// +/// Represents an GenHTTP handler used to process web requests and forward them to the right +/// . +/// +public class StatusHandler : IHandler +{ + /// + public ValueTask PrepareAsync() + { + return ValueTask.CompletedTask; + } + + /// + public ValueTask HandleAsync(IRequest request) + { + // Used to be part of the RemoteController but moved here to avoid the /remote/ prefix enforced by GenHTTP + return request.Target.Current?.Value == "status" + ? ValueTask.FromResult(request.Respond().Status(ResponseStatus.NoContent).Build()) + : ValueTask.FromResult(null); + } +} \ No newline at end of file diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs index ffe72f464..fcce9ef12 100644 --- a/src/Artemis.Core/Services/WebServer/WebServerService.cs +++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs @@ -3,20 +3,21 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Text; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Artemis.Core.Modules; using GenHTTP.Api.Infrastructure; using GenHTTP.Api.Protocol; using GenHTTP.Engine.Internal; -using GenHTTP.Modules.Controllers; +using GenHTTP.Modules.Conversion; +using GenHTTP.Modules.Conversion.Serializers; using GenHTTP.Modules.ErrorHandling; using GenHTTP.Modules.Layouting; using GenHTTP.Modules.Layouting.Provider; +using GenHTTP.Modules.Practices; using GenHTTP.Modules.Security; +using GenHTTP.Modules.Webservices; using Serilog; namespace Artemis.Core.Services; @@ -29,7 +30,13 @@ internal class WebServerService : IWebServerService, IDisposable private readonly PluginSetting _webServerEnabledSetting; private readonly PluginSetting _webServerPortSetting; private readonly SemaphoreSlim _webserverSemaphore = new(1, 1); - internal static readonly JsonSerializerOptions JsonOptions = new(CoreJson.GetJsonSerializerOptions()) {ReferenceHandler = ReferenceHandler.IgnoreCycles, WriteIndented = true}; + + internal static readonly JsonSerializerOptions JsonOptions = new(CoreJson.GetJsonSerializerOptions()) + { + ReferenceHandler = ReferenceHandler.IgnoreCycles, + WriteIndented = true, + Converters = {new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)} + }; public WebServerService(ILogger logger, ICoreService coreService, ISettingsService settingsService, IPluginManagementService pluginManagementService) { @@ -43,7 +50,7 @@ internal class WebServerService : IWebServerService, IDisposable _webServerPortSetting.SettingChanged += WebServerPortSettingOnSettingChanged; pluginManagementService.PluginFeatureDisabled += PluginManagementServiceOnPluginFeatureDisabled; - PluginsModule = new PluginsModule("/plugins"); + PluginsHandler = new PluginsHandler("plugins"); if (coreService.IsInitialized) AutoStartWebServer(); else @@ -86,7 +93,7 @@ internal class WebServerService : IWebServerService, IDisposable mustRestart = true; _controllers.RemoveAll(c => c.Feature == e.PluginFeature); } - + if (mustRestart) _ = StartWebServer(); } @@ -99,13 +106,13 @@ internal class WebServerService : IWebServerService, IDisposable } public IServer? Server { get; private set; } - public PluginsModule PluginsModule { get; } + public PluginsHandler PluginsHandler { get; } public event EventHandler? WebServerStarting; #region Web server managament - private async Task CreateWebServer() + private async Task CreateWebServer() { if (Server != null) { @@ -114,27 +121,29 @@ internal class WebServerService : IWebServerService, IDisposable Server = null; } - PluginsModule.ServerUrl = $"http://localhost:{_webServerPortSetting.Value}/"; - + PluginsHandler.ServerUrl = $"http://localhost:{_webServerPortSetting.Value}/"; + LayoutBuilder serverLayout = Layout.Create() - .Add(PluginsModule) + .Add(PluginsHandler) .Add(ErrorHandler.Structured()) .Add(CorsPolicy.Permissive()); - - // Add registered controllers to the API module + + // Add registered controllers to the API module as services. + // GenHTTP also has controllers but services are more flexible and match EmbedIO's approach more closely. + SerializationBuilder serialization = Serialization.Default(JsonOptions); foreach (WebApiControllerRegistration registration in _controllers) { - serverLayout = serverLayout.Add(registration.Path, Controller.From(registration.Factory())); + serverLayout = serverLayout.AddService(registration.Path, registration.Factory(), serializers: serialization); } IServer server = Host.Create() .Handler(serverLayout.Build()) .Bind(IPAddress.Loopback, (ushort) _webServerPortSetting.Value) - .Development() + .Defaults() .Build(); - + // Store the URL in a webserver.txt file so that remote applications can find it - await File.WriteAllTextAsync(Path.Combine(Constants.DataFolder, "webserver.txt"), PluginsModule.ServerUrl); + await File.WriteAllTextAsync(Path.Combine(Constants.DataFolder, "webserver.txt"), PluginsHandler.ServerUrl); return server; } @@ -169,6 +178,7 @@ internal class WebServerService : IWebServerService, IDisposable _logger.Warning(e, "Failed to start webserver"); throw; } + OnWebServerStarted(); } finally @@ -198,8 +208,8 @@ internal class WebServerService : IWebServerService, IDisposable if (feature == null) throw new ArgumentNullException(nameof(feature)); if (endPointName == null) throw new ArgumentNullException(nameof(endPointName)); if (requestHandler == null) throw new ArgumentNullException(nameof(requestHandler)); - JsonPluginEndPoint endPoint = new(feature, endPointName, PluginsModule, requestHandler); - PluginsModule.AddPluginEndPoint(endPoint); + JsonPluginEndPoint endPoint = new(feature, endPointName, PluginsHandler, requestHandler); + PluginsHandler.AddPluginEndPoint(endPoint); return endPoint; } @@ -208,8 +218,8 @@ internal class WebServerService : IWebServerService, IDisposable if (feature == null) throw new ArgumentNullException(nameof(feature)); if (endPointName == null) throw new ArgumentNullException(nameof(endPointName)); if (requestHandler == null) throw new ArgumentNullException(nameof(requestHandler)); - JsonPluginEndPoint endPoint = new(feature, endPointName, PluginsModule, requestHandler); - PluginsModule.AddPluginEndPoint(endPoint); + JsonPluginEndPoint endPoint = new(feature, endPointName, PluginsHandler, requestHandler); + PluginsHandler.AddPluginEndPoint(endPoint); return endPoint; } @@ -218,8 +228,8 @@ internal class WebServerService : IWebServerService, IDisposable if (feature == null) throw new ArgumentNullException(nameof(feature)); if (endPointName == null) throw new ArgumentNullException(nameof(endPointName)); if (requestHandler == null) throw new ArgumentNullException(nameof(requestHandler)); - StringPluginEndPoint endPoint = new(feature, endPointName, PluginsModule, requestHandler); - PluginsModule.AddPluginEndPoint(endPoint); + StringPluginEndPoint endPoint = new(feature, endPointName, PluginsHandler, requestHandler); + PluginsHandler.AddPluginEndPoint(endPoint); return endPoint; } @@ -228,8 +238,8 @@ internal class WebServerService : IWebServerService, IDisposable if (feature == null) throw new ArgumentNullException(nameof(feature)); if (endPointName == null) throw new ArgumentNullException(nameof(endPointName)); if (requestHandler == null) throw new ArgumentNullException(nameof(requestHandler)); - StringPluginEndPoint endPoint = new(feature, endPointName, PluginsModule, requestHandler); - PluginsModule.AddPluginEndPoint(endPoint); + StringPluginEndPoint endPoint = new(feature, endPointName, PluginsHandler, requestHandler); + PluginsHandler.AddPluginEndPoint(endPoint); return endPoint; } @@ -238,26 +248,16 @@ internal class WebServerService : IWebServerService, IDisposable if (feature == null) throw new ArgumentNullException(nameof(feature)); if (endPointName == null) throw new ArgumentNullException(nameof(endPointName)); if (requestHandler == null) throw new ArgumentNullException(nameof(requestHandler)); - RawPluginEndPoint endPoint = new(feature, endPointName, PluginsModule, requestHandler); - PluginsModule.AddPluginEndPoint(endPoint); - return endPoint; - } - - [Obsolete("Use AddJsonEndPoint(PluginFeature feature, string endPointName, Action requestHandler) instead")] - public DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(Module module, string endPointName) where T : DataModel, new() - { - if (module == null) throw new ArgumentNullException(nameof(module)); - if (endPointName == null) throw new ArgumentNullException(nameof(endPointName)); - DataModelJsonPluginEndPoint endPoint = new(module, endPointName, PluginsModule); - PluginsModule.AddPluginEndPoint(endPoint); + RawPluginEndPoint endPoint = new(feature, endPointName, PluginsHandler, requestHandler); + PluginsHandler.AddPluginEndPoint(endPoint); return endPoint; } public void RemovePluginEndPoint(PluginEndPoint endPoint) { - PluginsModule.RemovePluginEndPoint(endPoint); + PluginsHandler.RemovePluginEndPoint(endPoint); } - + #endregion #region Controller management diff --git a/src/Artemis.UI/Controllers/RemoteController.cs b/src/Artemis.UI/Controllers/RemoteController.cs index 377767eed..1aa86305f 100644 --- a/src/Artemis.UI/Controllers/RemoteController.cs +++ b/src/Artemis.UI/Controllers/RemoteController.cs @@ -7,8 +7,7 @@ using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Services.MainWindow; using Avalonia.Threading; using GenHTTP.Api.Protocol; -using GenHTTP.Modules.Controllers; -using GenHTTP.Modules.Reflection; +using GenHTTP.Modules.Webservices; namespace Artemis.UI.Controllers; @@ -25,18 +24,7 @@ public class RemoteController _router = router; } - public void Index() - { - // HTTP 204 No Content - } - - [ControllerAction(RequestMethod.Get)] - public void Status() - { - // HTTP 204 No Content - } - - [ControllerAction(RequestMethod.Post)] + [ResourceMethod(RequestMethod.Post, "bring-to-foreground")] public void BringToForeground(IRequest request) { // Get the route from the request content stream @@ -55,13 +43,13 @@ public class RemoteController }); } - [ControllerAction(RequestMethod.Post)] + [ResourceMethod(RequestMethod.Post, "restart")] public void Restart(List args) { Utilities.Restart(_coreService.IsElevated, TimeSpan.FromMilliseconds(500), args.ToArray()); } - [ControllerAction(RequestMethod.Post)] + [ResourceMethod(RequestMethod.Post, "shutdown")] public void Shutdown() { Utilities.Shutdown(); diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 035e5ef05..28bfcc235 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -15,7 +15,7 @@ - +