/* * Copyright (c) 2022 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Essentials.ServiceStack * File: ServiceGroup.cs * * ServiceGroup.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.Net; using System.Collections.Generic; using System.Runtime.CompilerServices; using VNLib.Utils.Extensions; using VNLib.Plugins.Runtime; using VNLib.Plugins.Essentials.Content; using VNLib.Plugins.Essentials.Sessions; namespace VNLib.Plugins.Essentials.ServiceStack { /// /// Represents a collection of virtual hosts that share a /// common transport (interface, port, and SSL status) /// and may be loaded by a single server instance. /// public sealed class ServiceGroup { private readonly LinkedList _vHosts; private readonly ConditionalWeakTable _endpointsForPlugins; /// /// The transport endpoint for all loaded service hosts /// public IPEndPoint ServiceEndpoint { get; } /// /// The collection of hosts that are loaded by this group /// public IReadOnlyCollection Hosts => _vHosts; /// /// Initalizes a new of virtual hosts /// with common transport /// /// The to listen for connections on /// The hosts that share a common interface endpoint public ServiceGroup(IPEndPoint serviceEndpoint, IEnumerable hosts) { _endpointsForPlugins = new(); _vHosts = new(hosts); ServiceEndpoint = serviceEndpoint; } /// /// Sets the specified page rotuer for all virtual hosts /// /// The page router to user internal void UpdatePageRouter(IPageRouter router) => _vHosts.TryForeach(v => v.Processor.SetPageRouter(router)); /// /// Sets the specified session provider for all virtual hosts /// /// The session provider to use internal void UpdateSessionProvider(ISessionProvider current) => _vHosts.TryForeach(v => v.Processor.SetSessionProvider(current)); /// /// Adds or updates all endpoints exported by all plugins /// within the specified loader. All endpoints exposed /// by a previously loaded instance are removed and all /// currently exposed endpoints are added to all virtual /// hosts /// /// The plugin loader to get add/update endpoints from internal void AddOrUpdateEndpointsForPlugin(RuntimePluginLoader loader) { //Get all new endpoints for plugin IEndpoint[] newEndpoints = loader.LivePlugins.SelectMany(static pl => pl.Plugin!.GetEndpoints()).ToArray(); //See if if(_endpointsForPlugins.TryGetValue(loader, out IEndpoint[]? oldEps)) { //Remove old endpoints _vHosts.TryForeach(v => v.Processor.RemoveEndpoint(oldEps)); } //Add endpoints to dict _endpointsForPlugins.AddOrUpdate(loader, newEndpoints); //Add endpoints to hosts _vHosts.TryForeach(v => v.Processor.AddEndpoint(newEndpoints)); } /// /// Unloads all previously stored endpoints, router, session provider, and /// clears all internal data structures /// internal void UnloadAll() { //Remove all loaded endpoints _vHosts.TryForeach(v => _endpointsForPlugins.TryForeach(eps => v.Processor.RemoveEndpoint(eps.Value))); //Remove all routers _vHosts.TryForeach(static v => v.Processor.SetPageRouter(null)); //Remove all session providers _vHosts.TryForeach(static v => v.Processor.SetSessionProvider(null)); //Clear all hosts _vHosts.Clear(); //Clear all endpoints _endpointsForPlugins.Clear(); } } }