/* * Copyright (c) 2023 Vaughn Nugent * * Library: VNLib * Package: VNLib.Plugins.Runtime * File: PluginController.cs * * PluginController.cs is part of VNLib.Plugins.Runtime which is part of the larger * VNLib collection of libraries and utilities. * * VNLib.Plugins.Runtime is free software: you can redistribute it and/or modify * it under the terms of the GNU 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.Runtime 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VNLib.Plugins.Runtime. If not, see http://www.gnu.org/licenses/. */ using System; using System.Linq; using System.Text.Json; using System.Reflection; using System.Collections.Generic; using VNLib.Utils.Extensions; namespace VNLib.Plugins.Runtime { /// /// Manages the lifetime of a collection of instances, /// and their dependent event listeners /// public sealed class PluginController : IPluginEventRegistrar { private readonly List _plugins; private readonly List> _listeners; internal PluginController() { _plugins = new (); _listeners = new (); } /// /// The current collection of plugins. Valid before the unload event. /// public IEnumerable Plugins => _plugins; /// /// public void Register(IPluginEventListener listener, object? state = null) { _ = listener ?? throw new ArgumentNullException(nameof(listener)); _listeners.Add(new(listener, state)); } /// public bool Unregister(IPluginEventListener listener) { //Remove listener return _listeners.RemoveAll(p => p.Key == listener) > 0; } internal void InitializePlugins(Assembly asm) { //get all Iplugin types Type[] types = asm.GetTypes().Where(static type => !type.IsAbstract && typeof(IPlugin).IsAssignableFrom(type)).ToArray(); //Initialize the new plugin instances IPlugin[] plugins = types.Select(static t => (IPlugin)Activator.CreateInstance(t)!).ToArray(); //Crate new containers LivePlugin[] lps = plugins.Select(p => new LivePlugin(p, asm)).ToArray(); //Store containers _plugins.AddRange(lps); } internal void ConfigurePlugins(JsonDocument hostDom, JsonDocument pluginDom, string[] cliArgs) { _plugins.TryForeach(lp => lp.InitConfig(hostDom, pluginDom)); _plugins.TryForeach(lp => lp.InitLog(cliArgs)); } internal void LoadPlugins() { //Load all plugins _plugins.TryForeach(static p => p.LoadPlugin()); //Notify event handlers _listeners.TryForeach(l => l.Key.OnPluginLoaded(this, l.Value)); } internal void UnloadPlugins() { try { //Notify event handlers _listeners.TryForeach(l => l.Key.OnPluginUnloaded(this, l.Value)); //Unload plugin instances _plugins.TryForeach(static p => p.UnloadPlugin()); } finally { //Always _plugins.Clear(); } } internal void Dispose() { _plugins.Clear(); _listeners.Clear(); } } }