using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Artemis.Plugins.Exceptions; using Artemis.Plugins.Interfaces; using CSScriptLibrary; using Newtonsoft.Json; using Ninject; namespace Artemis.Plugins.Models { public class PluginInfo { private static Assembly _assembly; /// /// The name of the plugin /// public string Name { get; set; } /// /// The version of the plugin /// public string Version { get; set; } /// /// The file implementing IPlugin, loaded on startup /// public string Main { get; set; } /// /// The instantiated plugin, available after successful load /// [JsonIgnore] public IPlugin Plugin { get; set; } /// /// Full path to the plugin's current folder /// [JsonIgnore] public string Folder { get; set; } /// /// Unloads the plugin and clears the plugin info's internal data /// public void UnloadPlugin() { Plugin.UnloadPlugin(); _assembly = null; } /// /// Load a plugin from a folder /// /// The Ninject kernel to use for DI /// The folder in which plugin.json is located /// public static async Task FromFolder(IKernel kernel, string folder) { // Make sure the right engine is used CSScript.EvaluatorConfig.Engine = EvaluatorEngine.CodeDom; CSScript.EvaluatorConfig.DebugBuild = true; CSScript.GlobalSettings.SearchDirs = folder; if (!folder.EndsWith("\\")) folder += "\\"; if (!File.Exists(folder + "plugin.json")) throw new ArtemisPluginException(null, "Failed to load plugin, no plugin.json found in " + folder); var pluginInfo = JsonConvert.DeserializeObject(File.ReadAllText(folder + "plugin.json")); pluginInfo.Folder = folder; await pluginInfo.CompilePlugin(kernel); return pluginInfo; } /// /// Compiles the plugin's main CS file and any of it's includes and instantiates it. /// /// The Ninject kernel to use for DI public async Task CompilePlugin(IKernel kernel) { // Load the main script and get the type _assembly = await CSScript.Evaluator.CompileCodeAsync(File.ReadAllText(Folder + Main)); var pluginType = _assembly.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t)).ToList(); if (!pluginType.Any()) throw new ArtemisPluginException(this, "Failed to load plugin, no type found that implements IPlugin"); if (pluginType.Count > 1) throw new ArtemisPluginException(this, "Failed to load plugin, more than one type found that implements IPlugin"); // Instantiate the plugin with Ninject Plugin = (IPlugin) kernel.Get(pluginType.First()); Plugin.LoadPlugin(); } /// /// Gets the view model of the module accompanying the provided plugin info /// /// The Ninject kernel to use for DI /// public IModuleViewModel GetModuleViewModel(IKernel kernel) { // Don't attempt to locave VMs for something other than a module if (Plugin == null) throw new ArtemisPluginException(this, "Cannot locate a view model for this plugin because it's not compiled."); if (!(Plugin is IModule module)) throw new ArtemisPluginException(this, "Cannot locate a view model for this plugin as it's not a module."); // Get the type from the module var vmType = module.ViewModelType; if (!typeof(IModuleViewModel).IsAssignableFrom(vmType)) throw new ArtemisPluginException(this, "ViewModel must implement IModuleViewModel."); // Instantiate the ViewModel with Ninject var vm = (IModuleViewModel) kernel.Get(vmType); vm.PluginInfo = this; return vm; } } }