< Summary

Class:DCL.PluginSystem
Assembly:PluginSystem
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PluginSystem/PluginSystem.cs
Covered lines:61
Uncovered lines:15
Coverable lines:76
Total lines:226
Line coverage:80.2% (61 of 76)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
PluginSystem()0%110100%
PluginSystem()0%110100%
IsEnabled[T]()0%2.062075%
RegisterWithFlag[T](...)0%110100%
Register[T](...)0%220100%
Unregister[T]()0%5.935066.67%
Initialize()0%330100%
BindFlag[T](...)0%220100%
SetFlag(...)0%2.52050%
EnableFlag(...)0%330100%
DisableFlag(...)0%12300%
SetFeatureFlagsData(...)0%2.022083.33%
OnFeatureFlagsChange(...)0%220100%
Dispose()0%330100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/PluginSystem/PluginSystem.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using UnityEngine;
 4using UnityEngine.Assertions;
 5
 6namespace DCL
 7{
 8    public delegate IPlugin PluginBuilder();
 9
 10    /// <summary>
 11    /// This class implements a plugin system pattern described in:
 12    /// https://github.com/decentraland/adr/blob/main/docs/ADR-56-plugin-system.md
 13    ///
 14    /// - Many plugins can share the same feature flag
 15    /// - Plugins are registered by using a PluginBuilder delegate that must create and return the plugin instance.
 16    /// - Any active plugin is an instantiated plugin. A disabled plugin is a never created or disposed plugin.
 17    /// - No Initialize() pattern. Plugins abide to RAII idiom.
 18    /// - Feature flags can be set automatically by using SetFeatureFlagsData.
 19    /// </summary>
 20    public class PluginSystem : IDisposable
 21    {
 122        private static ILogger logger = new Logger(Debug.unityLogger);
 823        internal PluginGroup allPlugins = new PluginGroup();
 824        private Dictionary<string, PluginGroup> pluginGroupByFlag = new Dictionary<string, PluginGroup>();
 25        private BaseVariable<FeatureFlag> featureFlagsDataSource;
 26
 27        /// <summary>
 28        /// Returns true if the plugin defined by the PluginBuilder delegate is currently enabled.
 29        ///
 30        /// An enabled plugin is an instantiated and currently active plugin.
 31        /// </summary>
 32        /// <param name="pluginBuilder">The PluginBuilder delegate instance used to instance this plugin.</param>
 33        /// <returns>True if the plugin defined by the PluginBuilder delegate is currently enabled</returns>
 34        public bool IsEnabled<T>() where T : IPlugin
 35        {
 1436            Type type = typeof(T);
 1437            if (!allPlugins.plugins.ContainsKey(type))
 038                return false;
 39
 1440            return allPlugins.plugins[type].isEnabled;
 41        }
 42
 43        /// <summary>
 44        /// Registers a plugin builder and binds it to a feature flag.
 45        /// </summary>
 46        /// <param name="pluginBuilder">The builder used to construct the plugin.</param>
 47        /// <param name="featureFlag">The flag to be bounded. When this flag is true, the plugin will be created.</param
 48        public void RegisterWithFlag<T>(PluginBuilder pluginBuilder, string featureFlag) where T : IPlugin
 49        {
 850            Register<T>(pluginBuilder, false);
 851            BindFlag<T>(pluginBuilder, featureFlag);
 852        }
 53
 54        /// <summary>
 55        /// Registers a new plugin to be built by the PluginBuilder delegate.
 56        /// </summary>
 57        /// <param name="pluginBuilder">The pluginBuilder instance. This instance will create the plugin when enabled.</
 58        /// <param name="enable">If true, the plugin will be constructed as soon as this method is called.</param>
 59        public void Register<T>(PluginBuilder pluginBuilder, bool enable = true) where T : IPlugin
 60        {
 1161            Type type = typeof(T);
 1162            Assert.IsNotNull(pluginBuilder);
 63
 1164            PluginInfo pluginInfo = new PluginInfo() { builder = pluginBuilder };
 65
 1166            if (allPlugins.ContainsKey(type))
 67            {
 168                Unregister<T>();
 69            }
 70
 1171            allPlugins.Add(type, pluginInfo);
 72
 1173            pluginInfo.enableOnInit = enable;
 1174        }
 75
 76        /// <summary>
 77        /// Unregisters a registered plugin. If the plugin was active, it will be disposed.
 78        /// </summary>
 79        /// <param name="plugin">The plugin builder instance used to register the plugin.</param>
 80        public void Unregister<T>() where T : IPlugin
 81        {
 182            Type type = typeof(T);
 183            if ( !allPlugins.plugins.ContainsKey(type))
 084                return;
 85
 186            PluginInfo info = allPlugins.plugins[type];
 87
 188            string flag = info.flag;
 89
 190            if (flag != null)
 91            {
 092                if (pluginGroupByFlag.ContainsKey(flag))
 93                {
 094                    if (pluginGroupByFlag[flag].ContainsKey(type))
 95                    {
 096                        pluginGroupByFlag[flag].Remove(type);
 97                    }
 98                }
 99            }
 100
 1101            allPlugins.Remove(type);
 1102            info.Disable();
 1103        }
 104
 105        /// <summary>
 106        /// Initialize all enabled and registered plugin.
 107        /// </summary>
 108        public void Initialize()
 109        {
 22110            foreach ( var kvp in allPlugins.plugins )
 111            {
 8112                PluginInfo info = kvp.Value;
 8113                if (info.enableOnInit)
 2114                    info.Enable();
 115            }
 3116        }
 117
 118        /// <summary>
 119        /// Bind a feature flag to the given plugin builder.
 120        /// When the given feature flag is set to true, this class will construct the plugin, initializing it.
 121        /// </summary>
 122        /// <param name="plugin">The given plugin builder.</param>
 123        /// <param name="featureFlag">The given feature flag. If this feature flag is set to true the plugin will be cre
 124        public void BindFlag<T>(PluginBuilder plugin, string featureFlag) where T : IPlugin
 125        {
 8126            Type type = typeof(T);
 8127            Assert.IsNotNull(plugin);
 128
 8129            if ( !pluginGroupByFlag.ContainsKey(featureFlag) )
 4130                pluginGroupByFlag.Add(featureFlag, new PluginGroup());
 131
 8132            allPlugins.plugins[type].flag = featureFlag;
 8133            pluginGroupByFlag[featureFlag].Add(type, allPlugins.plugins[type]);
 8134        }
 135
 136        /// <summary>
 137        /// Sets a feature flag. Disabling or enabling any plugin that was bounded to it.
 138        /// </summary>
 139        /// <param name="featureFlag">The given feature flag to set.</param>
 140        /// <param name="enabled">The feature flag is enabled?</param>
 141        public void SetFlag(string featureFlag, bool enabled)
 142        {
 5143            if (enabled)
 5144                EnableFlag(featureFlag);
 145            else
 0146                DisableFlag(featureFlag);
 0147        }
 148
 149        /// <summary>
 150        /// Enables a given feature flag. This enables any plugin that was bounded to it.
 151        /// Enabling a plugin means that the plugin instance will be created.
 152        /// </summary>
 153        /// <param name="featureFlag">The feature flag to enable</param>
 154        public void EnableFlag(string featureFlag)
 155        {
 5156            if ( !pluginGroupByFlag.ContainsKey(featureFlag) )
 1157                return;
 158
 4159            PluginGroup pluginGroup = pluginGroupByFlag[featureFlag];
 160
 24161            foreach ( var feature in pluginGroup.plugins )
 162            {
 8163                PluginInfo info = feature.Value;
 8164                info.Enable();
 165            }
 4166        }
 167
 168        /// <summary>
 169        /// Disables a given feature flag. This disables any plugin that was bounded to it.
 170        /// Disabling a plugin means that the plugin instance will be disposed.
 171        /// </summary>
 172        /// <param name="featureFlag">The feature flag to enable</param>
 173        public void DisableFlag(string featureFlag)
 174        {
 0175            if ( !pluginGroupByFlag.ContainsKey(featureFlag) )
 0176                return;
 177
 0178            PluginGroup pluginGroup = pluginGroupByFlag[featureFlag];
 179
 0180            foreach ( var feature in pluginGroup.plugins )
 181            {
 0182                PluginInfo info = feature.Value;
 0183                info.Disable();
 184            }
 0185        }
 186
 187        /// <summary>
 188        /// Sets the FeatureFlag instance used to listen for feature flag changes.
 189        ///
 190        /// After setting the feature flags data of the given instance, the PluginSystem
 191        /// will react to all the feature flag changes.
 192        /// </summary>
 193        /// <param name="featureFlagsBaseVariable">The data object to listen to.</param>
 194        public void SetFeatureFlagsData(BaseVariable<FeatureFlag> featureFlagsBaseVariable)
 195        {
 4196            if ( featureFlagsDataSource != null )
 0197                featureFlagsDataSource.OnChange -= OnFeatureFlagsChange;
 198
 4199            featureFlagsDataSource = featureFlagsBaseVariable;
 4200            featureFlagsDataSource.OnChange += OnFeatureFlagsChange;
 4201            OnFeatureFlagsChange(featureFlagsBaseVariable.Get(), featureFlagsBaseVariable.Get());
 4202        }
 203
 204        private void OnFeatureFlagsChange(FeatureFlag current, FeatureFlag previous)
 205        {
 6206            Assert.IsNotNull(current, "Current feature flags object should never be null!");
 207
 22208            foreach ( var flag in current.flags )
 209            {
 5210                SetFlag(flag.Key, current.IsFeatureEnabled(flag.Key));
 211            }
 6212        }
 213
 214        public void Dispose()
 215        {
 36216            foreach ( var kvp in allPlugins.plugins )
 217            {
 10218                PluginInfo info = kvp.Value;
 10219                info.Disable();
 220            }
 221
 8222            if ( featureFlagsDataSource != null )
 4223                featureFlagsDataSource.OnChange -= OnFeatureFlagsChange;
 8224        }
 225    }
 226}