aboutsummaryrefslogtreecommitdiff
path: root/lib/Plugins.Essentials.ServiceStack
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-02-14 14:10:27 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2024-02-14 14:10:27 -0500
commit2b1314c1475e7e1831c691cf349cb89c66fa320c (patch)
tree091fc132a2bee2e79a68d8c6d5eb20f1d989a3d2 /lib/Plugins.Essentials.ServiceStack
parentf4e4db7c5320976406feb252ae8f8bdbe9b3e351 (diff)
Squashed commit of the following:
commit ddd8a651b6eb43cfdd49d84056f8b9c34b543992 Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 14 00:15:50 2024 -0500 ci: reduce output noise and update Argon2 build commit cf942959ff2feea03d3eda2ff2a263bdac4d6bc6 Author: vnugent <public@vaughnnugent.com> Date: Mon Feb 12 18:39:18 2024 -0500 chore: update packages and minor fixes commit ab506af9e2de2876b11bb45b3c7e787616c80155 Author: vnugent <public@vaughnnugent.com> Date: Fri Feb 9 21:27:24 2024 -0500 fix: patch and update core runtime service injection commit 7ed5e8b19164c28d3a238bd56878d2161fbea2e4 Author: vnugent <public@vaughnnugent.com> Date: Thu Feb 8 18:26:11 2024 -0500 fork dotnetplugins and make some intial updates/upgrades commit f4cab88d67be5da0953b14bd46fc972d4acc8606 Author: vnugent <public@vaughnnugent.com> Date: Thu Feb 8 12:16:13 2024 -0500 update some heap api functions commit 6035bf7ed8412f1da361cc5feddd860abfaf4fc1 Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 7 22:09:11 2024 -0500 working file-watcher notifications/rework commit 698f8edf694ad9700ee2ce2220e692b496448ff9 Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 7 20:37:28 2024 -0500 remove mem-template and add file-watcher utility commit b17591e0fb363222fcd7d93c2bad4ab1b102385f Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 7 18:28:21 2024 -0500 add small memmove support for known small blocks commit 631be4d4b27fdbcd4b0526e17a128bb0d86911eb Author: vnugent <public@vaughnnugent.com> Date: Wed Feb 7 18:08:02 2024 -0500 setup some readonly ref arguments and convert copy apis to readonly refs commit 2ba8dec68d5cb192e61ad0141d4b460076d3f90a Author: vnugent <public@vaughnnugent.com> Date: Mon Feb 5 18:30:38 2024 -0500 restructure internal memmove strategies commit 25cf02872da980893ad7fb51d4eccc932380582b Author: vnugent <public@vaughnnugent.com> Date: Sun Feb 4 01:29:18 2024 -0500 add http stream interface, profiling -> file read updates commit 757668c44e78864dc69d5713a2cfba6db2ed9a2a Author: vnugent <public@vaughnnugent.com> Date: Fri Feb 2 14:27:04 2024 -0500 streamline data-copy api with proper large block support and net8 feature updates commit f22c1765fd72ab40a10d8ec92a8cb6d9ec1b1a04 Author: vnugent <public@vaughnnugent.com> Date: Mon Jan 29 16:16:23 2024 -0500 check for compression lib updates to close #2 and fix some ci build stuff commit f974bfdef6a795b4a1c04602502ef506ef2587a9 Author: vnugent <public@vaughnnugent.com> Date: Tue Jan 23 17:36:17 2024 -0500 switch allocator libs to lgpl2.1 commit 1fe5e01b329cd27b675000f1a557b784d3c88b56 Author: vnugent <public@vaughnnugent.com> Date: Tue Jan 23 17:05:59 2024 -0500 consolidate allocator packages and close #1 commit 74e1107e522f00b670526193396217f40a6bade7 Author: vnugent <public@vaughnnugent.com> Date: Tue Jan 23 15:43:40 2024 -0500 cache extension api tweaks commit 96ca2b0388a6326b9bb74f3ab2f62eaede6681e0 Author: vnugent <public@vaughnnugent.com> Date: Mon Jan 22 17:54:23 2024 -0500 explicit tcp server args reuse
Diffstat (limited to 'lib/Plugins.Essentials.ServiceStack')
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs2
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs44
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IRuntimeServiceInjection.cs49
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs169
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs9
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs11
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs23
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginRutimeEventHandler.cs (renamed from lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs)10
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs30
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs9
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs29
11 files changed, 201 insertions, 184 deletions
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
index f100c1d..3ae2183 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
@@ -168,7 +168,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
private PluginStackInitializer GetPluginStack(ServiceDomain domain)
{
//Always init manual array
- manualPlugins ??= Array.Empty<IManualPlugin>();
+ manualPlugins ??= [];
//Only load plugins if the callback is configured
IPluginStack? plugins = _getPlugins?.Invoke();
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs
deleted file mode 100644
index eee7a2e..0000000
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/IAccountSecUpdateable.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-* Copyright (c) 2023 Vaughn Nugent
-*
-* Library: VNLib
-* Package: VNLib.Plugins.Essentials.ServiceStack
-* File: IAccountSecUpdateable.cs
-*
-* IAccountSecUpdateable.cs is part of VNLib.Plugins.Essentials.ServiceStack which is part of the larger
-* VNLib collection of libraries and utilities.
-*
-* VNLib.Plugins.Essentials.ServiceStack is free software: you can redistribute it and/or modify
-* it under the terms of the GNU Affero General Public License as
-* published by the Free Software Foundation, either version 2 of the
-* License, or (at your option) any later version.
-*
-* VNLib.Plugins.Essentials.ServiceStack is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU Affero General Public License for more details.
-*
-* You should have received a copy of the GNU Affero General Public License
-* along with this program. If not, see https://www.gnu.org/licenses/.
-*/
-
-using VNLib.Plugins.Essentials.Accounts;
-
-
-namespace VNLib.Plugins.Essentials.ServiceStack.Construction
-{
- /// <summary>
- /// Adds functionality to event processors to allow them to be updated
- /// with a new <see cref="IAccountSecurityProvider"/> instance dynamically
- /// at runtime
- /// </summary>
- public interface IAccountSecUpdateable
- {
- /// <summary>
- /// Sets the <see cref="IAccountSecurityProvider"/> instance for the event processor
- /// may be null to remove a previous provider
- /// </summary>
- /// <param name="provider">The new <see cref="IAccountSecurityProvider"/> instance</param>
- void SetAccountSecProvider(IAccountSecurityProvider? provider);
- }
-}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/IRuntimeServiceInjection.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IRuntimeServiceInjection.cs
new file mode 100644
index 0000000..c18289e
--- /dev/null
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IRuntimeServiceInjection.cs
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.ServiceStack
+* File: IRuntimeServiceInjection.cs
+*
+* IRuntimeServiceInjection.cs is part of VNLib.Plugins.Essentials.ServiceStack which
+* is part of the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Plugins.Essentials.ServiceStack is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 2 of the
+* License, or (at your option) any later version.
+*
+* VNLib.Plugins.Essentials.ServiceStack is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see https://www.gnu.org/licenses/.
+*/
+
+using System;
+
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
+{
+ /// <summary>
+ /// Adds functionality to event processors for runtime service injection
+ /// that can be used to add and remove services from the service provider
+ /// at runtime.
+ /// </summary>
+ public interface IRuntimeServiceInjection
+ {
+ /// <summary>
+ /// Adds a collection of services to event processors
+ /// that can be used.
+ /// </summary>
+ /// <param name="services">The collection of exported services</param>
+ void AddServices(IServiceProvider services);
+
+ /// <summary>
+ /// Removes a collection of services from event processors
+ /// </summary>
+ /// <param name="services">The service container that contains services to remove</param>
+ void RemoveServices(IServiceProvider services);
+ }
+}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
index d96809b..5512e49 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
@@ -26,14 +26,14 @@ using System;
using System.IO;
using System.Net;
using System.Linq;
+using System.Collections.Frozen;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;
using VNLib.Utils.Logging;
+using VNLib.Utils.Extensions;
using VNLib.Net.Http;
-using VNLib.Plugins.Essentials.Accounts;
-using VNLib.Plugins.Essentials.Content;
-using VNLib.Plugins.Essentials.Sessions;
using VNLib.Plugins.Essentials.Middleware;
namespace VNLib.Plugins.Essentials.ServiceStack.Construction
@@ -51,7 +51,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// </summary>
/// <param name="stack"></param>
/// <returns>The <see cref="IDomainBuilder"/> used to define your service domain</returns>
- public static IDomainBuilder WithDomain(this HttpServiceStackBuilder stack) => stack.WithDomain(p => new BasicVirtualHost(p.Clone()));
+ public static IDomainBuilder WithDomain(this HttpServiceStackBuilder stack) => WithDomain(stack, vhc => FromVirtualHostConfig(vhc.Clone()));
/// <summary>
/// Creates a new <see cref="IDomainBuilder"/> instance to define your
@@ -74,7 +74,8 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// <param name="stack"></param>
/// <param name="callback">The custom event processor type</param>
/// <returns></returns>
- public static IDomainBuilder WithDomain<T>(this HttpServiceStackBuilder stack, Func<VirtualHostConfiguration, T> callback) where T : EventProcessor, IAccountSecUpdateable
+ public static IDomainBuilder WithDomain<T>(this HttpServiceStackBuilder stack, Func<VirtualHostConfiguration, T> callback)
+ where T : EventProcessor, IRuntimeServiceInjection
{
List<VirtualHostConfiguration> configs = new();
DomainBuilder domains = new(configs, stack);
@@ -174,14 +175,54 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
return vhBuilder;
}
+ /// <summary>
+ /// Adds an array of IP addresses to the downstream server collection. This is a security
+ /// features that allows event handles to trust connections/ipaddresses that originate from
+ /// trusted downstream servers
+ /// </summary>
+ /// <param name="vhBuilder"></param>
+ /// <param name="addresses">The collection of IP addresses to set as trusted servers</param>
+ /// <returns></returns>
public static IVirtualHostBuilder WithDownstreamServers(this IVirtualHostBuilder vhBuilder, params IPAddress[] addresses)
{
vhBuilder.WithOption(c => c.DownStreamServers = new HashSet<IPAddress>(addresses));
return vhBuilder;
}
+ private static BasicVirtualHost FromVirtualHostConfig(VirtualHostConfiguration configuration)
+ {
+ /*
+ * Event processors configurations are considered immutable. That is,
+ * top-level elements are not allowed to be changed after the processor
+ * has been created. Some properties/containers are allowed to be modified
+ * such as middleware chains, and the service pool.
+ */
+
+ EventProcessorConfig conf = new(
+ configuration.RootDir.FullName,
+ configuration.Hostname,
+ configuration.LogProvider,
+ configuration)
+ {
+ AllowedAttributes = configuration.AllowedAttributes,
+ DissallowedAttributes = configuration.DissallowedAttributes,
+ DefaultFiles = configuration.DefaultFiles,
+ ExecutionTimeout = configuration.ExecutionTimeout,
+
+ //Frozen sets are required for the event processor, for performance reasons
+ DownStreamServers = configuration.DownStreamServers.ToFrozenSet(),
+ ExcludedExtensions = configuration.ExcludedExtensions.ToFrozenSet(),
+ };
+
+ //Add all pre-configured middleware to the chain
+ configuration.CustomMiddleware.ForEach(conf.MiddlewareChain.Add);
+
+ return new(configuration.EventHooks, conf);
+ }
+
- private static void AddHosts(this HttpServiceStackBuilder stack, Func<IServiceHost[]> hosts) => stack.WithDomain(p => Array.ForEach(hosts(), h => p.Add(h)));
+ private static void AddHosts(this HttpServiceStackBuilder stack, Func<IServiceHost[]> hosts)
+ => stack.WithDomain(p => Array.ForEach(hosts(), h => p.Add(h)));
private static void OnPluginServiceEvent<T>(this IManagedPlugin plugin, Action<T> loader)
{
@@ -193,7 +234,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
private sealed record class DomainBuilder(List<VirtualHostConfiguration> Configs, HttpServiceStackBuilder Stack) : IDomainBuilder
{
-
///<inheritdoc/>
public IVirtualHostBuilder WithVirtualHost(DirectoryInfo rootDirectory, IVirtualHostHooks hooks, ILogProvider logger)
{
@@ -217,6 +257,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
private sealed record class VHostBuilder(VirtualHostConfiguration Config) : IVirtualHostBuilder
{
+ ///<inheritdoc/>
public IVirtualHostBuilder WithOption(Action<VirtualHostConfiguration> configCallback)
{
configCallback(Config);
@@ -225,23 +266,9 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
}
}
- private sealed class CustomServiceHost<T> : IServiceHost where T : EventProcessor, IAccountSecUpdateable
+ private sealed class CustomServiceHost<T>(IHostTransportInfo Config, T Instance) : IServiceHost
+ where T : EventProcessor, IRuntimeServiceInjection
{
- private readonly VirtualHostConfiguration Config;
- private readonly T Instance;
-
- public CustomServiceHost(VirtualHostConfiguration Config, T Instance)
- {
- this.Config = Config;
- this.Instance = Instance;
-
- //Add middleware to the chain
- foreach (IHttpMiddleware mw in Config.CustomMiddleware)
- {
- Instance.MiddlewareChain.Add(mw);
- }
- }
-
///<inheritdoc/>
public IWebRoot Processor => Instance;
@@ -252,78 +279,90 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
void IServiceHost.OnRuntimeServiceAttach(IManagedPlugin plugin, IEndpoint[] endpoints)
{
//Add endpoints to service
- Instance.EndpointTable.AddEndpoint(endpoints);
-
- //Add all services
- plugin.OnPluginServiceEvent<ISessionProvider>(Instance.SetSessionProvider);
- plugin.OnPluginServiceEvent<IPageRouter>(Instance.SetPageRouter);
- plugin.OnPluginServiceEvent<IAccountSecurityProvider>(Instance.SetAccountSecProvider);
+ Instance.Options.EndpointTable.AddEndpoint(endpoints);
+
+ //Inject services into the event processor service pool
+ Instance.AddServices(plugin.Services);
- //Add all middleware to the chain
- plugin.OnPluginServiceEvent<IHttpMiddleware[]>(p => Array.ForEach(p, mw => Instance.MiddlewareChain.Add(mw)));
+ //Add all exposed middleware to the chain
+ plugin.OnPluginServiceEvent<ICollection<IHttpMiddleware>>(p => p.TryForeach(Instance.Options.MiddlewareChain.Add));
}
///<inheritdoc/>
void IServiceHost.OnRuntimeServiceDetach(IManagedPlugin plugin, IEndpoint[] endpoints)
{
//Remove endpoints
- Instance.EndpointTable.RemoveEndpoint(endpoints);
-
- //Remove all services
- plugin.OnPluginServiceEvent<ISessionProvider>(p => Instance.SetSessionProvider(null));
- plugin.OnPluginServiceEvent<IPageRouter>(p => Instance.SetPageRouter(null));
- plugin.OnPluginServiceEvent<IAccountSecurityProvider>(p => Instance.SetAccountSecProvider(null));
+ Instance.Options.EndpointTable.RemoveEndpoint(endpoints);
+ Instance.RemoveServices(plugin.Services);
//Remove all middleware from the chain
- plugin.OnPluginServiceEvent<IHttpMiddleware[]>(p => Array.ForEach(p, mw => Instance.MiddlewareChain.RemoveMiddleware(mw)));
+ plugin.OnPluginServiceEvent<ICollection<IHttpMiddleware>>(p => p.TryForeach(Instance.Options.MiddlewareChain.Remove));
}
}
- private sealed class BasicVirtualHost : EventProcessor, IAccountSecUpdateable
+ private sealed class BasicVirtualHost(IVirtualHostHooks Hooks, EventProcessorConfig config) : EventProcessor(config), IRuntimeServiceInjection
{
- private readonly VirtualHostConfiguration Config;
- private readonly IVirtualHostHooks Hooks;
-
- internal IAccountSecurityProvider? SecProvider;
-
- public BasicVirtualHost(VirtualHostConfiguration config)
- {
- Config = config;
- Hooks = config.EventHooks;
- Directory = config.RootDir.FullName;
- }
+ /*
+ * Runtime service injection can be tricky, at least in my architecture. If all we have
+ * is am IServiceProvider instance, we cannot trust that the services availabe are
+ * exactly the same as the ones initially provided. So we can store the known types
+ * that a given service container DID export, and then use that to remove the services
+ * when the service provider is removed.
+ */
+ private readonly ConditionalWeakTable<IServiceProvider, Type[]> _exposedTypes = new();
///<inheritdoc/>
- public override string Directory { get; }
+ public override bool ErrorHandler(HttpStatusCode errorCode, IHttpEvent entity) => Hooks.ErrorHandler(errorCode, entity);
///<inheritdoc/>
- public override string Hostname => Config.Hostname;
+ public override void PreProcessEntity(HttpEntity entity, out FileProcessArgs preProcArgs) => Hooks.PreProcessEntityAsync(entity, out preProcArgs);
///<inheritdoc/>
- public override IEpProcessingOptions Options => Config;
+ public override void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine) => Hooks.PostProcessFile(entity, ref chosenRoutine);
///<inheritdoc/>
- public override IAccountSecurityProvider? AccountSecurity => SecProvider;
+ public override string TranslateResourcePath(string requestPath) => Hooks.TranslateResourcePath(requestPath);
///<inheritdoc/>
- protected override ILogProvider Log => Config.LogProvider;
+ public void AddServices(IServiceProvider services)
+ {
+ Type[] exposedForHandler = [];
- ///<inheritdoc/>
- public override bool ErrorHandler(HttpStatusCode errorCode, IHttpEvent entity) => Hooks.ErrorHandler(errorCode, entity);
+ foreach (Type type in ServicePool.Types)
+ {
+ //Get exported service by the desired type
+ object? service = services.GetService(type);
- ///<inheritdoc/>
- public override void PreProcessEntity(HttpEntity entity, out FileProcessArgs preProcArgs) => Hooks.PreProcessEntityAsync(entity, out preProcArgs);
+ //If its not null, then add it to the service pool
+ if (service is not null)
+ {
+ ServicePool.SetService(type, service);
- ///<inheritdoc/>
- public override void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine) => Hooks.PostProcessFile(entity, ref chosenRoutine);
+ //Add to the exposed types list
+ exposedForHandler = [.. exposedForHandler, type];
+ }
+ }
- ///<inheritdoc/>
- public override string TranslateResourcePath(string requestPath) => Hooks.TranslateResourcePath(requestPath);
+ //Add to the exposed types table
+ _exposedTypes.Add(services, exposedForHandler);
+ }
///<inheritdoc/>
- public void SetAccountSecProvider(IAccountSecurityProvider? provider) => SecProvider = provider;
-
+ public void RemoveServices(IServiceProvider services)
+ {
+ //Get all exposed types for this service provider
+ if (_exposedTypes.TryGetValue(services, out Type[]? exposed))
+ {
+ foreach (Type type in exposed)
+ {
+ ServicePool.SetService(type, null);
+ }
+
+ //Remove from the exposed types table
+ _exposedTypes.Remove(services);
+ }
+ }
}
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs b/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
index 16bc1a0..71db38f 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/HttpServiceStack.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.ServiceStack
@@ -29,6 +29,7 @@ using System.Collections.Generic;
using VNLib.Utils;
using VNLib.Net.Http;
+using VNLib.Utils.Logging;
namespace VNLib.Plugins.Essentials.ServiceStack
{
@@ -96,6 +97,12 @@ namespace VNLib.Plugins.Essentials.ServiceStack
}
/// <summary>
+ /// Loads all plugins into the service stack
+ /// </summary>
+ /// <param name="logProvider">A log provider for writing loading logs to</param>
+ public void LoadPlugins(ILogProvider logProvider) => _plugins.LoadPlugins(logProvider);
+
+ /// <summary>
/// Stops listening on all configured servers and returns a task that completes
/// when the service host has stopped all servers and unloaded resources
/// </summary>
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
index d8cdf75..52377ee 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginExtensions.cs
@@ -25,7 +25,6 @@
using System.Linq;
using System.Collections.Generic;
-using VNLib.Utils.Logging;
using VNLib.Plugins.Essentials.Runtime;
namespace VNLib.Plugins.Essentials.ServiceStack
@@ -53,14 +52,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack
return Enumerable.Empty<IEndpoint>();
}
- /// <summary>
- /// Loads all plugins that implement <see cref="IWebPlugin"/> interface into the
- /// service stack
- /// </summary>
- /// <param name="stack"></param>
- /// <param name="logProvider">A log provider for writing loading logs to</param>
- public static void LoadPlugins(this HttpServiceStack stack, ILogProvider logProvider) => (stack.PluginManager as PluginManager)!.LoadPlugins(logProvider);
-
- internal static PluginLoadEventListener GetListener(this ServiceDomain domain) => new(domain);
+ internal static PluginRutimeEventHandler GetListener(this ServiceDomain domain) => new(domain);
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
index f5f2abc..f43da78 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginManager.cs
@@ -36,22 +36,15 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// A sealed type that manages the plugin interaction layer. Manages the lifetime of plugin
/// instances, exposes controls, and relays stateful plugin events.
/// </summary>
- internal sealed class PluginManager : VnDisposeable, IHttpPluginManager
+ internal sealed class PluginManager(IPluginInitializer stack) : VnDisposeable, IHttpPluginManager
{
- private readonly IPluginInitializer _stack;
/// <summary>
/// The collection of internal controllers
/// </summary>
public IEnumerable<IManagedPlugin> Plugins => _loadedPlugins;
- private IManagedPlugin[] _loadedPlugins;
-
- public PluginManager(IPluginInitializer stack)
- {
- _stack = stack;
- _loadedPlugins = Array.Empty<IManagedPlugin>();
- }
+ private IManagedPlugin[] _loadedPlugins = [];
/// <summary>
/// Configures the manager to capture and manage plugins within a plugin stack
@@ -61,12 +54,12 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// <exception cref="AggregateException"></exception>
public void LoadPlugins(ILogProvider debugLog)
{
- _ = _stack ?? throw new InvalidOperationException("Plugin stack has not been set.");
+ _ = stack ?? throw new InvalidOperationException("Plugin stack has not been set.");
Check();
//Initialize the plugin stack and store the loaded plugins
- _loadedPlugins = _stack.InitializePluginStack(debugLog);
+ _loadedPlugins = stack.InitializePluginStack(debugLog);
debugLog.Information("Plugin loading completed");
}
@@ -94,7 +87,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Check();
//Reload all plugins, causing an event cascade
- _stack.ReloadPlugins();
+ stack.ReloadPlugins();
}
/// <inheritdoc/>
@@ -103,7 +96,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Check();
//Unload all plugin controllers
- _stack.UnloadPlugins();
+ stack.UnloadPlugins();
/*
* All plugin instances must be destroyed because the
@@ -116,10 +109,10 @@ namespace VNLib.Plugins.Essentials.ServiceStack
protected override void Free()
{
//Clear plugin table
- _loadedPlugins = Array.Empty<IManagedPlugin>();
+ _loadedPlugins = [];
//Dispose the plugin stack
- _stack.Dispose();
+ stack.Dispose();
}
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginRutimeEventHandler.cs
index b24019b..f892823 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginLoadEventListener.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginRutimeEventHandler.cs
@@ -3,9 +3,9 @@
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.ServiceStack
-* File: PluginLoadEventListener.cs
+* File: PluginRutimeEventHandler.cs
*
-* PluginLoadEventListener.cs is part of VNLib.Plugins.Essentials.ServiceStack which
+* PluginRutimeEventHandler.cs is part of VNLib.Plugins.Essentials.ServiceStack which
* is part of the larger VNLib collection of libraries and utilities.
*
* VNLib.Plugins.Essentials.ServiceStack is free software: you can redistribute it and/or modify
@@ -30,7 +30,7 @@ using VNLib.Plugins.Runtime;
namespace VNLib.Plugins.Essentials.ServiceStack
{
- internal sealed record class PluginLoadEventListener(ServiceDomain Domain) : IPluginEventListener
+ internal sealed class PluginRutimeEventHandler(ServiceDomain Domain) : IPluginEventListener
{
///<inheritdoc/>
void IPluginEventListener.OnPluginLoaded(PluginController controller, object? state) => OnPluginLoaded((state as IManagedPlugin)!);
@@ -43,7 +43,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// should be put into service
/// </summary>
/// <param name="plugin">The plugin that was loaded</param>
- public void OnPluginLoaded(IManagedPlugin plugin)
+ internal void OnPluginLoaded(IManagedPlugin plugin)
{
//Run onload method before invoking other handlers
plugin.OnPluginLoaded();
@@ -60,7 +60,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// be removed from service.
/// </summary>
/// <param name="plugin">The plugin instance to unload</param>
- public void OnPluginUnloaded(IManagedPlugin plugin)
+ internal void OnPluginUnloaded(IManagedPlugin plugin)
{
try
{
diff --git a/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs b/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
index e6489c9..5a33425 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/PluginStackInitializer.cs
@@ -39,7 +39,7 @@ using VNLib.Plugins.Runtime.Services;
namespace VNLib.Plugins.Essentials.ServiceStack
{
- internal sealed record class PluginStackInitializer(PluginLoadEventListener Listener, IPluginStack Stack, IManualPlugin[] ManualPlugins, bool ConcurrentLoad)
+ internal sealed class PluginStackInitializer(PluginRutimeEventHandler Listener, IPluginStack Stack, IManualPlugin[] ManualPlugins, bool ConcurrentLoad)
: IPluginInitializer
{
private readonly LinkedList<IManagedPlugin> _managedPlugins = new();
@@ -64,7 +64,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Array.ForEach(wrapper, p => p.Plugin.Controller.Register(Listener, p));
//Add manual plugins to list of managed plugins
- Array.ForEach(ManualPlugins, p => _manualPlugins.AddLast(new ManualPluginWrapper(p)));
+ Array.ForEach(ManualPlugins, p => _manualPlugins.AddLast(new ManualPluginWrapper(Listener, p)));
}
///<inheritdoc/>
@@ -103,7 +103,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
_loadedPlugins.TryForeach(_loadedPlugins => LoadPlugin(_loadedPlugins, debugLog));
}
- return _loadedPlugins.ToArray();
+ return [.. _loadedPlugins];
}
///<inheritdoc/>
@@ -112,7 +112,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack
Stack.UnloadAll();
//Unload manual plugins in listener
- _managedPlugins.TryForeach(mp => Listener.OnPluginUnloaded(mp));
_manualPlugins.TryForeach(static mp => mp.Unload());
}
@@ -121,13 +120,11 @@ namespace VNLib.Plugins.Essentials.ServiceStack
{
Stack.ReloadAll();
- //Unload manual plugins in listener, then call the unload method
- _managedPlugins.TryForeach(mp => Listener.OnPluginUnloaded(mp));
+ //Unload manual plugins in listener
_manualPlugins.TryForeach(static mp => mp.Unload());
//Load, then invoke on-loaded events
_manualPlugins.TryForeach(static mp => mp.Load());
- _managedPlugins.TryForeach(mp => Listener.OnPluginLoaded(mp));
}
///<inheritdoc/>
@@ -191,8 +188,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack
else if (plugin is ManualPluginWrapper mpw)
{
mpw.Load();
- //Call the on-load event in listener explicitly
- Listener.OnPluginLoaded(plugin);
}
else
{
@@ -219,14 +214,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
private ServiceContainer? _services;
///<inheritdoc/>
- public IServiceContainer Services
- {
- get
- {
- _ = _services ?? throw new InvalidOperationException("The service container is not currently loaded");
- return _services!;
- }
- }
+ public IServiceContainer Services => _services ?? throw new InvalidOperationException("The service container is not currently loaded");
/*
* Automatically called after the plugin has successfully loaded
@@ -275,7 +263,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public override string ToString() => Path.GetFileName(Plugin.Config.AssemblyFile);
}
- private sealed record class ManualPluginWrapper(IManualPlugin Plugin) : IManagedPlugin, IDisposable
+ private sealed record class ManualPluginWrapper(PluginRutimeEventHandler Listener, IManualPlugin Plugin) : IManagedPlugin, IDisposable
{
private ServiceContainer _container = new();
@@ -286,10 +274,16 @@ namespace VNLib.Plugins.Essentials.ServiceStack
{
Plugin.Load();
Plugin.GetAllExportedServices(Services);
+
+ //Finally notify of load
+ Listener.OnPluginLoaded(this);
}
public void Unload()
{
+ //Notify of unload
+ Listener.OnPluginUnloaded(this);
+
Plugin.Unload();
//Unload and re-init container
diff --git a/lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs b/lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs
index 4cff671..35bf65b 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/ServiceDomain.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.ServiceStack
@@ -38,7 +38,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// </summary>
public sealed class ServiceDomain
{
- private readonly LinkedList<ServiceGroup> _serviceGroups;
+ private readonly LinkedList<ServiceGroup> _serviceGroups = new();
/// <summary>
/// Gets all service groups loaded in the service manager
@@ -46,11 +46,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public IReadOnlyCollection<ServiceGroup> ServiceGroups => _serviceGroups;
/// <summary>
- /// Initializes a new empty <see cref="ServiceDomain"/>
- /// </summary>
- public ServiceDomain() => _serviceGroups = new();
-
- /// <summary>
/// Uses the supplied callback to get a collection of virtual hosts
/// to build the current domain with
/// </summary>
diff --git a/lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs b/lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs
index da34d54..29b9fdc 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/ServiceGroup.cs
@@ -37,15 +37,21 @@ namespace VNLib.Plugins.Essentials.ServiceStack
/// common transport (interface, port, and SSL status)
/// and may be loaded by a single server instance.
/// </summary>
- public sealed class ServiceGroup
+ /// <remarks>
+ /// Initalizes a new <see cref="ServiceGroup"/> of virtual hosts
+ /// with common transport
+ /// </remarks>
+ /// <param name="serviceEndpoint">The <see cref="IPEndPoint"/> to listen for connections on</param>
+ /// <param name="hosts">The hosts that share a common interface endpoint</param>
+ public sealed class ServiceGroup(IPEndPoint serviceEndpoint, IEnumerable<IServiceHost> hosts)
{
- private readonly LinkedList<IServiceHost> _vHosts;
- private readonly ConditionalWeakTable<IManagedPlugin, IEndpoint[]> _endpointsForPlugins;
+ private readonly LinkedList<IServiceHost> _vHosts = new(hosts);
+ private readonly ConditionalWeakTable<IManagedPlugin, IEndpoint[]> _endpointsForPlugins = new();
/// <summary>
/// The <see cref="IPEndPoint"/> transport endpoint for all loaded service hosts
/// </summary>
- public IPEndPoint ServiceEndpoint { get; }
+ public IPEndPoint ServiceEndpoint => serviceEndpoint;
/// <summary>
/// The collection of hosts that are loaded by this group
@@ -53,26 +59,13 @@ namespace VNLib.Plugins.Essentials.ServiceStack
public IReadOnlyCollection<IServiceHost> Hosts => _vHosts;
/// <summary>
- /// Initalizes a new <see cref="ServiceGroup"/> of virtual hosts
- /// with common transport
- /// </summary>
- /// <param name="serviceEndpoint">The <see cref="IPEndPoint"/> to listen for connections on</param>
- /// <param name="hosts">The hosts that share a common interface endpoint</param>
- public ServiceGroup(IPEndPoint serviceEndpoint, IEnumerable<IServiceHost> hosts)
- {
- _endpointsForPlugins = new();
- _vHosts = new(hosts);
- ServiceEndpoint = serviceEndpoint;
- }
-
- /// <summary>
/// Manually detatches runtime services and their loaded endpoints from all
/// endpoints.
/// </summary>
internal void UnloadAll()
{
//Remove all loaded endpoints
- _vHosts.TryForeach(v => _endpointsForPlugins.TryForeach(eps => v.OnRuntimeServiceDetach(eps.Key, eps.Value)));
+ _vHosts.TryForeach(v => _endpointsForPlugins.ForEach(eps => v.OnRuntimeServiceDetach(eps.Key, eps.Value)));
//Clear all hosts
_vHosts.Clear();