aboutsummaryrefslogtreecommitdiff
path: root/lib/Plugins.Essentials.ServiceStack/src/Construction
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-07-28 19:15:04 -0400
committerLibravatar vnugent <public@vaughnnugent.com>2024-07-28 19:15:04 -0400
commit7be5d6648e633ba46a270ca5784de6f4a5a4e0a9 (patch)
treea6b53de82f12e6778ede2b3974073a6c3b51aace /lib/Plugins.Essentials.ServiceStack/src/Construction
parent1b590c2517fef110564943ed8a10edd11fa758b0 (diff)
Squashed commit of the following:
commit a4dacd2909426bf628c1eee1253cc5c8a01e2691 Author: vnugent <public@vaughnnugent.com> Date: Sat Jul 27 22:41:04 2024 -0400 package updates commit f836e09981866f5c9f2ae46990d11b186a7d12bb Author: vnugent <public@vaughnnugent.com> Date: Wed Jul 24 19:15:54 2024 -0400 chore: Remove argon2 docs & optional tcp resuse commit b9b892ab2143b0ab92e4dcf0a8b043c5c6c17271 Author: vnugent <public@vaughnnugent.com> Date: Sun Jul 21 20:57:01 2024 -0400 fix spelling Enqueue and deprecate mispelled version commit 21ffa816f18be4b765ad740ed5d93346ec3b1fda Author: vnugent <public@vaughnnugent.com> Date: Sat Jul 20 19:44:31 2024 -0400 static arugment list parsing functions commit 85cd6793818a3edd0a963bb4829a960ee6b0e022 Author: vnugent <public@vaughnnugent.com> Date: Mon Jul 15 18:58:06 2024 -0400 chore: Just some minor checks and adjustments commit abfb5761ee381b7e1e5342a5525ceca8c8fd81dd Author: vnugent <public@vaughnnugent.com> Date: Thu Jul 4 23:57:37 2024 -0400 analyzer pass commit 4a96dbb924f2b5bf80293e4054f221efe67151dd Author: vnugent <public@vaughnnugent.com> Date: Thu Jul 4 22:45:28 2024 -0400 package updates commit 38ad7d923fa8d9e463d4aaa8e35f021086a03f2d Author: vnugent <public@vaughnnugent.com> Date: Thu Jul 4 16:20:48 2024 -0400 mimalloc merge upstream upgrades commit 981ba286e4793de95bf65e6588313411344c4d53 Author: vnugent <public@vaughnnugent.com> Date: Thu Jul 4 16:04:03 2024 -0400 refactor: Refactor extensions with perf updates commit 6b8c67888731f7dd210acdb2b1160cdbdbe30d47 Author: vnugent <public@vaughnnugent.com> Date: Fri Jun 28 15:48:22 2024 -0400 refactor: Update service stack to reflect new loading patterns commit 12391e9a207b60b41a074600fc2373ad3eb1c3ab Author: vnugent <public@vaughnnugent.com> Date: Wed Jun 26 21:01:15 2024 -0400 feat(server): Server arch update, Memory struct access commit 92e182ceaf843f8d859d38faa8b2c0ff53207ff6 Author: vnugent <public@vaughnnugent.com> Date: Fri Jun 21 16:02:34 2024 -0400 feat: Multi transport listeners commit ee3620b8168a42c8e571e853c751ad5999a9b907 Author: vnugent <public@vaughnnugent.com> Date: Tue Jun 18 21:17:28 2024 -0400 feat: Add file path caching support commit ff0926be56fc6eafdce36411847d73bf4ce9f183 Author: vnugent <public@vaughnnugent.com> Date: Sun Jun 16 13:08:31 2024 -0400 feat: Allow multiple plugin loading directories commit 07ddf6738d32127926d07b1366e56d2a2308b53b Author: vnugent <public@vaughnnugent.com> Date: Sun Jun 16 01:12:07 2024 -0400 perf: Absolutely yuge perf boosts commit ff15c05a9c3e632c39f3889820fb7d889342b452 Author: vnugent <public@vaughnnugent.com> Date: Fri Jun 14 14:16:24 2024 -0400 fix: Improper request buffer property assignment commit 7d2987f1d4048c30808a85798e32c99747f6cfe3 Author: vnugent <public@vaughnnugent.com> Date: Thu Jun 13 21:57:34 2024 -0400 perf: Async pre-buffer to avoid sync buffer commit 75c1d0cbf9a5a7856c544671a45f1b4312ffe7ce Author: vnugent <public@vaughnnugent.com> Date: Tue Jun 11 22:11:45 2024 -0400 feat: Add a default site adapater and interceptors commit a7c739b7db9a17622cee751fe0e8a10e4b84b48b Author: vnugent <public@vaughnnugent.com> Date: Sun Jun 9 13:05:12 2024 -0400 chore: Package updated commit b4b506a4b6c7c1e90b5b0980e4cfe0460e7546a2 Author: vnugent <public@vaughnnugent.com> Date: Sat Jun 8 21:54:52 2024 -0400 some minor touchups commit 2160510fcc22a8574b0090fd91ca29072f45ab59 Author: vnugent <public@vaughnnugent.com> Date: Fri May 31 15:12:20 2024 -0400 refactor: Immutable tcp listeners commit 51cb4eb93e4f1b4c47d35b105e72af1fe771abcc Author: vnugent <public@vaughnnugent.com> Date: Thu May 30 17:31:16 2024 -0400 refactor: minor non-breaking changes to VNEncoding commit 768ddc1eb949266d693f96c67d734e881bd59374 Merge: 9a835fe 1b590c2 Author: vnugent <public@vaughnnugent.com> Date: Wed May 22 17:50:57 2024 -0400 Merge branch 'main' into develop commit 9a835fe12c9586ab8dd44d7c96fef4a2d6017e4b Author: vnugent <public@vaughnnugent.com> Date: Fri May 17 18:27:03 2024 -0400 chore: Update mimmaloc v2.1.6, update fPIC & cleanup commit 3b7004b88acfc7f7baa3a8857a5a2f7cf3dd560e Author: vnugent <public@vaughnnugent.com> Date: Fri May 17 16:03:28 2024 -0400 feat: Added ReadFileDataAsync function commit 9a964795757bf0da4dd7fcab15ad304f4ea3fdf1 Author: vnugent <public@vaughnnugent.com> Date: Wed May 15 21:57:39 2024 -0400 refactor: Harden some argon2 password hashing commit 4035c838c1508af0aa7e767a97431a692958ce1c Author: vnugent <public@vaughnnugent.com> Date: Sun May 12 16:55:32 2024 -0400 perf: Utils + http perf mods commit f4f0d4f74250257991c57bfae74c4852c7e1ae46 Author: vnugent <public@vaughnnugent.com> Date: Thu May 2 15:22:53 2024 -0400 feat: Buff middleware handlers | | Added implicit support for middleware post processing of files before the filehandler closes the connection. Also cleaned up some project file stuff commit f0b7dca107659df1d7d4631fdbd2aae9d716d053 Merge: 8c4a45e 107b058 Author: vnugent <public@vaughnnugent.com> Date: Sat Apr 20 12:24:05 2024 -0400 Merge branch 'main' into develop commit 8c4a45e384accf92b1b6d748530e8d46f7de40d6 Author: vnugent <public@vaughnnugent.com> Date: Sat Apr 20 11:10:30 2024 -0400 refactor: Overhaul C libraries and fix builds commit 42ff77080d10b0fc9fecbbc46141e8e23a1d066a Author: vnugent <public@vaughnnugent.com> Date: Sat Apr 20 00:45:57 2024 -0400 fix!: Middlware array, multiple cookie set, and cookie check commit 97e82b9d66f387f9e6d21d88ddc7a8ab8693149c Merge: 4ca5791 e07537a Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 2 13:34:22 2024 -0400 Merge branch 'main' into develop commit 4ca5791ed67b9834bdbd010206b30373e4705e9b Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 2 13:32:12 2024 -0400 fix: Missed ! on null pointer check commit 9b4036377c52200c6488c98180d69a0e63321f97 Author: vnugent <public@vaughnnugent.com> Date: Tue Apr 2 13:22:29 2024 -0400 fix: Fix _In_ macro for compression public api commit 53a7b4b5c5b67b4a4e06e1d9098cac4bcd6afd7c Merge: 448a93b 21130c8 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 17:01:15 2024 -0400 Merge branch 'main' into develop commit 448a93bb1d18d032087afe2476ffccb98634a54c Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 16:56:51 2024 -0400 ci: fix third-party dir cleanup commit 9afed1427472da1ea13079f98dbe27339e55ee7d Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 31 16:43:15 2024 -0400 perf: Deprecate unsafememoryhandle span extensions commit 3ff90da4f02af47ea6d233fdd4445337ebe36452 Author: vnugent <public@vaughnnugent.com> Date: Sat Mar 30 21:36:18 2024 -0400 refactor: Updates, advanced tracing, http optimizations commit 8d6b79b5ae309b36f265ba81529bcef8bfcd7414 Merge: 6c1667b 5585915 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 24 21:01:31 2024 -0400 Merge branch 'main' into develop commit 6c1667be23597513537f8190e2f55d65eb9b7c7a Author: vnugent <public@vaughnnugent.com> Date: Fri Mar 22 12:01:53 2024 -0400 refactor: Overhauled native library loading and lazy init commit ebf688f2f974295beabf7b5def7e6f6f150551d0 Author: vnugent <public@vaughnnugent.com> Date: Wed Mar 20 22:16:17 2024 -0400 refactor: Update compression header files and macros + Ci build commit 9c7b564911080ccd5cbbb9851a0757b05e1e9047 Author: vnugent <public@vaughnnugent.com> Date: Tue Mar 19 21:54:49 2024 -0400 refactor: JWK overhaul & add length getter to FileUpload commit 6d8c3444e09561e5957491b3cc1ae858e0abdd14 Author: vnugent <public@vaughnnugent.com> Date: Mon Mar 18 16:13:20 2024 -0400 feat: Add FNV1a software checksum and basic correction tests commit 00d182088cecefc08ca80b1faee9bed3f215f40b Author: vnugent <public@vaughnnugent.com> Date: Fri Mar 15 01:05:27 2024 -0400 chore: #6 Use utils filewatcher instead of built-in commit d513c10d9895c6693519ef1d459c6a5a76929436 Author: vnugent <public@vaughnnugent.com> Date: Sun Mar 10 21:58:14 2024 -0400 source tree project location updated
Diffstat (limited to 'lib/Plugins.Essentials.ServiceStack/src/Construction')
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs68
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/HttpTransportMapping.cs37
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IDomainBuilder.cs24
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/IServiceGroupBuilder.cs60
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/ServiceBuilder.cs81
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs322
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConfiguration.cs33
-rw-r--r--lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConstructionExtensions.cs107
8 files changed, 487 insertions, 245 deletions
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
index 3ae2183..34c68bf 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpServiceStackBuilder.cs
@@ -28,16 +28,18 @@ using System.Collections.Generic;
using VNLib.Net.Http;
using VNLib.Plugins.Runtime;
-
+using VNLib.Plugins.Essentials.ServiceStack.Plugins;
namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
+
/// <summary>
/// A data structure used to build/create a <see cref="HttpServiceStack"/>
/// around a <see cref="ServiceDomain"/>
/// </summary>
public sealed class HttpServiceStackBuilder
{
+ private readonly ServiceBuilder _serviceBuilder = new();
/// <summary>
/// Initializes a new <see cref="HttpServiceStack"/> that will
@@ -47,8 +49,10 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
public HttpServiceStackBuilder()
{ }
- private Action<ICollection<IServiceHost>>? _hostBuilder;
- private Func<ServiceGroup, IHttpServer>? _getServers;
+ internal ServiceBuilder ServiceBuilder => _serviceBuilder;
+
+ private Action<ServiceBuilder>? _hostBuilder;
+ private Func<IReadOnlyCollection<ServiceGroup>, IHttpServer[]>? _getServers;
private Func<IPluginStack>? _getPlugins;
private IManualPlugin[]? manualPlugins;
private bool loadConcurrently;
@@ -59,7 +63,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// </summary>
/// <param name="hostBuilder">The callback method to build virtual hosts</param>
/// <returns>The current instance for chaining</returns>
- public HttpServiceStackBuilder WithDomain(Action<ICollection<IServiceHost>> hostBuilder)
+ public HttpServiceStackBuilder WithDomain(Action<ServiceBuilder> hostBuilder)
{
_hostBuilder = hostBuilder;
return this;
@@ -70,7 +74,7 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// </summary>
/// <param name="getServers">A callback method that gets the http server implementation for the service group</param>
/// <returns>The current instance for chaining</returns>
- public HttpServiceStackBuilder WithHttp(Func<ServiceGroup, IHttpServer> getServers)
+ public HttpServiceStackBuilder WithHttp(Func<IReadOnlyCollection<ServiceGroup>, IHttpServer[]> getServers)
{
_getServers = getServers;
return this;
@@ -90,24 +94,34 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// <summary>
/// Configures the stack to use the built-in http server implementation
/// </summary>
- /// <param name="transport">The transport builder callback function</param>
+ /// <param name="getTransports">The transport builder callback function</param>
/// <param name="config">The http configuration structure used to initalize servers</param>
/// <returns>The current instance for chaining</returns>
- public HttpServiceStackBuilder WithBuiltInHttp(Func<ServiceGroup, ITransportProvider> transport, HttpConfig config)
- {
- return WithBuiltInHttp(transport, sg => config);
- }
+ public HttpServiceStackBuilder WithBuiltInHttp(Func<IReadOnlyCollection<ServiceGroup>, HttpTransportMapping[]> getTransports, HttpConfig config)
+ => WithBuiltInHttp(getTransports, _ => config);
/// <summary>
/// Configures the stack to use the built-in http server implementation
/// </summary>
- /// <param name="transport">The transport builder callback function</param>
+ /// <param name="getBindings">A callback function that gets transport bindings for servie groups</param>
/// <param name="configCallback">The http configuration builder callback method</param>
/// <returns>The current instance for chaining</returns>
- public HttpServiceStackBuilder WithBuiltInHttp(Func<ServiceGroup, ITransportProvider> transport, Func<ServiceGroup, HttpConfig> configCallback)
- {
- return WithHttp(sg => new HttpServer(configCallback(sg), transport(sg), sg.Hosts.Select(static p => p.Processor)));
- }
+ public HttpServiceStackBuilder WithBuiltInHttp(
+ Func<IReadOnlyCollection<ServiceGroup>, HttpTransportMapping[]> getBindings,
+ Func<IReadOnlyCollection<ServiceGroup>, HttpConfig> configCallback
+ ) => WithHttp((sgs) => {
+
+ HttpTransportBinding[] vhBindings = getBindings(sgs)
+ .Select(static s =>
+ {
+ IEnumerable<IWebRoot> procs = s.Hosts.Select(static s => s.Processor);
+ return new HttpTransportBinding(s.Transport, procs);
+ })
+ .ToArray();
+
+ // A single built-in http server can service an entire domain
+ return [ new HttpServer(configCallback(sgs), vhBindings) ];
+ });
/// <summary>
/// Adds a collection of manual plugin instances to the stack. Every call
@@ -139,27 +153,27 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// <exception cref="ArgumentNullException"></exception>
public HttpServiceStack Build()
{
- _ = _hostBuilder ?? throw new ArgumentNullException("WithDomainBuilder", "You have not configured a service domain configuration callback");
_ = _getServers ?? throw new ArgumentNullException("WithHttp", "You have not configured a IHttpServer configuration callback");
+ //Host builder callback is optional
+ _hostBuilder?.Invoke(ServiceBuilder);
+
//Inint the service domain
ServiceDomain sd = new();
- if (!sd.BuildDomain(_hostBuilder))
- {
- throw new ArgumentException("Failed to configure the service domain, you must expose at least one service host");
- }
+ sd.BuildDomain(_serviceBuilder);
- LinkedList<IHttpServer> servers = new();
+ //Get http servers from the user callback for the service domain, let the caller decide how to route them
+ IHttpServer[] servers = _getServers.Invoke(sd.ServiceGroups);
- //enumerate hosts groups
- foreach (ServiceGroup hosts in sd.ServiceGroups)
+ if (servers.Length == 0)
{
- //Create new server
- IHttpServer server = _getServers.Invoke(hosts);
+ throw new ArgumentException("No service hosts were configured. You must define at least one virtual host for the domain");
+ }
- //Add server to internal list
- servers.AddLast(server);
+ if(servers.Any(servers => servers is null))
+ {
+ throw new ArgumentException("One or more servers were not initialized correctly. Check the server configuration callback");
}
return new(servers, sd, GetPluginStack(sd));
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpTransportMapping.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpTransportMapping.cs
new file mode 100644
index 0000000..c5fae41
--- /dev/null
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/HttpTransportMapping.cs
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.ServiceStack
+* File: HttpTransportMapping.cs
+*
+* HttpTransportMapping.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.Collections.Generic;
+
+using VNLib.Net.Http;
+
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
+{
+ /// <summary>
+ /// Represents a mapping of service hosts to a transport provider
+ /// </summary>
+ /// <param name="Hosts">The collection of service hosts to map to transports</param>
+ /// <param name="Transport">The transport that will provide networking to the host collection</param>
+ public record class HttpTransportMapping(IEnumerable<IServiceHost> Hosts, ITransportProvider Transport);
+}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/IDomainBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IDomainBuilder.cs
index 19d2a96..9bccf54 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/IDomainBuilder.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IDomainBuilder.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.ServiceStack
@@ -22,9 +22,7 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
-using System.IO;
-
-using VNLib.Utils.Logging;
+using System;
namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
@@ -34,19 +32,17 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
public interface IDomainBuilder
{
/// <summary>
- /// Adds a single virtual host to the domain that must be configured.
+ /// Allows for defining a new virtual host for the domain by manually configuring it.
/// </summary>
- /// <param name="rootDirectory">The service root directory</param>
- /// <param name="hooks">The virtual host event hook handler</param>
- /// <param name="Logger">The log provider</param>
- /// <returns>The <see cref="IVirtualHostBuilder"/> instance</returns>
- IVirtualHostBuilder WithVirtualHost(DirectoryInfo rootDirectory, IVirtualHostHooks hooks, ILogProvider Logger);
+ /// <param name="builder">A callback function that passes the new host builder</param>
+ /// <returns>The current instance</returns>
+ IDomainBuilder WithServiceGroups(Action<IServiceGroupBuilder> builder);
/// <summary>
- /// Adds a single pre-configured virtual host to the domain
+ /// Adds a collection of hosts to the domain
/// </summary>
- /// <param name="config">The pre-configured virtual host configuration</param>
- /// <returns>The current instance</returns>
- IDomainBuilder WithVirtualHost(VirtualHostConfiguration config);
+ /// <param name="host"></param>
+ /// <returns></returns>
+ IDomainBuilder WithHosts(IServiceHost[] host);
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/IServiceGroupBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/IServiceGroupBuilder.cs
new file mode 100644
index 0000000..1ffeb5c
--- /dev/null
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/IServiceGroupBuilder.cs
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.ServiceStack
+* File: IServiceGroupBuilder.cs
+*
+* IServiceGroupBuilder.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;
+using System.IO;
+
+using VNLib.Utils.Logging;
+
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
+{
+ /// <summary>
+ /// Allows for defining service groups for the service stack to manage
+ /// </summary>
+ public interface IServiceGroupBuilder
+ {
+ /// <summary>
+ /// Adds a single virtual host to the domain that must be configured.
+ /// </summary>
+ /// <param name="rootDirectory">The service root directory</param>
+ /// <param name="hooks">The virtual host event hook handler</param>
+ /// <param name="Logger">The log provider</param>
+ /// <returns>The <see cref="IVirtualHostBuilder"/> instance</returns>
+ IVirtualHostBuilder WithVirtualHost(DirectoryInfo rootDirectory, IVirtualHostHooks hooks, ILogProvider Logger);
+
+ /// <summary>
+ /// Allows for defining a new virtual host for the domain by manually configuring it.
+ /// </summary>
+ /// <param name="builder">A callback function that passes the new host builder</param>
+ /// <returns>The current instance</returns>
+ IServiceGroupBuilder WithVirtualHost(Action<IVirtualHostBuilder> builder);
+
+ /// <summary>
+ /// Adds a single pre-configured virtual host to the domain
+ /// </summary>
+ /// <param name="config">The pre-configured virtual host configuration</param>
+ /// <returns>The current instance</returns>
+ IServiceGroupBuilder WithVirtualHost(VirtualHostConfiguration config, object? userState);
+ }
+}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/ServiceBuilder.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/ServiceBuilder.cs
new file mode 100644
index 0000000..4817ba0
--- /dev/null
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/ServiceBuilder.cs
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.ServiceStack
+* File: ServiceBuilder.cs
+*
+* ServiceBuilder.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;
+using System.Linq;
+using System.Collections.Generic;
+
+
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
+{
+ /// <summary>
+ /// A data structure used to build groupings of service hosts used
+ /// to configure http servers.
+ /// </summary>
+ public sealed class ServiceBuilder
+ {
+ private readonly List<Action<ICollection<IServiceHost>>> _callbacks = [];
+
+ /// <summary>
+ /// Adds callback function that will add a collection of service hosts
+ /// and passes a state paramter to the callback
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="state">The optional state parameter</param>
+ /// <param name="host">The host collection to add new service hosts to</param>
+ /// <returns>The current instance for chaining</returns>
+ public ServiceBuilder AddHostCollection<T>(T state, Action<ICollection<IServiceHost>, T> host)
+ => AddHostCollection(col => host.Invoke(col, state));
+
+ /// <summary>
+ /// Adds a callback function that will add a collection of service hosts
+ /// </summary>
+ /// <param name="host">The callback function to return the collection of hosts</param>
+ /// <returns>The current instance for chaining</returns>
+ public ServiceBuilder AddHostCollection(Action<ICollection<IServiceHost>> host)
+ {
+ ArgumentNullException.ThrowIfNull(host);
+
+ _callbacks.Add(host);
+ return this;
+ }
+
+ /// <summary>
+ /// Builds the <see cref="ServiceGroup"/> collection from the user
+ /// defined service host arrays
+ /// </summary>
+ /// <returns>The numeration that builds the service groups</returns>
+ internal IEnumerable<ServiceGroup> BuildGroups()
+ {
+ return _callbacks.Select(static cb =>
+ {
+ LinkedList<IServiceHost> hosts = new();
+
+ cb.Invoke(hosts);
+
+ return new ServiceGroup(hosts);
+ });
+ }
+ }
+}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
index 4195553..62b5070 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/SsBuilderExtensions.cs
@@ -29,12 +29,12 @@ 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.Middleware;
+using VNLib.Plugins.Essentials.ServiceStack.Plugins;
namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
@@ -46,14 +46,6 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
{
/// <summary>
- /// Creates a new <see cref="IDomainBuilder"/> instance to define your
- /// virtual hosts using a built-in event processor type
- /// </summary>
- /// <param name="stack"></param>
- /// <returns>The <see cref="IDomainBuilder"/> used to define your service domain</returns>
- public static IDomainBuilder WithDomain(this HttpServiceStackBuilder stack) => WithDomain(stack, vhc => FromVirtualHostConfig(vhc.Clone()));
-
- /// <summary>
/// Creates a new <see cref="IDomainBuilder"/> instance to define your
/// virtual hosts with the supplied callback method
/// </summary>
@@ -62,167 +54,144 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// <returns>The service stack builder instance</returns>
public static HttpServiceStackBuilder WithDomain(this HttpServiceStackBuilder stack, Action<IDomainBuilder> domainBuilder)
{
- domainBuilder(stack.WithDomain());
+ domainBuilder(WithDomain(stack));
return stack;
}
/// <summary>
- /// Creates a new <see cref="IDomainBuilder"/> with your custom <see cref="EventProcessor"/> type
- /// that will be wrapped for runtime processing.
+ /// Creates a new <see cref="IDomainBuilder"/> instance to define your
+ /// virtual hosts using a built-in event processor type
/// </summary>
- /// <typeparam name="T"></typeparam>
/// <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, IRuntimeServiceInjection
- {
- List<VirtualHostConfiguration> configs = new();
- DomainBuilder domains = new(configs, stack);
-
- //Add callback to capture this collection of configs when built
- stack.AddHosts(() => configs.Select(c => new CustomServiceHost<T>(c.Clone(), callback(c))).ToArray());
-
- return domains;
- }
-
- /// <summary>
- /// Adds a single <see cref="IHttpMiddleware"/> instance to the virtual host
- /// </summary>
- /// <param name="vhBuilder"></param>
- /// <param name="middleware">The middleware instance to add</param>
- /// <returns></returns>
- public static IVirtualHostBuilder WithMiddleware(this IVirtualHostBuilder vhBuilder, IHttpMiddleware middleware)
- {
- vhBuilder.WithOption(c => c.CustomMiddleware.Add(middleware));
- return vhBuilder;
- }
-
- /// <summary>
- /// Adds multiple <see cref="IHttpMiddleware"/> instances to the virtual host
- /// </summary>
- /// <param name="vhBuilder"></param>
- /// <param name="middleware">The array of middleware instances to add to the collection</param>
- /// <returns></returns>
- public static IVirtualHostBuilder WithMiddleware(this IVirtualHostBuilder vhBuilder, params IHttpMiddleware[] middleware)
- {
- vhBuilder.WithOption(c => Array.ForEach(middleware, m => c.CustomMiddleware.Add(m)));
- return vhBuilder;
- }
-
-
- public static IVirtualHostBuilder WithLogger(this IVirtualHostBuilder vhBuilder, ILogProvider logger)
- {
- vhBuilder.WithOption(c => c.LogProvider = logger);
- return vhBuilder;
- }
-
- public static IVirtualHostBuilder WithEndpoint(this IVirtualHostBuilder vhBuilder, IPEndPoint endpoint)
- {
- vhBuilder.WithOption(c => c.TransportEndpoint = endpoint);
- return vhBuilder;
- }
-
- public static IVirtualHostBuilder WithTlsCertificate(this IVirtualHostBuilder vhBuilder, X509Certificate? cert)
- {
- vhBuilder.WithOption(c => c.Certificate = cert);
- return vhBuilder;
- }
+ /// <returns>The <see cref="IDomainBuilder"/> used to define your service domain</returns>
+ public static IDomainBuilder WithDomain(this HttpServiceStackBuilder stack)
+ => new DomainBuilder(stack.ServiceBuilder);
- public static IVirtualHostBuilder WithHostname(this IVirtualHostBuilder virtualHostBuilder, string hostname)
- {
- virtualHostBuilder.WithOption(c => c.Hostname = hostname);
- return virtualHostBuilder;
- }
- public static IVirtualHostBuilder WithDefaultFiles(this IVirtualHostBuilder vhBuidler, params string[] defaultFiles)
+ private sealed class DomainBuilder(ServiceBuilder svcBuilder) : IDomainBuilder
{
- return vhBuidler.WithDefaultFiles((IReadOnlyCollection<string>)defaultFiles);
- }
-
- public static IVirtualHostBuilder WithDefaultFiles(this IVirtualHostBuilder vhBuidler, IReadOnlyCollection<string> defaultFiles)
- {
- vhBuidler.WithOption(c => c.DefaultFiles = defaultFiles);
- return vhBuidler;
- }
+ ///<inheritdoc/>
+ public IDomainBuilder WithServiceGroups(Action<IServiceGroupBuilder> builder)
+ {
+ svcBuilder.AddHostCollection((col) =>
+ {
+ SvGroupBuilder group = new();
- public static IVirtualHostBuilder WithExcludedExtensions(this IVirtualHostBuilder vhBuilder, params string[] excludedExtensions)
- {
- return vhBuilder.WithExcludedExtensions(new HashSet<string>(excludedExtensions));
- }
+ builder(group);
- public static IVirtualHostBuilder WithExcludedExtensions(this IVirtualHostBuilder vhBuilder, IReadOnlySet<string> excludedExtensions)
- {
- vhBuilder.WithOption(c => c.ExcludedExtensions = excludedExtensions);
- return vhBuilder;
- }
+ group.Configs
+ .SelectMany(static vc => FromVirtualHostConfig(vc)
+ .Select(vh => new CustomServiceHost<BasicVirtualHost>(vh, vc.UserState)
+ ))
+ .ForEach(col.Add); //Force enumeration
+ });
- public static IVirtualHostBuilder WithAllowedAttributes(this IVirtualHostBuilder vhBuilder, FileAttributes attributes)
- {
- vhBuilder.WithOption(c => c.AllowedAttributes = attributes);
- return vhBuilder;
- }
-
- public static IVirtualHostBuilder WithDisallowedAttributes(this IVirtualHostBuilder vhBuilder, FileAttributes attributes)
- {
- vhBuilder.WithOption(c => c.DissallowedAttributes = attributes);
- return vhBuilder;
- }
+ return this;
+ }
- public static IVirtualHostBuilder WithDownstreamServers(this IVirtualHostBuilder vhBuilder, IReadOnlySet<IPAddress> addresses)
- {
- vhBuilder.WithOption(c => c.DownStreamServers = addresses);
- return vhBuilder;
- }
+ ///<inheritdoc/>
+ public IDomainBuilder WithHosts(IServiceHost[] hosts)
+ {
+ svcBuilder.AddHostCollection(col => Array.ForEach(hosts, col.Add));
+ return this;
+ }
- /// <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 IEnumerable<BasicVirtualHost> FromVirtualHostConfig(VirtualHostConfiguration configuration)
+ {
+ /*
+ * Configurations are allowed to define multiple hostnames for a single
+ * virtual host.
+ */
- 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.
- */
+ return configuration.Hostnames
+ .Select<string, BasicVirtualHost>((string hostname) =>
+ {
+ /*
+ * 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(
+ Directory: configuration.RootDir.FullName,
+ Hostname: hostname,
+ Log: configuration.LogProvider,
+ Options: configuration
+ )
+ {
+ AllowedAttributes = configuration.AllowedAttributes,
+ DissallowedAttributes = configuration.DissallowedAttributes,
+ DefaultFiles = configuration.DefaultFiles,
+ ExecutionTimeout = configuration.ExecutionTimeout,
+ FilePathCacheMaxAge = configuration.FilePathCacheMaxAge,
+
+ //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);
+ });
+ }
- EventProcessorConfig conf = new(
- configuration.RootDir.FullName,
- configuration.Hostname,
- configuration.LogProvider,
- configuration)
+ private sealed record class SvGroupBuilder : IServiceGroupBuilder
{
- AllowedAttributes = configuration.AllowedAttributes,
- DissallowedAttributes = configuration.DissallowedAttributes,
- DefaultFiles = configuration.DefaultFiles,
- ExecutionTimeout = configuration.ExecutionTimeout,
+ internal readonly List<VirtualHostConfiguration> Configs = new();
- //Frozen sets are required for the event processor, for performance reasons
- DownStreamServers = configuration.DownStreamServers.ToFrozenSet(),
- ExcludedExtensions = configuration.ExcludedExtensions.ToFrozenSet(),
- };
+ ///<inheritdoc/>
+ public IVirtualHostBuilder WithVirtualHost(DirectoryInfo rootDirectory, IVirtualHostHooks hooks, ILogProvider logger)
+ {
+ //Create new config instance and add to list
+ VirtualHostConfiguration config = new()
+ {
+ EventHooks = hooks,
+ RootDir = rootDirectory,
+ LogProvider = logger
+ };
+ Configs.Add(config);
+ return new VHostBuilder(config);
+ }
- //Add all pre-configured middleware to the chain
- configuration.CustomMiddleware.ForEach(conf.MiddlewareChain.Add);
+ ///<inheritdoc/>
+ public IServiceGroupBuilder WithVirtualHost(Action<IVirtualHostBuilder> builder)
+ {
+ //Create new config instance and add to list
+ VirtualHostConfiguration config = new()
+ {
+ RootDir = null!,
+ LogProvider = null!
+ };
+
+ //Pass the builder to the callback
+ builder(new VHostBuilder(config));
+
+ return WithVirtualHost(config, null);
+ }
- return new(configuration.EventHooks, conf);
- }
+ ///<inheritdoc/>
+ public IServiceGroupBuilder WithVirtualHost(VirtualHostConfiguration config, object? userState)
+ {
+ config.UserState = userState;
+ Configs.Add(config);
+ return this;
+ }
+ private sealed record class VHostBuilder(VirtualHostConfiguration Config) : IVirtualHostBuilder
+ {
+ ///<inheritdoc/>
+ public IVirtualHostBuilder WithOption(Action<VirtualHostConfiguration> configCallback)
+ {
+ configCallback(Config);
+ return this;
+ }
+ }
+ }
+ }
- 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)
{
@@ -232,48 +201,21 @@ 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)
- {
- //Create new config instance and add to list
- VirtualHostConfiguration config = new()
- {
- EventHooks = hooks,
- RootDir = rootDirectory,
- LogProvider = logger
- };
- Configs.Add(config);
- return new VHostBuilder(config);
- }
- ///<inheritdoc/>
- public IDomainBuilder WithVirtualHost(VirtualHostConfiguration config)
- {
- Configs.Add(config);
- return this;
- }
+ /*
+ * The goal of this class is to added the extra service injection
+ * and manage the IWebRoot instance that will be served by a
+ * webserver
+ */
- private sealed record class VHostBuilder(VirtualHostConfiguration Config) : IVirtualHostBuilder
- {
- ///<inheritdoc/>
- public IVirtualHostBuilder WithOption(Action<VirtualHostConfiguration> configCallback)
- {
- configCallback(Config);
- return this;
- }
- }
- }
-
- private sealed class CustomServiceHost<T>(IHostTransportInfo Config, T Instance) : IServiceHost
+ private sealed class CustomServiceHost<T>(T Instance, object? userState) : IServiceHost
where T : EventProcessor, IRuntimeServiceInjection
{
///<inheritdoc/>
public IWebRoot Processor => Instance;
///<inheritdoc/>
- public IHostTransportInfo TransportInfo => Config;
+ public object? UserState => userState;
///<inheritdoc/>
void IServiceHost.OnRuntimeServiceAttach(IManagedPlugin plugin, IEndpoint[] endpoints)
@@ -300,10 +242,12 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
plugin.OnPluginServiceEvent<IEnumerable<IHttpMiddleware>>(p => p.ForEach(Instance.Options.MiddlewareChain.Remove));
plugin.OnPluginServiceEvent<IHttpMiddleware[]>(p => p.ForEach(Instance.Options.MiddlewareChain.Remove));
}
+
}
- private sealed class BasicVirtualHost(IVirtualHostHooks Hooks, EventProcessorConfig config) : EventProcessor(config), IRuntimeServiceInjection
+ private sealed class BasicVirtualHost(IVirtualHostHooks Hooks, EventProcessorConfig config)
+ : EventProcessor(config), IRuntimeServiceInjection
{
/*
* Runtime service injection can be tricky, at least in my architecture. If all we have
@@ -315,16 +259,20 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
private readonly ConditionalWeakTable<IServiceProvider, Type[]> _exposedTypes = new();
///<inheritdoc/>
- public override bool ErrorHandler(HttpStatusCode errorCode, IHttpEvent entity) => Hooks.ErrorHandler(errorCode, entity);
+ public override bool ErrorHandler(HttpStatusCode errorCode, IHttpEvent entity)
+ => Hooks.ErrorHandler(errorCode, entity);
///<inheritdoc/>
- public override void PreProcessEntity(HttpEntity entity, out FileProcessArgs preProcArgs) => Hooks.PreProcessEntityAsync(entity, out preProcArgs);
+ public override void PreProcessEntity(HttpEntity entity, out FileProcessArgs preProcArgs)
+ => Hooks.PreProcessEntityAsync(entity, out preProcArgs);
///<inheritdoc/>
- public override void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine) => Hooks.PostProcessFile(entity, ref chosenRoutine);
+ public override void PostProcessEntity(HttpEntity entity, ref FileProcessArgs chosenRoutine)
+ => Hooks.PostProcessFile(entity, ref chosenRoutine);
///<inheritdoc/>
- public override string TranslateResourcePath(string requestPath) => Hooks.TranslateResourcePath(requestPath);
+ public override string TranslateResourcePath(string requestPath)
+ => Hooks.TranslateResourcePath(requestPath);
///<inheritdoc/>
public void AddServices(IServiceProvider services)
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConfiguration.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConfiguration.cs
index 97ad905..20e346e 100644
--- a/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConfiguration.cs
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConfiguration.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2023 Vaughn Nugent
+* Copyright (c) 2024 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Plugins.Essentials.ServiceStack
@@ -26,7 +26,6 @@ using System;
using System.IO;
using System.Net;
using System.Collections.Generic;
-using System.Security.Cryptography.X509Certificates;
using VNLib.Utils.Logging;
using VNLib.Plugins.Essentials.Middleware;
@@ -36,34 +35,28 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// <summary>
/// A virtual host configuration container
/// </summary>
- public class VirtualHostConfiguration : IHostTransportInfo, IEpProcessingOptions
+ public class VirtualHostConfiguration : IEpProcessingOptions
{
/// <summary>
- /// The directory that this virtual host will serve files from
- /// </summary>
- public DirectoryInfo RootDir { get; set; } = null!;
-
- /// <summary>
- /// The hostname, or domain name, that this virtual host will respond to
- /// <para>Default: *</para>
+ /// Optional user state object
/// </summary>
- public string Hostname { get; set; } = "*";
+ internal object? UserState { get; set; }
/// <summary>
- /// The transport endpoint that this virtual host will listen on
- /// <para>Default: 0.0.0.0:80</para>
+ /// The directory that this virtual host will serve files from
/// </summary>
- public IPEndPoint TransportEndpoint { get; set; } = new IPEndPoint(IPAddress.Any, 80);
+ public required DirectoryInfo RootDir { get; set; }
/// <summary>
- /// An optional certificate to use for TLS connections
+ /// The hostname, or domain name, that this virtual host will respond to
+ /// <para>Default: *</para>
/// </summary>
- public X509Certificate? Certificate { get; set; }
+ public string[] Hostnames { get; set; } = [ "*" ];
/// <summary>
/// A log provider to use for this virtual host
/// </summary>
- public ILogProvider LogProvider { get; set; } = null!;
+ public required ILogProvider LogProvider { get; set; }
/// <summary>
/// The name of a default file to search for within a directory if no file is specified (index.html).
@@ -112,6 +105,12 @@ namespace VNLib.Plugins.Essentials.ServiceStack.Construction
/// </summary>
public ICollection<IHttpMiddleware> CustomMiddleware { get; } = new List<IHttpMiddleware>();
+ /// <summary>
+ /// A <see cref="TimeSpan"/> for how long a file path may be cached before being revalidated. Setting to
+ /// zero will disable path caching
+ /// </summary>
+ public TimeSpan FilePathCacheMaxAge { get; set; } = TimeSpan.Zero;
+
internal VirtualHostConfiguration Clone() => (VirtualHostConfiguration)MemberwiseClone();
}
}
diff --git a/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConstructionExtensions.cs b/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConstructionExtensions.cs
new file mode 100644
index 0000000..acf1b53
--- /dev/null
+++ b/lib/Plugins.Essentials.ServiceStack/src/Construction/VirtualHostConstructionExtensions.cs
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2024 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Plugins.Essentials.ServiceStack
+* File: SsBuilderExtensions.cs
+*
+* SsBuilderExtensions.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;
+using System.IO;
+using System.Net;
+using System.Collections.Generic;
+
+using VNLib.Utils.Logging;
+using VNLib.Plugins.Essentials.Middleware;
+
+namespace VNLib.Plugins.Essentials.ServiceStack.Construction
+{
+ public static class VirtualHostConstructionExtensions
+ {
+ /// <summary>
+ /// Adds a single <see cref="IHttpMiddleware"/> instance to the virtual host
+ /// </summary>
+ /// <param name="vhBuilder"></param>
+ /// <param name="middleware">The middleware instance to add</param>
+ /// <returns></returns>
+ public static IVirtualHostBuilder WithMiddleware(this IVirtualHostBuilder vhBuilder, IHttpMiddleware middleware)
+ => vhBuilder.WithOption(c => c.CustomMiddleware.Add(middleware));
+
+ /// <summary>
+ /// Adds multiple <see cref="IHttpMiddleware"/> instances to the virtual host
+ /// </summary>
+ /// <param name="vhBuilder"></param>
+ /// <param name="middleware">The array of middleware instances to add to the collection</param>
+ /// <returns></returns>
+ public static IVirtualHostBuilder WithMiddleware(this IVirtualHostBuilder vhBuilder, params IHttpMiddleware[] middleware)
+ => vhBuilder.WithOption(c => Array.ForEach(middleware, m => c.CustomMiddleware.Add(m)));
+
+
+ /// <summary>
+ /// Takes a callback to allow you to inject middelware applications into
+ /// your virtual host
+ /// </summary>
+ /// <param name="vhBuilder"></param>
+ /// <param name="middleware">The array of middleware instances to add to the collection</param>
+ /// <returns></returns>
+ public static IVirtualHostBuilder WithMiddleware(this IVirtualHostBuilder vhBuilder, Action<ICollection<IHttpMiddleware>> middleware)
+ => vhBuilder.WithOption(c => middleware.Invoke(c.CustomMiddleware));
+
+ public static IVirtualHostBuilder WithLogger(this IVirtualHostBuilder vhBuilder, ILogProvider logger)
+ => vhBuilder.WithOption(c => c.LogProvider = logger);
+
+ public static IVirtualHostBuilder WithHostnames(this IVirtualHostBuilder virtualHostBuilder, string[] hostnames)
+ => virtualHostBuilder.WithOption(c => c.Hostnames = hostnames);
+
+ public static IVirtualHostBuilder WithDefaultFiles(this IVirtualHostBuilder vhBuidler, params string[] defaultFiles)
+ => vhBuidler.WithDefaultFiles((IReadOnlyCollection<string>)defaultFiles);
+
+ public static IVirtualHostBuilder WithDefaultFiles(this IVirtualHostBuilder vhBuidler, IReadOnlyCollection<string> defaultFiles)
+ => vhBuidler.WithOption(c => c.DefaultFiles = defaultFiles);
+
+ public static IVirtualHostBuilder WithExcludedExtensions(this IVirtualHostBuilder vhBuilder, params string[] excludedExtensions)
+ => vhBuilder.WithExcludedExtensions(new HashSet<string>(excludedExtensions));
+
+ public static IVirtualHostBuilder WithExcludedExtensions(this IVirtualHostBuilder vhBuilder, IReadOnlySet<string> excludedExtensions)
+ => vhBuilder.WithOption(c => c.ExcludedExtensions = excludedExtensions);
+
+ public static IVirtualHostBuilder WithAllowedAttributes(this IVirtualHostBuilder vhBuilder, FileAttributes attributes)
+ => vhBuilder.WithOption(c => c.AllowedAttributes = attributes);
+
+ public static IVirtualHostBuilder WithDisallowedAttributes(this IVirtualHostBuilder vhBuilder, FileAttributes attributes)
+ => vhBuilder.WithOption(c => c.DissallowedAttributes = attributes);
+
+ public static IVirtualHostBuilder WithDownstreamServers(this IVirtualHostBuilder vhBuilder, IReadOnlySet<IPAddress> addresses)
+ => vhBuilder.WithOption(c => c.DownStreamServers = addresses);
+
+ public static IVirtualHostBuilder WithFilePathCache(this IVirtualHostBuilder vhBuilder, TimeSpan maxAge = default)
+ => vhBuilder.WithOption(c => c.FilePathCacheMaxAge = maxAge);
+
+ /// <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));
+ }
+}