mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Webserver - Removed '/api/' part from URLs
Webserver - Added the ability to register custom EmbedIO modules Webserver - Ensure custom controllers/modules are always cleaned up on plugin feature disable
This commit is contained in:
parent
e32b181d9f
commit
ed704a165c
@ -55,7 +55,8 @@ namespace Artemis.Core.Services
|
|||||||
DataModelJsonPluginEndPoint<T> AddDataModelJsonEndPoint<T>(Module<T> module, string endPointName) where T : DataModel;
|
DataModelJsonPluginEndPoint<T> AddDataModelJsonEndPoint<T>(Module<T> module, string endPointName) where T : DataModel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new endpoint that directly maps received JSON to the data model of the provided <paramref name="profileModule" />.
|
/// Adds a new endpoint that directly maps received JSON to the data model of the provided
|
||||||
|
/// <paramref name="profileModule" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The data model type of the module</typeparam>
|
/// <typeparam name="T">The data model type of the module</typeparam>
|
||||||
/// <param name="profileModule">The module whose datamodel to apply the received JSON to</param>
|
/// <param name="profileModule">The module whose datamodel to apply the received JSON to</param>
|
||||||
@ -64,7 +65,8 @@ namespace Artemis.Core.Services
|
|||||||
DataModelJsonPluginEndPoint<T> AddDataModelJsonEndPoint<T>(ProfileModule<T> profileModule, string endPointName) where T : DataModel;
|
DataModelJsonPluginEndPoint<T> AddDataModelJsonEndPoint<T>(ProfileModule<T> profileModule, string endPointName) where T : DataModel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a new endpoint that directly maps received JSON to the data model of the provided <paramref name="dataModelExpansion" />.
|
/// Adds a new endpoint that directly maps received JSON to the data model of the provided
|
||||||
|
/// <paramref name="dataModelExpansion" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The data model type of the module</typeparam>
|
/// <typeparam name="T">The data model type of the module</typeparam>
|
||||||
/// <param name="dataModelExpansion">The data model expansion whose datamodel to apply the received JSON to</param>
|
/// <param name="dataModelExpansion">The data model expansion whose datamodel to apply the received JSON to</param>
|
||||||
@ -114,7 +116,7 @@ namespace Artemis.Core.Services
|
|||||||
/// Adds a new Web API controller and restarts the web server
|
/// Adds a new Web API controller and restarts the web server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of Web API controller to remove</typeparam>
|
/// <typeparam name="T">The type of Web API controller to remove</typeparam>
|
||||||
void AddController<T>() where T : WebApiController;
|
void AddController<T>(PluginFeature feature) where T : WebApiController;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes an existing Web API controller and restarts the web server
|
/// Removes an existing Web API controller and restarts the web server
|
||||||
@ -122,6 +124,18 @@ namespace Artemis.Core.Services
|
|||||||
/// <typeparam name="T">The type of Web API controller to remove</typeparam>
|
/// <typeparam name="T">The type of Web API controller to remove</typeparam>
|
||||||
void RemoveController<T>() where T : WebApiController;
|
void RemoveController<T>() where T : WebApiController;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new EmbedIO module and restarts the web server
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of module to add</typeparam>
|
||||||
|
void AddModule<T>(PluginFeature feature) where T : IWebModule;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a EmbedIO module and restarts the web server
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of module to remove</typeparam>
|
||||||
|
void RemoveModule<T>() where T : IWebModule;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when the web server has been created and is about to start. This is the ideal place to add your own modules.
|
/// Occurs when the web server has been created and is about to start. This is the ideal place to add your own modules.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -48,13 +48,13 @@ namespace Artemis.Core.Services
|
|||||||
protected override async Task OnRequestAsync(IHttpContext context)
|
protected override async Task OnRequestAsync(IHttpContext context)
|
||||||
{
|
{
|
||||||
if (context.Route.SubPath == null)
|
if (context.Route.SubPath == null)
|
||||||
throw HttpException.NotFound();
|
return;
|
||||||
|
|
||||||
// Split the sub path
|
// Split the sub path
|
||||||
string[] pathParts = context.Route.SubPath.Substring(1).Split('/');
|
string[] pathParts = context.Route.SubPath.Substring(1).Split('/');
|
||||||
// Expect a plugin ID and an endpoint
|
// Expect a plugin ID and an endpoint
|
||||||
if (pathParts == null || pathParts.Length != 2)
|
if (pathParts.Length != 2)
|
||||||
throw HttpException.BadRequest("Path must contain a plugin ID and endpoint and nothing else.");
|
return;
|
||||||
|
|
||||||
// Find a matching plugin
|
// Find a matching plugin
|
||||||
if (!_pluginEndPoints.TryGetValue(pathParts[0], out Dictionary<string, PluginEndPoint>? endPoints))
|
if (!_pluginEndPoints.TryGetValue(pathParts[0], out Dictionary<string, PluginEndPoint>? endPoints))
|
||||||
@ -78,7 +78,7 @@ namespace Artemis.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool IsFinalHandler => true;
|
public override bool IsFinalHandler => false;
|
||||||
|
|
||||||
internal string? ServerUrl { get; set; }
|
internal string? ServerUrl { get; set; }
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,9 @@ namespace Artemis.Core.Services
|
|||||||
{
|
{
|
||||||
internal class WebApiControllerRegistration<T> : WebApiControllerRegistration where T : WebApiController
|
internal class WebApiControllerRegistration<T> : WebApiControllerRegistration where T : WebApiController
|
||||||
{
|
{
|
||||||
public WebApiControllerRegistration(IKernel kernel) : base(typeof(T))
|
public WebApiControllerRegistration(PluginFeature feature) : base(feature, typeof(T))
|
||||||
{
|
{
|
||||||
Factory = () => kernel.Get<T>();
|
Factory = () => feature.Plugin.Kernel!.Get<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Func<T> Factory { get; set; }
|
public Func<T> Factory { get; set; }
|
||||||
@ -17,12 +17,14 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
internal abstract class WebApiControllerRegistration
|
internal abstract class WebApiControllerRegistration
|
||||||
{
|
{
|
||||||
protected WebApiControllerRegistration(Type controllerType)
|
protected WebApiControllerRegistration(PluginFeature feature, Type controllerType)
|
||||||
{
|
{
|
||||||
|
Feature = feature;
|
||||||
ControllerType = controllerType;
|
ControllerType = controllerType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract object UntypedFactory { get; }
|
public abstract object UntypedFactory { get; }
|
||||||
public Type ControllerType { get; set; }
|
public Type ControllerType { get; set; }
|
||||||
|
public PluginFeature Feature { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
20
src/Artemis.Core/Services/WebServer/WebModuleRegistration.cs
Normal file
20
src/Artemis.Core/Services/WebServer/WebModuleRegistration.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using EmbedIO;
|
||||||
|
using Ninject;
|
||||||
|
|
||||||
|
namespace Artemis.Core.Services
|
||||||
|
{
|
||||||
|
internal class WebModuleRegistration
|
||||||
|
{
|
||||||
|
public PluginFeature Feature { get; }
|
||||||
|
public Type WebModuleType { get; }
|
||||||
|
|
||||||
|
public WebModuleRegistration(PluginFeature feature, Type webModuleType)
|
||||||
|
{
|
||||||
|
Feature = feature;
|
||||||
|
WebModuleType = webModuleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IWebModule CreateInstance() => (IWebModule) Feature.Plugin.Kernel!.Get(WebModuleType);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.DataModelExpansions;
|
using Artemis.Core.DataModelExpansions;
|
||||||
@ -8,7 +9,6 @@ using Artemis.Core.Modules;
|
|||||||
using EmbedIO;
|
using EmbedIO;
|
||||||
using EmbedIO.WebApi;
|
using EmbedIO.WebApi;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Ninject;
|
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Artemis.Core.Services
|
namespace Artemis.Core.Services
|
||||||
@ -16,18 +16,19 @@ namespace Artemis.Core.Services
|
|||||||
internal class WebServerService : IWebServerService, IDisposable
|
internal class WebServerService : IWebServerService, IDisposable
|
||||||
{
|
{
|
||||||
private readonly List<WebApiControllerRegistration> _controllers;
|
private readonly List<WebApiControllerRegistration> _controllers;
|
||||||
private readonly IKernel _kernel;
|
private readonly List<WebModuleRegistration> _modules;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly PluginSetting<int> _webServerPortSetting;
|
private readonly PluginSetting<int> _webServerPortSetting;
|
||||||
|
|
||||||
public WebServerService(IKernel kernel, ILogger logger, ISettingsService settingsService)
|
public WebServerService(ILogger logger, ISettingsService settingsService, IPluginManagementService pluginManagementService)
|
||||||
{
|
{
|
||||||
_kernel = kernel;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_controllers = new List<WebApiControllerRegistration>();
|
_controllers = new List<WebApiControllerRegistration>();
|
||||||
|
_modules = new List<WebModuleRegistration>();
|
||||||
|
|
||||||
_webServerPortSetting = settingsService.GetSetting("WebServer.Port", 9696);
|
_webServerPortSetting = settingsService.GetSetting("WebServer.Port", 9696);
|
||||||
_webServerPortSetting.SettingChanged += WebServerPortSettingOnSettingChanged;
|
_webServerPortSetting.SettingChanged += WebServerPortSettingOnSettingChanged;
|
||||||
|
pluginManagementService.PluginFeatureDisabled += PluginManagementServiceOnPluginFeatureDisabled;
|
||||||
|
|
||||||
PluginsModule = new PluginsModule("/plugins");
|
PluginsModule = new PluginsModule("/plugins");
|
||||||
StartWebServer();
|
StartWebServer();
|
||||||
@ -43,12 +44,18 @@ namespace Artemis.Core.Services
|
|||||||
Server?.Dispose();
|
Server?.Dispose();
|
||||||
Server = null;
|
Server = null;
|
||||||
|
|
||||||
WebApiModule apiModule = new("/api/", JsonNetSerializer);
|
WebApiModule apiModule = new("/", JsonNetSerializer);
|
||||||
PluginsModule.ServerUrl = $"http://localhost:{_webServerPortSetting.Value}/";
|
PluginsModule.ServerUrl = $"http://localhost:{_webServerPortSetting.Value}/";
|
||||||
WebServer server = new WebServer(o => o.WithUrlPrefix($"http://*:{_webServerPortSetting.Value}/").WithMode(HttpListenerMode.EmbedIO))
|
WebServer server = new WebServer(o => o.WithUrlPrefix($"http://*:{_webServerPortSetting.Value}/").WithMode(HttpListenerMode.EmbedIO))
|
||||||
.WithLocalSessionManager()
|
.WithLocalSessionManager()
|
||||||
|
.WithModule(PluginsModule);
|
||||||
|
|
||||||
|
// Add registered modules
|
||||||
|
foreach (var webModule in _modules)
|
||||||
|
server = server.WithModule(webModule.CreateInstance());
|
||||||
|
|
||||||
|
server = server
|
||||||
.WithModule(apiModule)
|
.WithModule(apiModule)
|
||||||
.WithModule(PluginsModule)
|
|
||||||
.HandleHttpException((context, exception) => HandleHttpExceptionJson(context, exception))
|
.HandleHttpException((context, exception) => HandleHttpExceptionJson(context, exception))
|
||||||
.HandleUnhandledException(JsonExceptionHandlerCallback);
|
.HandleUnhandledException(JsonExceptionHandlerCallback);
|
||||||
|
|
||||||
@ -166,9 +173,9 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
#region Controller management
|
#region Controller management
|
||||||
|
|
||||||
public void AddController<T>() where T : WebApiController
|
public void AddController<T>(PluginFeature feature) where T : WebApiController
|
||||||
{
|
{
|
||||||
_controllers.Add(new WebApiControllerRegistration<T>(_kernel));
|
_controllers.Add(new WebApiControllerRegistration<T>(feature));
|
||||||
StartWebServer();
|
StartWebServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,6 +187,26 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Module management
|
||||||
|
|
||||||
|
public void AddModule<T>(PluginFeature feature) where T : IWebModule
|
||||||
|
{
|
||||||
|
if (feature == null) throw new ArgumentNullException(nameof(feature));
|
||||||
|
if (_modules.Any(r => r.WebModuleType == typeof(T)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_modules.Add(new WebModuleRegistration(feature, typeof(T)));
|
||||||
|
StartWebServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveModule<T>() where T : IWebModule
|
||||||
|
{
|
||||||
|
_modules.RemoveAll(r => r.WebModuleType == typeof(T));
|
||||||
|
StartWebServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Handlers
|
#region Handlers
|
||||||
|
|
||||||
private async Task JsonExceptionHandlerCallback(IHttpContext context, Exception exception)
|
private async Task JsonExceptionHandlerCallback(IHttpContext context, Exception exception)
|
||||||
@ -235,6 +262,25 @@ namespace Artemis.Core.Services
|
|||||||
StartWebServer();
|
StartWebServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PluginManagementServiceOnPluginFeatureDisabled(object? sender, PluginFeatureEventArgs e)
|
||||||
|
{
|
||||||
|
bool mustRestart = false;
|
||||||
|
if (_controllers.Any(c => c.Feature == e.PluginFeature))
|
||||||
|
{
|
||||||
|
mustRestart = true;
|
||||||
|
_controllers.RemoveAll(c => c.Feature == e.PluginFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modules.Any(m => m.Feature == e.PluginFeature))
|
||||||
|
{
|
||||||
|
mustRestart = true;
|
||||||
|
_modules.RemoveAll(m => m.Feature == e.PluginFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mustRestart)
|
||||||
|
StartWebServer();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IDisposable
|
#region IDisposable
|
||||||
|
|||||||
@ -64,7 +64,7 @@ namespace Artemis.UI
|
|||||||
|
|
||||||
string url = await File.ReadAllTextAsync(Path.Combine(Constants.DataFolder, "webserver.txt"));
|
string url = await File.ReadAllTextAsync(Path.Combine(Constants.DataFolder, "webserver.txt"));
|
||||||
using HttpClient client = new();
|
using HttpClient client = new();
|
||||||
await client.PostAsync(url + "api/remote/bring-to-foreground", null!);
|
await client.PostAsync(url + "remote/bring-to-foreground", null!);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UtilitiesOnRestartRequested(object sender, RestartEventArgs e)
|
private void UtilitiesOnRestartRequested(object sender, RestartEventArgs e)
|
||||||
|
|||||||
@ -106,7 +106,7 @@ namespace Artemis.UI.Services
|
|||||||
|
|
||||||
public void RegisterControllers()
|
public void RegisterControllers()
|
||||||
{
|
{
|
||||||
_webServerService.AddController<RemoteController>();
|
_webServerService.AddController<RemoteController>(Constants.CorePlugin.Features.First().Instance!);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user