/* * Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials.ServiceStack * File: HttpServiceStackBuilder.cs * * HttpServiceStackBuilder.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; using VNLib.Net.Http; using VNLib.Plugins.Runtime; namespace VNLib.Plugins.Essentials.ServiceStack { /// /// A data structure used to build/create a /// around a /// public sealed class HttpServiceStackBuilder { /// /// Initializes a new that will /// generate servers to listen for services exposed by the /// specified host context /// public HttpServiceStackBuilder() { } private Action>? _hostBuilder; private Func? _getServers; private Func? _getPlugins; /// /// Uses the supplied callback to get a collection of virtual hosts /// to build the current domain with /// /// The callback method to build virtual hosts /// The current instance for chaining public HttpServiceStackBuilder WithDomain(Action> hostBuilder) { _hostBuilder = hostBuilder; return this; } /// /// Spcifies a callback function that builds instances from the hosts /// /// A callback method that gets the http server implementation for the service group /// The current instance for chaining public HttpServiceStackBuilder WithHttp(Func getServers) { _getServers = getServers; return this; } /// /// Enables the stack to support plugins /// /// The callback function that returns the plugin stack when requested /// The current instance for chaining public HttpServiceStackBuilder WithPluginStack(Func getStack) { _getPlugins = getStack; return this; } /// /// Configures the stack to use the built-in http server implementation /// /// The transport builder callback function /// The http configuration structure used to initalize servers /// The current instance for chaining public HttpServiceStackBuilder WithBuiltInHttp(Func transport, HttpConfig config) { return WithHttp(sg => new HttpServer(config, transport(sg), sg.Hosts.Select(static p => p.Processor))); } /// /// Configures the stack to use the built-in http server implementation /// /// The transport builder callback function /// The http configuration builder callback method /// The current instance for chaining public HttpServiceStackBuilder WithBuiltInHttp(Func transport, Func configCallback) { return WithHttp(sg => new HttpServer(configCallback(sg), transport(sg), sg.Hosts.Select(static p => p.Processor))); } /// /// Builds the new from the configured callbacks /// /// The newly constructed that may be used to manage your http services /// 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"); //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"); } LinkedList servers = new(); //enumerate hosts groups foreach (ServiceGroup hosts in sd.ServiceGroups) { //Create new server IHttpServer server = _getServers.Invoke(hosts); //Add server to internal list servers.AddLast(server); } //Only load plugins if the callback is configured IPluginStack? plugins = _getPlugins?.Invoke(); #pragma warning disable CA2000 // Dispose objects before losing scope plugins ??= new EmptyPluginStack(); #pragma warning restore CA2000 // Dispose objects before losing scope return new(servers, sd, plugins); } /* * An empty plugin stack that is used when the plugin callback is not configured */ private sealed class EmptyPluginStack : IPluginStack { public IReadOnlyCollection Plugins { get; } = Array.Empty(); public void BuildStack() { } public void Dispose() { } } } }