/* * Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: SessionProvider * File: SessionProviderEntry.cs * * SessionProviderEntry.cs is part of SessionProvider which is part of the larger * VNLib collection of libraries and utilities. * * SessionProvider 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 3 of the * License, or (at your option) any later version. * * SessionProvider 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.Threading; using System.Threading.Tasks; using System.Collections.Generic; using System.ComponentModel.Design; using VNLib.Net.Http; using VNLib.Utils; using VNLib.Utils.Logging; using VNLib.Plugins.Attributes; using VNLib.Plugins.Extensions.Loading; namespace VNLib.Plugins.Essentials.Sessions { /// /// The implementation type for dynamic loading of unified session providers /// public sealed class SessionProviderEntry : PluginBase { /// public override string PluginName => "Essentials.Sessions"; private SessionProvider _provider = new(); /* * Declare a service configuration method to * expose the session provider, the service container * will dispose the provider instance */ [ServiceConfigurator] public void ConfigureServices(IServiceContainer services) { //publish the service services.AddService(_provider); } protected override void OnLoad() { List providers = new(); Log.Verbose("Loading all specified session providers"); //Get all provider names IEnumerable providerAssemblyNames = PluginConfig.GetProperty("provider_assemblies") .EnumerateArray() .Where(s => s.GetString() != null) .Select(s => s.GetString()!); foreach (string asm in providerAssemblyNames) { Log.Verbose("Loading {dll} session provider", asm); try { //Attempt to load provider ISessionProvider prov = this.CreateServiceExternal(asm); //Add to list providers.Add(new(prov)); } catch (Exception ex) { Log.Error("Failed to load session provider {dll}:\n{error}", asm, ex); } } if (providers.Count > 0) { //Create array for searching for providers _provider = new(providers.ToArray()); Log.Information("Loaded {count} session providers", providers.Count); } else { Log.Information("No session providers loaded"); } Log.Information("Plugin loaded"); } protected override void OnUnLoad() { Log.Information("Plugin unloaded"); } protected override void ProcessHostCommand(string cmd) { if (!this.IsDebug()) { return; } } /* * When exposing the session provider as a service, it may be disposed by the * service container if its delcared as disposable. */ private sealed class SessionProvider : VnDisposeable, ISessionProvider, IDisposable { //Default to an empty array for default support even if no runtime providers are loaded private RuntimeSessionProvider[] ProviderArray = Array.Empty(); public SessionProvider(RuntimeSessionProvider[] loaded) { ProviderArray = loaded; } public SessionProvider() { } ValueTask ISessionProvider.GetSessionAsync(IHttpEvent entity, CancellationToken cancellationToken) { //Loop through providers for (int i = 0; i < ProviderArray.Length; i++) { //Check if provider can process the entity if (ProviderArray[i].CanProcess(entity)) { //Get session return ProviderArray[i].GetSessionAsync(entity, cancellationToken); } } //Return empty session return new (SessionHandle.Empty); } protected override void Free() { //Remove current providers so we can dispose them ProviderArray = Array.Empty(); } } } }