Ejemplo n.º 1
0
        internal PluginFeatureInfo(Plugin plugin, Type featureType, PluginFeatureEntity pluginFeatureEntity, PluginFeatureAttribute?attribute)
        {
            Plugin      = plugin ?? throw new ArgumentNullException(nameof(plugin));
            FeatureType = featureType ?? throw new ArgumentNullException(nameof(featureType));
            Entity      = pluginFeatureEntity;

            Name          = attribute?.Name ?? featureType.Name.Humanize(LetterCasing.Title);
            Description   = attribute?.Description;
            Icon          = attribute?.Icon;
            AlwaysEnabled = attribute?.AlwaysEnabled ?? false;

            if (Icon != null)
            {
                return;
            }
            if (typeof(BaseDataModelExpansion).IsAssignableFrom(featureType))
            {
                Icon = "TableAdd";
            }
            else if (typeof(DeviceProvider).IsAssignableFrom(featureType))
            {
                Icon = "Devices";
            }
            else if (typeof(ProfileModule).IsAssignableFrom(featureType))
            {
                Icon = "VectorRectangle";
            }
            else if (typeof(Module).IsAssignableFrom(featureType))
            {
                Icon = "GearBox";
            }
            else if (typeof(LayerBrushProvider).IsAssignableFrom(featureType))
            {
                Icon = "Brush";
            }
            else if (typeof(LayerEffectProvider).IsAssignableFrom(featureType))
            {
                Icon = "AutoAwesome";
            }
            else
            {
                Icon = "Plugin";
            }
        }
Ejemplo n.º 2
0
        public Plugin LoadPlugin(DirectoryInfo directory)
        {
            _logger.Verbose("Loading plugin from {directory}", directory.FullName);

            // Load the metadata
            string metadataFile = Path.Combine(directory.FullName, "plugin.json");

            if (!File.Exists(metadataFile))
            {
                _logger.Warning(new ArtemisPluginException("Couldn't find the plugins metadata file at " + metadataFile), "Plugin exception");
            }

            // PluginInfo contains the ID which we need to move on
            PluginInfo pluginInfo = CoreJson.DeserializeObject <PluginInfo>(File.ReadAllText(metadataFile)) !;

            if (pluginInfo.Guid == Constants.CorePluginInfo.Guid)
            {
                throw new ArtemisPluginException($"Plugin {pluginInfo} cannot use reserved GUID {pluginInfo.Guid}");
            }

            lock (_plugins)
            {
                // Ensure the plugin is not already loaded
                if (_plugins.Any(p => p.Guid == pluginInfo.Guid))
                {
                    throw new ArtemisCoreException($"Cannot load plugin {pluginInfo} because it is using a GUID already used by another plugin");
                }
            }

            // Load the entity and fall back on creating a new one
            Plugin plugin = new(pluginInfo, directory, _pluginRepository.GetPluginByGuid(pluginInfo.Guid));

            OnPluginLoading(new PluginEventArgs(plugin));

            // Locate the main assembly entry
            string?mainFile = plugin.ResolveRelativePath(plugin.Info.Main);

            if (!File.Exists(mainFile))
            {
                throw new ArtemisPluginException(plugin, "Couldn't find the plugins main entry at " + mainFile);
            }
            FileInfo[] fileInfos = directory.GetFiles();
            if (!fileInfos.Any(f => string.Equals(f.Name, plugin.Info.Main, StringComparison.InvariantCulture)))
            {
                throw new ArtemisPluginException(plugin, "Plugin main entry casing mismatch at " + plugin.Info.Main);
            }

            // Load the plugin, all types implementing Plugin and register them with DI
            plugin.PluginLoader = PluginLoader.CreateFromAssemblyFile(mainFile !, configure =>
            {
                configure.IsUnloadable      = true;
                configure.LoadInMemory      = true;
                configure.PreferSharedTypes = true;
            });

            try
            {
                plugin.Assembly = plugin.PluginLoader.LoadDefaultAssembly();
            }
            catch (Exception e)
            {
                throw new ArtemisPluginException(plugin, "Failed to load the plugins assembly", e);
            }

            // Get the Plugin feature from the main assembly and if there is only one, instantiate it
            List <Type> featureTypes;

            try
            {
                featureTypes = plugin.Assembly.GetTypes().Where(t => typeof(PluginFeature).IsAssignableFrom(t)).ToList();
            }
            catch (ReflectionTypeLoadException e)
            {
                throw new ArtemisPluginException(
                          plugin,
                          "Failed to initialize the plugin assembly",
                          // ReSharper disable once RedundantEnumerableCastCall - Casting from nullable to non-nullable here
                          new AggregateException(e.LoaderExceptions.Where(le => le != null).Cast <Exception>().ToArray())
                          );
            }

            foreach (Type featureType in featureTypes)
            {
                // Load the enabled state and if not found, default to true
                PluginFeatureEntity featureEntity = plugin.Entity.Features.FirstOrDefault(i => i.Type == featureType.FullName) ??
                                                    new PluginFeatureEntity {
                    IsEnabled = plugin.Info.AutoEnableFeatures, Type = featureType.FullName !
                };
                plugin.AddFeature(new PluginFeatureInfo(plugin, featureType, featureEntity, (PluginFeatureAttribute?)Attribute.GetCustomAttribute(featureType, typeof(PluginFeatureAttribute))));
            }

            if (!featureTypes.Any())
            {
                _logger.Warning("Plugin {plugin} contains no features", plugin);
            }

            List <Type> bootstrappers = plugin.Assembly.GetTypes().Where(t => typeof(PluginBootstrapper).IsAssignableFrom(t)).ToList();

            if (bootstrappers.Count > 1)
            {
                _logger.Warning($"{plugin} has more than one bootstrapper, only initializing {bootstrappers.First().FullName}");
            }
            if (bootstrappers.Any())
            {
                plugin.Bootstrapper = (PluginBootstrapper?)Activator.CreateInstance(bootstrappers.First());
                plugin.Bootstrapper?.InternalOnPluginLoaded(plugin);
            }

            lock (_plugins)
            {
                _plugins.Add(plugin);
            }

            OnPluginLoaded(new PluginEventArgs(plugin));
            return(plugin);
        }