mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 13:28:33 +00:00
Finish implementing GenHTTP
This commit is contained in:
parent
e09389c6db
commit
eb4a6ceafb
@ -38,7 +38,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DryIoc.dll" />
|
||||
<PackageReference Include="GenHTTP.Core" />
|
||||
<PackageReference Include="GenHTTP.Modules.Controllers" />
|
||||
<PackageReference Include="GenHTTP.Modules.Webservices" />
|
||||
<PackageReference Include="HidSharp" />
|
||||
<PackageReference Include="HPPH.SkiaSharp" />
|
||||
<PackageReference Include="Humanizer.Core" />
|
||||
|
||||
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a plugin web endpoint receiving an object of type <typeparamref name="T" /> and returning any
|
||||
/// <see cref="object" /> or <see langword="null" />.
|
||||
/// <para>Note: Both will be deserialized and serialized respectively using JSON.</para>
|
||||
/// </summary>
|
||||
public class DataModelJsonPluginEndPoint<T> : PluginEndPoint where T : DataModel, new()
|
||||
{
|
||||
private readonly Module<T> _module;
|
||||
private readonly Action<T, T> _update;
|
||||
|
||||
internal DataModelJsonPluginEndPoint(Module<T> module, string name, PluginsModule pluginsModule) : base(module, name, pluginsModule)
|
||||
{
|
||||
_module = module ?? throw new ArgumentNullException(nameof(module));
|
||||
_update = CreateUpdateAction();
|
||||
|
||||
ThrowOnFail = true;
|
||||
Accepts = ContentType.ApplicationJson;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the end point should throw an exception if deserializing the received JSON fails.
|
||||
/// If set to <see langword="false" /> malformed JSON is silently ignored; if set to <see langword="true" /> malformed
|
||||
/// JSON throws a <see cref="JsonException" />.
|
||||
/// </summary>
|
||||
public bool ThrowOnFail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task<IResponse> 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<T>(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<T, T> CreateUpdateAction()
|
||||
{
|
||||
ParameterExpression sourceParameter = Expression.Parameter(typeof(T), "source");
|
||||
ParameterExpression targetParameter = Expression.Parameter(typeof(T), "target");
|
||||
|
||||
IEnumerable<BinaryExpression> 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<Action<T, T>>(body, sourceParameter, targetParameter).Compile();
|
||||
}
|
||||
}
|
||||
@ -17,19 +17,19 @@ public class JsonPluginEndPoint<T> : PluginEndPoint
|
||||
private readonly Action<T>? _requestHandler;
|
||||
private readonly Func<T, object?>? _responseRequestHandler;
|
||||
|
||||
internal JsonPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Action<T> requestHandler) : base(pluginFeature, name, pluginsModule)
|
||||
internal JsonPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Action<T> 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<T, object?> responseRequestHandler) : base(pluginFeature, name, pluginsModule)
|
||||
internal JsonPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Func<T, object?> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -10,15 +10,15 @@ using StringContent = GenHTTP.Modules.IO.Strings.StringContent;
|
||||
namespace Artemis.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a base type for plugin end points to be targeted by the <see cref="PluginsModule" />
|
||||
/// Represents a base type for plugin end points to be targeted by the <see cref="PluginsHandler" />
|
||||
/// </summary>
|
||||
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
|
||||
/// <summary>
|
||||
/// Gets the full URL of the end point
|
||||
/// </summary>
|
||||
public string Url => $"{_pluginsModule.ServerUrl?.TrimEnd('/')}{_pluginsModule.BaseRoute}{PluginFeature.Plugin.Guid}/{Name}";
|
||||
public string Url => $"{_pluginsHandler.ServerUrl}{_pluginsHandler.BaseRoute}/{PluginFeature.Plugin.Guid}/{Name}";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the plugin the end point is associated with
|
||||
@ -46,15 +46,15 @@ public abstract class PluginEndPoint
|
||||
/// </summary>
|
||||
public PluginInfo PluginInfo => PluginFeature.Plugin.Info;
|
||||
|
||||
/// <summary>
|
||||
/// <summary><summary>
|
||||
/// Gets the mime type of the input this end point accepts
|
||||
/// </summary>
|
||||
public ContentType Accepts { get; protected set; }
|
||||
public FlexibleContentType Accepts { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mime type of the output this end point returns
|
||||
/// </summary>
|
||||
public ContentType Returns { get; protected set; }
|
||||
public FlexibleContentType Returns { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,7 @@ namespace Artemis.Core.Services;
|
||||
public class RawPluginEndPoint : PluginEndPoint
|
||||
{
|
||||
/// <inheritdoc />
|
||||
internal RawPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Func<IRequest, Task<IResponse>> requestHandler) : base(pluginFeature, name, pluginsModule)
|
||||
internal RawPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Func<IRequest, Task<IResponse>> requestHandler) : base(pluginFeature, name, pluginsHandler)
|
||||
{
|
||||
RequestHandler = requestHandler;
|
||||
}
|
||||
@ -29,7 +29,7 @@ public class RawPluginEndPoint : PluginEndPoint
|
||||
/// </summary>
|
||||
public void SetAcceptType(ContentType type)
|
||||
{
|
||||
Accepts = type;
|
||||
Accepts = FlexibleContentType.Get(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -37,7 +37,7 @@ public class RawPluginEndPoint : PluginEndPoint
|
||||
/// </summary>
|
||||
public void SetReturnType(ContentType type)
|
||||
{
|
||||
Returns = type;
|
||||
Returns = FlexibleContentType.Get(type);
|
||||
}
|
||||
|
||||
#region Overrides of PluginEndPoint
|
||||
|
||||
@ -16,17 +16,17 @@ public class StringPluginEndPoint : PluginEndPoint
|
||||
private readonly Action<string>? _requestHandler;
|
||||
private readonly Func<string, string?>? _responseRequestHandler;
|
||||
|
||||
internal StringPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Action<string> requestHandler) : base(pluginFeature, name, pluginsModule)
|
||||
internal StringPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Action<string> requestHandler) : base(pluginFeature, name, pluginsHandler)
|
||||
{
|
||||
_requestHandler = requestHandler;
|
||||
Accepts = ContentType.TextPlain;
|
||||
Accepts = FlexibleContentType.Get(ContentType.TextPlain);
|
||||
}
|
||||
|
||||
internal StringPluginEndPoint(PluginFeature pluginFeature, string name, PluginsModule pluginsModule, Func<string, string?> requestHandler) : base(pluginFeature, name, pluginsModule)
|
||||
internal StringPluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler, Func<string, string?> 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
|
||||
|
||||
@ -19,7 +19,7 @@ public interface IWebServerService : IArtemisService
|
||||
/// <summary>
|
||||
/// Gets the plugins module containing all plugin end points
|
||||
/// </summary>
|
||||
PluginsModule PluginsModule { get; }
|
||||
PluginsHandler PluginsHandler { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new endpoint for the given plugin feature receiving an object of type <typeparamref name="T" />
|
||||
@ -44,16 +44,6 @@ public interface IWebServerService : IArtemisService
|
||||
/// <returns>The resulting end point</returns>
|
||||
JsonPluginEndPoint<T> AddResponsiveJsonEndPoint<T>(PluginFeature feature, string endPointName, Func<T, object?> requestHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new endpoint that directly maps received JSON to the data model of the provided <paramref name="module" />.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The data model type of the module</typeparam>
|
||||
/// <param name="module">The module whose datamodel to apply the received JSON to</param>
|
||||
/// <param name="endPointName">The name of the end point, must be unique</param>
|
||||
/// <returns>The resulting end point</returns>
|
||||
[Obsolete("This way of updating is too unpredictable in combination with nested events, use AddJsonEndPoint<T> to update manually instead")]
|
||||
DataModelJsonPluginEndPoint<T> AddDataModelJsonEndPoint<T>(Module<T> module, string endPointName) where T : DataModel, new();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new endpoint for the given plugin feature receiving an a <see cref="string" />.
|
||||
/// </summary>
|
||||
@ -95,7 +85,7 @@ public interface IWebServerService : IArtemisService
|
||||
/// <summary>
|
||||
/// Adds a new Web API controller and restarts the web server
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of Web API controller to remove</typeparam>
|
||||
/// <typeparam name="T">The type of Web API controller to add</typeparam>
|
||||
WebApiControllerRegistration AddController<T>(PluginFeature feature, string path) where T : class;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -12,14 +12,14 @@ using GenHTTP.Modules.IO.Strings;
|
||||
namespace Artemis.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
/// <see cref="PluginEndPoint" />.
|
||||
/// </summary>
|
||||
public class PluginsModule : IHandler
|
||||
public class PluginsHandler : IHandler
|
||||
{
|
||||
private readonly Dictionary<string, Dictionary<string, PluginEndPoint>> _pluginEndPoints;
|
||||
|
||||
internal PluginsModule(string baseRoute)
|
||||
internal PluginsHandler(string baseRoute)
|
||||
{
|
||||
BaseRoute = baseRoute;
|
||||
_pluginEndPoints = new Dictionary<string, Dictionary<string, PluginEndPoint>>(comparer: StringComparer.InvariantCultureIgnoreCase);
|
||||
@ -63,20 +63,30 @@ public class PluginsModule : IHandler
|
||||
/// <inheritdoc />
|
||||
public async ValueTask<IResponse?> 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<string, PluginEndPoint>? endPoints))
|
||||
if (!_pluginEndPoints.TryGetValue(pluginId, out Dictionary<string, PluginEndPoint>? 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();
|
||||
}
|
||||
27
src/Artemis.Core/Services/WebServer/StatusHandler.cs
Normal file
27
src/Artemis.Core/Services/WebServer/StatusHandler.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System.Threading.Tasks;
|
||||
using GenHTTP.Api.Content;
|
||||
using GenHTTP.Api.Protocol;
|
||||
|
||||
namespace Artemis.Core.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an GenHTTP handler used to process web requests and forward them to the right
|
||||
/// <see cref="PluginEndPoint" />.
|
||||
/// </summary>
|
||||
public class StatusHandler : IHandler
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ValueTask PrepareAsync()
|
||||
{
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ValueTask<IResponse?> 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<IResponse?>(request.Respond().Status(ResponseStatus.NoContent).Build())
|
||||
: ValueTask.FromResult<IResponse?>(null);
|
||||
}
|
||||
}
|
||||
@ -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<bool> _webServerEnabledSetting;
|
||||
private readonly PluginSetting<int> _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 <IServer> CreateWebServer()
|
||||
private async Task<IServer> 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<T> endPoint = new(feature, endPointName, PluginsModule, requestHandler);
|
||||
PluginsModule.AddPluginEndPoint(endPoint);
|
||||
JsonPluginEndPoint<T> 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<T> endPoint = new(feature, endPointName, PluginsModule, requestHandler);
|
||||
PluginsModule.AddPluginEndPoint(endPoint);
|
||||
JsonPluginEndPoint<T> 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<T>(PluginFeature feature, string endPointName, Action<T> requestHandler) instead")]
|
||||
public DataModelJsonPluginEndPoint<T> AddDataModelJsonEndPoint<T>(Module<T> module, string endPointName) where T : DataModel, new()
|
||||
{
|
||||
if (module == null) throw new ArgumentNullException(nameof(module));
|
||||
if (endPointName == null) throw new ArgumentNullException(nameof(endPointName));
|
||||
DataModelJsonPluginEndPoint<T> 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
|
||||
|
||||
@ -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<string> args)
|
||||
{
|
||||
Utilities.Restart(_coreService.IsElevated, TimeSpan.FromMilliseconds(500), args.ToArray());
|
||||
}
|
||||
|
||||
[ControllerAction(RequestMethod.Post)]
|
||||
[ResourceMethod(RequestMethod.Post, "shutdown")]
|
||||
public void Shutdown()
|
||||
{
|
||||
Utilities.Shutdown();
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<PackageVersion Include="Avalonia.Skia.Lottie" Version="11.0.0" />
|
||||
<PackageVersion Include="Avalonia.Win32" Version="11.2.3" />
|
||||
<PackageVersion Include="GenHTTP.Core" Version="9.6.2" />
|
||||
<PackageVersion Include="GenHTTP.Modules.Controllers" Version="9.6.2" />
|
||||
<PackageVersion Include="GenHTTP.Modules.Webservices" Version="9.6.2" />
|
||||
<PackageVersion Include="HPPH.SkiaSharp" Version="1.0.0" />
|
||||
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.1" />
|
||||
<PackageVersion Include="Avalonia.Xaml.Behaviors" Version="11.2.0.8" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user