diff --git a/API/Protocol/ContentType.cs b/API/Protocol/ContentType.cs index 65e134fa..c05550bc 100644 --- a/API/Protocol/ContentType.cs +++ b/API/Protocol/ContentType.cs @@ -23,6 +23,16 @@ public enum ContentType /// TextCss, + /// + /// A markdown file. + /// + TextMarkdown, + + /// + /// A scriban file. + /// + TextScriban, + /// /// A JavaScript source file. /// @@ -245,6 +255,7 @@ public class FlexibleContentType { { ContentType.TextHtml, "text/html" }, { ContentType.TextCss, "text/css" }, + { ContentType.TextMarkdown, "text/markdown" }, { ContentType.ApplicationJavaScript, "application/javascript" }, { ContentType.ImageIcon, "image/x-icon" }, { ContentType.ImageGif, "image/gif" }, diff --git a/Modules/AutoLayout/GenHTTP.Modules.AutoLayout.csproj b/Modules/AutoLayout/GenHTTP.Modules.AutoLayout.csproj index 2043d2e7..06ddaeff 100644 --- a/Modules/AutoLayout/GenHTTP.Modules.AutoLayout.csproj +++ b/Modules/AutoLayout/GenHTTP.Modules.AutoLayout.csproj @@ -45,7 +45,11 @@ + + + + diff --git a/Modules/AutoLayout/IResourceHandlerProvider.cs b/Modules/AutoLayout/IResourceHandlerProvider.cs new file mode 100644 index 00000000..76e4abe1 --- /dev/null +++ b/Modules/AutoLayout/IResourceHandlerProvider.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; +using GenHTTP.Api.Content; +using GenHTTP.Api.Content.IO; + +namespace GenHTTP.Modules.AutoLayout +{ + + public interface IResourceHandlerProvider + { + + public bool Supports(IResource resource); + + ValueTask GetHandlerAsync(IResource resource); + + } + +} diff --git a/Modules/AutoLayout/Provider/DownloadProvider.cs b/Modules/AutoLayout/Provider/DownloadProvider.cs new file mode 100644 index 00000000..9a206f13 --- /dev/null +++ b/Modules/AutoLayout/Provider/DownloadProvider.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using GenHTTP.Api.Content; +using GenHTTP.Api.Content.IO; +using GenHTTP.Modules.IO; + +namespace GenHTTP.Modules.AutoLayout.Provider +{ + + public class DownloadProvider : IResourceHandlerProvider + { + + public bool Supports(IResource resource) => true; + + public ValueTask GetHandlerAsync(IResource resource) => new(Content.From(resource)); + + } + +} diff --git a/Modules/AutoLayout/Provider/MarkdownProvider.cs b/Modules/AutoLayout/Provider/MarkdownProvider.cs new file mode 100644 index 00000000..64db7759 --- /dev/null +++ b/Modules/AutoLayout/Provider/MarkdownProvider.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading.Tasks; +using GenHTTP.Api.Content; +using GenHTTP.Api.Content.IO; +using GenHTTP.Api.Protocol; +using GenHTTP.Modules.Basics; +using GenHTTP.Modules.Markdown; + +namespace GenHTTP.Modules.AutoLayout.Provider +{ + + public class MarkdownProvider : IResourceHandlerProvider + { + + public bool Supports(IResource resource) => (resource.ContentType?.KnownType ?? resource.Name?.GuessContentType()) == ContentType.TextMarkdown; + + public ValueTask GetHandlerAsync(IResource resource) + { + return new(ModMarkdown.Page(resource)); + } + + } + +} diff --git a/Modules/AutoLayout/Provider/ScribanProvider.cs b/Modules/AutoLayout/Provider/ScribanProvider.cs new file mode 100644 index 00000000..f468a11e --- /dev/null +++ b/Modules/AutoLayout/Provider/ScribanProvider.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; + +using GenHTTP.Api.Content; +using GenHTTP.Api.Content.IO; +using GenHTTP.Api.Protocol; + +using GenHTTP.Modules.Basics; +using GenHTTP.Modules.Scriban; + +namespace GenHTTP.Modules.AutoLayout.Provider +{ + + public class ScribanProvider : IResourceHandlerProvider + { + + public bool Supports(IResource resource) => (resource.ContentType?.KnownType ?? resource.Name?.GuessContentType()) == ContentType.TextScriban; + + public ValueTask GetHandlerAsync(IResource resource) + { + return new(ModScriban.Page(resource)); + } + + } + +} diff --git a/Modules/AutoLayout/Resolvers.cs b/Modules/AutoLayout/Resolvers.cs new file mode 100644 index 00000000..e3aceade --- /dev/null +++ b/Modules/AutoLayout/Resolvers.cs @@ -0,0 +1,21 @@ +using GenHTTP.Modules.AutoLayout.Provider; +using GenHTTP.Modules.AutoLayout.Scanning; + +namespace GenHTTP.Modules.AutoLayout +{ + + public static class Resolvers + { + + public static HandlerRegistryBuilder Default() + { + return new HandlerRegistryBuilder().Fallback(new DownloadProvider()) + .Add(new MarkdownProvider()) + .Add(new ScribanProvider()); + } + + public static HandlerRegistryBuilder Empty() => new(); + + } + +} diff --git a/Modules/AutoLayout/Scanning/HandlerRegistry.cs b/Modules/AutoLayout/Scanning/HandlerRegistry.cs new file mode 100644 index 00000000..1becb258 --- /dev/null +++ b/Modules/AutoLayout/Scanning/HandlerRegistry.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +using GenHTTP.Api.Content; +using GenHTTP.Api.Content.IO; + +namespace GenHTTP.Modules.AutoLayout.Scanning +{ + + public class HandlerRegistry + { + + #region Get-/Setters + + public List Providers { get; } + + public IResourceHandlerProvider Fallback { get; } + + #endregion + + #region Initialization + + public HandlerRegistry(List providers, IResourceHandlerProvider fallback) + { + Providers = providers; + Fallback = fallback; + } + + #endregion + + #region Functionality + + public async ValueTask ResolveAsync(IResource resource) + { + foreach (var provider in Providers) + { + if (provider.Supports(resource)) + { + return await provider.GetHandlerAsync(resource); + } + } + + if (!Fallback.Supports(resource)) + { + throw new InvalidOperationException($"Fallback cannot handle resource '{resource.Name}'"); + } + + return await Fallback.GetHandlerAsync(resource); + } + + #endregion + + } + +} diff --git a/Modules/AutoLayout/Scanning/HandlerRegistryBuilder.cs b/Modules/AutoLayout/Scanning/HandlerRegistryBuilder.cs new file mode 100644 index 00000000..bf4e4d15 --- /dev/null +++ b/Modules/AutoLayout/Scanning/HandlerRegistryBuilder.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; + +using GenHTTP.Api.Infrastructure; + +namespace GenHTTP.Modules.AutoLayout.Scanning +{ + + public class HandlerRegistryBuilder : IBuilder + { + private readonly List _Providers = new(); + + private IResourceHandlerProvider? _Fallback; + + #region Functionality + + public HandlerRegistryBuilder Add(IResourceHandlerProvider provider) + { + _Providers.Add(provider); + return this; + } + + public HandlerRegistryBuilder Fallback(IResourceHandlerProvider provider) + { + _Fallback = provider; + return this; + } + + public HandlerRegistry Build() + { + return new HandlerRegistry(_Providers, _Fallback ?? throw new BuilderMissingPropertyException("fallback")); + } + + #endregion + + } + +} diff --git a/Modules/AutoLayout/Scanning/HandlerResolver.cs b/Modules/AutoLayout/Scanning/HandlerResolver.cs deleted file mode 100644 index 3bb8025d..00000000 --- a/Modules/AutoLayout/Scanning/HandlerResolver.cs +++ /dev/null @@ -1,26 +0,0 @@ -using GenHTTP.Api.Content; -using GenHTTP.Api.Content.IO; -using GenHTTP.Api.Protocol; - -using GenHTTP.Modules.Basics; -using GenHTTP.Modules.IO; - -namespace GenHTTP.Modules.AutoLayout.Scanning -{ - - public static class HandlerResolver - { - - public static IHandlerBuilder Resolve(IResource resource) - { - var type = resource.ContentType ?? FlexibleContentType.Get(resource.Name?.GuessContentType() ?? ContentType.ApplicationForceDownload); - - switch (type) - { - default: return Content.From(resource); - } - } - - } - -} diff --git a/Modules/AutoLayout/Scanning/TreeScanner.cs b/Modules/AutoLayout/Scanning/TreeScanner.cs index 0c721815..b5e50200 100644 --- a/Modules/AutoLayout/Scanning/TreeScanner.cs +++ b/Modules/AutoLayout/Scanning/TreeScanner.cs @@ -12,22 +12,25 @@ namespace GenHTTP.Modules.AutoLayout.Scanning public static class TreeScanner { - public static ValueTask ScanAsync(IResourceTree tree, params string[] indexNames) => ScanContainerAsync(tree, indexNames); + public static ValueTask ScanAsync(IResourceTree tree, HandlerRegistry registry, params string[] indexNames) + { + return ScanContainerAsync(tree, registry, indexNames); + } - private static async ValueTask ScanContainerAsync(IResourceContainer container, params string[] indexNames) + private static async ValueTask ScanContainerAsync(IResourceContainer container, HandlerRegistry registry, params string[] indexNames) { var layout = Layout.Create(); await foreach (var node in container.GetNodes()) { - layout.Add(node.Name, await ScanContainerAsync(node)); + layout.Add(node.Name, await ScanContainerAsync(node, registry)); } await foreach (var resource in container.GetResources()) { if (resource.Name is not null) { - var handler = HandlerResolver.Resolve(resource); + var handler = await registry.ResolveAsync(resource); var fileName = Path.GetFileNameWithoutExtension(resource.Name).ToLowerInvariant(); diff --git a/Modules/Basics/CoreExtensions.cs b/Modules/Basics/CoreExtensions.cs index 493607b0..17ece2e1 100644 --- a/Modules/Basics/CoreExtensions.cs +++ b/Modules/Basics/CoreExtensions.cs @@ -81,6 +81,15 @@ public static bool HasType(this IRequest request, params RequestMethod[] methods { "cfg", ContentType.TextPlain }, { "conf", ContentType.TextPlain }, { "config", ContentType.TextPlain }, + // Markdown + { "md", ContentType.TextMarkdown }, + // Scriban + { "scriban-html", ContentType.TextScriban }, + { "criban-htm", ContentType.TextScriban }, + { "sbn-html", ContentType.TextScriban }, + { "sbn-htm", ContentType.TextScriban }, + { "sbnhtml", ContentType.TextScriban }, + { "sbnhtm", ContentType.TextScriban }, // Fonts { "eot", ContentType.FontEmbeddedOpenTypeFont }, { "ttf", ContentType.FontTrueTypeFont },