/// <inheritdoc /> public IPluginDescription ReflectPlugin(string pluginPath) { try { var archive = PluginArchive.OpenRead(pluginPath); var description = CreateDescription(archive); _archivesByPlugin.Add(description, archive); return(description); } catch (Exception e) { Log.ErrorFormat("Unable to load '{0}': {1}", pluginPath, e); string id; Version version; ExtractIdAndVersion(pluginPath, out id, out version); var description = new PluginDescription { Id = id, Version = version, Error = string.Format("The plugin couldn't be loaded: {0}", e.Message), Plugins = new Dictionary <Type, string>(), FilePath = pluginPath }; _archivesByPlugin.Add(description, new EmptyPluginArchive()); return(description); } }
private static IPluginDescription CreateDescription(PluginArchive archive) { var archiveIndex = archive.Index; Uri.TryCreate(archiveIndex.Website, UriKind.Absolute, out var website); var plugins = new Dictionary <Type, string>(); foreach (var pair in archiveIndex.ImplementedPluginInterfaces) { var pluginInterfaceType = typeof(IPlugin).Assembly.GetType(pair.InterfaceTypename); if (pluginInterfaceType != null) { plugins.Add(pluginInterfaceType, pair.ImplementationTypename); } else { Log.WarnFormat("Plugin implements unknown interface '{0}', skipping it...", pair.InterfaceTypename); } } var desc = new PluginDescription { Id = new PluginId(archiveIndex.Id), Name = archiveIndex.Name, Version = archiveIndex.Version, Icon = LoadIcon(archive.ReadIcon()), Author = archiveIndex.Author, Description = archiveIndex.Description, Website = website, Plugins = plugins }; return(desc); }
/// <summary> /// Loads the best version of the given plugin. /// </summary> public void Load() { Log.DebugFormat("Found {0} version(s) of plugin '{1}', finding compatible ones...", _pluginsByVersion.Count, _id); var compatiblePlugins = _pluginsByVersion.Where(x => !(x.Value.Archive is EmptyPluginArchive)) .Where(x => IsCompatible(x.Value.Archive.Index)) .OrderByDescending(x => x.Key) .Select(x => x.Value).ToList(); if (compatiblePlugins.Any()) { Log.DebugFormat("Found {0} compatible version(s) of plugin '{1}', loading newest...", _pluginsByVersion.Count, _id); // It's possible that despite our best efforts, the plugin with the highest version // refuses to be loaded (for example because it's broken, or the compatibility check might miss something). // If that's the case, we try to load earlier versions until we either find one that works or // give up... if (TryLoad(compatiblePlugins, out var loadedPlugin)) { _selectedPlugin = CreateDescription(loadedPlugin); _selectedPluginArchive = loadedPlugin.Archive; _status.IsLoaded = true; } else { _selectedPlugin = new PluginDescription { Id = _id, Error = "The plugin couldn't be loaded", PluginImplementations = new IPluginImplementationDescription[0] }; var plugin = compatiblePlugins.First(); //< Never empty: we have at least 1 plugin _selectedPlugin.FilePath = plugin.FilePath; _selectedPlugin.Version = plugin.Archive.Index.Version; _status.IsLoaded = false; } } else { Log.ErrorFormat("Found 0 compatible version(s) of plugin '{0}' (tried all {1} version(s) of this plugin)", _id, _pluginsByVersion.Count); _selectedPlugin = new PluginDescription { Id = _id, Error = "The plugin couldn\'t be loaded", PluginImplementations = new IPluginImplementationDescription[0] }; if (_pluginsByVersion.Any()) //< Might be empty { var plugin = _pluginsByVersion.Values.First(); _selectedPlugin.FilePath = plugin.FilePath; _selectedPlugin.Version = plugin.Archive.Index.Version; } _status.IsLoaded = false; } }
private static PluginDescription CreateDescription(Plugin plugin) { var archive = plugin.Archive; var archiveIndex = plugin.Archive.Index; Uri.TryCreate(archiveIndex.Website, UriKind.Absolute, out var website); var plugins = new List <IPluginImplementationDescription>(); foreach (var description in archiveIndex.ImplementedPluginInterfaces) { var pluginInterfaceType = ResolvePluginInterface(description); if (pluginInterfaceType != null) { plugins.Add(new PluginImplementationDescription(description) { InterfaceType = pluginInterfaceType }); } else { Log.WarnFormat("Plugin implements unknown interface '{0}', skipping it...", description.InterfaceTypename); } } var serializableTypes = new Dictionary <string, string>(); foreach (var pair in archiveIndex.SerializableTypes) { serializableTypes.Add(pair.Name, pair.FullName); } var changes = new List <Change>(); foreach (var serializableChange in archive.LoadChanges()) { changes.Add(new Change(serializableChange)); } var desc = new PluginDescription { Id = new PluginId(archiveIndex.Id), Name = archiveIndex.Name, Version = archiveIndex.Version, Icon = LoadIcon(plugin.Archive.ReadIcon()), FilePath = plugin.FilePath, Author = archiveIndex.Author, Description = archiveIndex.Description, Website = website, PluginImplementations = plugins, SerializableTypes = serializableTypes, Changes = changes, TailviewerApiVersion = archiveIndex.TailviewerApiVersion }; return(desc); }
private bool TryLoad(string filePath, out IPluginDescription description) { try { description = ReflectPlugin(filePath); return(true); } catch (FileLoadException e) { var error = string.Format("Unable to load plugin '{0}': {1}", filePath, e); Log.Error(error); description = new PluginDescription { FilePath = filePath, Error = error }; return(false); } catch (BadImageFormatException e) { var error = string.Format("Unable to load plugin '{0}' (plugins must be compiled against AnyCPU): {1}", filePath, e); Log.Error(error); description = new PluginDescription { FilePath = filePath, Error = error }; return(false); } catch (Exception e) { var error = string.Format("Caught unexpected exception while trying to load plugin '{0}': {1}", filePath, e); Log.Error(error); description = new PluginDescription { FilePath = filePath, Error = error }; return(false); } }